8000 support different pyodide versions by fpliger · Pull Request #328 · pyscript/pyscript · GitHub
[go: up one dir, main page]

Skip to content

support different pyodide versions #328

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 11 commits into from
May 11, 2022
Prev Previous commit
Next Next commit
move initialization out of svelte file, into app config
  • Loading branch information
fpliger committed May 10, 2022
commit b03e7a92b64a1757644171d5d026c96ed5434fa0
2 changes: 2 additions & 0 deletions pyscriptjs/examples/simple_clock.html
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@
</py-env>
<py-config>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i like this pattern

- autoclose_loader: false
- runtimes:
- "https://cdn.jsdelivr.net/pyodide/v0.20.0/full/pyodide.js"
</py-config>
</head>

Expand Down
75 changes: 0 additions & 75 deletions pyscriptjs/src/App.svelte
Original file line number Diff line number Diff line change
@@ -1,76 +1,5 @@
<script lang="ts">
import Tailwind from './Tailwind.svelte';
import { loadInterpreter } from './interpreter';
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why was this moved? So it's easier to use with the new array of runtimes that should be on the pyconfig? Or just in general this is the wrong place for this kind of config?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I removed it because the whole logic was moved to pyconfig.ts and not used here anymore, if needed, other parts can import directly from ./interpreter

The reason I moved to pyconfig was that it helps isolate the whole logic around declaring and initializing runtimes somewhere more contained than just the App. Not sure if pyconfig is the best place for it to be, but it's better than before.

I think there's less and less need for us to have the svelte app... and this also helps us understand how much we depend on it. Atm, afaict, we are only relying on its stores.

import type { AppConfig } from './components/pyconfig';
import { initializers, loadedEnvironments, mode, postInitializers, pyodideLoaded, scriptsQueue, globalLoader, appConfig } from './stores';

let pyodideReadyPromise;

let loader;
let appConfig_: AppConfig = {
autoclose_loader: true,
};

globalLoader.subscribe(value => {
loader = value;
});

appConfig.subscribe( (value:AppConfig) => {
if (value){
appConfig_ = value;
}
console.log("config set!")
});

const initializePyodide = async () => {
loader.log("Loading runtime...")
pyodideReadyPromise = loadInterpreter();
const pyodide = await pyodideReadyPromise;
let newEnv = {
id: 'a',
promise: pyodideReadyPromise,
runtime: pyodide,
state: 'loading',
};
pyodideLoaded.set(pyodide);

// Inject the loader into the runtime namespace
pyodide.globals.set("pyscript_loader", loader);

loader.log("Runtime created...")
loadedEnvironments.update((value: any): any => {
value[newEnv['id']] = newEnv;
});

// now we call all initializers before we actually executed all page scripts
loader.log("Initializing components...")
for (let initializer of $initializers) {
await initializer();
}

// now we can actually execute the page scripts if we are in play mode
loader.log("Initializing scripts...")
if ($mode == 'play') {
for (let script of $scriptsQueue) {
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 ------");
}

setTimeout(() => {
for (let initializer of $postInitializers) {
initializer();
}
}, 3000);
};
</script>

<style global>
Expand Down Expand Up @@ -105,8 +34,4 @@
}
</style>

<svelte:head>
<script src="https://cdn.jsdelivr.net/pyodide/v0.20.0/full/pyodide.js" on:load={initializePyodide}></script>
</svelte:head>

<Tailwind />
137 changes: 130 additions & 7 deletions pyscriptjs/src/components/pyconfig.ts
Original file line number Diff line number Diff line change
@@ -1,19 +1,124 @@
import * as jsyaml from 'js-yaml';
import { BaseEvalElement } from './base';
import { appConfig } from '../stores';
import { initializers, loadedEnvironments, mode, postInitializers, pyodideLoaded, scriptsQueue, globalLoader, appConfig, Initializer } from '../stores';
import { loadInterpreter } from '../interpreter';
import type { PyScript } from './pyscript';

let appConfig_;

appConfig.subscribe(value => {
appConfig_ = value;
});
const DEFAULT_RUNTIME = "https://cdn.jsdelivr.net/pyodide/v0.20.0/full/pyodide.js";

export type AppConfig = {
autoclose_loader: boolean;
name?: string;
version?: string;
runtimes?: Array<string>;
};

let appConfig_: AppConfig = {
autoclose_loader: true,
};

appConfig.subscribe( (value:AppConfig) => {
if (value){
appConfig_ = value;
}
console.log("config set!")
});

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("post initializers set")
});

let mode_: string;
mode.subscribe( (value:string) => {
mode_ = value;
console.log("post initializers set")
});


let pyodideReadyPromise;
let loader;


globalLoader.subscribe(value => {
loader = value;
});


export class PyodideRuntime extends Object{
src: string;

constructor(url:string) {
super();
this.src = url;
}

async initialize(){
loader.log("Loading runtime...")
pyodideReadyPromise = loadInterpreter(this.src);
const pyodide = await pyodideReadyPromise;
let newEnv = {
id: 'a',
promise: pyodideReadyPromise,
runtime: pyodide,
state: 'loading',
};
pyodideLoaded.set(pyodide);

// Inject the loader into the runtime namespace
pyodide.globals.set("pyscript_loader", loader);

loader.log("Runtime created...")
loadedEnvironments.update((value: any): any => {
value[newEnv['id']] = newEnv;
});

// now we call all initializers before we actually executed all page scripts
loader.log("Initializing components...")
for (let initializer of initializers_) {
await initializer();
}

// now we can actually execute the page scripts if we are in play mode
loader.log("Initializing scripts...")
if (mode_ == 'play') {
for (let script of scriptsQueue_) {
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 ------");
}

setTimeout(() => {
for (let initializer of postInitializers_) {
initializer();
}
}, 3000);
}
}

8000
export class PyConfig extends BaseEvalElement {
shadow: ShadowRoot;
wrapper: HTMLElement;
Expand All @@ -33,14 +138,21 @@ export class PyConfig extends BaseEvalElement {
this.code = this.innerHTML;
this.innerHTML = '';

this.values = jsyaml.load(this.code);
if (this.values === undefined){
const loadedValues = jsyaml.load(this.code);
if (loadedValues === undefined){
this.values = {
autoclose_loader: true,
};
}else{
this.values = Object.assign({}, ...loadedValues);
};
if (this.values.runtimes === undefined){
this.values.runtimes = [DEFAULT_RUNTIME];
}
appConfig.set(this.values);
console.log("config set", this.values);

this.loadRuntimes();
}

log(msg: string){
Expand All @@ -52,4 +164,15 @@ export class PyConfig extends BaseEvalElement {
close() {
this.remove();
}

loadRuntimes(){
console.log("Initializing runetimes...")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Typo? runetimes

for (let runtime of this.values.runtimes) {
var script = document.createElement("script"); // create a script DOM node
const runtimeSpec = new PyodideRuntime(runtime);
script.src = runtime; // set its src to the provided URL
script.onload = runtimeSpec.initialize;
document.head.appendChild(script);
}
}
}
3 changes: 2 additions & 1 deletion pyscriptjs/src/interpreter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,12 @@ import { getLastPath } from './utils';
let pyodideReadyPromise;
let pyodide;

const loadInterpreter = async function (): Promise<any> {
const loadInterpreter = async function (indexUrl:string): Promise<any> {
console.log('creating pyodide runtime');
// eslint-disable-next-line
// @ts-ignore
pyodide = await loadPyodide({
// indexURL: indexUrl,
stdout: console.log,
stderr: console.log,
fullStdLib: false
Expand Down
0