Skip to main content

TUI toolkit for maintaining a PyPI mirror on an airgapped network

Project description

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.

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

Re-run pigeon merge after every bandersnatch sync — bandersnatch overwrites simple/<pkg>/index.html for packages it manages, wiping supplement links for those packages. Merge is 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 merge Fold supplement/dist/ into the mirror's simple/ index
pigeon add <pkg> Append packages to the supplement list

--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.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

pypi_pigeon-0.1.0.tar.gz (25.1 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

pypi_pigeon-0.1.0-py3-none-any.whl (25.7 kB view details)

Uploaded Python 3

File details

Details for the file pypi_pigeon-0.1.0.tar.gz.

File metadata

  • Download URL: pypi_pigeon-0.1.0.tar.gz
  • Upload date:
  • Size: 25.1 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.11.15 {"installer":{"name":"uv","version":"0.11.15","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}

File hashes

Hashes for pypi_pigeon-0.1.0.tar.gz
Algorithm Hash digest
SHA256 86cd877309a3bf556d193a3ffc4930a50b611924bc6338c3a304e161e7cecca1
MD5 09e1b9d80482068b6529691f96158327
BLAKE2b-256 86682de1f560988766a3175f91eb1311d401b7bce82ccc178de463e1ad472514

See more details on using hashes here.

File details

Details for the file pypi_pigeon-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: pypi_pigeon-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 25.7 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.11.15 {"installer":{"name":"uv","version":"0.11.15","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}

File hashes

Hashes for pypi_pigeon-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 598c8693fda23004850c9d6a31dab4b8a95ea73b9e31d9bcba32659965c7de5c
MD5 20dfd1593102a9937df70cf593988cc8
BLAKE2b-256 e4050eb3334fd7639e95f838835211672e421fca6f3c057d5deb4325ecb7c59f

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page