Shared global environment package installer using symlinks โ like pnpm for Python
Project description
๐ pepip
uv and pip, but shared. Install packages once. Use them everywhere.
pepip is the pnpm of Python โ a drop-in alternative to pip / uv that stores each resolved package version once in a shared store and wires your project .venv to it via symlinks. No more downloading torch five times. It internatly uses uv for package resolution and venv management, so you get all the same features and compatibility, but with a fraction of the disk usage and faster installs for subsequent projects.
๐ค The Problem
Every Python project gets its own virtual environment. That means every project downloads and stores its own copy of every dependency โ including the big ones.
project-a/.venv/ โ numpy (35 MB) pandas (15 MB) torch (2.4 GB)
project-b/.venv/ โ numpy (35 MB) pandas (15 MB) torch (2.4 GB)
project-c/.venv/ โ numpy (35 MB) pandas (15 MB) torch (2.4 GB)
โ stored 3ร for no reason
โ The Solution
pepip keeps an immutable shared package-version store and symlinks each project's .venv back to the exact versions it resolved. Same Python import behaviour. A fraction of the disk usage.
~/.pepip/packages/ โ numpy 2.0 (35 MB) pandas 2.2 (15 MB) torch 2.5 (2.4 GB) โ stored once per version
project-a/.venv/ โ numpy (symlink) pandas (symlink) torch (symlink)
project-b/.venv/ โ numpy (symlink) pandas (symlink) torch (symlink)
project-c/.venv/ โ numpy (symlink) pandas (symlink) torch (symlink)
๐ Installation
pip install pepip
Requirements: Python 3.8+ ยท uv (auto-installed)
๐ฆ Usage
Install packages using pepip
# Install one or more packages
pepip install numpy pandas
# Install from a requirements file
pepip install -r requirements.txt
# Use a custom local venv path (default: .venv)
pepip install numpy --venv /path/to/my-env
Then activate and use your .venv exactly as you normally would:
source .venv/bin/activate
python -c "import numpy; print(numpy.__version__)"
Override the global store location
PEPIP_HOME=/shared/team-env pepip install torch
This is handy for sharing a global store across a whole team on a shared machine.
๐ How it works
~/.pepip/
โโโ global-venv/ โ build interpreter for uv installs
โโโ packages/
โโโ cpython-312-linux-x86_64/
โโโ numpy-2.0/
โ โโโ numpy/ โ real files, stored once
โ โโโ numpy-2.0.dist-info/
โโโ requests-2.25.1/
โ โโโ requests/
โ โโโ requests-2.25.1.dist-info/
โโโ requests-2.26.0/
โโโ requests/
โโโ requests-2.26.0.dist-info/
my-project/
โโโ .venv/
โโโ lib/
โโโ python3.12/
โโโ site-packages/
โโโ numpy โโโโโโโโโโโ ~/.pepip/packages/.../numpy-2.0/numpy (symlink, ~bytes)
โโโ pandas โโโโโโโโโโโ ~/.pepip/packages/.../pandas-2.2/pandas (symlink, ~bytes)
โโโ ...
- First install of a package version โ downloads once into the shared store, then symlinks.
- Every subsequent project using the same package version โ symlinks only. Near-instant, zero extra disk.
- Different projects can use different versions โ for example, one project can link to
requests==2.25.1while another links torequests==2.26.0.
๐ Benchmarks
The eval/benchmark.py script measures installation latency and disk usage across N projects compared to a plain uv workflow.
# 5 projects, mixed real-world packages
python eval/benchmark.py --projects 5 --packages tomli packaging requests numpy pandas
# Keep temp directories for manual inspection
python eval/benchmark.py --no-cleanup
Latest results โ 5 projects ยท tomli packaging requests numpy pandas
| Metric | uv (baseline) | pepip | Improvement |
|---|---|---|---|
| โฑ Latency | 0.56 s | 0.33 s โ | โ41.3 % |
| ๐พ Disk usage | 475.19 MB | 95.22 MB โ | โ80.0 % |
โฑ pepip saved 0.23 s of install time across 5 projects. ๐พ pepip saved 379.97 MB of disk space across 5 projects.
Why the savings get better over time
- Storage savings are consistent from project one: each package version lives exactly once in the global store, so local
.venvdirectories contain only tiny symlinks (dozens of bytes each) instead of full copies. - Latency savings grow with project count: the first project pays the same download cost as plain
uv. Every additional project only needs venv creation + symlink creation, which is nearly instant. For large packages liketorchortransformers(GBs in size), these savings per extra project are proportionally enormous.
๐ Development
# Clone and install in editable mode
git clone https://github.com/perf-pip/pepip
cd pepip
pip install -e .
# Run tests
pip install pytest
pytest
๐ก Inspired by
pnpm โ the Node.js package manager that pioneered content-addressable, symlink-based shared stores. pepip brings the same idea to the Python ecosystem.
Acknowledgements
- uv โ used for venv management, package resolution, and shared download caching.
Made with โค๏ธ for developers tired of downloading torch over and over again.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
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 pepip-0.0.2.tar.gz.
File metadata
- Download URL: pepip-0.0.2.tar.gz
- Upload date:
- Size: 188.9 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
fa3b68cf5d420264c0b4d3ecf3ed00512463021c0c05838682748952c8eee892
|
|
| MD5 |
eaa7969f6710dd7eca32210a46ad2833
|
|
| BLAKE2b-256 |
3a3db6d77378de3b8527d18177e87d77cc6043858b4b6dbe5bd0397817e7c199
|
Provenance
The following attestation bundles were made for pepip-0.0.2.tar.gz:
Publisher:
publish-pypi.yml on perf-pip/pepip
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
pepip-0.0.2.tar.gz -
Subject digest:
fa3b68cf5d420264c0b4d3ecf3ed00512463021c0c05838682748952c8eee892 - Sigstore transparency entry: 1291858971
- Sigstore integration time:
-
Permalink:
perf-pip/pepip@305c3d5b681e2ecd923f18dc4b239eb189cb5268 -
Branch / Tag:
refs/tags/v0.0.2 - Owner: https://github.com/perf-pip
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish-pypi.yml@305c3d5b681e2ecd923f18dc4b239eb189cb5268 -
Trigger Event:
release
-
Statement type:
File details
Details for the file pepip-0.0.2-py3-none-any.whl.
File metadata
- Download URL: pepip-0.0.2-py3-none-any.whl
- Upload date:
- Size: 11.3 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
83eb8da04c33a97f576db4f97f8ed00f5bb41e5aca89e3d4a8c378b4c46505e1
|
|
| MD5 |
56b7330bac47a792f1a33f04bdc7877f
|
|
| BLAKE2b-256 |
04d69ecd6ef7bf60e0f94b707926171a61767c6aec8111709a348d36d9236161
|
Provenance
The following attestation bundles were made for pepip-0.0.2-py3-none-any.whl:
Publisher:
publish-pypi.yml on perf-pip/pepip
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
pepip-0.0.2-py3-none-any.whl -
Subject digest:
83eb8da04c33a97f576db4f97f8ed00f5bb41e5aca89e3d4a8c378b4c46505e1 - Sigstore transparency entry: 1291859033
- Sigstore integration time:
-
Permalink:
perf-pip/pepip@305c3d5b681e2ecd923f18dc4b239eb189cb5268 -
Branch / Tag:
refs/tags/v0.0.2 - Owner: https://github.com/perf-pip
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish-pypi.yml@305c3d5b681e2ecd923f18dc4b239eb189cb5268 -
Trigger Event:
release
-
Statement type: