pigar extracts imports with AST, then admits it is not a dependency manager
:coffee: A tool to generate requirements.txt for Python project, and more than that. (IT IS NOT A PACKAGE MANAGEMENT TOOL)
At a glance
- What is it?
- pigar generates a requirements.txt by parsing your source tree with Python's AST rather than regular expressions, handling notebooks, exec and eval strings, and standard library differences across Python versions. The author states plainly that it is not a package management tool.
- Who is it for?
- Adopt pigar as a one time migration aid when you are moving an old Python project to a declared dependency workflow, especially if it contains Jupyter notebooks, exec or eval driven imports, or code that must support more than one Python version. Do not adopt it as ongoing dependency management, which the author rules out directly, and do not trust it on a project that relies on framework magic to import modules, since the README states that case cannot be handled.
- Can I use it commercially?
- Yes. BSD-3-Clause 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?
- Yes. The repository last received commits 91 days 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 October 23, 2026, and from our analysis. They are not legal advice.
Editorial analysis
The author answers the dependency management question before you ask it
The repository description carries the warning in capitals: it is not a package management tool. The FAQ repeats it as its first entry and then explains why, which is the most useful thing about this project.
The author's reasoning is that there is too much dirty work to be done to make that approach reliable, and that while pigar does the generation job well, it does a bad job of managing dependencies. The stated purpose is narrower: a tool to assist an old project in migrating to a new development workflow.
That framing matters because the alternative tools are named directly. The README points to Pipenv, uv and other approaches linked from the Python packaging documentation as recommended for improving your development flow. So pigar positions itself as the tool you run once on a legacy codebase, not the tool that owns your dependency resolution afterwards.
The remaining three capability claims are: generate requirements.txt while handling the difference between Python versions, support Jupyter notebooks with `*.ipynb`, and pick up import statements hidden in `exec`, `eval` and `importlib` calls as well as doctests inside docstrings. Two supporting commands extend that: searching for the distribution that provides an import name, and checking requirements files against the latest available versions.
AST parsing is why it catches what a regex cannot
The README is explicit about method: pigar does not use regular expressions in what it calls a violent way, and instead uses AST, described as a better method for extracting imported names from arguments of `exec`, `eval` and `importlib`, and from doctests in docstrings.
That is the whole technical argument, and it is correct in a way that matters practically. A regex over source text sees the string literal `import numpy` inside a call to exec and does not know whether it is code. An AST walk of the call arguments can tell which arguments are string constants and which are names, so a dynamic import string gets treated as an import. The same distinction lets a docstring containing an example import be read as an example rather than as a dependency.
The README is careful not to overclaim. It says pigar cannot solve all the tricky problems and directs readers to the FAQ, which is honest given how much magic real codebases contain.
The second mechanism is Python version awareness. The README's example is `concurrent.futures`, which exists in the Python 3.2 standard library but required installing a package called `futures` on earlier versions. pigar detects that difference rather than hardcoding it, and v1 of the project carried separate py2_requirements.txt and py3_requirements.txt files for exactly this reason.
generate, search and check are the three commands
Installation is three alternatives. pip, conda from conda-forge, or straight from GitHub for the newest code:
[sudo] pip install pigarconda install -c conda-forge pigarpip install git+https://github.com/damnever/pigar.git@[main or other branch] --upgradeGeneration takes the current directory by default, and the `-f` flag changes both the output file and the directory scanned:
# Generate requirements.txt for current directory.
$ pigar generate
# Generating requirements.txt for given directory in given file.
$ pigar gen -f ../dev-requirements.txt ../Commands accept prefixes, so `pigar gen` and `pigar c` both work, and `pigar --help` lists what is available. That abbreviation scheme is unusual and worth knowing before you read an error message.
`search` answers the question that motivates the tool in practice. When you see `ImportError` for a name you cannot place, the import name and the distribution name often differ:
$ pigar search bs4 MySQLdbThe README's examples are `bs4`, which may come from `beautifulsoup4`, and `MySQLdb`, which could come from `mysql-python`. This is a lookup convenience, not a resolver, and it works against the search index rather than your environment.
`check` compares a requirements file against latest versions, either with an explicit path or by letting pigar find every requirements file in the current directory level by level:
# Specify a requirements file.
$ pigar check -f ./requirements.txtNote that check reports newer versions. It does not upgrade anything, and the README does not claim it resolves compatibility.
Referenced comments and the difference display
Two smaller behaviours are worth understanding because they change how you review generated output.
The first is provenance. `pigar gen --with-referenced-comments` emits the file and line references behind each package, so a generated entry looks like this:
# project/foo.py: 2,3
# project/bar/baz.py: 2,7,8,9
foobar == 3.3.3For a project with hundreds of imports, being able to trace an entry to two files rather than ninety is the difference between a reviewable diff and a rubber stamp. The README warns that line numbers for Jupyter notebooks may be a bit confusing, which is an artifact of mapping notebook cell content back to source positions.
The second is the overwrite diff. When requirements.txt already exists, pigar shows the difference between old and new, and `--dont-show-differences` turns that off. On a large project that display is the actual review step, so leaving it on matters.
One operational note the README is candid about: pigar searches the local environment first, and only then does further analysis and searches PyPI for missing distributions. So results depend on what happens to be installed in the environment where you run it. That is the direct cause of the duplicate package behaviour in the next section.
Where it fails, according to its own FAQ
The README documents three failure modes, and they are honest.
The first is duplicate candidates for one import name. A name like `bs4` can be provided by more than one distribution, and pigar may list several. The stated remedy is manual: remove the duplicates from requirements.txt yourself, or pick one when pigar asks. Installing only the package you want in the local environment is said to fix it as well, which confirms that the local environment is the input to this decision.
The second is the same problem across environments. Because resolution prefers what is installed locally, running pigar on two machines with different environments can produce different results for the same code. The README's own example makes the distinction concrete: pigar v1 shipped separate py2_requirements.txt and py3_requirements.txt files for different Python versions.
The third is the one that decides adoption. If a framework imports modules for you through some magic, pigar cannot find them, because the import is not in your source. The README says you may need to fix it manually or use the experimental features.
Those experimental features are annotation comments. The format uses comments beginning with `pigar:` alongside imports or feature calls:
import foo # pigar: required-imports=import_name_bar,import_name_baz
import foo # pigar: required-packages=package-name-bar,package-name-baz # Extra comments are allowed.
foo(features=['bar', 'baz']) # pigar: required-distributions=package-name-bar,package-name-bazThree keys are supported: required-imports, required-packages and required-distributions. Enable the feature with `pigar generate --enable-feature requirement-annotations`. The README also notes that if the comments are intrusive in your source, you can move them into a separate Python file such as `pigar_annotations.py` and delete it afterwards.
This is the honest shape of the tool. It covers what static analysis can see, and it asks you to declare the rest by hand.
Maintenance, licence and how it compares
The repository is not archived and the last push was on 2026-07-24. Releases are less frequent: v2.2.0 from 2025-11-09, v2.1.7 from 2024-12-18 and v2.1.6 from 2024-07-10. A push between tags means work is landing that has not been released, so pin a version rather than tracking the branch.
There is a small inconsistency in the version requirements worth noting before you pick an environment. The README says pigar can run on Python 3.7+, while the package metadata declares `requires-python = ">=3.8"` and lists classifiers only for CPython and Python 3.10 through 3.14. The metadata is what pip enforces, so treat 3.8 as the real floor and read the classifier list as untested rather than unsupported.
Licence is BSD 3-Clause, permissive with no copyleft obligation on your project.
The comparison is straightforward. The README recommends Pipenv, uv and other dependency-management approaches for improving the development flow. pigar is a static extraction step that produces a requirements file, so it is positioned as a migration aid rather than the tool that manages dependencies.
Against other extractors, the difference is AST versus text scanning, which decides whether dynamic imports and notebook cells are found at all. Against a frozen legacy environment where nothing can be installed, the check command can still tell you what is behind, which is occasionally useful on its own.
Support runs through GitHub issues, with contributions welcomed. The repository carries a CHANGELOG.md, a makefile, a requirements/ directory and both setup.py and pyproject.toml, with the latter declaring setuptools>=69.0 and wheel as the build system.
Editorial conclusion
Adopt pigar as a one time migration aid when you are moving an old Python project to a declared dependency workflow, especially if it contains Jupyter notebooks, exec or eval driven imports, or code that must support more than one Python version. Do not adopt it as ongoing dependency management, which the author rules out directly, and do not trust it on a project that relies on framework magic to import modules, since the README states that case cannot be handled. Verify first the Python version floor in the package metadata, which requires-python is >=3.8 even though the README says the tool runs on Python 3.7+.
Frequently asked questions
Is pigar a package management tool?
No. The README states plainly that pigar is not a package management tool, because there is too much dirty work to make that approach reliable. It describes itself as a tool to assist an old project in migrating to a new development workflow.
How do I install pigar?
Use [sudo] pip install pigar, or conda install -c conda-forge pigar, or install the newest code from GitHub with pip install git+https://github.com/damnever/pigar.git@[main or other branch] --upgrade. The README says it runs on Python 3.7+, while the package metadata requires Python 3.8 or later.
How do I find which package provides an import name?
Run pigar search followed by the import names, for example pigar search bs4 MySQLdb. The README notes that bs4 may come from beautifulsoup4 and MySQLdb could come from mysql-python.
Why does pigar list several packages for one import name?
pigar cannot resolve that case gracefully and the README says you may need to remove the duplicates from requirements.txt manually or select one when it asks. Installing only the required packages in the local environment is stated to fix it, because pigar searches the local environment first.
Can pigar find imports that a framework loads automatically?
No. The README states that frameworks which use magic to import modules for users automatically cannot be handled, and you may need to fix it manually or use the experimental features with pigar generate --enable-feature requirement-annotations and pigar: annotated comments.
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/damnever-pigar)Was this useful?