From pypicloud
pypicloud is a Pyramid application for private package hosting on local, S3,
GCS, or Azure storage. Its fallback = cache mode downloads misses from another index, stores them, and serves them.
The project entered maintenance mode in 2023, and its repository is
archived. The latest release is 1.3.12 from December 2022 and
declares Python 3.7 or newer.
Comparison against peryx
Overlap
- Read-through cache-on-miss. pypicloud's
fallback = cacheis peryx's default cached-index behavior: fetch a miss, store it, serve it. - Private hosting of your own packages, private names taking precedence over public ones.
- Authenticated uploads. pypicloud uses user credentials; peryx uses scoped tokens.
pypicloud-only behavior
- GCS and Azure storage backends. pypicloud supports them directly. peryx supports the local filesystem and S3-compatible object storage.
- Pluggable cache and access backends. pypicloud configures cache and access implementations by dotted class path, with built-in SQL, Redis, or DynamoDB caches and configuration, SQL, or LDAP access backends. peryx embeds its redb metadata store. Artifact access uses configured or managed scoped tokens.
- Shared metadata backend. pypicloud's
cache backend can be shared by several
stateless web servers. Each peryx node keeps local metadata and coordinates through the selected
dcorhaavailability contract.
peryx-only behavior
- Active releases. pypicloud's repository is archived, and its maintenance policy accepts bug fixes rather than feature work.
- A streaming cold path. pypicloud buffers a missed wheel fully into a
TemporaryFile, writes it to storage and a cache row, and only then serves it, so the client waits for the whole download plus the disk write plus the DB commit. peryx streams the bytes to the client and into the store at once. - Concurrency correctness. A cold burst of clients asking pypicloud for the same wheel each download it and race to
insert the same primary key into single-writer SQLite; the losers surface as
HTTP 500. peryx single-flights the fetch, so all waiters tail one download. - Content-addressed dedup and PEP 658 metadata, neither of which pypicloud
offers (it stores files by
name/version/filenameand serves no.metadatasibling).
Performance vs peryx
The benchmark suite runs both from their published packages. Cold and warm installs through uv:
| peryx | pypicloud | |
|---|---|---|
| cold cache net | 4.4 s ±6% (1.18x) | 7.0 s ±3% (1.88x) |
| warm cache | 3.3 s ±1% (0.90x) | 3.9 s ±2% (1.08x) |
| server CPU | 1.8 s ±4% (1.00x) | 3.5 s ±6% (1.99x) |
| server peak memory | 699 MB ±2% (1.00x) | 376 MB ±0% (0.54x) |
The throughput workload includes the cold burst that pypicloud answers with HTTP 500: four clients ask for one large
wheel the instant it lands.
| peryx | pypicloud | |
|---|---|---|
| cold cache: 4 clients, one wheel net | 1.0 s ±1% (0.24x) | 4.6 s (1.05x) |
| hot cache: single download | 5,526 MB/s ±4% (48.67x) | 2,716 MB/s (23.92x) |
| hot cache: 8 parallel downloads | 7,273 MB/s ±2% (64.08x) | 3,441 MB/s (30.32x) |
| server CPU | 412 ms ±2% (1.00x) | 1.8 s ±48% (4.43x) |
| server peak memory | 44 MB ±1% (1.00x) | 279 MB ±34% (6.34x) |
Migration procedure
Peryx's read-through cached index matches pypicloud's fallback = cache. Cached state refills on first use; only hosted
uploads need to move. Map the configuration across:
| pypicloud | peryx |
|---|---|
ppc-make-config + pserve config.ini | a TOML file + peryx serve |
pypi.fallback = cache | the default cached-index behavior |
pypi.fallback = redirect / none | not offered; misses serve through the cache or 404 on hosted-only indexes |
storage = s3 | [blob] backend = "s3" |
storage = gcs / azure | no native backend |
db = sqlalchemy / redis / dynamo cache | embedded (redb), nothing to provision |
| access backends (config / SQL / LDAP) | configured or managed scoped tokens for artifact access |
/simple/ and /pypi/ routes | /{route}/simple/ |
Gotchas
- S3 settings differ. Configure the bucket under
[blob]; the AWS SDK provider chain supplies credentials. The object-storage guide lists durability requirements and migration limits. - Permissions move to grants. Set
anonymous_read = falseand addread,write, ordeleteactions to each configured or managed scoped token as needed. Peryx LDAP and OIDC logins cover management and UI access, not artifact-client authentication. - Metadata stays node-local. Shared S3 stores blobs, not redb metadata. Use
dcorhafor coordinated nodes.