Why isolate your dev tools?#
There are several reasons to manage your dev tools separately from your project dependencies.
Dev-dependency conflicts in Poetry and PDM#
Poetry and PDM let you define dev-dependencies similar to npm's devDependencies. There is however a major difference between Python and npm dependencies: npm can install multiple versions of the same package, meaning that devDependencies do not interfere with main dependencies. Python, on the other hand, can only install one version of a package. This means that all dependencies will have to meet both the main dependency constraints and all the dev-dependency constraints.
If you install all your development tools as dev-dependencies, some packages that your production code depends on, will likely be downgraded to older versions. Or worse: your project fails to install because of dependency conflicts.
Tip: Only install test packages as dev-dependencies
pytest and friends need to be installed together with your code, so you will need to add them as Poetry or PDM dev-dependencies. Other tools and utilities can be managed by Pyprojectx in order to get reproducible builds.
uv already isolates tools -- why add Pyprojectx?#
uv is excellent at managing Python projects and running tools. But its tool-isolation mechanisms leave gaps that Pyprojectx fills:
uvx/uv tool runcreates ephemeral environments that are not version-locked. Each invocation may resolve different transitive dependencies, making builds unreproducible.uv tool installpins a tool version, but globally. Two projects on the same machine cannot use different versions of ruff or mypy, and transitive dependencies are still not locked.- Pyprojectx gives you per-project (even per-branch) version pinning combined with full transitive dependency locking via
pw.lock. And because thepwwrapper script bootstraps everything -- including Pyprojectx itself -- contributors and CI don't need to pre-install anything, not even uv.
The unreliable pip install#
One would expect that pip install tool-x==1.2.3 always installs exactly the same version of tool-x.
Unfortunately, this is not the case because most Python packages do not pin the versions of their dependencies.
This means that released versions of tools can be broken at any time by a new release of one of their dependencies.
This is exactly what happened with PDM 2.5.3.
For this reason, all the dependencies of pyprojectx are locked when publishing to PyPI.