wppm — Manage your Python packages
wppm is a complement 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
Global navigation commands
What packages are there? package version and summary
$ wppm -ls
Package Version Summary
__________________ ______________ ______________________________________________________________________
build 1.5.0 A simple, correct Python build frontend
certifi 2026.6.17 Python package for providing Mozilla's CA Bundle.
charset-normalizer 3.4.9 The Real First Universal Charset Detector. Open, modern and actively m
...
What did I actually ask for? Nothing in an environment records which packages you
chose and which merely came along. -tl keeps only the entries nothing else pulls in:
$ wppm -tl
build
duckdb
flake8
flit
pandas
pillow
pipdeptree
pytest
PyYAML
wppm
# 32 entries -> 10 kept, 22 already pulled in
What are the dependencies?
$ wppm -tl -p
build==1.5.0 ,
colorama==0.4.6 ;os_name==nt
packaging==26.2 >=24.0
pyproject-hooks==1.2.0
duckdb==1.5.4
flake8==7.1.1 ,
mccabe==0.7.0 (<0.8.0,>=0.7.0)
...
Navigation per package(s)
What does a package need? -p walks downwards, -l says how many levels:
$ wppm -p pandas -l2
pandas==3.0.3 ,
numpy==2.4.6 >=2.3.3;python_version>=3.14
python-dateutil==2.9.0.post0 >=2.8.2,
six==1.17.0 >=1.5
tzdata==2025.3 ;sys_platform==win32
What packages are upgrade constrained? -r walks upwards, and ! keeps only the packages
that pin or cap the one you name, . means to look for every package:
$ wppm -r ".!"
charset-normalizer==3.4.9 ,
requests==2.34.2 [requires: charset-normalizer<4,>=2]
idna==3.18 ,
requests==2.34.2 [requires: idna<4,>=2.5]
...
Quoting:
!and[are shell metacharacters in POSIX shells, so quote any argument containing them (wppm -r "pluggy!"). Incmd.exethe quotes are optional.
Package [Extras] analysis
use brackets to specify extra(s) [extra], [.] means every extra,
and ! narrows the answer to what is missing — ==? marks a requirement that is
not installed:
What am I missing, per flit extra?
$ 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
Which package[extra] may want numpy?
$ wppm -r "numpy[.]"
numpy==2.4.6 ,
pandas==3.0.3 [requires: numpy>=2.3.3;python_version>=3.14]
numpy[all]==2.4.6 ,
duckdb[all]==1.5.4 [requires: numpy;extra==all]
Pruning a requirements file
Given a file, -tl answers for that file's entries. Plainly, it prints the pruned list
and nothing else — so the output is a reduced requirement file, -v will include the
reason for each pruned package:
$ wppm requirements.txt -tl > requirements_new.txt
# 160 entries -> 112 kept, 48 already pulled in
# 8 repeated, collapsed: brotli, openai, pympler, pytest, python-barcode, ...
$ wppm requirements.txt -tl -v
# requirements.txt, sorted, 2026-08-13 19:22:43
# 160 entries -> 112 kept, 48 already pulled in
...
#numpy # <- baresql, clarabel, cvxpy, dask[array,dataframe,diagnostics], datashader, ...
#scikit-learn # <- imbalanced-learn, mlxtend, prince, skrub, umap-learn
#whatthepatch # <- spyder
Answers a script can read
-p, -r, -tl, -ls and -md all accept -j / --json, so the same answers can
gate a CI job or be diffed between two environments:
$ 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)"
Better still, skip the terminal: the tree engine is a plain importable module — no subprocess, no parsing of terminal output.
>>> from wppm import piptree
>>> pip = piptree.PipData() # or PipData(target=r"D:\WPy64\python")
>>> print(pip.down("pandas", "mysql"))
pandas[mysql]==3.0.3 ,
numpy==2.4.6 >=2.3.3;python_version>=3.14
pymysql==? >=1.1.1;extra==mysql
python-dateutil==2.9.0.post0 >=2.8.2,
six==1.17.0 >=1.5
sqlalchemy==? >=2.0.36;extra==mysql
tzdata==2025.3 ;sys_platform==win32
>>> pip.summary("pandas")
'Powerful data structures for data analysis, time series, and statistics'
down() and up() return indented text by default, or a JSON string with
format="json"; both take top_level=True to start from the top-level entries.
top_level() itself returns plain data — kept, and dropped mapping each dropped
entry to whatever pulls it in:
>>> pip.top_level()["kept"]
['build', 'duckdb', 'flake8', 'flit', 'pandas', 'pillow', 'pipdeptree', 'pytest', 'PyYAML', 'wppm']
>>> pip.top_level(["pandas", "numpy", "requests[socks]", "pytest"])["dropped"]
{'numpy': ['pandas']}
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 -p "pandas[.]" -t D:\WPy64\python
$ wppm -ls -ws .\wheelhouse\included.wheels --json
With -ws the facts come from the wheelhouse rather than an installation, so a
requirements list can be pruned before anything is built; where several versions of a
package are present, the newest one answers.
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.
wppm -h lists every option.
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.12.20260816-py3-none-any.whl.
File metadata
- Download URL: wppm-17.12.20260816-py3-none-any.whl
- Upload date:
- Size: 41.3 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 |
c41a205f17dbef6b752d89ce3497a99253f1c3b927d8bc3674c04a36dcd741b0
|
|
| MD5 |
bb8bef6dbe38d354aa6c25e539e987f4
|
|
| BLAKE2b-256 |
7ab982f5e3fc98810e8349fb26b89cb36619f3f8f09f46796516b2c19cd62bf5
|
Provenance
The following attestation bundles were made for wppm-17.12.20260816-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.12.20260816-py3-none-any.whl -
Subject digest:
c41a205f17dbef6b752d89ce3497a99253f1c3b927d8bc3674c04a36dcd741b0 - Sigstore transparency entry: 2486477251
- Sigstore integration time:
-
Permalink:
winpython/winpython@45e14ac0e1a6b6593476642f240ed305832b47dc -
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@45e14ac0e1a6b6593476642f240ed305832b47dc -
Trigger Event:
workflow_dispatch
-
Statement type: