Skip to main content

PYRE — Flask-flavored Python on the Internet Computer: certified reads, urllib-shaped outcalls, stable-memory collections

Project description

PYRE — Python on the Internet Computer

PyPI CI MIT Python 3.10

Write recognizable Python — Flask-style routes, a data layer, an outbound HTTP call — and run it on the Internet Computer (ICP), a decentralized WASM host. No Candid, no Rust, no Motoko.

What that buys you over Flask-on-a-VPS:

  • Certified responses — clients cryptographically verify your API's answers against the network's root of trust, not "trust the server."
  • Threshold-signed JWTs — the subnet signs cooperatively; there is no private key anywhere to steal.
  • Consensus-safe randomness & audited encryption — the platform footguns are defused; the safe paths look like ordinary Python.
  • ~$0.40/month for a light backend, measured on mainnet.
from pyre import App, Request, Response, data

app = App()
app.enable_cors(origins="*")

items = data.collection("items", schema={"name": str, "qty": (int, 1)})

@app.get("/health", certified=True)     # served with a verifiable certificate
def health(req: Request) -> Response:
    return Response.json({"status": "ok"})

@app.post("/items")                     # runs as an update: writes persist
def create_item(req: Request) -> Response:
    return Response.json(items.insert(req.json()), status=201)

@app.get("/items")
def list_items(req: Request) -> Response:
    return Response.json(items.list(limit=20, after=req.query.get("after")))

Outbound HTTPS looks like urllib, but async — because on ICP it is:

from pyre.compat import urllib_request as urllib

@app.get("/quote", update=True)
async def quote(req):
    resp = await urllib.urlopen("https://api.example.com/quote",
                                max_response_bytes=8_192)
    return Response.json({"upstream_status": resp.status, "data": resp.json()})

And ICP's genuinely differentiated capabilities read like ordinary Python (every one opt-in — a plain CRUD app never meets them):

from pyre import random as prandom, time as ptime, sign
from pyre.adapters import supabase

@app.get("/id")
def new_id(req):
    return Response.json({"id": prandom.uuid4()})   # consensus-safe; naive uuid4 fails loudly

@app.get("/attest", update=True)
async def attest(req):
    token = await sign.jwt({"sub": req.caller, "iat": ptime.now()})
    return Response.json({"jwt": token})            # threshold-signed: no key to steal

@app.get("/external", update=True)
async def external(req):
    db = supabase.Client(url=SUPA_URL, anon_key=SUPA_KEY)
    return Response.json(await db.table("items").select().limit(10))

Install

pip install pyre-icp

