Stream Python packages at runtime โ the PyPI CDN client
Project description
๐ Whispy โ The Python Package CDN
Stream Python packages at runtime. No
pip install, no virtual envs, no environment setup. The PyPI equivalent of unpkg.com / jsDelivr.
from whispy_client import remote
requests = remote("requests")
numpy = remote("numpy==1.26.4")
bs4 = remote("beautifulsoup4", module="bs4", deps=True)
print(requests.get("https://httpbin.org/get").status_code) # 200
Packages are streamed from PyPI through the Whispy CDN, SHA-256 verified, extracted to a temporary directory, and imported at runtime. Nothing is permanently installed. Everything disappears when your process exits.
Architecture
โโโโโโโโโโโโโโโ HTTPS โโโโโโโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโโ
โ Your Script โ โโโโโโโโโโโบ โ Cloudflare Edge โ โโโบโ Whispy โ
โ (client) โ โ (CDN cache) โ โ Origin Serverโ
โโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโโโโโโ โโโโโโโโฌโโโโโโโโ
โ
โโโโโโโโผโโโโโโโโ
โ PyPI API โ
โโโโโโโโโโโโโโโโ
- Client (
whispy_client) โ Zero-dependency installable. Computes PEP 425 tags, fetches the right wheel, extracts to tmpdir, imports. - CDN Edge (Cloudflare Worker) โ Caches versioned package zips with 1-year immutable TTL. Adds security headers, validates inputs.
- Origin Server (
server/app.py) โ Resolves packages, fetches from PyPI, verifies SHA-256, zips for serving, maintains disk cache.
Repository Structure
whispy/
โโโ server/ # Whispy CDN origin server
โ โโโ app.py # Flask application
โ โโโ requirements.txt
โ โโโ Dockerfile
โ
โโโ client/ # whispy-client Python package
โ โโโ whispy_client/
โ โ โโโ __init__.py # Public API: remote(), configure()
โ โ โโโ core.py # Zero-dep implementation
โ โโโ pyproject.toml
โ
โโโ docs/ # whispy.dev documentation site
โ โโโ index.html
โ
โโโ deploy/ # Infrastructure configs
โ โโโ docker-compose.yml
โ โโโ cloudflare-worker.js # Cloudflare CDN edge layer
โ โโโ wrangler.toml
โ
โโโ .github/
โโโ workflows/
โโโ ci.yml # CI: test โ build โ publish โ deploy
Quick Start
Use the hosted CDN
pip install whispy-client
from whispy_client import remote, configure
# Optional: enable dep resolution and verbose logging
configure(deps=True, verbose=True)
requests = remote("requests")
print(requests.get("https://httpbin.org/get").status_code)
Self-host
# Clone
git clone https://github.com/Dark-Avenger-Reborn/Whispy
cd Whispy
# Run with Docker Compose
docker compose -f deploy/docker-compose.yml up -d
# Point your client at it
WHISPY_HOST=http://localhost:8000 python my_script.py
Run server locally (dev)
cd server
pip install -r requirements.txt
python app.py --debug
Client API
remote(package, *, module=None, version=None, deps=False, host=None)
| Param | Description |
|---|---|
package |
PyPI name, optionally with ==version e.g. "requests==2.31.0" |
module |
Import name if different from package name (e.g. module="bs4") |
version |
Explicit version, overrides embedded spec |
deps |
If True, resolve and fetch transitive dependencies |
host |
Per-call CDN URL override |
Common name mismatches:
bs4 = remote("beautifulsoup4", module="bs4")
PIL = remote("pillow", module="PIL")
yaml = remote("pyyaml", module="yaml")
dateutil = remote("python-dateutil",module="dateutil")
cv2 = remote("opencv-python", module="cv2")
configure(*, host=None, deps=None, verbose=None)
Set global defaults. Can also use WHISPY_HOST env var.
Server API
| Endpoint | Description |
|---|---|
GET /get_package?name=X&tags=...&version=Y&deps=1 |
Download package zip |
GET /metadata/<package> |
Package metadata without download |
GET /health |
Health check + cache stats |
GET /stats |
Cache statistics |
Security
- SHA-256 verification โ Every file verified against PyPI digests before serving
- Blocklist โ Known typosquatted packages are rejected
- Input validation โ Package names validated against
[A-Za-z0-9_.-]+ - Rate limiting โ 60 req/min per IP on
/get_package - HTTPS enforced โ Cloudflare handles TLS termination
- Immutable URLs โ Versioned package URLs are
Cache-Control: immutable - Server never imports packages โ Only proxies/caches them
Deployment
CI/CD (GitHub Actions)
The .github/workflows/ci.yml pipeline:
- Test โ server tests + client across Python 3.8โ3.13, Linux/macOS/Windows
- Lint โ ruff
- Docker โ builds and pushes to GHCR on every
mainpush - PyPI โ publishes
whispy-clienton version tags (v*) - Cloudflare โ deploys the Worker on
main
Required secrets
| Secret | Description |
|---|---|
CF_API_TOKEN |
Cloudflare API token with Workers:Edit permission |
Environment vars (server)
| Var | Default | Description |
|---|---|---|
WHISPY_CACHE_DIR |
./cache |
Disk cache directory |
WHISPY_MAX_CACHE_MB |
2048 |
Max cache size in MB |
REDIS_URL |
memory:// |
Redis URL for distributed rate limiting |
Roadmap
- Conflict-aware dependency resolver (full PubGrub/resolvelib integration)
-
whispy lockCLI โ generate a lockfile for reproducible scripts - Browser / Pyodide support
- Package usage analytics dashboard
- Webhook notifications for new package versions
License
MIT โ see LICENSE.
Packages are sourced from PyPI and served under their original licenses. Whispy does not host or redistribute package source code โ it proxies directly from PyPI's CDN.
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
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file whispy_client-1.1.0.tar.gz.
File metadata
- Download URL: whispy_client-1.1.0.tar.gz
- Upload date:
- Size: 6.9 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
9fd36ddc0509f9b89306fb505965a40f81dc9753e71b06affbbe8ed4dcb95f4e
|
|
| MD5 |
b337d05da539c09221cbdfe88d322dfc
|
|
| BLAKE2b-256 |
cb1f5d7488238be60aac9317a895030d12b27392c301ff8fbded20d59c6df989
|
Provenance
The following attestation bundles were made for whispy_client-1.1.0.tar.gz:
Publisher:
ci.yml on Dark-Avenger-Reborn/Whispy
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
whispy_client-1.1.0.tar.gz -
Subject digest:
9fd36ddc0509f9b89306fb505965a40f81dc9753e71b06affbbe8ed4dcb95f4e - Sigstore transparency entry: 1466207165
- Sigstore integration time:
-
Permalink:
Dark-Avenger-Reborn/Whispy@73af5c55e6afdbcb18f2402cdadaba22415ca2a4 -
Branch / Tag:
refs/tags/v1.1.1 - Owner: https://github.com/Dark-Avenger-Reborn
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
ci.yml@73af5c55e6afdbcb18f2402cdadaba22415ca2a4 -
Trigger Event:
push
-
Statement type:
File details
Details for the file whispy_client-1.1.0-py3-none-any.whl.
File metadata
- Download URL: whispy_client-1.1.0-py3-none-any.whl
- Upload date:
- Size: 7.6 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
30bdc73c6ae11280830ad7fb1f6d2dbf88bdc9a7b72c77687189f7813085340f
|
|
| MD5 |
fa9e4a1fffd12eb8151327c382e380ac
|
|
| BLAKE2b-256 |
047641851b4c15865789d46488e4fc68c36e875cb360f9dda05d60a0b729a1ad
|
Provenance
The following attestation bundles were made for whispy_client-1.1.0-py3-none-any.whl:
Publisher:
ci.yml on Dark-Avenger-Reborn/Whispy
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
whispy_client-1.1.0-py3-none-any.whl -
Subject digest:
30bdc73c6ae11280830ad7fb1f6d2dbf88bdc9a7b72c77687189f7813085340f - Sigstore transparency entry: 1466207207
- Sigstore integration time:
-
Permalink:
Dark-Avenger-Reborn/Whispy@73af5c55e6afdbcb18f2402cdadaba22415ca2a4 -
Branch / Tag:
refs/tags/v1.1.1 - Owner: https://github.com/Dark-Avenger-Reborn
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
ci.yml@73af5c55e6afdbcb18f2402cdadaba22415ca2a4 -
Trigger Event:
push
-
Statement type: