pip-auto
Just import it. Missing packages install themselves.
pip install pip-auto
That's the whole setup. From now on, when your code imports something that isn't installed, pip-auto finds the
right package on PyPI, installs it on the spot, and your program keeps running — no ModuleNotFoundError,
no stopping to run pip install, no restarting.
import pyfiglet # not installed? fine
from PIL import Image # import name ≠ package name? fine (installs pillow)
import cv2 # installs opencv-python
print(pyfiglet.figlet_format("hello"))
[autopip] 'pyfiglet' not found → installing pyfiglet
[autopip] installed pyfiglet==1.0.4 (2.51s)
Why it's nice
-
Zero setup.
pip install pip-autoturns it on for that Python.pip uninstall pip-autoremoves every trace. -
It knows the real package name.
PIL→pillow,cv2→opencv-python,sklearn→scikit-learn,bs4→beautifulsoup4,google.generativeai→google-generativeai, plus ~1,000 more mappings — and it learns new ones from every wheel it sees. Before installing, it opens the wheel and checks the module is really inside, so a same-named impostor never gets installed. -
Fast. Its own installer (pip is not used): the whole dependency tree is discovered in parallel over one shared connection setup, and every file of every wheel is written in a single parallel pass. From the second time on it just hard-links from a local cache (filled in the background, at low priority). Measured with
bench/bench.py, which gives pip, uv and pip-auto the same throttled network (10 MB/s shared, +30 ms per connection), a brand-new venv every run, no bytecode compiled by anyone, and checks that all three installed the same packages. Heavy set (numpy, pandas, scipy, matplotlib, scikit-learn, pillow: 19 packages, 7,757 files), median of 3 on one Windows PC:first install (empty cache) second install (warm cache) pip 40 s 47 s uv (default: hard links) 35 s 3.3 s pip-auto (default: junctions) 19.5 s 0.8 s uv ( --link-mode copy)35.5 s 8.9 s pip-auto ( link_mode copy, same work as pip)34.8 s 5.2 s Read it honestly: the first install is dominated by the network and by writing ~8,700 files, so with the same amount of writing (copy mode) pip-auto and uv are about equal; the big differences are on repeat installs, where folder links (junctions, Windows) skip the writing altogether. Numbers vary with machine load; run
bench/bench.pyyourself. It adds only about 5 ms to Python startup. -
Safe. Names that look like popular packages (typosquats such as
requets) and brand-new unknown packages are never installed automatically. If anything fails halfway, everything — including the old versions it replaced — is rolled back. -
Respects "optional" imports.
try: import x / except ImportError:in your code, optional imports inside libraries, andimportlib.util.find_spec("x")checks are left alone. -
Works everywhere you run Python: scripts, Jupyter / IPython, virtual environments.
-
Speaks your language. Messages follow your OS language: English, 日本語, 简体中文, 繁體中文, 한국어, Español, Français, Deutsch, Português, Русский.
Tell it what you want (optional)
# /// script
# dependencies = ["requests<3", "rich"]
# ///
import requests, rich # a PEP 723 block is installed up front, all at once
import numpy # autopip: numpy<2 ← pin a version with an end-of-line comment
Project settings: allow / deny lists (optional)
Put an autopip.toml (or a [tool.autopip] table in pyproject.toml) next to your scripts. autopip init creates one.
[autopip]
allow = ["requests<3", "numpy", "types-*"] # only these may be installed automatically (versions and wildcards OK)
deny = ["evil-pkg"] # never — even when something else needs it as a dependency
constraints = ["numpy<2"] # version limits for automatic installs (same as pip -c)
ask = true # settings here override your personal ones
It is looked up from the script's folder upwards and applies to automatic installs only (imports, autopip run, PEP 723);
what you type yourself with autopip install is never blocked. autopip policy [x.py] [pkg...] shows what is in effect
and whether a package would be allowed. With a settings file present, autopip never falls back to plain pip
(which would bypass the lists).
One-file bundles
autopip bundle app.py # → app.pyz
python app.pyz # the other person needs nothing else installed
app.py, the local modules it imports, and every dependency are packed into one solid-compressed block (all files
concatenated, compressed once — smaller than zipping file by file: e.g. 28 MB of wheels → 18 MB). At run time the block
is decompressed in a single streaming pass while files are written in parallel, then cached; later runs start instantly.
Bundles that contain compiled packages (numpy, …) are tied to the Python version and OS they were built for. For those,
all bytecode goes into one code-archive file instead of thousands of .py/.pyc files: a tiny import hook loads
modules straight from it (sources are kept inside, so tracebacks and inspect.getsource still show code), and only real
files — .pyd/.so, data — are written to disk. Example (numpy + pandas + flask + rich + requests): 7,357 files → 2,022;
first run ≈ 8 s instead of ≈ 40 s. Child processes (multiprocessing spawn) work too. Pure-Python bundles are portable and
are extracted as ordinary files.
Options: --codec lzma|zlib|none, --level N, --include "pkg==1.0", --loose (ordinary files, no code archive),
--no-pyc, --info app.pyz, --diff old.pyz new.pyz (which packages and files changed). The loader depends on nothing but the standard library. Limitation: with
python -S / -I (no site), child processes cannot use the code archive.
Speed and robustness details
- Connection reuse: requests to the same host share one keep-alive connection (about 30 ms of TLS handshake saved per request;
a cold resolve of 9 packages went from a median 3.2 s to 2.4 s). Proxy settings still use urllib.
AUTOPIP_NO_POOL=1turns it off. - Resumable, single downloader: an interrupted download continues from where it stopped (
Range), and when several pip-auto processes need the same wheel, one downloads and the others wait for it; the same applies to building the unpacked cache. Stale locks from crashed processes are taken over. - Longer-lived solutions: a resolved dependency set is reused for up to 6 hours as long as the index pages of every package in it are unchanged (checked with ETag, about 0.5 s instead of about 1.1 s for a 9-package set with stale indexes).
- Shared
.pyc: with junction mode,.pycfiles are compiled once into the shared cache (in the background), so every environment and its first import use them. autopip prefetch pkg...resolves, downloads and prepares the cache without installing, so a later install is only links.- Download and unpack overlap (auto): when the network is slower than about 30 MB/s the disk is idle while waiting, so each
wheel is unpacked into the cache as soon as it arrives. Same throttled network, heavy set, first install, median of 3:
10 MB/s 19.8 s -> 18.5 s, 40 MB/s 16.1 s -> 14.3 s, unthrottled 16.1 s -> 13.6 s (a small but steady gain; forcing it on for a
fast network made things worse in an earlier test, hence the automatic switch).
AUTOPIP_EARLY_UNPACK=0/1/auto. - Bandwidth limit:
autopip install --limit-rate 5M ...,AUTOPIP_LIMIT_RATE=500K, orautopip config limit_rate 5Mcaps the total download speed of all threads (useful on a shared connection, or to make benchmarks repeatable). - Repeatable benchmarks:
bench/bench.pyruns pip, uv and pip-auto throughbench/throttle_proxy.py, a local proxy with a fixed shared rate and added latency, so every tool sees the same network (python bench/bench.py --rate 10M --latency 30).
Virtual install (experimental: autopip config link_mode virtual)
With virtual, a package's .py files are not written to disk at all. pip-auto writes only the real files
(compiled extensions, data, dist-info) plus a tiny index, and a small import finder (_apk_lazy.py, standard library only,
loaded through a .pth file) reads each .py straight out of the cached wheel the moment it is imported. Tracebacks and
inspect.getsource still show the source. Measured on numpy + pandas + scipy + matplotlib + scikit-learn + pillow: 7,769 files ->
3,465 files on disk, disk-only cold install about 15-20% faster than junction, steady-state imports slightly faster, and the
whole set imports and runs (regression, FFT, random forest, plotting).
Trade-offs: the wheel cache must stay (don't delete ~/.autopip); tools that read .py files from disk
(type checkers, IDE indexing, pkgutil.iter_modules on such a package) will not see them; the environment must be a real
site directory (so .pth files are processed). Default stays junction (Windows) / hardlink.
Commands
| Command | What it does |
|---|---|
autopip run x.py |
Install everything x.py needs first, then run it (--venv creates and uses .venv next to it) |
autopip lock x.py |
Write x.autopip.lock with every version and sha256 pinned; run then installs exactly that |
autopip install ... |
Same syntax as pip install: -r requirements.txt (nested -r, -c, --hash, -i), -e ., -U, --no-deps, --force-reinstall, --dry-run, -t DIR, --user (--dry-run prints a per-package plan: new / upgrade) |
autopip uninstall pkg... |
Remove (also -r file) |
autopip list [--outdated] / show pkg |
Installed packages / packages with newer versions / details |
autopip upgrade pkg... / --all |
Upgrade (--dry-run to only show) |
autopip freeze [x.py] |
Pin what a script uses (--requirements, --pep723), or the whole environment |
autopip clean [--days 30] [--yes] |
Remove auto-installed packages you haven't used for a while |
autopip bundle x.py |
Pack a script + dependencies into one solid-compressed file: python x.pyz |
autopip init / policy |
Create / inspect the project settings file (allow / deny lists) |
autopip gui |
Browser dashboard: sizes, last used, clean-up, settings (127.0.0.1 only) |
autopip tree [pkg] / why pkg |
Dependency tree of what is installed / which installed packages need pkg |
autopip why-slow pkg... / install --timing |
Where the time went (resolve / download / disk / link) with a hint about the likely cause |
autopip snapshot save|list|restore|delete |
Save the installed set by name; restore NAME --yes rolls the environment back to it |
autopip list --outdated --security / upgrade --security |
Outdated packages with known-vulnerable ones first; upgrade only the vulnerable ones |
autopip sandbox x.py [--keep] |
Run a script in a throwaway environment that is deleted afterwards |
autopip size [--top N] |
Which packages take the most space (and which are linked to the cache) |
autopip compile req.in [-o req.txt] |
Resolve and pin every version (+ sha256 of the file this Python installs, + # via reasons) into a requirements file |
autopip prefetch pkg... [--recent] |
Resolve + download + prepare the cache without installing |
autopip cache [status] |
How much space the cache uses and where |
autopip audit |
Look up known vulnerabilities (PyPI advisory data) for everything installed; exit code 1 if any are found |
autopip doctor [--fix] |
Diagnose the setup (hook, cache, settings file, PyPI); --fix repairs the hook file, leftovers of interrupted installs and broken links |
autopip check pkg |
Run the safety check only |
autopip off / on |
Turn it off / back on |
AUTOPIP_DISABLE=1 turns it off for a single command.
Settings (autopip config KEY VALUE)
ask—trueto confirm before every install (asks on the console; never installs when nobody can answer)safety—strict(default) /warn/offlink_mode—junction(default on Windows, fastest: one folder link per package instead of one link per file) /hardlink(default elsewhere) /copy(separate files per environment). Withjunctionandhardlinkthe files are shared with the cache (~/.autopip): don't delete the cache while environments use it, and don't edit installed files in place (usecopyfor that).lang—en,ja,zh,zh-TW,ko,es,fr,de,pt,ru(default: your OS language; alsoAUTOPIP_LANG)index_url/extra_index_urls— other package indexes (pip.ini/PIP_INDEX_URLare read too)
Compatibility
- Python 3.8 – 3.14 (the test suite runs on all seven). Tested mainly on Windows; wheel selection on Linux / macOS
is handled by
packaging. - Modules removed from the standard library in Python 3.13 (
imghdr,cgi,telnetlib, …) are provided by installing their maintained successors (standard-imghdr,legacy-cgi, …). - No dependencies. MIT license.
Good to know
- Only packages from PyPI (or the indexes you configure) are installed, and every install is logged.
- In
junction/hardlinkmode, environments share the same files. If you edit installed files in place, uselink_mode copy.
日本語の説明: README.ja.md (included in the source distribution)
Metadata
Release files for pip-auto 0.8.4
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| pip_auto-0.8.4.tar.gz | 157.8 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| pip_auto-0.8.4-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 288.9 kB
Release files / pip_auto-0.8.4.tar.gz
| Download URL | pip_auto-0.8.4.tar.gz |
|---|---|
| Size | 157.8 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
4b56a5b07a434f15cae9427aebeb9354c06c3b653fad6dd5fdb42eba98a68064
|
|
BLAKE2b-256 checksum How to use checksums |
3e05cf53357e694d22be948638ed9ed935a11c07b926473685eed668fc352589
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.10.5
|
Release files / pip_auto-0.8.4-py3-none-any.whl
| Download URL | pip_auto-0.8.4-py3-none-any.whl |
|---|---|
| Size | 131.1 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
c75e8adcfdf4447182d3239fc487a19d7ab5b4e1c84faf0a3d8f48f49166283b
|
|
BLAKE2b-256 checksum How to use checksums |
79c2394128a263a4513bfb6f6aaf08e9fa205773d0f44618f63d11ca44a0d8f6
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.10.5
|