mirror of
https://github.com/pyscript/pyscript.git
synced 2025-12-21 11:15:36 -05:00
PyodideRuntime should be one of the runtimes (#698)
* PyodideRuntime should be one of the runtimes * subsume interpreter into runtime API * fix eslint * add comments * move initializers, postInitializers, scriptsQueue, etc. to initialize() of Runtime Super Class * modify comment for initialize * small renaming * change id to default * fix pyscript.py import * try adding tests * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * Add inlineDynamicImports option * Make jest happy about ESM modules * Attempt to make jest happy about pyodide * point to version in accordance with node module being used * fix base.ts * fix tests * fix indexURL path determination * edit pyodide.asm.js as a part of setup process * load runtime beforeAll tests * add test for loading a package * use only runPythonAsync underneath for pyodide * import PyodideInterface type directly from pyodide * add some comments Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> Co-authored-by: Philipp Rudiger <prudiger@anaconda.com>
This commit is contained in:
175
pyscriptjs/src/runtime.ts
Normal file
175
pyscriptjs/src/runtime.ts
Normal file
@@ -0,0 +1,175 @@
|
||||
import type { PyodideInterface } from 'pyodide';
|
||||
import type { PyLoader } from './components/pyloader';
|
||||
import {
|
||||
runtimeLoaded,
|
||||
loadedEnvironments,
|
||||
globalLoader,
|
||||
initializers,
|
||||
postInitializers,
|
||||
Initializer,
|
||||
scriptsQueue,
|
||||
appConfig
|
||||
} from './stores'
|
||||
import type { PyScript } from './components/pyscript';
|
||||
|
||||
export type RuntimeInterpreter = PyodideInterface | null;
|
||||
|
||||
export type AppConfig = {
|
||||
autoclose_loader: boolean;
|
||||
name?: string;
|
||||
version?: string;
|
||||
runtimes?: Array<Runtime>;
|
||||
};
|
||||
|
||||
let loader: PyLoader | undefined;
|
||||
globalLoader.subscribe(value => {
|
||||
loader = value;
|
||||
});
|
||||
|
||||
let initializers_: Initializer[];
|
||||
initializers.subscribe((value: Initializer[]) => {
|
||||
initializers_ = value;
|
||||
console.log('initializers set');
|
||||
});
|
||||
|
||||
let postInitializers_: Initializer[];
|
||||
postInitializers.subscribe((value: Initializer[]) => {
|
||||
postInitializers_ = value;
|
||||
console.log('post initializers set');
|
||||
});
|
||||
|
||||
let scriptsQueue_: PyScript[];
|
||||
scriptsQueue.subscribe((value: PyScript[]) => {
|
||||
scriptsQueue_ = value;
|
||||
console.log('scripts queue set');
|
||||
});
|
||||
|
||||
let appConfig_: AppConfig = {
|
||||
autoclose_loader: true,
|
||||
};
|
||||
|
||||
appConfig.subscribe((value: AppConfig) => {
|
||||
if (value) {
|
||||
appConfig_ = value;
|
||||
}
|
||||
console.log('config set!');
|
||||
});
|
||||
|
||||
/*
|
||||
Runtime class is a super class that all different runtimes must respect
|
||||
and adhere to.
|
||||
|
||||
Currently, the only runtime available is Pyodide as indicated by the
|
||||
`RuntimeInterpreter` type above. This serves as a Union of types of
|
||||
different runtimes/interpreters which will be added in near future.
|
||||
|
||||
The class has abstract methods available which each runtime is supposed
|
||||
to implement.
|
||||
|
||||
Methods available handle loading of the interpreter, initialization,
|
||||
running code, loading and installation of packages, loading from files etc.
|
||||
|
||||
For an example implementation, refer to the `PyodideRuntime` class
|
||||
in `pyodide.ts`
|
||||
*/
|
||||
export abstract class Runtime extends Object {
|
||||
abstract src: string;
|
||||
abstract name?: string;
|
||||
abstract lang?: string;
|
||||
abstract interpreter: RuntimeInterpreter;
|
||||
/**
|
||||
* global symbols table for the underlying interpreter.
|
||||
* */
|
||||
abstract globals: any;
|
||||
|
||||
/**
|
||||
* loads the interpreter for the runtime and saves an instance of it
|
||||
* in the `this.interpreter` property along with calling of other
|
||||
* additional convenience functions.
|
||||
* */
|
||||
abstract loadInterpreter(): Promise<void>;
|
||||
|
||||
/**
|
||||
* delegates the code to be run to the underlying interpreter
|
||||
* (asynchronously) which can call its own API behind the scenes.
|
||||
* */
|
||||
abstract run(code: string): Promise<any>;
|
||||
|
||||
/**
|
||||
* delegates the setting of JS objects to
|
||||
* the underlying interpreter.
|
||||
* */
|
||||
abstract registerJsModule(name: string, module: object): void;
|
||||
|
||||
/**
|
||||
* delegates the loading of packages to
|
||||
* the underlying interpreter.
|
||||
* */
|
||||
abstract loadPackage(names: string | string[]): Promise<void>;
|
||||
|
||||
/**
|
||||
* delegates the installation of packages
|
||||
* (using a package manager, which can be specific to
|
||||
* the runtime) to the underlying interpreter.
|
||||
*
|
||||
* For Pyodide, we use `micropip`
|
||||
* */
|
||||
abstract installPackage(package_name: string | string[]): Promise<void>;
|
||||
|
||||
/**
|
||||
* delegates the loading of files to the
|
||||
* underlying interpreter.
|
||||
* */
|
||||
abstract loadFromFile(path: string): Promise<void>;
|
||||
|
||||
/**
|
||||
* initializes the page which involves loading of runtime,
|
||||
* as well as evaluating all the code inside <py-script> tags
|
||||
* along with initializers and postInitializers
|
||||
* */
|
||||
async initialize(): Promise<void> {
|
||||
loader?.log('Loading runtime...');
|
||||
await this.loadInterpreter();
|
||||
const newEnv = {
|
||||
id: 'default',
|
||||
runtime: this,
|
||||
state: 'loading',
|
||||
};
|
||||
runtimeLoaded.set(this);
|
||||
|
||||
// Inject the loader into the runtime namespace
|
||||
// eslint-disable-next-line
|
||||
this.globals.set('pyscript_loader', loader);
|
||||
|
||||
loader?.log('Runtime created...');
|
||||
loadedEnvironments.update(environments => ({
|
||||
...environments,
|
||||
[newEnv['id']]: newEnv,
|
||||
}));
|
||||
|
||||
// now we call all initializers before we actually executed all page scripts
|
||||
loader?.log('Initializing components...');
|
||||
for (const initializer of initializers_) {
|
||||
await initializer();
|
||||
}
|
||||
|
||||
loader?.log('Initializing scripts...');
|
||||
for (const script of scriptsQueue_) {
|
||||
await script.evaluate();
|
||||
}
|
||||
scriptsQueue.set([]);
|
||||
|
||||
// now we call all post initializers AFTER we actually executed all page scripts
|
||||
loader?.log('Running post initializers...');
|
||||
|
||||
if (appConfig_ && appConfig_.autoclose_loader) {
|
||||
loader?.close();
|
||||
console.log('------ loader closed ------');
|
||||
}
|
||||
|
||||
for (const initializer of postInitializers_) {
|
||||
await initializer();
|
||||
}
|
||||
console.log('===PyScript page fully initialized===');
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user