Installing Python packages globally on a system can lead to version conflicts, dependency issues, and broken production environments. Virtual environments solve this by creating isolated Python installations for each project.
In this lab, you'll learn to:
- Create and activate virtual environments
- Install and manage packages with pip
- Export and recreate environments for reproducibility
- Use virtual environment interpreters without activation
- Configure scripts to run in specific environments
Prerequisites:
- Completed Lab 1.1 (Python Basics)
- SSH access to a Linux VM
- Python 3.3+ installed
# See where Python is installed
which python
# See globally installed packages
pip listWhat happens when you install packages globally:
# Install a package globally (DON'T do this in production!)
pip install requestsProblems with global installs:
- Project A needs
requests==2.28.0 - Project B needs
requests==2.31.0 - You can only have ONE version globally
- System tools might break if you upgrade their dependencies
- No reproducibility - different servers have different packages
The solution: Virtual environments!
# Create a project folder
mkdir ~/my-api-project
cd ~/my-api-project# Create a venv named 'venv'
python -m venv venvWhat this does:
- Creates a
venv/directory - Copies Python interpreter into
venv/bin/python - Creates isolated
site-packages/directory for packages - Includes pip and setuptools
# See what was created
ls -la venv/
# Check the structure
tree venv/ -L 2 # If tree is installed, otherwise use ls -RKey directories:
venv/bin/- Python interpreter and activation scriptsvenv/lib/python3.x/site-packages/- Where packages get installedvenv/include/- C header files for building packages
# Before activation - using system Python
which python
python --version# Activate (notice the dot or 'source' command)
source venv/bin/activateYou will need to give the current shell (no system wide changes) permissions to execute
Set-ExecutionPolicy RemoteSigned -Scope CurrentUser
.\venv\Scripts\Activate.ps1
(venv) PS C:\Users\blanc>You'll see your prompt change:
(venv) user@hostname:~/my-api-project$
The (venv) prefix shows you're in the virtual environment!
# After activation - using venv Python
which python
# Output: /home/user/my-api-project/venv/bin/python
python --versionNotice: The Python path changed! You're now using the isolated interpreter.
# List packages in this venv
pip listExpected output:
Package Version
---------- -------
pip XX.X.X
setuptools XX.X.X
Only base packages! Nothing from the global environment.
# Install the requests library
pip install requests# List all packages
pip list
# Show details about a specific package
pip show requestsOutput of pip show requests:
Name: requests
Version: 2.31.0
Location: /home/user/my-api-project/venv/lib/python3.x/site-packages
Requires: charset-normalizer, idna, urllib3, certifi
Notice the Location - it's in YOUR venv, not the global site-packages!
# Quick test
python -c "import requests; print(requests.__version__)"# Shows all installed packages with details
pip list
# Shows only what you explicitly installed (and their dependencies)
pip freezeKey difference:
pip list- human-readable, shows everythingpip freeze- machine-readable, perfect for requirements files
# Export all installed packages
pip freeze > requirements.txt
# View the file
cat requirements.txtExpected output:
certifi==2023.11.17
charset-normalizer==3.3.2
idna==3.6
requests==2.31.0
urllib3==2.1.0
This file lists exact versions - critical for reproducibility!
# Install additional packages
pip install python-dotenv
# Update requirements file
pip freeze > requirements.txt
# Check what changed
cat requirements.txtNow let's prove we can recreate this exact environment on another machine (or project).
# Exit the virtual environment
deactivateNotice: Your prompt returns to normal (no more (venv) prefix).
# Verify you're back to system Python
which python# Create a second project
mkdir ~/my-api-project-v2
cd ~/my-api-project-v2
# Create new venv
python -m venv venv
# Activate it
source venv/bin/activate# Should only have pip and setuptools
pip list# Copy requirements file from first project
cp ~/my-api-project/requirements.txt .
# Install everything at once
pip install -r requirements.txtWatch it install all the packages!
# Compare
pip freeze
# Should match the original requirements.txt exactly!
diff <(pip freeze) requirements.txtNo output from diff = identical environments!
Here's a powerful technique: You don't actually need to activate a venv to use it!
deactivate# Run Python from the venv without activating
~/my-api-project/venv/bin/python --version
# Test that packages work
~/my-api-project/venv/bin/python -c "import requests; print(requests.__version__)"It works! The venv's Python knows to look in its own site-packages.
cd ~/my-api-projectCreate test_requests.py:
import requests
response = requests.get('https://api.github.com')
print(f"Status Code: {response.status_code}")
print(f"Using requests version: {requests.__version__}")# Run with venv interpreter directly
./venv/bin/python test_requests.pyWhy this matters:
- Cron jobs can't activate environments
- CI/CD scripts can use direct paths
- System services need explicit interpreter paths
Create api_checker.py: (replace ec2-user if needed)
#!/home/ec2-user/my-api-project/venv/bin/python
import requests
import sys
def check_api(url):
try:
response = requests.get(url, timeout=5)
print(f"✓ {url} - Status: {response.status_code}")
return response.status_code
except Exception as e:
print(f"✗ {url} - Error: {e}")
return None
if __name__ == "__main__":
urls = [
"https://api.github.com",
"https://httpbin.org/get",
]
for url in urls:
check_api(url)# Add execute permission
chmod +x api_checker.py# Run it like a binary
./api_checker.pyWhat happened:
- Linux reads the shebang line (
#!/path/to/venv/bin/python) - Uses that interpreter to run the script
- That interpreter has access to the venv packages
- No activation needed!
Add these lines to the end of api_checker.py:
# Debug: Show which Python we're using
import sys
print(f"\nPython interpreter: {sys.executable}")Then run it:
./api_checker.pyYou'll see it's using the venv Python!
Docker containers use your requirements.txt file to install dependencies:
When building Docker images, you copy your requirements.txt into the container and install packages from it. The container itself provides isolation, so you don't need a virtual environment inside Docker. Your requirements.txt ensures every container has the exact same package versions.
GitHub Actions, Jenkins, GitLab CI all use requirements.txt:
CI/CD pipelines create fresh environments for every build. They typically:
- Set up Python
- Create a virtual environment
- Install dependencies from your
requirements.txt - Run tests or build artifacts
This ensures your tests run in a clean, reproducible environment every time.
You can create virtual environments from different Python versions:
# Different projects, different Python versions (FOR REFERENCE - don't run!)
python3.9 -m venv ~/project-a/venv
python3.11 -m venv ~/project-b/venv
python3.12 -m venv ~/project-c/venvNote: You likely only have one Python version installed right now. This example is just to show that if you had multiple Python versions on your system, you could create separate venvs for each. This is common in production environments where you need to maintain legacy applications alongside newer ones.
# Development
pip install requests flask pytest black
# Freeze it
pip freeze > requirements.txt
# Commit to git
git add requirements.txt
git commit -m "Add dependencies"Create .gitignore:
# Virtual environments
venv/
.venv/
env/
ENV/
# Python cache
__pycache__/
*.pyc
*.pyo
*.pyd
# IDEs
.vscode/
.idea/Never commit virtual environments to git! They're large, binary files, and platform-specific.
# Only show packages installed in this venv (excludes global)
pip freeze --local > requirements.txtCommon conventions:
venv/- most common.venv/- hidden folderenv/- shortervirtualenv/- explicit
Pick one and stick with it across all projects!
Your task: Create an RSS feed reader environment
- Create a new project:
~/rss-reader - Create and activate a venv
- Install these packages:
requests,beautifulsoup4,lxml - Find a website with an RSS feed (examples: news sites, blogs, tech sites)
- Check the site's
robots.txtfile to verify scraping is allowed - Create a script that fetches the RSS feed and displays article titles
- Export requirements.txt
- Create a second environment and reproduce it
- Make the script executable with a shebang
Important: Always check robots.txt before scraping:
- Look for
User-agent: *rules - Respect
Disallow:directives - Check for
Crawl-delay:requirements
Example RSS feeds to try:
https://news.ycombinator.com/rsshttps://www.reddit.com/r/python/.rss- Any blog with
/feedor/rssin the URL
Hints:
import requests
from bs4 import BeautifulSoup
# Fetch RSS feed
response = requests.get('YOUR_RSS_FEED_URL')
soup = BeautifulSoup(response.text, 'xml') # Note: 'xml' not 'lxml'
# Find all items
items = soup.find_all('item')
for item in items:
title = item.find('title').text
link = item.find('link').text
print(f"{title}\n{link}\n")You've completed this lab when you can:
- Create a virtual environment with
python -m venv - Activate and deactivate environments
- Install packages with pip
- Use
pip list,pip show, andpip freeze - Export dependencies to requirements.txt
- Recreate an environment from requirements.txt
- Run Python scripts using the venv interpreter without activation
- Create executable scripts with venv shebangs
- Understand when and why to use virtual environments
What you learned:
- Isolation - Each project has its own dependencies
- Reproducibility - requirements.txt ensures consistent environments
- Portability - Same environment on dev, staging, and production
- Version control - Multiple versions of the same package across projects
- Professional workflow - How real Python projects are managed
Why this matters:
- Every Python project in production uses virtual environments
- Docker images rely on requirements.txt
- CI/CD pipelines create fresh environments for each build
- Prevents "works on my machine" problems
- Makes debugging and collaboration easier
- Python venv Documentation
- pip User Guide
- Python Packaging Guide
- Real Python: Virtual Environments Primer
# Create venv
python -m venv venv
# Activate
source venv/bin/activate # Linux/Mac
venv\Scripts\activate # Windows
# Deactivate
deactivate
# Install packages
pip install requests
# Export dependencies
pip freeze > requirements.txt
# Install from requirements
pip install -r requirements.txt
# Use without activating
./venv/bin/python script.py
# Check what's installed
pip list
pip show package-nameCongratulations! You now understand Python virtual environments - a fundamental skill for professional Python development and DevOps work!