Skip to main content

Incremental PyPI Simple API caching mirror

Project description

PyTail

pytail is a minimal incremental PyPI caching mirror.

It is no longer a devpi clone. The new server only does four things:

  • expose a valid Python Simple Repository API root at /simple/
  • lazily fetch and cache /simple/<project>/ from an upstream index
  • rewrite file links to a devpi-style root/pypi/+f/... path
  • serve cached project pages and cached files on later requests

Plan

  1. Implement the smallest Simple API surface that pip and uv actually need: root index, project index, normalized names, file links, and content negotiation for HTML vs JSON responses.
  2. Keep the cache incremental: do not mirror the full upstream project list, only remember projects that have already been requested.
  3. Use conditional project refresh: cache upstream project pages, preserve ETag, and refresh a project after a TTL with If-None-Match.
  4. Keep package files immutable: once a file URL is requested, cache it under +files/ and serve it from a stable devpi-style file route on later requests.
  5. Store the index in SQLite: project pages, file metadata, and known-project state live in SQLite, while package bytes live on disk.
  6. Handle concurrent requests safely inside one process: per-project and per-file locks avoid duplicate upstream fetches and duplicate downloads.
  7. Explicitly drop old devpi goals: no users, no ACLs, no upload API, no index inheritance, no replication, no snapshot format, no mirror whitelist, no web UI.

Spec Coverage

The implementation is intentionally narrow:

  • PEP 503 HTML Simple API for /simple/ and /simple/<project>/
  • PEP 691 JSON Simple API responses when Accept asks for application/vnd.pypi.simple.v1+json
  • preservation of requires-python, yanked, gpg-sig, dist-info-metadata, and core-metadata markers when they are present on the upstream project page
  • lazy local root index containing only already-cached projects

The implementation does not currently fetch or synthesize a full global upstream project list. That is deliberate: the root index is only a local catalogue of known projects, while project pages are fetched on demand.

Why This Is Enough

Package resolution for pip and uv depends primarily on per-project Simple API pages. A full pre-fetched mirror root is not required for normal dependency resolution as long as:

  • /simple/<normalized-project>/ is available and correct
  • file links are reachable
  • project metadata such as hashes and requires-python are preserved

Run

cargo run -- \
  --bind 127.0.0.1:3141 \
  --upstream-base-url https://pypi.org \
  --cache-dir .cache/pytail

Then point tools at it:

uv pip install --index-url http://127.0.0.1:3141/simple/ requests
pip install --index-url http://127.0.0.1:3141/simple/ requests

Configuration

  • --bind: listen address, default 127.0.0.1:3141
  • --upstream-base-url: upstream index origin, default https://pypi.org
  • --cache-dir: local cache directory, default .cache/pytail
  • --project-cache-ttl-secs: refresh age for cached project pages, default 900
  • --request-timeout-secs: upstream HTTP timeout, default 15

Package

Build a Python wheel with maturin:

maturin build --release

Publish to PyPI:

maturin publish --release

The wheel installs the pytail command as a native Rust binary.

Cache Layout

<cache-dir>/
  index.sqlite3
  +files/
    root/
      pypi/
        +f/
          f0a/
            f3fc39e7459b0/
              gradio_client-1.0.2-py3-none-any.whl
          _url/
            <url-digest>/
              <filename>
  • SQLite stores project cache entries, parsed file rows, upstream ETag, and known project names
  • +files/root/pypi/+f/<first-3-sha256>/<next-13-sha256>/<filename> stores hashed files in the same shape as devpi's filesystem layout
  • +files/root/pypi/+f/_url/<url-digest>/<filename> is used only when an upstream file link does not provide a usable sha256 hash

Non-Goals

  • full PyPI mirroring
  • authentication or private indexes
  • package upload
  • merge of local and upstream package sources
  • replica mode or background synchronization

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

pytail-0.1.0.tar.gz (49.3 kB view details)

Uploaded Source

Built Distributions

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

pytail-0.1.0-py3-none-win_amd64.whl (2.1 MB view details)

Uploaded Python 3Windows x86-64

pytail-0.1.0-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (2.3 MB view details)

Uploaded Python 3manylinux: glibc 2.17+ x86-64

pytail-0.1.0-py3-none-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl (4.1 MB view details)

Uploaded Python 3macOS 10.12+ universal2 (ARM64, x86-64)macOS 10.12+ x86-64macOS 11.0+ ARM64

File details

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

File metadata

  • Download URL: pytail-0.1.0.tar.gz
  • Upload date:
  • Size: 49.3 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for pytail-0.1.0.tar.gz
Algorithm Hash digest
SHA256 292cd55b2c21484a986b072a4cb791703b13de3bd598a04e495374fd5a7b5a67
MD5 e95200f23e62a00edae138a6ae17549c
BLAKE2b-256 70b38a1517a7234a383db1e7e4a7e089cdfdbc4c43697492c63f7f3541c527f5

See more details on using hashes here.

Provenance

The following attestation bundles were made for pytail-0.1.0.tar.gz:

Publisher: release.yml on AndPuQing/PyTail

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file pytail-0.1.0-py3-none-win_amd64.whl.

File metadata

  • Download URL: pytail-0.1.0-py3-none-win_amd64.whl
  • Upload date:
  • Size: 2.1 MB
  • Tags: Python 3, Windows x86-64
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for pytail-0.1.0-py3-none-win_amd64.whl
Algorithm Hash digest
SHA256 198308fcba17145f1f5dd28798d95c4114adce727c29a81605987b2ad4139eb1
MD5 4cecebcd71ef0b0355f97a8304130603
BLAKE2b-256 35964e9175310fb4303475e8199ff82948141a3ac11f4691e0a3adccdb15022c

See more details on using hashes here.

Provenance

The following attestation bundles were made for pytail-0.1.0-py3-none-win_amd64.whl:

Publisher: release.yml on AndPuQing/PyTail

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file pytail-0.1.0-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.

File metadata

File hashes

Hashes for pytail-0.1.0-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 6207c4dedb466f1d68fa1decb05503310e576d66c581d738752dc43c5b6d9f82
MD5 3e8a460a61e4814a773df9abfe5db442
BLAKE2b-256 0c3ca542ba1227ce9d9c8c9d5116f931d4b8b43a508e02d522e778046351abe0

See more details on using hashes here.

Provenance

The following attestation bundles were made for pytail-0.1.0-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl:

Publisher: release.yml on AndPuQing/PyTail

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file pytail-0.1.0-py3-none-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl.

File metadata

File hashes

Hashes for pytail-0.1.0-py3-none-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl
Algorithm Hash digest
SHA256 1aa32534f1024193be697f765350033097e8161495bcb543c070c014b644536c
MD5 8101348eeb927670699540072494d7fc
BLAKE2b-256 af98d51b9c7b46cc2832c722163e2608210131eff1eb2e3974c0437de909c544

See more details on using hashes here.

Provenance

The following attestation bundles were made for pytail-0.1.0-py3-none-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl:

Publisher: release.yml on AndPuQing/PyTail

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

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