Open README.ipynb to view the full README (unfortunately github does not render notebook readme's)
Pyprojectx demo project
Clone the repo, run one command, everything works.
Onboarding on a Python project usually starts with a wall of instructions: install the right Python, create a virtualenv, activate it (differently on Windows), install the dependencies, and then install the linter, the formatter, the test runner and the build tool that CI happens to use.
Pyprojectx replaces all of that with a small pw script
that you commit next to your pyproject.toml. It bootstraps every tool your project
needs, on demand, in isolated environments inside the project directory.
If you have python 3.9+ and git, you're ready to go. There is nothing else to install: no jupyter, no uv, no ruff, not even pyprojectx itself.
git clone https://github.com/houbie/px-demo.git
cd px-demo
./pw notebookThat one command installed JupyterLab, installed this project in editable mode and opened the notebook you are reading right now.
Things to try
| Command | What happens |
|---|---|
./pw -i |
list every tool and alias, straight from pyproject.toml |
./pw build |
sync dependencies, lint, test and build a wheel |
./pw uv --help or ./pw https --help |
run uv or HTTPie without ever installing them |
./pw post-json |
POST some json to pie.dev with HTTPie |
./pw c |
aliases resolve on a unique prefix (here: check) |
./pw pJ |
... and on camel case initials (here: post-json) |
./pw --add mypy |
add a tool to the main context (writes it to pyproject.toml) |
./pw --clean build |
throw away all cached tools and prove it still works from scratch |
Tired of typing ./pw?
./pw --install-px installs the tiny px script in your home directory and adds it to your
PATH. After that:
px buildruns the project's aliases from any subdirectory, without the./prefix (and without the Windows/linux difference betweenpwand./pw)
Your pyproject.toml is the build script
No Makefile, no scripts/ directory full of shell scripts that only work on one OS:
[tool.pyprojectx.main] requirements = ["uv", "ruff", "prek", "px-utils", "httpie"] post-install = "prek install" [tool.pyprojectx.aliases] install = "uv sync" test = "uv run pytest" lint = ["ruff check"] check = ["@lint", "@test"] build = ["@install", "@check", "uv build"]
- Tools are declared, not documented. Everything in
requirementsis installed on first use and pinned in pw.lock, so you, your colleagues and CI all run the exact same ruff. - Aliases compose.
@lintrefers to another alias, which turns./pw buildinto a readable pipeline instead of a paragraph of setup instructions. - Contexts are isolated.
[tool.pyprojectx.jupyter]keeps JupyterLab's dependencies away from themaincontext, and[tool.pyprojectx.venv]is the project's own uv-managed.venv. - Nobody forgets the git hooks.
post-install = "prek install"installs them the first time anyone runs./pw.
Your project is already installed
Experimenting with your own code in a notebook takes exactly one command: ./pw notebook. The project
is installed in editable mode, together with its dependencies.
NOTE: restart the notebook kernel to activate changes to the project's dependencies.
import os import shutil import sys # nothing was installed globally: this kernel and everything it can import # live in a throw-away environment inside the project directory print("python :", os.path.relpath(sys.executable)) print("pycowsay:", os.path.relpath(shutil.which("pycowsay")))
# the project and all its dependencies are automatically available here from px_demo import moo moo.say_moo()
Nothing leaks onto your machine
The pw script installs every tool context in its own virtual environment under .pyprojectx/, much
like npm keeps everything in node_modules. Your system Python stays clean, two projects can happily
use two different ruff versions, and ./pw clean undoes it all.
Commands and their arguments are forwarded to the right environment by typing ./pw in front of them.
Simplified CI/CD pipelines
Because the tools install themselves, there is no toolchain to set up in CI. The entire build step is:
- name: Test and build run: python pw --clean build
See it in action in this project's github action workflow or in the pyprojectx workflow for a bigger example.
NOTE: If your CI/CD server runs on both linux and windows, you can merge the linux style
./pw buildand the windows stylepw buildinto a single command:python pw build
Use it in your own project
Copy pw and pw.bat into your repository, add a [tool.pyprojectx] section to your
pyproject.toml and commit them. Later on, ./pw --upgrade fetches the latest wrapper scripts.
See the documentation for all the details.
This branch uses uv, but pyprojectx doesn't care which dependency manager you prefer: the same demo is available with PDM and Poetry on sibling branches.