# pipreqs: Generate requirements.txt From Imports


pipreqs reads a project's `import` statements and writes a `requirements.txt` containing only the distributions those imports resolve to. It works from the source tree, not from an installed environment.

> [!NOTE]
> This is the opposite approach to `pip freeze`, which reports the environment. Imports are evidence of what the code needs; an environment records what resolution and years of drift produced. For recovering a dependency list from an undocumented project, the import scan is the better starting point, with the environment used afterwards to supply versions and to catch dependencies that are never imported.

## Import Scanning

pipreqs parses each `.py` file for top-level imports, discards standard-library modules, and maps the rest to PyPI distribution names. Given a file importing `flask`, `requests`, `jinja2`, and `os`:

```console
$ pipreqs --print src
Flask==3.1.3
Jinja2==3.1.6
Requests==2.34.2
```

`os` is dropped as standard library. The names are capitalized because they come from PyPI metadata rather than the import statement, and `pip install` treats them case-insensitively.

Import names and distribution names often differ, so pipreqs resolves them against a bundled mapping and falls back to a PyPI lookup, which it reports:

```console
WARNING: Import named "Requests" not found locally. Trying to resolve it at the PyPI server.
WARNING: Import named "Requests" was resolved to "requests:2.34.2" package (https://pypi.org/project/requests/).
Please, verify manually the final list of requirements.txt to avoid possible dependency confusions.
```

The warning is worth heeding. A wrong mapping produces a plausible package name that installs something the project never used.

## Version Schemes

`--mode` controls how versions are written. The default pins with `==`, which manufactures constraints the original author may never have declared:

| Mode | Output |
|---|---|
| default | `Flask==3.1.3` |
| `compat` | `Flask~=3.1.3` |
| `gt` | `Flask>=3.1.3` |
| `no-pin` | `Flask` |

```bash
pipreqs --print --mode no-pin src
```

The `--help` text lists this mode as `non-pin`, but that value raises `ValueError: Invalid argument for mode flag, use 'compat', 'gt' or 'no-pin' instead`. Use `no-pin`.

## Auditing an Existing File

`--diff` compares a `requirements.txt` against the imports without modifying it, which finds declared packages the code stopped using:

```console
$ pipreqs --diff requirements.txt src
INFO: The following modules are in requirements.txt but do not seem to be imported: boto3
```

`--clean` rewrites the file in place, dropping unimported entries:

```bash
pipreqs --clean requirements.txt src
```

Both operate on direct imports only, so a package required at runtime but never imported is reported as unused. Read the diff before running `--clean`.

## Installation

```bash
# Run without installing
uvx pipreqs --print src

# Install once as a user-level tool
uv tool install pipreqs

# Install with pip
pip install pipreqs
```

Release 0.5.0 declares `python_requires >=3.8.1,<3.13`. On a newer interpreter, resolvers fall back to 0.4.13 from 2023, so `uvx pipreqs` reports `0.4.13` on Python 3.13 and later. Both releases scan imports correctly; the older one emits a `SyntaxWarning` from its `yarg` dependency.

## Pros

- Reports what the code imports instead of what the environment contains
- `--mode no-pin` and `--mode gt` avoid inventing exact pins
- `--diff` and `--clean` audit an existing `requirements.txt` against real usage
- Resolves import names to distribution names, including via PyPI lookup
- Needs no working virtual environment, only the source tree

## Cons

- Misses every dependency that is never imported: gunicorn, database drivers, pytest plugins, `importlib` loads
- Import-to-distribution mapping can resolve to the wrong package, which the tool warns about but cannot settle
- No release since February 2024, and 0.5.0 excludes Python 3.13 and later, so new interpreters silently get 0.4.13
- Reports no dependency groups, extras, or environment markers
- [pigar](https://github.com/damnever/pigar) releases more regularly and carries no upper Python bound

## Learn More

### Handbook guides

- [How to inspect a virtual environment you did not create](https://pydevtools.com/handbook/how-to/how-to-inspect-an-existing-virtual-environment.md)
- [How to migrate from requirements.txt to pyproject.toml with uv](https://pydevtools.com/handbook/how-to/migrate-requirements.txt.md)
- [requirements.txt](https://pydevtools.com/handbook/reference/requirements.md)

### Official documentation

- [pipreqs on GitHub](https://github.com/bndr/pipreqs)
- [pipreqs on PyPI](https://pypi.org/project/pipreqs/)
- [pigar, an actively released alternative](https://github.com/damnever/pigar)
