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.1.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.1-py3-none-any.whl (76.5 kB view details)

Uploaded Python 3

File details

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

File metadata

  • Download URL: pyre_icp-1.1.1.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.1.tar.gz
Algorithm Hash digest
SHA256 9e5443514ce33923019eeeb17c1706f74de57ee6aeb809287130bae6b5f80b99
MD5 17b3a04d093292392b5f017c5ddef7b0
BLAKE2b-256 70ab136320dfabd4e7166528f0d6638dc3c98ba499b3722930f7059f9b2e89dd

See more details on using hashes here.

File details

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

File metadata

  • Download URL: pyre_icp-1.1.1-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.1-py3-none-any.whl
Algorithm Hash digest
SHA256 5ed2d44ca59b609b4b86469cce3e5629edfbf727fa46f49c9fc3f37bf323f35d
MD5 3e94ea6744b21ca484253438bc22265e
BLAKE2b-256 331b734073ecf7effb874717a1708b2ec8fa8fe43e80cb6b82ab6b7c1a7e283d

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