Skip to main content

pypi-pigeon

A toolkit for maintaining a PyPI mirror on an airgapped network. Packages are brought over via sneakernet (DTA — physically moving drives between networks).

Uses bandersnatch for the base mirror and a supplement workflow for packages that need full dependency resolution. Features a Textual TUI for interactive use and --plain mode for scripting.

Running in a true airgap? See docs/airgap-workflow.md for the full operational workflow — including one-time server setup, the security-wipe transfer model, and pigeon-merge.py, a standalone merge script that runs on the airgapped server with no dependencies beyond Python 3.6.

Install

pip install pypi-pigeon
# or with uv:
uv tool install pypi-pigeon

Workflow

Internet-connected machine

pigeon setup      # one-time wizard: configure pigeon.toml + generate bandersnatch.conf
pigeon dry-run    # optional: estimate mirror size before committing (takes hours, resumable)
pigeon sync       # run bandersnatch + fetch supplement packages

DTA the following to your airgapped server:

  • <mirror-dir>/web/ — the base mirror
  • supplement/dist/ — supplement wheels (if you used pigeon add)

Airgapped server

pigeon merge      # fold supplement wheels into the mirror's simple/ index
# or on servers without pigeon installed:
python3 pigeon-merge.py --mirror /your/mirror --dist supplement/dist

Re-run after every sync — bandersnatch overwrites simple/<pkg>/index.html for packages it manages, wiping supplement links for those packages. Both merge commands are idempotent and fast.

Commands

Command Description
pigeon setup TUI wizard — configure pigeon.toml and generate bandersnatch.conf
pigeon dry-run Fetch PyPI metadata to estimate mirror size before syncing
pigeon sync Run bandersnatch + fetch supplement packages
pigeon mirror Alias for sync (bandersnatch's own term)
pigeon update Alias for sync with update framing; --check checks supplement packages for newer versions without syncing
pigeon merge Fold supplement/dist/ into the mirror's simple/ index
pigeon add <pkg> Append packages to the supplement list
pigeon status Show mirror health — package count, last sync time, cached wheels, and an outdated check against PyPI

--plain flag — add to dry-run, sync/mirror, or merge to stream plain stdout instead of launching the TUI. Useful for scripting and CI.

--config PATH — available on all commands. By default pigeon searches up the directory tree for pigeon.toml (git-style), so you can run commands from any subdirectory of your mirror workspace.

Config

pigeon setup creates pigeon.toml:

[mirror]
dir = "/path/to/mirror"   # where bandersnatch writes; nginx serves web/ from here
workers = 10              # hard max 10 (bandersnatch limit)
keep_releases = 3
diff_file = ""            # path to write a changed-file list each sync; "" = disabled

[filter]
python_versions = ["3.10"]
platforms = ["linux-manylinux-x86_64"]
include_sdists = false
include_prereleases = false
allowlist_packages = []   # mirror only these packages; empty = mirror everything
blocklist_packages = []

[supplement]
dist_dir = "supplement/dist"
packages_file = "requirements.txt"

Edit directly or re-run pigeon setup anytime to reconfigure.

Supplement packages

The base mirror uses aggressive filtering (specific Python version, platform, latest N releases). For packages outside those filters — or pinned versions you need — use the supplement:

pigeon add requests numpy==1.26.0
# or edit supplement/packages.txt directly (standard requirements.txt format)

During pigeon sync, supplement packages are fetched via pip download --only-binary :all: with full transitive dependency resolution. The result is a self-contained closure of wheels — no missing dependencies on the airgapped side.

Supported platforms

The setup wizard lets you pick any combination of:

  • Linux manylinux x86_64 / aarch64 / i686
  • Linux musllinux x86_64 / aarch64 (Alpine)
  • Windows AMD64 / x86 / ARM64
  • macOS x86_64 (Intel) / ARM64 (Apple Silicon)

Bandersnatch gotchas

Plugin names changed in 7.xblocklist_release_files and keep_only_latest_releases no longer exist and are silently ignored. pigeon generates the correct config automatically; don't hand-edit bandersnatch.conf for anything covered by pigeon.toml.

Workers hard max = 10 — bandersnatch raises an exception above 10. The setup wizard enforces this.

Test runs — to verify filters before committing to a full sync, temporarily add an [allowlist] section to bandersnatch.conf. Expected results: numpy → only cp310-manylinux-x86_64 wheels; cryptography → only abi3-manylinux-x86_64; requests → only py3-none-any. Zero .tar.gz files. Remove the allowlist before re-running pigeon setup — it regenerates bandersnatch.conf from scratch.

Release files for pypi-pigeon 0.3.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for pypi-pigeon 0.3.0
File Size Uploaded
pypi_pigeon-0.3.0.tar.gz 32.0 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for pypi-pigeon 0.3.0
File Interpreter ABI Platform
pypi_pigeon-0.3.0-py3-none-any.whl Python 3 none any Details

Total release size: 62.6 kB

Release files / pypi_pigeon-0.3.0.tar.gz

Download URL pypi_pigeon-0.3.0.tar.gz
Size 32.0 kB
Tags Source
SHA-256 checksum
How to use checksums
d5184902eb00f2f5db37bd47d77760714f97aaa82e4e4455ecdd7b91425b5597
BLAKE2b-256 checksum
How to use checksums
042adc62876e8a967ffc3742097925f1fcbc80a7b24fce3f954847e4b971e6d2
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via uv/0.11.17 {"installer":{"name":"uv","version":"0.11.17","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

Release files / pypi_pigeon-0.3.0-py3-none-any.whl

Download URL pypi_pigeon-0.3.0-py3-none-any.whl
Size 30.6 kB
Tags Python 3
SHA-256 checksum
How to use checksums
622ee695fccfcb12541fcd32988563cd3803033fe156a89b2aba7728bebcf6cc
BLAKE2b-256 checksum
How to use checksums
3cbc6a3ad6ee64d7e776b002a9f3e794026284dcd346d110d6ade6433442cdba
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via uv/0.11.17 {"installer":{"name":"uv","version":"0.11.17","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

Release history Release notifications | RSS feed

This release

0.3.0 This release

2 release files

0.2.0

2 release files

0.1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page