wppm — the dependency questions pip won't answer
wppm is a small companion to pip, for any Python environment (it was born in
WinPython, the portable Windows distribution, but does
not require it). Keep using pip to install and remove things — use wppm to see
what is actually there.
pip install wppm
Which extras of a package are actually usable here?
You installed flit. Its [doc] and [test] extras promise more. What is missing?
$ wppm -p "flit![.]"
flit[doc]==3.12.0 ,
pygments-github-lexers==? ;extra==doc
sphinx==? ;extra==doc
sphinxcontrib-github-alt==? ;extra==doc
flit[test]==3.12.0 ,
pytest-cov==? ;extra==test
responses==? ;extra==test
testpath==? ;extra==test
tomli==? ;extra==test
[.] means every extra, ! means only show what is missing, and ==? marks a
requirement that is not installed. Extras with nothing missing are simply not printed —
so an empty answer means "everything this package offers is ready to use".
Drop the ! to see the whole picture instead, installed versions included:
$ wppm -p "requests[.]" -l1
requests==2.34.2 ,
certifi==2026.6.17 >=2023.5.7
charset-normalizer==3.4.9 <4,>=2
idna==3.18 <4,>=2.5
urllib3==2.7.0 <3,>=1.26
requests[socks]==2.34.2 ,
certifi==2026.6.17 >=2023.5.7
charset-normalizer==3.4.9 <4,>=2
idna==3.18 <4,>=2.5
pysocks==? !=1.5.7,>=1.5.6;extra==socks
urllib3==2.7.0 <3,>=1.26
requests[use-chardet-on-py3]==2.34.2 ,
certifi==2026.6.17 >=2023.5.7
chardet==? <8,>=3.0.2;extra==use-chardet-on-py3
charset-normalizer==3.4.9 <4,>=2
idna==3.18 <4,>=2.5
urllib3==2.7.0 <3,>=1.26
Who pulls in pytest, and through which extra?
The reverse direction, -r, is extras-aware too — it tells you why something is in
your environment, down to the extra that asked for it:
$ wppm -r "pytest[.]"
pytest==9.0.3
pytest[all]==9.0.3 ,
idna[all]==3.18 [requires: pytest>=8.3.2;extra==all]
pandas[all]==3.0.3 [requires: pytest>=8.3.4;extra==all]
pytest[dev]==9.0.3
pytest[test]==9.0.3 ,
flit[test]==3.12.0 [requires: pytest>=2.7.3;extra==test]
pandas[test]==3.0.3 [requires: pytest>=8.3.4;extra==test]
pytest[testing]==9.0.3 ,
pluggy[testing]==1.6.0 [requires: pytest;extra==testing]
pytest[tests]==9.0.3 ,
pillow[tests]==12.3.0 [requires: pytest;extra==tests]
What will break when I upgrade?
With -r, the ! filter keeps only the packages that pin or cap the one you name —
the handful that will actually fight your next upgrade, instead of the long list of
packages that merely depend on it:
$ wppm -r "pluggy!"
pluggy==1.6.0 ,
pytest==9.0.3 [requires: pluggy<2,>=1.5]
An empty answer here is good news: nothing constrains it, upgrade away.
And the whole constraint web of an environment — every package, every extra, nine levels deep — is one command:
$ wppm -p ".[.]" -l9
Everything is available as JSON
Any of -p, -r, -ls, -md accepts -j / --json, so the same answers can gate a
CI job or be diffed between two environments:
$ wppm -p pluggy -j
[
{
"package": "pluggy",
"extra": "",
"version": "1.6.0",
"installed": true,
"constraint": "",
"depends": []
}
]
$ wppm -p myapp -j | python -c "import sys,json; s=json.load(sys.stdin); [s.extend(n['depends']) for n in s]; sys.exit(1 if any(not n['installed'] for n in s) else 0)"
Or use it from Python
The tree engine is a plain importable module — no subprocess, no parsing of terminal
output. down() walks dependencies, up() walks them backwards, and both return
indented text by default or a JSON string with format="json":
import json
from wppm import piptree
pip = piptree.PipData() # or PipData(target=r"D:\WPy64\python")
tree = json.loads(pip.down("pandas", "mysql", format="json"))
missing = [d["package"] for d in tree[0]["depends"] if not d["installed"]]
print(f"pandas[mysql] needs: {missing}")
pandas[mysql] needs: ['pymysql', 'sqlalchemy']
>>> print(pip.up("pluggy!")) # who caps pluggy?
pluggy==1.6.0 ,
pytest==9.0.3 [requires: pluggy<2,>=1.5]
>>> pip.summary("pandas")
'Powerful data structures for data analysis, time series, and statistics'
It also works on environments you have not installed anything into
-t points wppm at another Python distribution, and -ws at a plain directory of
wheels — so you can inspect a portable distribution, or an offline bundle, without
installing it first:
$ wppm -ls -ws .\wheelhouse\included.wheels --json
$ wppm -p "pandas[.]" -t D:\WPy64\python
Beyond inspection, wppm installs from a wheelhouse or a pylock.toml (-i, -ws,
-wd), emits a one-document environment manifest — distribution, tools, packages,
wheelhouse — as Markdown or JSON (-md, a lightweight SBOM), and does portability
housekeeping: on any Windows Python, --movable / --fix rewrite the Scripts\
launchers and shebangs between relative and absolute paths, so a directory can be moved
(or pinned back down) without breaking its entry points.
--register / --unregister associate file extensions, icons, context menu and start
menu entries with the target Python. Each distribution gets its own start menu folder,
so registering one never disturbs another — but note that the target is declared under
the WinPython PEP-514 vendor key.
Compared with pipdeptree
wppm adds per-[extra] granularity in both directions, the ! filter (missing
dependencies forward, constraining dependencies backward), and the ability to inspect
another environment (-t) or a bare directory of wheels (-ws) without installing
anything into it.
Quoting:
!and[are shell metacharacters in POSIX shells, so quote the argument (wppm -p "flit![.]"). Incmd.exethe quotes are optional.
Command line
usage: wppm [-h] [-v] [--register] [--unregister] [--fix] [--movable]
[-ws WHEELSOURCE] [-wd WHEELDRAIN] [-ls] [-lsa] [-md] [-p] [-r]
[-l LEVELS] [-j] [-t TARGET] [-i] [-u]
[package(s) or lockfile ...]
WinPython Package Manager: handle a Python distribution (WinPython or not) and its packages (17.10.20260808)
positional arguments:
package(s) or lockfile
optional package names, wheels, or lockfile
options:
-h, --help show this help message and exit
-v, --verbose show more details on packages and actions
--register Register the target Python in Windows (file extensions, icons, context menu, start menu), under the 'WinPython' PEP-514 vendor key
--unregister Unregister the target Python from Windows: de-associate file extensions, icons and context menu, and remove its start menu folder
--fix make the target Python use absolute (fixed) paths in launchers and shebangs
--movable make the target Python (any Windows Python) movable/portable: relative paths in launchers and shebangs
-ws WHEELSOURCE wheels location, ('.' = WheelHouse): wppm pylock.toml -ws source_of_wheels, wppm -ls -ws .
-wd WHEELDRAIN wheels destination: wppm pylock.toml -wd destination_of_wheels
-ls, --list list installed packages matching [optional] expression: wppm -ls, wppm -ls pand
-lsa list details of packages matching [optional] expression: wppm -lsa pandas -l1
-md markdown summary of the installation
-p show Package (!= missing) dependencies of the given package[option], [.]=all: wppm -p pandas[.]
-r show Reverse (!= constraining) dependancies of the given package[option]: wppm -r pytest![test]
-l LEVELS show 'LEVELS' levels of dependencies (with -p, -r): wppm -p pandas -l1
-j, --json machine-readable JSON output (with -p, -r, -ls, -md): wppm -p pandas[.] -j
-t TARGET path to target Python distribution (default: current environment)
-i, --install install a given package wheel or pylock file (use pip for more features)
-u, --uninstall uninstall package (use pip for more features)
Links
- Source code: https://github.com/winpython/winpython
- Issues and feature requests: https://github.com/winpython/winpython/issues
- Discussions: https://github.com/winpython/winpython/discussions
- WinPython distribution: https://winpython.github.io/
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distributions
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file wppm-17.10.20260808-py3-none-any.whl.
File metadata
- Download URL: wppm-17.10.20260808-py3-none-any.whl
- Upload date:
- Size: 38.4 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
18df2d9fa2ae37081341edbb566476c8ab763663dd6ddad143343ca84f32b6dd
|
|
| MD5 |
a6a161fcb880ad01c59deb5a9f312519
|
|
| BLAKE2b-256 |
b29fbad3e1e5e02dd1c9c67b92091231af2936ae4ee6e72e7dd33344139e0a26
|
Provenance
The following attestation bundles were made for wppm-17.10.20260808-py3-none-any.whl:
Publisher:
build_wppm_prod_publish.yml on winpython/winpython
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
wppm-17.10.20260808-py3-none-any.whl -
Subject digest:
18df2d9fa2ae37081341edbb566476c8ab763663dd6ddad143343ca84f32b6dd - Sigstore transparency entry: 2386073120
- Sigstore integration time:
-
Permalink:
winpython/winpython@aabece85455c16c4b91f347e564aa260addc808a -
Branch / Tag:
refs/heads/master - Owner: https://github.com/winpython
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
build_wppm_prod_publish.yml@aabece85455c16c4b91f347e564aa260addc808a -
Trigger Event:
workflow_dispatch
-
Statement type: