Find undeclared 3rd-party dependencies in your Python project.
Project description
FawltyDeps
A dependency checker for Python.
Find undeclared and/or unused 3rd-party dependencies in your Python project.
Key Concepts
- undeclared dependency: a package that's used (in particular,
import
ed) by a project and which lacks a corresponding declaration to ensure that it's available. For example, youimport numpy
, but you've forgotten to includenumpy
in yourrequirements.txt
. Pragmatically, this means the project is prone to runtime errors. - unused dependency: a package that's declared as necessary for a project but which is never used by project code.
For example, you have
numpy
listed in yourrequirements.txt
, but you never actuallyimport numpy
. Pragmatically, this means that project installation may consume more space than needed and will be more likely to break with future software releases; in short, these are costs paid for no benefit.
Installation
The library is distributed with PyPI, so simply:
pip install fawltydeps
or any other way to install Python packages from PyPI should be enough to make it available in your environment.
Consider adding fawltydeps
to your development dependencies, to help you catch undeclared and unused dependencies in your projects.
Usage
To check the project in the current directory run:
fawltydeps
This will find imports in all the Python code under the current directory, extract dependencies declared by your project, and then report undeclared and unused dependencies.
Available Actions
FawltyDeps provides the following options for controlling what actions to perform. Only one of these can be used at a time:
--check
: Report both undeclared and unused dependencies--check-undeclared
: Report only undeclared dependencies--check-unused
: Report only unused dependencies--list-imports
: List third-party imports extracted from the project--list-deps
: List declared dependencies extracted from the project
When none of these are specified, the default action is --check
.
Where to find Python code
The --code
option tells FawltyDeps where to find the Python code to parse for
import
statements. You can pass either of these:
- a single file: Either a Python file (
*.py
) or a Jupyter Notebook (*.ipynb
) - a directory: FawltyDeps will find all Python files and Jupyter notebooks under this directory.
-
: Passing a single dash (--code=-
) tells FawltyDeps to read Python code from stdin.
If no --code
option is passed, FawltyDeps will find all Python code under the
current directory, i.e. same as --code=.
Where to find declared dependencies
The --deps
option tells FawltyDeps where to look for your project's declared
dependencies. A number of file formats are supported:
*requirements*.txt
and*requirements*.in
pyproject.toml
(following PEP 621 or Poetry conventions)setup.py
(only limited support for simple files with a singlesetup()
call and no computation involved for setting theinstall_requires
andextras_require
arguments)setup.cfg
The --deps
option accepts either a directory, in which case FawltyDeps will go
looking for the above files under that directory. or a file, in case you want to
be explicit about where to find the declared dependencies.
If no --deps
option is passed, FawltyDeps will look for the above files under
the current directory, i.e. same as --deps=.
Ignoring irrelevant results
There may be import
statements in your code that should not be considered an
undeclared dependency. This might happen if you for example do a conditional
import
with a try: ... except ImportError: ...
block (or similar).
FawltyDeps is not able to recognize whether these dependencies should have been
declared or not, but you can ask for them to be ignored with the
--ignore-undeclared
option, for example:
--ignore-undeclared some_module some_other_module
Conversely, there may be dependencies that you have declared without intending
to import
them. This is often the case for developer tools like Black or Mypy
that are part of your project's development environment.
FawltyDeps cannot automatically tell which of your declared dependencies are
meant to be import
ed or not, but you ask for specific deps to be ignored with
the --ignore-unused
option, for example:
--ignore-unused black mypy
Output formats
The default output from FawltyDeps is a summary outlining the relevant dependencies found (according to the selected actions). However you can also ask for more information from FawltyDeps:
--summary
: Default (human-readable) summary output--detailed
: Longer (human-readable) output that includes the location of the relevant dependencies.--json
: Verbose JSON-formatted output for other tools to consume and process further.
Only one of these options can be used at a time.
More help
Run fawltydeps --help
to get the full list of available options.
Configuration
You can use a [tool.fawltydeps]
section in pyproject.toml
to configure the
default behavior of FawltyDeps. Here's a fairly comprehensive example:
[tool.fawltydeps]
code = "myproject" # Only search for imports under ./myproject
deps = "pyproject.toml" # Only look for declared dependencies here
ignore_unused = ["black"] # We use `black`, but we don't intend to import it
output_format = "human_detailed" # Detailed report by default
Here is a complete list of configuration directives we support:
actions
: A list of one or more of these actions to perform:list_imports
,list_deps
,check_undeclared
,check_unused
. The default behavior corresponds toactions = ["check_undeclared", "check_unused"]
.code
: A file or directory containing the code to parse for import statements. Defaults to the current directory, i.e. likecode = .
.deps
: A file or directory containing the declared dependencies. Defaults to the current directory, i.e. likedeps = .
.output_format
: Which output format to use by default. One ofhuman_summary
,human_detailed
, orjson
. The default corresponds tooutput_format = "human_summary"
.ignore_undeclared
: A list of specific dependencies to ignore when reporting undeclared dependencies, for example:["some_module", "some_other_module"]
. The default is the empty list:ignore_undeclared = []
.ignore_unused
: A list of specific dependencies to ignore when reporting unused dependencies, for example:["black", "mypy"]
. The default is the empty list:ignore_unused = []
.deps_parser_choice
: Manually select which format to use for parsing declared dependencies. Must be one of"requirements.txt"
,"setup.py"
,"setup.cfg"
,"pyproject.toml"
, or leave it unset (i.e. the default) for auto-detection (based on filename).verbosity
: An integer controlling the default log level of FawltyDeps:-2
: OnlyCRITICAL
-level log messages are shown.-1
:ERROR
-level log messages and above are shown.0
:WARNING
-level log messages and above are shown. This is the default.1
:INFO
-level log messages and above are shown.2
: All log messages (includingDEBUG
) are shown.
Environment variables
In addition to configuring FawltyDeps via pyproject.toml
as show above, you
may also pass the above configuration directives via the environment, using a
fawltydeps_
prefix. For example, to enable JSON output via the environment,
set fawltydeps_output_format=json
in FawltyDeps' environment.
Configuration cascade
- Command-line options take precedence, and override corresponding settings
passed via the environment or
pyproject.toml
. - Environment variables override corresponding settings from
pyproject.toml
. - Configuration in
pyproject.toml
override only the ultimate hardcoded defaults. - The ultimate defaults when no cutomizations takes place are hardcoded inside FawltyDeps, and are documented above.
Documentation
This project began with an exploration and design phase, yielding this design document, which lays out the main objective for this project and compares various strategies considered
In the code design section of documentation we lay out rules which we adopt to guide code architecture decisions and maintain code quality as the project evolves.
Development
Poetry
The project uses Poetry. Install Poetry, and then run:
poetry install --with=dev
to create a virtualenv with all (development) dependencies installed.
From there you can run:
poetry shell
to jump into a development shell with this virtualenv activated. Here you will
have all the dependencies declared in our pyproject.toml
installed. (Without this shell activated you will have to prefix the more
specific commands below with poetry run ...
).
Nox
We use Nox for test/workflow automation:
nox --list # List sessions
nox # Run all available sessions
nox -R # Run all available sessions, while reusing virtualenvs (i.e. faster)
nox -s tests # Run unit tests on supported Python versions (that are available)
nox -s tests-3.7 # Run unit tests on Python v3.7 (assuming it is available locally)
nox -s integration_tests-3.11 # Run integration tests on Python 3.11
nox -s lint # Run linters (mypy + pylint) on all supported Python versions
nox -s format # Check formatting (isort + black)
nox -s reformat # Fix formatting (isort + black)
If you want to run a command individually, the corresponding session is defined inside
noxfile.py
. For example, these
commands will work:
pytest # Run unit tests
pytest -m integration # Run integration tests
mypy # Run static type checking
pylint fawltydeps tests # Run Pylint
isort fawltydeps tests # Fix sorting of import statements
black . # Fix code formatting
Shortcut: Nix
We have a shell.nix
which provides Poetry in addition to all of
our supported Python versions. If you have Nix available
on your machine, then running:
nix-shell
will put you inside a shell where the Poetry virtualenv (with all development dependencies) is activated, and all supported Python versions are available. This also provides isolation from whatever Python version(s) and packages are installed on your system.
From there, a simple nox
will run all tests + linters against all supported
Python versions, as well as checking/formatting the code.
Integration tests
In addition to comprehensive unit tests under tests/
, we also verify
FawltyDeps' behavior with integration tests which (among other things) include
testing with real-world projects. To that end, we have a framework in
tests/test_real_projects.py
for downloading
and unpacking tarballs of 3rd-party projects, and then running fawltydeps on them,
while verifying their output. These projects, along with the expected FawltyDeps
outputs, are defined in TOML files under
tests/real_projects
.
Contributing
For bug reports, when a user reports that fawltydeps
does not work on their project, we adopt the following process:
- The project is added to
real_projects
. - We isolate the problems/issues/features and define/express them succinctly as a sample project under
sample_projects
. - We examine the issue more closely and update core logic, adding/altering unit tests along the way.
The resulting updates are introduced to fawltydeps
and reflected in our expectations, first in the TOML for the sample project(s) and then finally in the real_projects
TOML.
If you find a project where FawltyDeps is not doing a good job, we would appreciate
if you add that project under tests/real_projects
.
To see how these tests work, look at the existing files in that directory.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
File details
Details for the file fawltydeps-0.4.1.tar.gz
.
File metadata
- Download URL: fawltydeps-0.4.1.tar.gz
- Upload date:
- Size: 29.7 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: poetry/1.2.2 CPython/3.10.9 Linux/5.15.89
File hashes
Algorithm | Hash digest | |
---|---|---|
SHA256 | fcba7693f1ef77d471cd5d0081443add506cc9a55ad961dde2f70c200d5ee4f9 |
|
MD5 | 6d4c431d38514e6ef0665c872ed96f80 |
|
BLAKE2b-256 | 0772bdc996a0356f2a2225646c045ed5887537bb6103263f5a79d0de94d00bb2 |
File details
Details for the file fawltydeps-0.4.1-py3-none-any.whl
.
File metadata
- Download URL: fawltydeps-0.4.1-py3-none-any.whl
- Upload date:
- Size: 28.9 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: poetry/1.2.2 CPython/3.10.9 Linux/5.15.89
File hashes
Algorithm | Hash digest | |
---|---|---|
SHA256 | 8290784db95cb189321c3053d7cf896b46ce426973d3d3c2f42353b75b67f6cf |
|
MD5 | e3eabb2c62ccd43adb906945a79c230b |
|
BLAKE2b-256 | cb492d1af3759638896b42ce9931d3d34696082d268f13082923bbb7be2844eb |