Introduction to requirements.txt Files
Welcome to our session on requirements.txt files! In Python development, effectively managing your project's dependencies is crucial for creating reproducible, shareable, and maintainable code. The requirements.txt file is a cornerstone of Python dependency management—a simple yet powerful tool that helps you specify exactly what packages your project needs.
Think of a requirements.txt file as a shopping list for your Python environment. Just as a detailed shopping list ensures you get exactly what you need at the grocery store—no more, no less—a well-crafted requirements.txt file ensures that anyone (including future you) can recreate your Python environment exactly as needed for your project to run successfully.
Today, we'll explore how to create, maintain, and leverage requirements.txt files effectively as part of your Python development workflow. Whether you're working on solo projects or collaborating in large teams, mastering this aspect of dependency management will save you countless hours of troubleshooting and help you create more professional, distributable Python applications.
Why Use requirements.txt Files?
Before diving into the technical details, let's understand why requirements.txt files are so important in Python projects:
1. Environment Reproducibility
One of the most challenging aspects of software development is ensuring that code works consistently across different environments. A requirements.txt file serves as a precise record of your dependencies, allowing anyone to recreate your environment exactly.
Real-World Scenario: Imagine deploying your application to a production server, only to discover it breaks because the server has different package versions installed. With a requirements.txt file, you can ensure the production environment has exactly the same dependencies as your development environment.
2. Collaboration Facilitation
When working in teams, having a standardized way to manage dependencies is essential for smooth collaboration.
Real-World Scenario: A new developer joins your team and needs to set up the project environment. Instead of asking them to manually install each dependency or providing a lengthy setup document, you can simply direct them to run pip install -r requirements.txt.
3. Version Control Integration
Requirements files are typically plain text and small in size, making them perfect for version control systems like Git.
Real-World Scenario: When you add a new feature that requires a new dependency, committing the updated requirements.txt file allows other team members to see exactly what changed in the dependency landscape.
4. Deployment Automation
Modern deployment pipelines often automatically install dependencies from requirements.txt during the build process.
Real-World Scenario: CI/CD pipelines like GitHub Actions, GitLab CI, or Jenkins can automatically install requirements, run tests, and deploy your application—all using your requirements.txt file to ensure consistent environments.
5. Dependency Documentation
A requirements.txt file serves as documentation of what packages your project depends on, making it easier for others to understand your project's external needs.
Real-World Scenario: When evaluating an open-source project, developers often check the requirements.txt file first to understand what technologies the project uses and whether it might have security concerns or conflicts with their existing environment.
Real-World Analogy: Think of a requirements.txt file as a recipe. A good recipe doesn't just list ingredients—it specifies exact amounts. Similarly, a good requirements.txt doesn't just list packages—it specifies exact versions to ensure consistent results every time.
Basic Usage of requirements.txt
Creating a requirements.txt File
There are several ways to create a requirements.txt file:
Method 1: Manual Creation
You can create a requirements.txt file manually by listing each package on a separate line:
# requirements.txt
flask
requests
numpy
pandas
Method 2: Using pip freeze
The more common approach is to let pip generate the file based on your current environment:
# Generate requirements.txt from your current environment
pip freeze > requirements.txt
This command captures all installed packages and their exact versions:
# requirements.txt generated by pip freeze
flask==2.0.1
requests==2.26.0
numpy==1.21.2
pandas==1.3.3
# ... potentially many more dependencies
Installing Dependencies from requirements.txt
Once you have a requirements.txt file, others can recreate your environment:
# Install all packages listed in requirements.txt
pip install -r requirements.txt
Updating a requirements.txt File
When you add or update dependencies, you should update your requirements.txt file:
# Install a new package
pip install matplotlib
# Update requirements.txt with the new dependency
pip freeze > requirements.txt
Basic Syntax and Options
A requirements.txt file has a simple syntax, but offers several options:
Package Names Only
flask
requests
numpy
Specifying Exact Versions
flask==2.0.1
requests==2.26.0
numpy==1.21.2
Specifying Minimum Versions
flask>=2.0.0
requests>=2.25.0
numpy>=1.20.0
Specifying Version Ranges
flask>=2.0.0,<3.0.0
requests>=2.25.0,<2.27.0
numpy>=1.20.0,<1.22.0
Installing from Version Control
flask==2.0.1
git+https://github.com/psf/requests.git@v2.26.0
numpy==1.21.2
Including Comments
# Web framework
flask==2.0.1
# HTTP library for API requests
requests==2.26.0
# Numerical computing
numpy==1.21.2
Using Environment Markers
flask==2.0.1
requests==2.26.0
numpy==1.21.2
pywin32==301; sys_platform == 'win32'
Best Practices for requirements.txt Files
1. Pin Your Versions
Always specify exact versions of packages to ensure reproducibility.
# Not recommended
flask
requests
numpy
# Recommended
flask==2.0.1
requests==2.26.0
numpy==1.21.2
Explanation: Without version pinning, pip will install the latest available version of each package, which might introduce breaking changes over time. Pinning ensures everyone gets exactly the same versions you tested with.
2. Be Selective About What You Include
Only include direct dependencies, not every package in your environment.
Problem with pip freeze: It includes everything in your environment, including packages you might not need for your project. For example, if you've installed Jupyter Notebook globally, it doesn't mean your web application depends on it.
Consider maintaining your requirements manually or using tools like pip-tools (discussed later).
3. Organize with Comments
Use comments to organize and explain dependencies.
# Web Framework
flask==2.0.1
flask-wtf==1.0.0
flask-sqlalchemy==2.5.1
# Data Processing
numpy==1.21.2
pandas==1.3.3
matplotlib==3.4.3
# Testing - not required for production
pytest==6.2.5
pytest-cov==2.12.1
4. Split Requirements by Environment
For larger projects, consider separating requirements by environment:
Project structure:
requirements/
├── base.txt # Core dependencies used in all environments
├── development.txt # Development-specific packages
├── production.txt # Production-specific packages
└── testing.txt # Testing-specific packages
Example of requirements/base.txt:
# Core dependencies
flask==2.0.1
sqlalchemy==1.4.25
requests==2.26.0
Example of requirements/development.txt:
# Include base requirements
-r base.txt
# Development tools
flask-debugtoolbar==0.11.0
ipython==7.27.0
black==21.8b0
flake8==3.9.2
Example of requirements/production.txt:
# Include base requirements
-r base.txt
# Production-specific packages
gunicorn==20.1.0
sentry-sdk==1.3.1
Example of requirements/testing.txt:
# Include base requirements
-r base.txt
# Testing tools
pytest==6.2.5
pytest-cov==2.12.1
coverage==5.5
Usage:
# For development
pip install -r requirements/development.txt
# For production
pip install -r requirements/production.txt
# For testing
pip install -r requirements/testing.txt
5. Include a Header Comment
Add documentation at the top of your requirements file:
# Requirements for MyProject
# Python 3.9+
# Generated on 2023-05-15
# Usage: pip install -r requirements.txt
flask==2.0.1
# ... more packages ...
6. Check in Requirements to Version Control
Always commit your requirements.txt file(s) to your version control system. This allows others to reproducibly set up the project and provides a history of dependency changes.
7. Regularly Update and Audit Dependencies
Periodically review your dependencies for updates, especially security patches.
# Check for outdated packages
pip list --outdated
# Use safety to check for security vulnerabilities
pip install safety
safety check -r requirements.txt
Advanced Techniques for Dependency Management
1. Using pip-tools
pip-tools provides a more sophisticated approach to dependency management, separating direct dependencies from the complete dependency tree.
Installation:
pip install pip-tools
Create a requirements.in file with your direct dependencies:
# requirements.in - Direct dependencies only
flask>=2.0.0
requests>=2.25.0
numpy>=1.20.0
Compile it to a pinned requirements.txt:
pip-compile requirements.in
This generates a requirements.txt with all dependencies (including sub-dependencies) pinned:
# requirements.txt
#
# This file is autogenerated by pip-compile
# To update, run:
#
# pip-compile requirements.in
#
click==8.0.1
# via flask
flask==2.0.1
# via -r requirements.in
itsdangerous==2.0.1
# via flask
jinja2==3.0.1
# via flask
markupsafe==2.0.1
# via jinja2
numpy==1.21.2
# via -r requirements.in
requests==2.26.0
# via -r requirements.in
werkzeug==2.0.1
# via flask
Upgrading dependencies:
# Upgrade all packages
pip-compile --upgrade requirements.in
# Upgrade specific packages
pip-compile --upgrade-package flask requirements.in
# Install the compiled requirements
pip-sync requirements.txt
2. Using constraints.txt
A constraints.txt file allows you to constrain versions without declaring dependencies.
# constraints.txt
flask==2.0.1
werkzeug==2.0.1
Usage:
# Install dependencies with constraints
pip install -r requirements.txt -c constraints.txt
This is particularly useful when you need to ensure specific versions of transitive dependencies (dependencies of your dependencies).
3. Using Hash Verification
For enhanced security, you can include hash values for packages:
flask==2.0.1 --hash=sha256:7b2fb8e039275d1d88d09fdf6bd64319f1f3e6c4a82178e18a0a0b70a2f7883b
requests==2.26.0 --hash=sha256:6c1246513ecd5ecd4528a0906f910e8f0f9c6b8ec72030dc9fd154dc1a6efd24
Generate requirements with hashes:
pip-compile --generate-hashes requirements.in
Install with hash verification:
pip install --require-hashes -r requirements.txt
This ensures the integrity of packages during installation, preventing supply-chain attacks.
4. Using setup.py with install_requires
For Python packages (not just applications), you can specify dependencies in setup.py:
from setuptools import setup, find_packages
setup(
name="mypackage",
version="0.1.0",
packages=find_packages(),
install_requires=[
"flask>=2.0.0,<3.0.0",
"requests>=2.25.0",
"numpy>=1.20.0",
],
extras_require={
"dev": [
"pytest>=6.0.0",
"black>=21.5b2",
],
"docs": [
"sphinx>=4.0.0",
],
},
)
You can then generate a requirements.txt from setup.py:
pip install -e .
pip freeze > requirements.txt
5. Using pyproject.toml (Poetry or Pipenv)
Modern Python projects often use tools like Poetry or Pipenv with pyproject.toml:
Poetry example (pyproject.toml):
[tool.poetry]
name = "myproject"
version = "0.1.0"
description = "My Python Project"
authors = ["Your Name "]
[tool.poetry.dependencies]
python = "^3.9"
flask = "^2.0.1"
requests = "^2.26.0"
numpy = "^1.21.2"
[tool.poetry.dev-dependencies]
pytest = "^6.2.5"
black = "^21.8b0"
[build-system]
requires = ["poetry-core>=1.0.0"]
build-backend = "poetry.core.masonry.api"
Generate requirements.txt from Poetry:
poetry export -f requirements.txt --output requirements.txt
Pipenv example (Pipfile):
[[source]]
url = "https://pypi.org/simple"
verify_ssl = true
name = "pypi"
[packages]
flask = "==2.0.1"
requests = "==2.26.0"
numpy = "==1.21.2"
[dev-packages]
pytest = "==6.2.5"
black = "==21.8b0"
[requires]
python_version = "3.9"
Generate requirements.txt from Pipenv:
pipenv lock -r > requirements.txt
Common Issues and Solutions
Issue 1: Sub-dependencies Conflicts
Problem: Two packages require different versions of the same dependency.
Example: PackageA requires requests==2.25.0, but PackageB requires requests==2.26.0.
Solutions:
- Use constraints: Specify exact versions in constraints.txt
- Try compatible versions: Test if both packages work with either version
- Use virtual environments: Create separate environments for conflicting packages
- Contact maintainers: Report the issue to package maintainers
Issue 2: Platform-Specific Packages
Problem: Some packages are only needed on specific platforms.
Example: You need pywin32 on Windows, but not on Linux or macOS.
Solutions:
- Use environment markers:
pywin32==301; sys_platform == 'win32' pyobjc-core==7.3; sys_platform == 'darwin' - Split requirements by platform:
# requirements_windows.txt -r requirements.txt pywin32==301
Issue 3: pip freeze Includes Too Many Packages
Problem: pip freeze outputs all installed packages, not just direct dependencies.
Solutions:
- Use a clean virtual environment: Create a new environment and install only the packages you need
- Use pip-tools: Maintain a requirements.in file with direct dependencies
- Manually curate: Maintain requirements.txt by hand, only adding packages you explicitly install
- Use pipdeptree: Visualize dependencies to identify direct ones:
pip install pipdeptree pipdeptree --packages flask
Issue 4: Version Conflicts During Installation
Problem: pip install -r requirements.txt fails with dependency conflicts.
Solutions:
- Install packages in order: List the most constrained packages first
- Use --no-dependencies: Install packages without their dependencies, then resolve manually
- Use constraints: Specify compatible versions with constraints.txt
- Use pip-tools: pip-compile can resolve dependencies more effectively
Issue 5: Outdated Requirements
Problem: Requirements.txt contains outdated or vulnerable packages.
Solutions:
- Regular audits: Check for outdated packages:
pip list --outdated - Security scanning: Check for vulnerabilities:
pip install safety safety check -r requirements.txt - Automated updates: Use tools like Dependabot, PyUp, or pip-upgrader
Real-World Scenario: Managing Dependencies in a Flask Web Application
Let's walk through a practical example of managing dependencies for a Flask web application project.
Project Structure
flask_project/
├── .gitignore
├── README.md
├── requirements/
│ ├── base.txt
│ ├── development.txt
│ ├── production.txt
│ └── testing.txt
├── app/
│ ├── __init__.py
│ ├── models.py
│ ├── routes.py
│ ├── templates/
│ └── static/
├── config.py
├── run.py
└── tests/
Initial Dependency Setup
Create a virtual environment and install the base packages:
# Create and activate virtual environment
python -m venv venv
source venv/bin/activate # On Windows: venv\Scripts\activate
# Install initial packages
pip install flask flask-sqlalchemy flask-wtf pytest
Creating Base Requirements
Create requirements/base.txt with core dependencies:
# Base requirements for Flask Project
# Python 3.9+
# Web Framework
flask==2.0.1
# Database
flask-sqlalchemy==2.5.1
sqlalchemy==1.4.25
# Forms
flask-wtf==1.0.0
wtforms==2.3.3
# Security
flask-login==0.5.0
# API
flask-restful==0.3.9
Creating Environment-Specific Requirements
Create environment-specific requirements files that include the base requirements:
requirements/development.txt:
# Development requirements for Flask Project
# Includes base requirements
-r base.txt
# Debugging
flask-debugtoolbar==0.11.0
# Code Quality
black==21.8b0
flake8==3.9.2
# Development Server
watchdog==2.1.5
# Development Database
# SQLite is included in Python standard library
requirements/testing.txt:
# Testing requirements for Flask Project
# Includes base requirements
-r base.txt
# Testing
pytest==6.2.5
pytest-cov==2.12.1
pytest-flask==1.2.0
# Mocking
faker==8.13.2
requirements/production.txt:
# Production requirements for Flask Project
# Includes base requirements
-r base.txt
# WSGI Server
gunicorn==20.1.0
# Monitoring and Logging
sentry-sdk==1.3.1
# Performance
flask-caching==1.10.1
Working with Different Environments
Install dependencies for specific environments:
# For development
pip install -r requirements/development.txt
# For testing
pip install -r requirements/testing.txt
# For production
pip install -r requirements/production.txt
Adding New Dependencies
When adding a new dependency, determine which environment it belongs to:
# Install a new package (e.g., for file uploads)
pip install flask-uploads
# Add it to base.txt
echo "flask-uploads==0.2.1 # For file uploads" >> requirements/base.txt
Updating Dependencies
Periodically update dependencies to get security fixes and improvements:
# Check for outdated packages
pip list --outdated
# Update a specific package
pip install --upgrade flask-sqlalchemy
# Update base.txt with new version
# Edit requirements/base.txt to update the version
# Or use pip-tools for more controlled updates
pip install pip-tools
pip-compile --upgrade-package flask-sqlalchemy requirements/base.in
Handling Security Vulnerabilities
Check for security vulnerabilities in your dependencies:
# Check for security vulnerabilities
pip install safety
safety check -r requirements/base.txt
If vulnerabilities are found, update the affected packages to secure versions.
CI/CD Pipeline
Integrate dependency management into your CI/CD pipeline:
# .github/workflows/python-test.yml
name: Python Tests
on:
push:
branches: [ main ]
pull_request:
branches: [ main ]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Set up Python
uses: actions/setup-python@v2
with:
python-version: '3.9'
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install -r requirements/testing.txt
- name: Check for security vulnerabilities
run: |
pip install safety
safety check -r requirements/base.txt
- name: Run tests
run: |
pytest --cov=app
Deployment
When deploying to production, use the production requirements:
# On production server
git clone https://github.com/username/flask_project.git
cd flask_project
python -m venv venv
source venv/bin/activate
pip install -r requirements/production.txt
# Start the application with gunicorn
gunicorn wsgi:app
Development Workflow with requirements.txt
Here's a comprehensive workflow for managing dependencies in a Python project:
1. Project Initialization
- Create a virtual environment:
python -m venv venv source venv/bin/activate # On Windows: venv\Scripts\activate - Create requirements structure:
mkdir -p requirements - Install initial dependencies:
pip install flask flask-sqlalchemy - Generate initial requirements:
pip freeze > requirements/base.txt - Create environment-specific files:
echo "-r base.txt" > requirements/development.txt echo "-r base.txt" > requirements/production.txt echo "-r base.txt" > requirements/testing.txt - Add additional environment-specific packages:
pip install black pytest echo "black==21.8b0 # Code formatting" >> requirements/development.txt echo "pytest==6.2.5 # Testing framework" >> requirements/testing.txt
2. Daily Development Workflow
- Activate virtual environment:
source venv/bin/activate # On Windows: venv\Scripts\activate - Install dependencies for your work:
# For development pip install -r requirements/development.txt # For testing pip install -r requirements/testing.txt - When adding a new dependency:
# Install the package pip install new-package # Add to appropriate requirements file echo "new-package==1.0.0 # Purpose of this package" >> requirements/base.txt - Before committing:
# Check for outdated packages pip list --outdated # Check for security vulnerabilities safety check -r requirements/base.txt
3. Collaboration Workflow
- When pulling changes with new dependencies:
git pull pip install -r requirements/development.txt - When dependency conflicts arise:
# Create a new virtual environment to test python -m venv test_env source test_env/bin/activate pip install -r requirements/development.txt - If changes to dependencies are needed, discuss with team and update requirements files accordingly.
4. Deployment Workflow
- Prepare for deployment:
# Ensure production requirements are up to date python -m pip install -r requirements/production.txt # Test with production settings python run.py --prod - Deploy to production:
# On production server pip install -r requirements/production.txt - Monitor for dependency issues:
# Set up alerts for security vulnerabilities # Integrate with security scanning tools
5. Maintenance Workflow
- Regular dependency updates:
# Schedule regular reviews (e.g., monthly) pip list --outdated pip install --upgrade flask # Update version in requirements file - Security patching:
# Subscribe to security alerts # Promptly update vulnerable packages - Removing unused dependencies:
# Periodically review and remove unused packages # Update requirements files accordingly
Advanced Tools for Dependency Management
Beyond basic requirements.txt files, several advanced tools can enhance your dependency management:
1. pip-tools
We mentioned pip-tools earlier, but it deserves more explanation:
# Install pip-tools
pip install pip-tools
# Create a requirements.in file
flask
sqlalchemy
requests
# Compile to requirements.txt with pinned versions
pip-compile
# Install dependencies
pip-sync
Key Features:
- Separates direct dependencies (requirements.in) from full dependency tree (requirements.txt)
- Automatically resolves dependencies
- Precise control over updates
- Support for multiple requirements files
- Hash generation for verifiable builds
2. Poetry
Poetry is a modern dependency management tool that replaces pip, virtualenv, and other tools:
# Install Poetry
pip install poetry
# Initialize a new project
poetry new myproject
cd myproject
# Add dependencies
poetry add flask sqlalchemy
# Add development dependencies
poetry add --dev pytest black
# Install dependencies
poetry install
# Export to requirements.txt
poetry export -f requirements.txt --output requirements.txt
Key Features:
- Project metadata and dependencies in one file (pyproject.toml)
- Built-in virtual environment management
- Dependency resolution
- Publishing to PyPI
- Lock file for deterministic builds
3. Pipenv
Pipenv combines pip and virtualenv with a lockfile mechanism:
# Install Pipenv
pip install pipenv
# Initialize a project
mkdir myproject
cd myproject
# Install packages
pipenv install flask sqlalchemy
# Install development packages
pipenv install --dev pytest black
# Create a virtual environment and install dependencies
pipenv install
# Export to requirements.txt
pipenv lock -r > requirements.txt
Key Features:
- Pipfile and Pipfile.lock for dependency tracking
- Integrated virtual environment management
- Security vulnerability checking
- Environment variable management
- Dependency graphing
4. conda
For scientific computing and data science, conda offers advanced dependency management:
# Create a conda environment with dependencies
conda create -n myenv python=3.9 numpy pandas matplotlib
# Export to environment.yml
conda env export > environment.yml
# Create environment from environment.yml
conda env create -f environment.yml
Key Features:
- Handles non-Python dependencies (e.g., C libraries)
- Cross-platform binary packages
- Separate channel system for packages
- Environment management
- Integration with pip for Python-specific packages
5. pip-audit
pip-audit is a tool for auditing Python dependencies for security vulnerabilities:
# Install pip-audit
pip install pip-audit
# Audit installed packages
pip-audit
# Audit requirements file
pip-audit -r requirements.txt
Key Features:
- Checks dependencies against vulnerability databases
- Integration with CI/CD pipelines
- Support for various output formats
- Customizable vulnerability handling
6. pip-review
pip-review helps you keep your packages up-to-date:
# Install pip-review
pip install pip-review
# Check for updates
pip-review
# Update all packages
pip-review --auto
# Update specific packages
pip-review --interactive
Key Features:
- Interactive updates
- Selective package updating
- Simple interface
Comparison of Tools
| Tool | Best For | Learning Curve | Compatibility |
|---|---|---|---|
| requirements.txt | Simple projects, compatibility | Low | Universal |
| pip-tools | Medium projects, better dependency resolution | Low-Medium | Compatible with requirements.txt |
| Poetry | Modern projects, library development | Medium | Can export to requirements.txt |
| Pipenv | Application development | Medium | Can export to requirements.txt |
| conda | Scientific computing, complex dependencies | Medium-High | Works alongside pip |
Exercise: Requirements.txt Management for a Web Application
Let's apply what we've learned with a practical exercise:
Exercise: Create a Requirements Structure for a Web Application
Scenario: You're starting a new Flask web application that will have these features:
- Web interface with forms and templates
- Database integration with SQLAlchemy
- User authentication
- RESTful API
- Background task processing with Celery
Tasks:
- Create a virtual environment for the project
- Create a directory structure with separate requirements files for different environments
- Populate the requirements files with appropriate packages
- Create a script to install dependencies for different environments
- Add security checking to ensure dependencies are up-to-date and secure
Step 1: Project Setup
# Create project directory
mkdir flask_project
cd flask_project
# Create virtual environment
python -m venv venv
source venv/bin/activate # On Windows: venv\Scripts\activate
# Create directory structure
mkdir -p requirements app/templates app/static tests
Step 2: Create Requirements Files
Create these files in the requirements directory:
requirements/base.txt:
# Base requirements for Flask Web Application
# Python 3.9+
# Web Framework
flask==2.0.1
# Database
flask-sqlalchemy==2.5.1
sqlalchemy==1.4.25
alembic==1.7.3
flask-migrate==3.1.0
# Forms
flask-wtf==1.0.0
wtforms==2.3.3
# Authentication
flask-login==0.5.0
flask-bcrypt==0.7.1
# API
flask-restful==0.3.9
marshmallow==3.13.0
# Background Tasks
celery==5.1.2
redis==3.5.3
# Utilities
python-dotenv==0.19.0
requirements/development.txt:
# Development requirements
-r base.txt
# Debugging
flask-debugtoolbar==0.11.0
# Code Quality
black==21.8b0
flake8==3.9.2
isort==5.9.3
# Documentation
sphinx==4.2.0
# Development Server
watchdog==2.1.5
# REPL
ipython==7.27.0
requirements/testing.txt:
# Testing requirements
-r base.txt
# Testing
pytest==6.2.5
pytest-cov==2.12.1
pytest-flask==1.2.0
pytest-sugar==0.9.4
# Mocking
faker==8.13.2
factory-boy==3.2.0
requirements/production.txt:
# Production requirements
-r base.txt
# WSGI Server
gunicorn==20.1.0
# Performance
flask-caching==1.10.1
# Monitoring and Logging
sentry-sdk[flask]==1.3.1
prometheus-flask-exporter==0.18.2
Step 3: Create Installation Script
Create a script to help with dependency installation:
scripts/install_deps.sh:
#!/bin/bash
# Script to install dependencies for different environments
# Check if virtual environment is activated
if [[ "$VIRTUAL_ENV" == "" ]]; then
echo "Virtual environment not activated. Please activate it first."
echo "Run: source venv/bin/activate"
exit 1
fi
# Process command line arguments
ENV=${1:-development}
case $ENV in
development|dev)
REQUIREMENTS="requirements/development.txt"
;;
testing|test)
REQUIREMENTS="requirements/testing.txt"
;;
production|prod)
REQUIREMENTS="requirements/production.txt"
;;
*)
echo "Unknown environment: $ENV"
echo "Usage: $0 [development|testing|production]"
exit 1
;;
esac
echo "Installing dependencies for $ENV environment..."
pip install -r $REQUIREMENTS
# Check for security vulnerabilities
echo "Checking for security vulnerabilities..."
pip install safety
safety check -r $REQUIREMENTS
echo "Done!"
Make the script executable:
chmod +x scripts/install_deps.sh
Step 4: Create a Project Initialization Script
scripts/setup_project.sh:
#!/bin/bash
# Script to set up a new project environment
# Create virtual environment if it doesn't exist
if [ ! -d "venv" ]; then
echo "Creating virtual environment..."
python -m venv venv
fi
# Activate virtual environment
source venv/bin/activate
# Install dependencies
./scripts/install_deps.sh development
# Initialize git repository if it doesn't exist
if [ ! -d ".git" ]; then
echo "Initializing git repository..."
git init
# Create .gitignore
echo "Creating .gitignore..."
cat > .gitignore << EOL
# Python
__pycache__/
*.py[cod]
*$py.class
*.so
.Python
venv/
ENV/
env/
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
wheels/
*.egg-info/
.installed.cfg
*.egg
# Flask
instance/
.webassets-cache
# Celery
celerybeat-schedule
celerybeat.pid
# Testing
.coverage
htmlcov/
.pytest_cache/
# IDE
.idea/
.vscode/
*.swp
*.swo
# Environment
.env
.env.local
# Logs
logs/
*.log
EOL
# Initial commit
git add .
git commit -m "Initial project setup"
fi
echo "Project setup complete!"
echo "Activate the virtual environment with: source venv/bin/activate"
Make the script executable:
chmod +x scripts/setup_project.sh
Step 5: Create a Requirements Updating Script
scripts/update_deps.sh:
#!/bin/bash
# Script to update dependencies
# Check if virtual environment is activated
if [[ "$VIRTUAL_ENV" == "" ]]; then
echo "Virtual environment not activated. Please activate it first."
echo "Run: source venv/bin/activate"
exit 1
fi
# Install pip-tools if not installed
pip install pip-tools
# Check outdated packages
echo "Checking for outdated packages..."
pip list --outdated
# Ask for confirmation
read -p "Do you want to update packages? (y/n) " -n 1 -r
echo
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
echo "Update canceled."
exit 0
fi
# Create requirements.in files if they don't exist
if [ ! -f "requirements/base.in" ]; then
echo "Creating requirements.in files from current requirements.txt files..."
# Extract direct dependencies from requirements.txt
grep -v "^-r" requirements/base.txt | grep -v "^#" | grep -v "^$" > requirements/base.in
grep -v "^-r" requirements/development.txt | grep -v "^#" | grep -v "^$" > requirements/development.in
echo "-r base.in" > requirements/development.in.tmp
grep -v "^-r" requirements/development.in >> requirements/development.in.tmp
mv requirements/development.in.tmp requirements/development.in
# Same for testing and production
# ... similar commands for testing.in and production.in ...
fi
# Update base requirements
echo "Updating base requirements..."
pip-compile --upgrade requirements/base.in
# Update environment-specific requirements
for env in development testing production; do
echo "Updating $env requirements..."
pip-compile --upgrade requirements/${env}.in
done
# Check for security vulnerabilities
echo "Checking for security vulnerabilities..."
pip install safety
safety check -r requirements/base.txt
echo "Dependencies updated successfully!"
Make the script executable:
chmod +x scripts/update_deps.sh
Step 6: Create a Basic Flask Application
app/__init__.py:
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
from flask_migrate import Migrate
from flask_login import LoginManager
from flask_wtf.csrf import CSRFProtect
# Initialize extensions
db = SQLAlchemy()
migrate = Migrate()
login_manager = LoginManager()
csrf = CSRFProtect()
def create_app(config_object='app.config.DevelopmentConfig'):
"""Create and configure the Flask application."""
app = Flask(__name__)
app.config.from_object(config_object)
# Initialize extensions
db.init_app(app)
migrate.init_app(app, db)
login_manager.init_app(app)
csrf.init_app(app)
# Register blueprints
from app.routes import main_bp
app.register_blueprint(main_bp)
return app
app/config.py:
import os
from dotenv import load_dotenv
# Load environment variables from .env file
load_dotenv()
class Config:
"""Base configuration class."""
SECRET_KEY = os.environ.get('SECRET_KEY', 'dev-key-please-change')
SQLALCHEMY_DATABASE_URI = os.environ.get('DATABASE_URL', 'sqlite:///app.db')
SQLALCHEMY_TRACK_MODIFICATIONS = False
class DevelopmentConfig(Config):
"""Development configuration."""
DEBUG = True
SQLALCHEMY_ECHO = True
class TestingConfig(Config):
"""Testing configuration."""
TESTING = True
SQLALCHEMY_DATABASE_URI = 'sqlite:///:memory:'
WTF_CSRF_ENABLED = False
class ProductionConfig(Config):
"""Production configuration."""
DEBUG = False
TESTING = False
app/routes.py:
from flask import Blueprint, render_template
main_bp = Blueprint('main', __name__)
@main_bp.route('/')
def index():
return render_template('index.html')
app/templates/index.html:
<html>
<head>
<title>Flask App</title>
</head>
<body>
<h1>Welcome to Flask App</h1>
<p>This is a Flask application with proper dependency management.</p>
</body>
</html>
run.py:
from app import create_app
app = create_app()
if __name__ == '__main__':
app.run()
Running the Application
# Set up the project
./scripts/setup_project.sh
# Activate virtual environment
source venv/bin/activate
# Run the application
python run.py
This exercise demonstrates:
- Structured requirements management for different environments
- Scripts for automating dependency installation and updates
- Security checking of dependencies
- Integration with a Flask application
- Project initialization and setup automation
By completing this exercise, you've created a robust dependency management system for a Python web application that follows best practices and can scale as the project grows.
Conclusion
We've explored requirements.txt files from basic usage to advanced techniques, and seen how they fit into the Python dependency management ecosystem. Let's recap the key takeaways:
- Importance of Dependency Management: Well-managed dependencies ensure reproducible environments, easier collaboration, and more reliable applications.
- Best Practices: Pin your versions, organize requirements by environment, include comments, and regularly audit for security vulnerabilities.
- Advanced Techniques: Consider tools like pip-tools, Poetry, or Pipenv for more sophisticated dependency management as your projects grow.
- Workflow Integration: Incorporate dependency management into your development workflow, CI/CD pipelines, and deployment processes.
- Security Awareness: Regularly check for outdated or vulnerable dependencies to maintain application security.
Mastering requirements.txt and dependency management is a fundamental skill for Python developers. As you build more complex applications, these practices will help you maintain codebases that are easier to work with, share, and deploy.
Remember: "A chain is only as strong as its weakest link." In software, your dependencies are links in that chain. Proper dependency management helps ensure none of those links break unexpectedly.
Additional Resources
- pip documentation: Requirements Files
- Python Packaging Authority: Tool Recommendations
- Real Python: Using Requirement Files
- pip-tools GitHub Repository
- Poetry Documentation
- Pipenv Documentation
- safety: Python Vulnerability Scanner
- pip-tools: A set of tools to keep your pinned Python dependencies fresh