import { PythonRuntime } from './base.ts'; import { EVALUATOR, type Evaluator } from '../mixin.ts'; import type { EvalResult, EvalValue, RunArgs, RunResult, RuntimeOptions } from '../types.ts'; import { type MountResolver } from '../resolver.ts'; import type { BridgeDispatchFn } from '../types.ts'; /** * Rewrite top-level imports of denied packages so Pyodide's * `loadPackagesFromImports` skips fetching them. The rewritten code is only * fed to the auto-loader's import scanner — user code still runs unchanged, * so the actual `import X` will hit any meta_path blocker installed in the * Python bootstrap. * * Recognises: * - `import X`, `import X.Y`, `import X as alias` * - `from X import …`, `from X.Y import …` * The match is line-scoped (`/m`) so multi-import lines like * `import X, Y` are blanked out as a single statement. */ export declare function stripDeniedImports(code: string, denyPackages: ReadonlySet): string; /** The pyodide runtime's implementation knobs (its `config` block). */ export interface PyodideConfig { autoLoadFromImports?: boolean; bootstrapCode?: string; denyPackages?: readonly string[]; /** * Virtual paths prepended to sys.path once the mounts are in place, so * an agent can `import openpyxl` without writing sys.path.append * itself. Entries are MOUNT paths, not host paths: the glob runs * inside the interpreter against the mounted tree. A `.whl` may be * named directly (zipimport reads a pure-python wheel in place), and a * pattern may contain `*`, `?` or `[`. * * Prepended, not appended: a vendored package of the same name must * win over a bundled one, which is also CPython's own PYTHONPATH * precedence. */ sysPath?: readonly string[]; /** * Packages loaded once at init from the pyodide distribution, before * the first run. Composes with autoLoadFromImports rather than * replacing it: the per-run import scan is a no-op for anything * already resident. */ packages?: readonly string[]; /** * Where package wheels are fetched from. Distinct from `home`, which * only sets indexURL: the npm pyodide package ships the lock file and * NO wheels, so a deployment that wants `packages` working offline * points this at its own prebuilt distribution. A `://` value makes * package loading a network fetch; a local path keeps it on disk. */ packageBaseUrl?: string; /** A custom pyodide-lock.json, for a prebuilt distribution. */ lockFileURL?: string; home?: string; } export declare class PyodideRuntime extends PythonRuntime implements Evaluator { readonly name = "pyodide"; readonly reach = "vfs"; readonly [EVALUATOR]: true; private pyodide; private initPromise; private bootstrapPromise; private queue; private readonly autoLoadFromImports; private readonly bootstrapCode; private workspaceBridge; private readonly denyPackages; private resolver; private readonly home; private readonly sysPath; private readonly packages; private readonly packageBaseUrl; private readonly lockFileURL; private vfs; private readonly journal; private readonly mounted; private readonly refused; private readonly seedMissesReported; private seedNotices; private interrupter; private interrupterTried; constructor(options?: RuntimeOptions); attach(dispatch: BridgeDispatchFn, resolver: MountResolver): void; run(args: RunArgs): Promise; /** * Evaluate code; the last expression is the value. One-shot mode * runs on the eval wrapper (value crosses the WASM boundary as * JSON); a session id routes through the console wrapper (globals * persist per id, value is streamed output only). Console failures * come back as transcript results; one-shot failures reject with * EvalError. */ eval(code: string, opts?: { inputs?: Record; session?: string; }): Promise; private evalOne; close(): Promise; private wireInterruptIfNeeded; private ensureLoaded; private wireBridgeIfNeeded; /** * Rebuild the guest's mount table from the workspace's, before every * run. * * Every prefix is re-seeded, not just a newly added one, because the * filesystem's callbacks are synchronous and so this is the only place * that can await the bridge at all. A stale snapshot is not merely a * missed read: a file the snapshot lacks looks like a new file, so * `open(path, 'a')` would start from an empty buffer and the flush * would replace content the guest never saw. Re-seeding is what keeps * that impossible without JSPI, which no shipping Node has and Safari * does not implement. * * The cost is one readdir plus one read per file per run. Narrowing that * to what actually changed needs a per-entry change stamp the bridge * does not carry yet; until it does, correctness is the side to err on. * * A prefix the workspace has dropped is unmounted, so a removed mount * stops being visible instead of lingering for the interpreter's life. */ private syncMounts; /** * Put the configured paths on sys.path, after every mount is in place. * * Runs on EVERY syncMounts pass rather than once at load: each pass * unmounts and remounts the prefixes, and zipimport caches an * archive's table of contents by path, so a `.whl` served from a * remounted tree would keep answering from the previous run. Both * guards inside are idempotent, so repeating is cheap. * * Args: * pyodide: the loaded interpreter. */ private seedSysPath; /** * Queue a notice for each glob that expanded to nothing this pass. * * The seed cannot report these itself: it runs inside syncMounts, * before the run's stdout/stderr are captured, so anything it wrote * to sys.stderr reached nobody. Queuing here and draining onto the * run's stderr puts the warning in front of the same agent whose * import is about to fail. * * Args: * pyodide: the loaded interpreter, holding the seed's `_seed_misses`. */ private recordSeedMisses; private takeSeedNotices; /** * Replay every mutation the shim recorded during the run, in the order * the guest performed them. The guest cannot await the bridge from its * sync WASM frames without JSPI, so it only records; ordering is what * makes a create-then-rename or mkdir-then-write sequence land the same * way it ran. Returns one message per failure for the caller's stderr. */ private drainMutations; private loadImports; private runOne; private runOneRepl; } //# sourceMappingURL=pyodide.d.ts.map