pipreqs: reads your imports, asks PyPI, writes a requirements.txt
pipreqs - Generate pip requirements.txt file based on imports of any project. Looking for maintainers to move this project forward.
At a glance
- What is it?
- A small Python tool that answers the question pip freeze cannot, which is what this project actually imports. Its real limits are the import-to-package mapping table and how old the last release is.
- Who is it for?
- pipreqs is worth having in a toolbox for the specific case it was built for: standing up a new project, or importing an old script into one, where you know which modules the code touches and need names pip will accept. It is not a dependency manager, it cannot see imports inside functions it fails to parse or packages loaded dynamically, and its output needs a human pass because a wrong guess becomes a wrong package name.
- Can I use it commercially?
- Yes. Apache-2.0 is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Activity is slowing. The repository last received commits 6 months ago.
- What is it written in?
- Mainly Python, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on September 21, 2026, and from our analysis. They are not legal advice.
Editorial analysis
Installing, and the notebook dependency you can skip
Installation is a single command from PyPI:
pip install pipreqsThe README then makes an unusual offer: if you do not want notebook support, install without the dependencies that provide it and add the two you actually need by hand.
pip install --no-deps pipreqs
pip install yarg==0.1.9 docopt==0.6.2That option exists because `pyproject.toml` lists four runtime dependencies, and two of them are there only for Jupyter: `nbconvert>=7.11.0` and `ipython>=8.12.3`, alongside `yarg>=0.1.9` and `docopt>=0.6.2`. On a server or in a container where you do not want IPython, `--no-deps` followed by the two pinned packages is the documented way to get a minimal install.
The packaging metadata is otherwise current and specific. The version is 0.5.0, the classifier reads `Development Status :: 4 - Beta`, `requires-python` is `>=3.9, <3.14`, and the console script is registered as `pipreqs = "pipreqs.pipreqs:main"`. The project migrated packaging to poetry in v0.5.0 and `pyproject.toml` still carries a legacy `[tool.poetry.group.dev.dependencies]` block alongside the modern `[project.optional-dependencies]` one.
The mapping table is the actual product
pipreqs works by parsing imports out of your source and converting each one into a name pip will accept. That conversion is a lookup table, and the release history is a record of the table growing.
v0.4.13, published 2023-04-14, is almost entirely mapping work: an update for `python-slugify`, a fix mapping `socketio` to `python-socketio`, a new mapping for `python-constraint`, an airflow mapping, and Telegram mapped to `python-telegram-bot`. It also includes a mitigation for dependency confusion, contributed as PR #364, which is the one security-relevant change in the visible history. Dependency confusion is the attack where a package name on PyPI shadows a private one, so a tool that invents package names from import statements is exactly where you want that mitigation.
The gap this creates is worth stating clearly. A module name and its distribution name are related by convention, not by rule: `yaml` comes from `PyYAML`, `sklearn` from `scikit-learn`, `PIL` from `Pillow`. Where the convention holds, the table works and the mapping entries above are the maintainers fixing the places where it did not. Where a project uses an unusual name, a vendored module, or a local package that shadows a real one, pipreqs either needs an entry added or produces a name that does not resolve.
So the honest framing is that pipreqs gets you most of the way in seconds and a person closes the rest. That is a different bargain from a resolver.
Running it, and the options that change the output
The usage is `pipreqs [options] [<path>]`, with the path defaulting to the current working directory. The example in the README is a directory scan that reports where it wrote the file:
$ pipreqs /home/project/location
Successfully saved requirements file in /home/project/location/requirements.txtMost of the option list is about controlling the network and the scope of the scan. `--use-local` uses only local package info instead of querying PyPI, which makes it work offline and makes it slower to resolve. `--pypi-server <url>` points at a custom index, and `--proxy <url>` is handed to the requests library, with the README noting you can set `HTTP_PROXY` and `HTTPS_PROXY` in the environment instead. `--ignore <dirs>...` skips extra directories, `--no-follow-links` stops the walk descending through symbolic links, and `--ignore-errors` keeps going when a file will not parse.
The output options are the ones to know. `--print` writes to standard output instead of a file, `--savepath <file>` names the destination, and `--force` overwrites an existing requirements.txt. `--diff <file>` compares modules in an existing requirements.txt against the project's imports and prints the difference, and `--clean <file>` removes entries in that file which the project does not import. Those two are the ones that make pipreqs safe to run on a repository that already has a working file.
Version formatting is a separate axis. `--mode <scheme>` accepts `<compat>`, `<gt>` or `<non-pin>`, producing `Flask~=1.1.2`, `Flask>=1.1.2` or plain `Flask`. `--scan-notebooks` extends the scan to Jupyter notebook files, which is the v0.5.0 feature that brought in the `nbconvert` and `ipython` dependencies, and `--encoding <charset>` sets the file open encoding, with v0.5.0 forcing utf-8 as the default.
Why not pip freeze, according to the README
The README has a section titled Why not pip freeze?, and its three bullets are the clearest statement of what pipreqs is for.
`pip freeze` only saves the packages that were installed with `pip install` in your environment. `pip freeze` saves all packages in the environment, including ones your current project does not use, if you do not have a virtualenv. And sometimes you just need to create a requirements.txt for a new project without installing the modules at all.
That third point is the real use case and it is narrower than people expect. pipreqs is for when you have source code and no environment: a script someone sent you, a tutorial project, a repository you are importing into your own layout. In that situation there is nothing to freeze, because nothing is installed, and the imports in the files are the only available description of the dependency set.
The corollary is that pipreqs is not a lockfile. It produces a starting point from static reading of your code, not a resolved, pinned, verified environment. `--diff` is the honest companion command: run it against a file you already trust and see what the scanner thinks differs.
What the parser cannot see
Every tool that infers dependencies from source has a blind spot, and for pipreqs it comes from the parsing step. Imports that appear only inside a docstring, inside a string passed to `importlib.import_module`, or inside a plugin registry are invisible to a scanner reading import statements. Dynamic loading is common in plugin-heavy code and in anything built around entry points.
Standard library modules are another category: pipreqs knows not to emit them, which is correct behaviour and one of the reasons the output is usable without editing. Local modules in your own package are the third, and they need to be excluded or they get looked up on PyPI, where the name may well exist and mean something else. `--ignore <dirs>` and `--encoding <charset>` exist because these cases are common enough to have flags for them, and `--ignore-errors` exists because a file that will not parse would otherwise abort the run.
There is a related risk with names that resolve but are wrong. Because the output is a package name looked up against PyPI, an incorrect mapping does not fail loudly as a syntax error; it produces an installable but wrong dependency. That is why the dependency confusion mitigation in v0.4.13 matters more here than it would in most tools, and it is why reviewing a generated requirements.txt before committing it is not optional advice but part of using the tool.
Maintenance state, tooling around the code, and licence
The repository description says it is looking for maintainers to move the project forward, which is the clearest signal about its status. The last push was on 2026-03-30. The most recent release is v0.5.0, published 2024-02-18, titled finally jupyter support!, and before that v0.4.13 and v0.4.12 in April 2023.
Those two release dates tell a story. v0.4.12 was published by a contributor who noted the PyPI package had not been updated in a long time and cut a release from two years of accumulated changes. v0.5.0 credits six contributors by name and credits most of the release to them. That is a project with real contribution and an uneven release process, which is a workable but different thing from steady maintenance.
The repository is set up properly regardless. `Makefile` targets cover `lint` with flake8, `test`, `test-all` with tox, `coverage`, `docs` with Sphinx, `build`, `install`, `publish` and `publish-to-test`. `tox.ini` handles multiple Python versions, `.pre-commit-config.yaml` and `.editorconfig` cover style, `.python-version` and `.tool-versions` pin interpreter versions, and `HISTORY.rst`, `AUTHORS.rst` and `CONTRIBUTING.rst` are all present. `poetry.lock` and `poetry.toml` sit alongside the pyproject file. Licence is Apache 2.0.
For a tool this small, that setup is the main argument for using it: the code is small enough to read end to end, which means when pipreqs guesses wrong about a package name you can find out why rather than filing a ticket and waiting.
Editorial conclusion
pipreqs is worth having in a toolbox for the specific case it was built for: standing up a new project, or importing an old script into one, where you know which modules the code touches and need names pip will accept. It is not a dependency manager, it cannot see imports inside functions it fails to parse or packages loaded dynamically, and its output needs a human pass because a wrong guess becomes a wrong package name. The repository description asks for maintainers to move the project forward, the last push was on 2026-03-30, and the newest release is v0.5.0 from 2024-02-18, so treat it as a stable tool with an uncertain future rather than one to build a pipeline around. Run it with `--use-local` for an offline check and `--diff` against an existing file to see what it would change before you commit to it.
Frequently asked questions
How do I use pipreqs?
Install it with `pip install pipreqs`, then run `pipreqs` in a project directory, or pass a path such as `pipreqs /home/project/location`. It parses your imports, looks each one up, and writes requirements.txt, reporting the path it saved to. Useful options are `--print` for standard output, `--force` to overwrite an existing file, `--use-local` to avoid querying PyPI, and `--scan-notebooks` to include Jupyter notebooks.
What does pip freeze or requirements.txt do?
The README explains the difference in its Why not pip freeze? section. `pip freeze` lists what is installed in your environment, including packages your project does not use if you lack a virtualenv, and it needs something installed first. pipreqs instead reads the imports in your source files, which is why it works when you have code but no environment, such as a new project where you have not installed anything yet.
Why did pipreqs generate a requirements.txt with the wrong package name?
pipreqs converts import names into distribution names using a mapping table, because the two do not always match: `yaml` comes from PyYAML, `sklearn` from scikit-learn, `PIL` from Pillow. Past releases are largely mapping fixes, such as socketio to python-socketio in v0.4.13. A wrong entry produces an installable but incorrect package, so review the generated file, and use `--diff <file>` to compare it against one you already trust.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/bndr-pipreqs)