Manage Dependencies#
PDM provides a bunch of handful commands to help manage your project and dependencies. The following examples are run on Ubuntu 18.04, a few changes must be done if you are using Windows.
Add dependencies#
pdm add
can be followed by one or several dependencies, and the dependency specification is described in PEP 508.
Examples:
1 2 3 4 |
|
PDM also allows extra dependency groups by providing -G/--group <name>
option, and those dependencies will go to
[project.optional-dependencies.<name>]
table in the project file, respectively.
You can reference other optional groups in optional-dependencies
, even before the package is uploaded:
1 2 3 4 5 6 7 8 |
|
After that, dependencies and sub-dependencies will be resolved properly and installed for you, you can view pdm.lock
to see the resolved result of all dependencies.
Local dependencies#
Local packages can be added with their paths. The path can be a file or a directory:
1 2 |
|
The paths MUST start with a .
, otherwise it will be recognized as a normal named requirement. The local dependencies will be written to the pyproject.toml
file with the URL format:
1 2 3 4 5 |
|
Using other build backends
If you are using hatchling
instead of the pdm backend, the URLs would be as follows:
1 2 |
|
VCS dependencies#
You can also install from a git repository url or other version control systems. The following are supported:
- Git:
git
- Mercurial:
hg
- Subversion:
svn
- Bazaar:
bzr
The URL should be like: {vcs}+{url}@{rev}
Examples:
1 2 3 4 5 6 7 8 9 10 |
|
Hide credentials in the URL#
You can hide the credentials in the URL by using the ${ENV_VAR}
variable syntax:
1 2 3 4 |
|
These variables will be read from the environment variables when installing the project.
Add development only dependencies#
New in 1.5.0
PDM also supports defining groups of dependencies that are useful for development,
e.g. some for testing and others for linting. We usually don't want these dependencies appear in the distribution's metadata
so using optional-dependencies
is probably not a good idea. We can define them as development dependencies:
1 |
|
This will result in a pyproject.toml as following:
1 2 |
|
You can have several groups of development only dependencies. Unlike optional-dependencies
, they won't appear in the package distribution metadata such as PKG-INFO
or METADATA
.
The package index won't be aware of these dependencies. The schema is similar to that of optional-dependencies
, except that it is in tool.pdm
table.
1 2 3 4 5 6 7 |
|
-d
or --dev
is specified, dependencies will go to dev
group under [tool.pdm.dev-dependencies]
by default.
Note
The same group name MUST NOT appear in both [tool.pdm.dev-dependencies]
and [project.optional-dependencies]
.
Editable dependencies#
Local directories and VCS dependencies can be installed in editable mode. If you are familiar with pip
, it is just like pip install -e <package>
. Editable packages are allowed only in development dependencies:
Note
Editable installs are only allowed in the dev
dependency group. Other groups, including the default, will fail with a [PdmUsageError]
.
1 2 3 4 5 6 |
|
Save version specifiers#
If the package is given without a version specifier like pdm add requests
. PDM provides three different behaviors of what version
specifier is saved for the dependency, which is given by --save-<strategy>
(Assume 2.21.0
is the latest version that can be found
for the dependency):
minimum
: Save the minimum version specifier:>=2.21.0
(default).compatible
: Save the compatible version specifier:>=2.21.0,<3.0.0
.exact
: Save the exact version specifier:==2.21.0
.wildcard
: Don't constrain version and leave the specifier to be wildcard:*
.
Add prereleases#
One can give --pre/--prerelease
option to pdm add
so that prereleases are allowed to be pinned for the given packages.
Update existing dependencies#
To update all dependencies in the lock file:
1 |
|
To update the specified package(s):
1 |
|
To update multiple groups of dependencies:
1 |
|
Or using comma-separated list:
1 |
|
To update a given package in the specified group:
1 |
|
If the group is not given, PDM will search for the requirement in the default dependencies set and raises an error if none is found.
To update packages in development dependencies:
1 2 3 4 |
|
About update strategy#
Similarly, PDM also provides 2 different behaviors of updating dependencies and sub-dependencies,
which is given by --update-<strategy>
option:
reuse
: Keep all locked dependencies except for those given in the command line (default).eager
: Try to lock a newer version of the packages in command line and their recursive sub-dependencies and keep other dependencies as they are.all
: Update all dependencies and sub-dependencies.
Update packages to the versions that break the version specifiers#
One can give -u/--unconstrained
to tell PDM to ignore the version specifiers in the pyproject.toml
.
This works similarly to the yarn upgrade -L/--latest
command. Besides, pdm update
also supports the
--pre/--prerelease
option.
Remove existing dependencies#
To remove existing dependencies from project file and the library directory:
1 2 3 4 5 6 |
|
Install the packages pinned in lock file#
There are a few similar commands to do this job with slight differences:
pdm sync
installs packages from the lock file.pdm update
will update the lock file, thensync
.pdm install
will check the project file for changes, update the lock file if needed, thensync
.
sync
also has a few options to manage installed packages:
--clean
: will remove packages no longer in the lockfile--only-keep
: only selected packages (using options like-G
or--prod
) will be kept.
Specify the lockfile to use#
You can specify another lockfile than the default pdm lock
by using the -L/--lockfile <filepath>
option or the PDM_LOCKFILE
environment variable.
Select a subset of dependency groups to be installed or locked#
Say we have a project with following dependencies:
1 2 3 4 5 6 7 8 9 10 |
|
Command | What it does | Comments |
---|---|---|
pdm install |
install prod and dev deps (no optional) | |
pdm install -G extra1 |
install prod deps, dev deps, and "extra1" optional group | |
pdm install -G dev1 |
install prod deps and only "dev1" dev group | |
pdm install -G:all |
install prod deps, dev deps and "extra1", "extra2" optional groups | |
pdm install -G extra1 -G dev1 |
install prod deps, "extra1" optional group and only "dev1" dev group | |
pdm install --prod |
install prod only | |
pdm install --prod -G extra1 |
install prod deps and "extra1" optional | |
pdm install --prod -G dev1 |
Fail, --prod can't be given with dev dependencies |
Leave the --prod option |
All development dependencies are included as long as --prod
is not passed and -G
doesn't specify any dev groups.
Besides, if you don't want the root project to be installed, add --no-self
option, and --no-editable
can be used when you want all packages to be installed in non-editable versions. With --no-editable
turn on, you can safely archive the whole __pypackages__
and copy it to the target environment for deployment.
You may also use the pdm lock command with these options to lock only the specified groups, which will be recorded in the [metadata]
table of the lock file. If no --group/--prod/--dev/--no-default
option is specified, pdm sync
and pdm update
will operate using the groups in the lockfile. However, if any groups that are not included in the lockfile are given as arguments to the commands, PDM will raise an error.
This feature is especially valuable when managing multiple lockfiles, where each may have different versions of the same package pinned. To switch between lockfiles, you can use the --lockfile/-L
option.
For a realistic example, your project depends on a release version of werkzeug
and you may want to work with a local in-development copy of it when developing. You can add the following to your pyproject.toml
:
1 2 3 4 5 6 |
|
Then, run pdm lock
with different options to generate lockfiles for different purposes:
1 2 3 4 5 6 |
|
Check the metadata.groups
field in the lockfile to see which groups are included.
Cross-platform lockfile#
By default, the generated lockfile is cross-platform, which means the current platform isn't taken into account when resolving the dependencies. The result lockfile will contain wheels and dependencies for all possible platforms and Python versions.
However, sometimes this will result in a wrong lockfile when a release doesn't contain all wheels. To avoid this, you can tell PDM
to create a lockfile that works for this platform only, trimming the wheels not relevant to the current platform. This can be done by passing the --no-cross-platform
option to pdm lock
:
1 |
|
Show what packages are installed#
Similar to pip list
, you can list all packages installed in the packages directory:
1 |
|
Or show a dependency graph by:
1 2 3 4 5 6 7 8 9 10 11 12 |
|
Allow prerelease versions to be installed#
Include the following setting in pyproject.toml
to enable:
1 2 |
|
Set acceptable format for locking or installing#
If you want to control the format(binary/sdist) of the packages, you can set the env vars PDM_NO_BINARY
and PDM_ONLY_BINARY
.
Each env var is a comma-separated list of package name. You can set it to :all:
to apply to all packages. For example:
1 2 3 4 5 6 7 8 |
|
Solve the locking failure#
If PDM is not able to find a resolution to satisfy the requirements, it will raise an error. For example,
1 2 3 4 5 6 7 |
|
You can either change to a lower version of django
or remove the upper bound of asgiref
. But if it is not eligible for your project, you can try overriding the resolved package versions in pyproject.toml
.
Manage global project#
Sometimes users may want to keep track of the dependencies of global Python interpreter as well.
It is easy to do so with PDM, via -g/--global
option which is supported by most subcommands.
If the option is passed, <CONFIG_ROOT>/global-project
will be used as the project directory, which is
almost the same as normal project except that pyproject.toml
will be created automatically for you
and it doesn't support build features. The idea is taken from Haskell's stack.
However, unlike stack
, by default, PDM won't use global project automatically if a local project is not found.
Users should pass -g/--global
explicitly to activate it, since it is not very pleasing if packages go to a wrong place.
But PDM also leave the decision to users, just set the config global_project.fallback
to true
.
By default, when pdm
uses global project implicitly the following message is printed: Project is not found, fallback to the global project
. To disable this message set the config global_project.fallback_verbose
to false
.
If you want global project to track another project file other than <CONFIG_ROOT>/global-project
, you can provide the
project path via -p/--project <path>
option.
Warning
Be careful with remove
and sync --clean/--pure
commands when global project is used, because it may remove packages installed in your system Python.
Export locked packages to alternative formats#
You can also export pdm lock
to other formats, to ease the CI flow or image building process. Currently,
only requirements.txt
format is supported:
1 |
|
Note
You can also run pdm export
with a .pre-commit
hook.