deptry can be run with:
deptry .
where .
is the path to the root directory of the project to be scanned.
If your project has multiple source directories, multiple root directories can be provided:
deptry a_directory another_directory
If you want to configure deptry using pyproject.toml
, or if your dependencies are stored in pyproject.toml
, but it is located in another location than the one deptry is run from, you can specify the location to it by using --config <path_to_pyproject.toml>
argument.
deptry extracts dependencies into 2 separate groups:
- "production" ones, meant to be used in the codebase
- development ones
This is an important distinction, as development dependencies are usually meant to only be used outside the codebase (for instance in tests, or as CLI tools for type-checking, formatting, etc.). For this reason, deptry will not run Unused dependencies (DEP002) for development dependencies.
To determine the project's dependencies, deptry will scan the directory it is run from for files in the following order:
- If a
pyproject.toml
file with a[tool.poetry.dependencies]
section is found, deptry will assume it uses Poetry and extract:- dependencies from
[tool.poetry.dependencies]
section - development dependencies from
[tool.poetry.group.dev.dependencies]
or[tool.poetry.dev-dependencies]
section
- dependencies from
- If a
pyproject.toml
file with a[tool.pdm.dev-dependencies]
section is found, deptry will assume it uses PDM and extract:- dependencies from
[project.dependencies]
and[project.optional-dependencies]
sections - development dependencies from
[tool.pdm.dev-dependencies]
section and from the groups under[project.optional-dependencies]
passed via the--pep621-dev-dependency-groups
argument.
- dependencies from
- If a
pyproject.toml
file with a[tool.uv.dev-dependencies]
section is found, deptry will assume it uses uv and extract:- dependencies from
[project.dependencies]
and[project.optional-dependencies]
sections - development dependencies from
[tool.uv.dev-dependencies]
section and from the groups under[project.optional-dependencies]
passed via the--pep621-dev-dependency-groups
argument.
- dependencies from
- If a
pyproject.toml
file with a[project]
section is found, deptry will assume it uses PEP 621 for dependency specification and extract:- dependencies from
[project.dependencies]
and[project.optional-dependencies]
. - development dependencies from the groups under
[dependency-groups]
, and the ones under[project.optional-dependencies]
passed via the--pep621-dev-dependency-groups
argument.
- dependencies from
- If a
requirements.in
orrequirements.txt
file is found, deptry will:- extract dependencies from that file.
- extract development dependencies from
dev-dependencies.txt
anddependencies-dev.txt
, if any exist
deptry can be configured to look for pip
requirements files with other names or in other directories.
See Requirements files and Requirements files dev.
deptry will search for imports in Python files (*.py
, and *.ipynb
unless --ignore-notebooks
is set) that are not part of excluded files.
Imports will be extracted regardless of where they are made in a file (top-level, functions, class methods, guarded by conditions, ...).
The only exception is imports that are guarded
by TYPE_CHECKING
. In this specific case,
deptry will not extract those imports, as they are not considered problematic. For instance:
from __future__ import annotations
from typing import TYPE_CHECKING
if TYPE_CHECKING:
# This import will not be extracted as it is guarded by `TYPE_CHECKING` and `from __future__ import annotations`
# is used. This means the import should only be evaluated by type checkers, and should not be evaluated during runtime.
import mypy_boto3_s3
There is some support for imports created with importlib.import_module
that use a string literal:
import importlib
importlib.import_module("foo") # package 'foo' imported
but not where the argument is provided dynamically from a variable, attribute, etc., e.g.:
bar = "foo"
importlib.import_module(bar) # Not detected
To determine issues with imported modules and dependencies, deptry will scan the working directory and its subdirectories recursively for .py
and .ipynb
files, so it can
extract the imported modules from those files. Any file solely used for development purposes, such as a file used for unit testing, should not be scanned. By default, the directories
venv
, .venv
, .direnv
, tests
, .git
and the file setup.py
are excluded.
deptry also reads entries in .gitignore
file, to ignore any pattern present in the file, similarly to what git
does.
To ignore other directories and files than the defaults, use the --exclude
(short -e
) flag. The argument can either be one long regular expression, or it can be reused multiple times to pass multiple smaller regular expressions. The paths should be specified as paths relative to the directory deptry is running in, without the trailing ./
. An example:
deptry . --exclude bar --exclude ".*/foo/"
deptry . --exclude "bar|.*/foo/"
The two statements above are equivalent, and will both ignore all files in the directory bar
, and all files within any directory named foo
.
Note that using the --exclude
argument overwrites the defaults, and will prevent deptry from considering entries in
.gitignore
.
To add additional patterns to ignore on top of the defaults instead of overwriting them, or to make sure that deptry
still considers .gitignore
, use the --extend-exclude
(short -ee
) flag.
deptry . --extend-exclude bar --extend-exclude ".*/foo/"
deptry . --extend-exclude "bar|.*/foo/"
This will exclude venv
, .venv
, .direnv
, .git
, tests
, setup.py
, bar
, and any directory named foo
, as well
as entries in .gitignore
, if there are some.
deptry can be added to your pre-commit rules. Here is
an example config for your .pre-commit-config.yaml
file:
- repo: https:/fpgmaas/deptry.git
rev: "<tag>"
hooks:
- id: deptry
args: ["--ignore", "DEP001"]
Replace <tag>
with one of the tags from the
project or a specific commit hash.
!!! important
This will only pull in the pre commit-hooks config file from the version passed to the `rev` agument. The actual version of _deptry_ that will be run will be the first one found in your path, so you will need to add _deptry_ to your local virtual environment.
For the pre-commit hook to run successfully, it should be run within the virtual environment of the project to be scanned, since it needs access to the metadata of the installed packages.
To show more details about the scanned Python files, the imported modules found, and how deptry determines issues in dependencies, add the --verbose
(short -v
) flag:
deptry . --verbose
deptry can be configured with command line arguments or by adding a [tool.deptry]
section to pyproject.toml
.
The lookup hierarchy for each configuration option is as follows:
- Default value is used
- If set, value in
[tool.deptry]
section ofpyproject.toml
is used, overriding the default - If set, value passed through the CLI is used, overriding both the default and
pyproject.toml
values
Path to the pyproject.toml
file that holds deptry's configuration and dependencies definition (if any).
- Type:
Path
- Default:
pyproject.toml
- CLI option name:
--config
- CLI example:
deptry . --config sub_directory/pyproject.toml
Disable ANSI characters in terminal output.
- Type:
bool
- Default:
False
- CLI option name:
--no-ansi
- CLI example:
deptry . --no-ansi
List of patterns to exclude when searching for source files.
- Type:
list[str]
- Default:
["venv", "\.venv", "\.direnv", "tests", "\.git", "setup\.py"]
pyproject.toml
option name:exclude
- CLI option name:
--exclude
(short:-e
) pyproject.toml
example:
[tool.deptry]
exclude = ["a_directory", "a_python_file\\.py", "a_pattern/.*"]
- CLI example:
deptry . --exclude "a_directory|a_python_file\.py|a_pattern/.*"
Additional list of patterns to exclude when searching for source files. This extends the patterns set in Exclude, to allow defining patterns while keeping the default list.
- Type:
list[str]
- Default:
[]
pyproject.toml
option name:extend_exclude
- CLI option name:
--extend-exclude
(short:-ee
) pyproject.toml
example:
[tool.deptry]
extend_exclude = ["a_directory", "a_python_file\\.py", "a_pattern/.*"]
- CLI example:
deptry . --extend-exclude "a_directory|a_python_file\.py|a_pattern/.*"
A comma-separated list of rules to ignore.
- Type:
list[str]
- Default:
[]
pyproject.toml
option name:ignore
- CLI option name:
--ignore
(short:-i
) pyproject.toml
example:
[tool.deptry]
ignore = ["DEP003", "DEP004"]
- CLI example:
deptry . --ignore DEP003,DEP004
A comma-separated mapping of packages or modules to be ignored per rule .
- Type:
dict[str, list[str] | str]
- Default:
{}
pyproject.toml
option name:per_rule_ignores
- CLI option name:
--per-rule-ignores
(short:-pri
) pyproject.toml
example:
[tool.deptry.per_rule_ignores]
DEP001 = ["matplotlib"]
DEP002 = ["pandas", "numpy"]
- CLI example:
deptry . --per-rule-ignores "DEP001=matplotlib,DEP002=pandas|numpy"
Disable searching for notebooks (*.ipynb
) files when looking for imports.
- Type:
bool
- Default:
False
pyproject.toml
option name:ignore_notebooks
- CLI option name:
--ignore-notebooks
(short:-nb
) pyproject.toml
example:
[tool.deptry]
ignore_notebooks = true
- CLI example:
deptry . --ignore-notebooks
List of pip
requirements files that contain the source dependencies.
- Type:
list[str]
- Default:
["requirements.txt"]
pyproject.toml
option name:requirements_files
- CLI option name:
--requirements-files
(short:-rt
) pyproject.toml
example:
[tool.deptry]
requirements_files = ["requirements.txt", "requirements-private.txt"]
- CLI example:
deptry . --requirements-files requirements.txt,requirements-private.txt
List of pip
requirements files that contain the source development dependencies.
- Type:
list[str]
- Default:
["dev-requirements.txt", "requirements-dev.txt"]
pyproject.toml
option name:requirements_files_dev
- CLI option name:
--requirements-files-dev
(short:-rtd
) pyproject.toml
example:
[tool.deptry]
requirements_files_dev = ["requirements-dev.txt", "requirements-tests.txt"]
- CLI example:
deptry . --requirements-files-dev requirements-dev.txt,requirements-tests.txt
List of Python modules that should be considered as first party ones. This is useful in case deptry is not able to automatically detect modules that should be considered as local ones.
- Type:
list[str]
- Default:
[]
pyproject.toml
option name:known_first_party
- CLI option name:
--known-first-party
(short:-kf
) pyproject.toml
example:
[tool.deptry]
known_first_party = ["bar", "foo"]
- CLI example:
deptry . --known-first-party bar --known-first-party foo
Write the detected issues to a JSON file. This will write the following kind of output:
[
{
"error": {
"code": "DEP002",
"message": "uvicorn defined as a dependency but not used in the codebase"
},
"module": "uvicorn",
"location": {
"file": "pyproject.toml",
"line": null,
"column": null
}
},
{
"error": {
"code": "DEP002",
"message": "uvloop defined as a dependency but not used in the codebase"
},
"module": "uvloop",
"location": {
"file": "pyproject.toml",
"line": null,
"column": null
}
},
{
"error": {
"code": "DEP004",
"message": "black imported but declared as a dev dependency"
},
"module": "black",
"location": {
"file": "src/main.py",
"line": 4,
"column": 0
}
},
{
"error": {
"code": "DEP003",
"message": "httpx imported but it is a transitive dependency"
},
"module": "httpx",
"location": {
"file": "src/main.py",
"line": 6,
"column": 0
}
}
]
- Type:
Path
- Default:
None
pyproject.toml
option name:json_output
- CLI option name:
--json-output
(short:-o
) pyproject.toml
example:
[tool.deptry]
json_output = "deptry_report.txt"
- CLI example:
deptry . --json-output deptry_report.txt
Deptry will automatically detect top level modules names that belong to a
module in two ways.
The first is by inspecting the installed packages. The second, used as fallback
for when the package is not installed, is by translating the package name to a
module name (Foo-Bar
translates to foo_bar
).
This however is not always sufficient. A situation may occur where a package is
not installed because it is optional and unused in the current installation.
Then when the package name doesn't directly translate to the top level module
name, or there are more top level modules names, Deptry may report both
unused packages, and missing packages. A concrete example is deptry reporting unused (optional) dependency
foo-python
, and missing package foo
, while package foo-python
would
install top level module foo
, if it were installed.
A solution is to pre-define a mapping between the package name and the top level module name(s).
- Type
dict[str, list[str] | str]
- Default:
{}
pyproject.toml
option name:package_module_name_map
- CLI option name:
--package-module-name-map
(short:-pmnm
) pyproject.toml
examples:
[tool.deptry.package_module_name_map]
foo-python = "foo"
Or for multiple top level module names:
[tool.deptry.package_module_name_map]
foo-python = [
"foo",
"bar",
]
- CLI examples:
deptry . --package-module-name-map "foo-python=foo"
Multiple module names are joined by a pipe (|
):
deptry . --package-module-name-map "foo-python=foo|bar"
Multiple package name to module name mappings are joined by a comma (,
):
deptry . --package-module-name-map "foo-python=foo,bar-python=bar"
PEP 621 does not define a standard convention for specifying development dependencies. However, deptry offers a mechanism to interpret specific optional dependency groups as development dependencies.
By default, all dependencies under [project.dependencies]
and [project.optional-dependencies]
are extracted as regular dependencies. By using the --pep621-dev-dependency-groups
argument, users can specify which groups defined under [project.optional-dependencies]
should be treated as development dependencies instead. This is particularly useful for projects that adhere to PEP 621 but do not employ a separate build tool for declaring development dependencies.
For example, consider a project with the following pyproject.toml
:
[project]
...
dependencies = [
"httpx",
]
[project.optional-dependencies]
test = [
"pytest < 5.0.0",
]
plot = [
"matplotlib",
]
By default, httpx
, pytest
and matplotlib
are extracted as regular dependencies. By specifying --pep621-dev-dependency-groups=test
,
the dependency pytest
will be considered a development dependency instead.
- Type:
list[str]
- Default:
[]
pyproject.toml
option name:pep621_dev_dependency_groups
- CLI option name:
--pep621-dev-dependency-groups
(short:-ddg
) pyproject.toml
example:
[tool.deptry]
pep621_dev_dependency_groups = ["test", "docs"]
- CLI example:
deptry . --pep621-dev-dependency-groups "test,docs"
!!! warning This option is experimental and disabled by default for now, as it could degrade performance in large codebases.
Enable experimental namespace package (PEP 420) support.
When enabled, deptry will not only rely on the presence of __init__.py
file in a directory to determine if it is a
local Python module or not, but will consider any Python file in the directory or its subdirectories, recursively. If a
Python file is found, then the directory will be considered as a local Python module.
- Type:
bool
- Default:
False
pyproject.toml
option name:experimental_namespace_package
- CLI option name:
--experimental-namespace-package
pyproject.toml
example:
[tool.deptry]
experimental_namespace_package = true
- CLI example:
deptry . --experimental-namespace-package