Python Runtime Assets
Python cells execute in a browser worker using Pyodide. Oxiquill resolves the installed Pyodide release and lockfile during generation, downloads only the core files and declared packages that the manifest requires, and publishes them under public/oxiquill/pyodide.
The built site loads those local assets. A reader does not need access to a public CDN after the site has been generated and deployed.
Configuration
Section titled “Configuration”import { defineOxiquillConfig } from 'oxiquill/astro';
export default defineOxiquillConfig({ python: { offline: process.env.OXIQUILL_OFFLINE === '1', packageMirror: 'https://packages.example/pyodide/' }, paths: { downloadCacheDir: '.cache/oxiquill/downloads/v1' }});offline defaults to false. packageMirror and downloadCacheDir accept either a string or URL. TypeScript consumers can import OxiquillPythonOptions and OxiquillPathOptions from oxiquill/astro.
Browser Preparation
Section titled “Browser Preparation”Set python: { preload: true } to prepare Python as soon as the page DOM is ready. The default is false; this documentation site enables it. Pages without Python cells do not start a Python worker. Preparation uses only the first Python cell’s declared packages and does not execute authored code. Button cells still wait for Run, and reactive and autorun cells retain their visible hydration behavior.
The first request passes its declared packages into Pyodide initialization so their downloads overlap runtime startup. Preparation and execution share one worker, one initialization promise, and a serial queue. Later cells load additional declared packages and discover imports before execution. The UI distinguishes Preparing Python… from Running. A failed preparation can be retried by running a cell; cancellation, timeout, and runtime reset clear the worker and preparation state together.
Browser assets remain on the site’s origin and respect its base path, including /oxiquill/. This option adds no CDN dependency, service worker, custom Pyodide distribution, or persistent browser cache. Normal HTTP caching still applies. Display helpers use pandas and Matplotlib only when authored imports have loaded them; Matplotlib keeps the noninteractive Agg backend and automatic figure collection.
For local profiling, browser User Timing entries named oxiquill:<phase>:<cell-id> record hydration, worker startup, initialization, display support, package loading, import discovery, execution, and output rendering. Initialization entries use python as their ID. Entries retain the latest measurement per phase and cell and are never sent to a server. The repository’s tests/performance/python-startup.mjs measures fresh contexts, reloads, and repeated runs against a gzip-served production build.
Verified Downloads
Section titled “Verified Downloads”For each wheel, Oxiquill takes the filename, release location, and expected SHA-256 from the installed pyodide-lock.json. A configured mirror changes only the download base; it never weakens or replaces the lockfile hash.
Downloads use this sequence:
- Check the versioned Oxiquill download cache.
- Verify a cached file against its expected SHA-256 before use.
- If it is missing or corrupt and offline mode is disabled, stream the response to a uniquely named temporary file while incrementally calculating SHA-256.
- Process at most four core files and wheels concurrently. Retries remain inside the same worker slot, use a 30-second timeout, and make no more than three total attempts with bounded backoff.
- Verify the completed temporary file, then atomically claim its cache name. Concurrent generators reuse the verified winner instead of overwriting it with partial content.
- After every required cache entry is verified, copy artifacts into the resolved public Pyodide directory in deterministic order.
A hash mismatch is always fatal for that source. A failed, interrupted, or aborted operation removes its temporary files. Oxiquill never publishes or caches an unverified partial response, and public staging does not begin until every required cache entry is ready.
Cache Behavior
Section titled “Cache Behavior”The default cache layout is .cache/oxiquill/downloads/v1/pyodide/<pyodide-version>/<lock-sha256>/<filename>. A Pyodide version or lockfile-byte change selects a new namespace, so files from incompatible releases are not reused. Every core asset and wheel is also checked against its expected SHA-256 before use.
Preserve the cache between local or CI builds to avoid repeat network work. oxiquill clean removes generated .oxiquill, public runtime, and build output but deliberately preserves downloadCacheDir. A later generation, including offline generation, can reconstruct public/oxiquill/pyodide from the verified cache.
If a cache entry is corrupt, remove that named entry or run online generation again; Oxiquill detects the mismatch before use. Cache diagnostics include the filename, cache path, and expected hash.
Mirrors
Section titled “Mirrors”Configure a Pyodide package mirror when the default CDN is unavailable or policy requires an internal source. The mirror must expose the same release filenames. Integrity always comes from the installed lockfile, not from mirror metadata.
Mirror failures report the effective URL and distinguish DNS/connection failures, HTTP status failures, timeout, retry exhaustion, and SHA-256 mismatch. Switching mirrors does not require changing authored packages metadata.
Offline Mode
Section titled “Offline Mode”Offline generation performs no package download. Every required core asset and wheel must already be present in the verified cache. A miss fails with the missing filename and expected SHA-256 so the cache can be populated on a connected machine and transferred without guesswork.
Use offline mode only after an online generation has completed for the same Oxiquill, Pyodide, manifest, and package set. Browser execution remains offline-capable because the deployed site serves the copied assets locally.
Runtime Invalidation
Section titled “Runtime Invalidation”The Python runtime fingerprint records the Pyodide version, lockfile hash, core-asset hashes, selected package name/version/dependency/file/hash metadata, and the sorted requested package set. Changing any of these semantic inputs regenerates the published runtime. Cache reuse is narrower: its version-and-lock namespace can reuse any still-valid file even when the requested package subset changes.
Declared Packages
Section titled “Declared Packages”Python packages must be a non-empty, unique list of names vendored by the installed Pyodide release. Generation rejects unknown names before downloading. Imports discovered from source may load packages already present in the published runtime, but release builds should declare non-core dependencies explicitly for deterministic preflight and caching.
See Interactive Cells for metadata and Troubleshooting for recovery steps.