The distribution is pyre-icp; the import package and the CLI are both pyre. To deploy canisters you also need, one time:

  • Python 3.10.x (Kybra's RustPython targets 3.10 — pyenv recommended)
  • dfx (the ICP SDK): DFXVM_INIT_YES=true sh -ci "$(curl -fsSL https://internetcomputer.org/install.sh)"
  • Kybra in your project's deploy venv: pip install kybra==0.7.1 + python -m kybra install-dfx-extension

Then:

pyre new myapp --template crud-kv     # bare-api | crud-kv | outbound-proxy
cd myapp
pyre dev src/app.py                   # instant local server, no replica needed
dfx start --background && dfx deploy  # real local canister
dfx deploy --network ic               # mainnet

The quickstart walks the whole path in ~15 minutes.

The API surface

Module What it gives you Docs
pyre.App / Request / Response Flask-style routing, path params, hooks, error handlers, CORS, certified routes api.md
pyre.data / pyre.kv Collections + KV over stable memory — survives upgrades; schemas, pagination, lazy migration api.md
pyre.validate Dict-schema request validation → clean per-field 400s api.md
pyre.auth Bearer / API-key / HTTP Basic middleware, constant-time, hash-stored creds api.md
pyre.compat.urllib_request urllib-shaped async HTTPS outcalls with determinism transforms concepts.md
pyre.random / pyre.uuid / pyre.time Consensus-safe RNG, UUIDs, timestamps (naive stdlib entropy fails loudly in-canister — by design) random-uuid-time.md
pyre.crypto AES-GCM, ChaCha20-Poly1305, sha2/sha3/blake2/blake3, HMAC — audited RustCrypto under the hood crypto.md
pyre.sign Threshold tECDSA signatures + ES256K JWTs — no private key exists api.md
pyre.adapters Supabase (PostgREST) + Upstash Redis over outcalls, amplification-safe writes adapters.md
pyre.log Structured logging retrievable via dfx canister logs observability.md
pyre CLI pyre new (templates), pyre dev (local server + footgun warnings) quickstart.md

All docs: quickstart · concepts · API reference · troubleshooting · stdlib support matrix · secrets & outcalls · extending with Rust · observability · LLM/agent skill file · reference app: examples/food_tracker

The four ICP concepts PYRE teaches (and hides everything else)

  1. Query vs. update calls. Queries are fast, read-only, uncertified; updates go through consensus (~1–2 s) and can write. PYRE maps GET → query, writes/async → update; honesty guards raise if you write state or make outcalls from a query.
  2. Outbound HTTP is async and consensus-gated. Every replica performs your outcall independently and must agree byte-for-byte — hence await, and hence transforms.
  3. The determinism transform. Upstream responses differ per replica (Date headers, request ids). Outcalls run through a transform that canonicalizes the response before consensus; pyre dev shows you what gets stripped before you ever deploy.
  4. Canisters are long-lived actors. The interpreter boots once at install and stays warm — no cold starts, but funding (cycles) and instruction budgets are real. make budgets measures; DECISIONS.md records.

Full explanations with failure symptoms in concepts.md.

Mainnet-proven, not aspirational

Every load-bearing claim was tested against ICP mainnet (13-node subnet) and recorded in DECISIONS.md: response certification verified by the official DFINITY verifier (BLS to the NNS root key, tamper/stale rejected), outcall determinism proven across real replicas, threshold signatures externally verified (26.19B cycles ≈ 3.5¢ each), 13× write-amplification converging to single rows through the adapters, and a light backend costing ≈ $0.40/month.

Working from a clone

make setup          # venvs (Python 3.10.7 via pyenv), kybra, dfx extension
make test           # ~240 unit tests, no replica needed
make dev            # instant local server for examples/rest_api
make start deploy   # local replica + all example canisters
make e2e            # 20-check acceptance suite
make pocketic       # canister-level integration tests
make budget-gate    # instruction + wasm-size/idle-burn regression gates

CI runs the same gates on every push. See CONTRIBUTING.

Scope fences

Pure Python only — no C extensions, no Pydantic. No sockets/threads (stubbed with guidance), no websockets/streaming. Secret-bearing outcalls (calling Stripe/OpenAI with a private key) are a documented limitation until v1.2's signed proxy.

License

MIT © Sweet Papa Technologies

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

pyre_icp-1.1.2.tar.gz (62.5 kB view details)

Uploaded Source

Built Distribution

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

pyre_icp-1.1.2-py3-none-any.whl (76.5 kB view details)

Uploaded Python 3

File details

Details for the file pyre_icp-1.1.2.tar.gz.

File metadata

  • Download URL: pyre_icp-1.1.2.tar.gz
  • Upload date:
  • Size: 62.5 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.10.7

File hashes

Hashes for pyre_icp-1.1.2.tar.gz
Algorithm Hash digest
SHA256 5d5d8cd82ada5bcd958870ae1f8fb460ab702b6f95dbd8ebfe734ebde8fa37e7
MD5 5135d266c558a2166cbc542b8abe926f
BLAKE2b-256 2b84b3d934327049b8624bb8bde3e3d35c6ef5cd34348cb898feae064e747aa3

See more details on using hashes here.

File details

Details for the file pyre_icp-1.1.2-py3-none-any.whl.

File metadata

  • Download URL: pyre_icp-1.1.2-py3-none-any.whl
  • Upload date:
  • Size: 76.5 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.10.7

File hashes

Hashes for pyre_icp-1.1.2-py3-none-any.whl
Algorithm Hash digest
SHA256 b703fc55ae05ed6eae2b6805e08898251bd724209321faf69598cbcff11c7f9f
MD5 4fff4c385d32ede8dcb9c32af090baf7
BLAKE2b-256 9947ce32e989b8e65c0f894f96a9d33f7217950a0131577b04b18dd296de4cb5

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