Skip to main content

Incremental PyPI Simple API caching mirror

Project description

PyTail

CI Release PyPI Python

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
  • --verbose: enable debug logging for pytail

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.1.tar.gz (51.7 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.1-py3-none-win_amd64.whl (2.3 MB view details)

Uploaded Python 3Windows x86-64

pytail-0.1.1-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (2.5 MB view details)

Uploaded Python 3manylinux: glibc 2.17+ x86-64

pytail-0.1.1-py3-none-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl (4.5 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.1.tar.gz.

File metadata

  • Download URL: pytail-0.1.1.tar.gz
  • Upload date:
  • Size: 51.7 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.1.tar.gz
Algorithm Hash digest
SHA256 e9ab14589a82ceacb1848e91817ffefc20c322be2fd013eb70f47b87a390738b
MD5 a0d723871aa20fddfd9b12bdcef2c498
BLAKE2b-256 76dd166d88fc0e62097f22b9deceb1cd4585cbba43b61e478f75a327273b3953

See more details on using hashes here.

Provenance

The following attestation bundles were made for pytail-0.1.1.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.1-py3-none-win_amd64.whl.

File metadata

  • Download URL: pytail-0.1.1-py3-none-win_amd64.whl
  • Upload date:
  • Size: 2.3 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.1-py3-none-win_amd64.whl
Algorithm Hash digest
SHA256 42a072b872d4bb8f1aeb606a1e086617d7ab6f7738c24b7a539e492d6f32d97c
MD5 4c48e0431b71efafe1bb2817e4e7ac33
BLAKE2b-256 6ef257f231d5e812d90bceaf43d778344c2f02ad3904f2fecefbd7f4b2bd94ef

See more details on using hashes here.

Provenance

The following attestation bundles were made for pytail-0.1.1-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.1-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.

File metadata

File hashes

Hashes for pytail-0.1.1-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 89d6e246d93c6330b0845d23f386b398afeb7392d5bbf9f467b7e31b9c6583be
MD5 4f3d773db5b6e238e6fe5fde4d83dd1b
BLAKE2b-256 a3574c177a1a8315502b21c7bc446cd5144c25eec4edf33bf1fcb6b136d3f2ab

See more details on using hashes here.

Provenance

The following attestation bundles were made for pytail-0.1.1-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.1-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.1-py3-none-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl
Algorithm Hash digest
SHA256 39bb6c7e54be617776c3737034dd22cad3c351eb61137cb203dcc590ab17fa9a
MD5 30b600bebe2f5d1d78359587ca7777fa
BLAKE2b-256 38a8e36f2db6f188169568151b6c3a07bb3ef9fca57538fa063b6042a9d6b3ba

See more details on using hashes here.

Provenance

The following attestation bundles were made for pytail-0.1.1-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