> ## Documentation Index
> Fetch the complete documentation index at: https://guide.codepure.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Unpinned Dependencies in Pip

> Properly pinning Python package versions for security

## Common Misconfigurations

1. **Using version ranges instead of exact versions**
2. **Not using requirements.txt in production**
3. **Missing version constraints in setup.py**
4. **Not locking transitive dependencies**
5. **Mixing pip and conda without constraints**

## Vulnerable Example

```python theme={null}
# requirements.txt with unpinned versions
Django>=3.0  # Allows any version above 3.0
requests     # No version specified
numpy>1.19   # Open-ended range
pandas~=1.3  # Compatible release clause
scipy        # Latest version always
Pillow<9     # Only upper bound
```

```python theme={null}
# setup.py with loose constraints
from setuptools import setup

setup(
    name="unpinned-app",
    install_requires=[
        "flask",           # No version
        "sqlalchemy>=1.0", # Open range
        "celery>4,<6",     # Wide range
        "redis",           # Unpinned
    ],
    extras_require={
        "dev": [
            "pytest",      # No version
            "black",       # No version
        ]
    }
)
```

```bash theme={null}
# Direct pip install without constraints
pip install django requests numpy
# No lock file generation
```

## Secure Solution

```txt theme={null}
# requirements.txt with pinned versions
# Generated with: pip freeze > requirements.txt
Django==4.2.9
requests==2.31.0
numpy==1.26.3
pandas==2.1.4
scipy==1.11.4
Pillow==10.2.0

# Include all transitive dependencies
certifi==2023.11.17
charset-normalizer==3.3.2
idna==3.6
urllib3==2.1.0
```

```txt theme={null}
# requirements.in for pip-tools
# Source file for pip-compile
Django==4.2.9
requests==2.31.0
numpy==1.26.3
pandas==2.1.4
```

```bash theme={null}
# Generate locked requirements
pip-compile --generate-hashes requirements.in -o requirements.txt
```

```python theme={null}
# setup.py with proper constraints
from setuptools import setup

# Read requirements from file
with open('requirements.txt') as f:
    requirements = f.read().splitlines()

setup(
    name="secure-app",
    version="1.0.0",
    install_requires=requirements,
    python_requires=">=3.9,<3.12",  # Specify Python version
)
```

```toml theme={null}
# pyproject.toml for modern Python projects
[project]
name = "secure-app"
version = "1.0.0"
requires-python = ">=3.9,<3.12"
dependencies = [
    "Django==4.2.9",
    "requests==2.31.0",
    "numpy==1.26.3",
    "pandas==2.1.4",
]

[tool.pip-tools]
generate-hashes = true
allow-unsafe = false

[tool.poetry.dependencies]
python = "^3.9"
Django = "4.2.9"
requests = "2.31.0"
```

```yaml theme={null}
# Dependabot configuration
version: 2
updates:
  - package-ecosystem: "pip"
    directory: "/"
    schedule:
      interval: "weekly"
    reviewers:
      - "security-team"
    labels:
      - "dependencies"
      - "security"
```

## Key Commands for Pinning

Here are the commands that power the secure workflows described above.

### 1. Simple Pinning (pip freeze)

This command "freezes" the current virtual environment, capturing the exact versions of *everything* installed and saving it to a file.

```bash theme={null}
pip freeze > requirements.txt
```

* **Pro:** Very simple.
* **Con:** Not reproducible. It captures all dependencies in your environment, not just the ones your project needs. It's hard to update.

### 2. Modern Pinning (pip-tools)

This is the recommended approach. It uses `pip-compile` to generate a locked `requirements.txt` from a simple `requirements.in` file.

**Step 1: Install pip-tools**

```bash theme={null}
pip install pip-tools
```

**Step 2: Create `requirements.in`**
Create a file listing *only* your direct dependencies (e.g., `django`, `requests`).

**Step 3: Compile the lock file**
This command resolves all dependencies (direct and transitive) and pins them with hashes.

```bash theme={null}
pip-compile requirements.in -o requirements.txt --generate-hashes
```

### 3. Installing Pinned Dependencies

This command installs *only* the exact versions specified in your lock file. It is the standard command for production and CI/CD.

```bash theme={null}
pip install -r requirements.txt
```

### 4. Syncing Your Environment

This command (from `pip-tools`) is even better. It makes your virtual environment *exactly* match the `requirements.txt` file, installing missing packages and **uninstalling** any that don't belong.

```bash theme={null}
pip-sync
```

## Best Practices

* Use **pip-tools** or **Poetry** for dependency management.
* Generate `requirements.txt` with exact versions.
* Include hash verification.
* Use separate files for dev and prod dependencies.
* Implement automated dependency updates with review.
