8000 support different pyodide versions (#328) · Siddharth-cmd/pyscript@363f375 · GitHub
[go: up one dir, main page]

Skip to content

Commit 363f375

Browse files
authored
support different pyodide versions (pyscript#328)
* add PyLoader class * create global loader during app creation time and remove it when pyscript loading operations are done * make the loader global and open/close when apps is starting. Also add concept of app config so users can set if they want to autoclose the loader of handle it themselves * add pyconfig file * auto add global config if there's no config set in the page * export initializer type * define type for config * move initialization out of svelte file, into app config * change runtimes from strings to objects * fix typo
1 parent 73a0d9b commit 363f375

File tree

7 files changed

+157
-88
lines changed

7 files changed

+157
-88
lines changed

pyscriptjs/examples/simple_clock.html

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,14 @@
1414
- paths:
1515
- ./utils.py
1616
</py-env>
17+
<py-config>
18+
- autoclose_loader: false
19+
- runtimes:
20+
-
21+
src: "https://cdn.jsdelivr.net/pyodide/v0.20.0/full/pyodide.js"
22+
name: pyodide-0.20
23+
lang: python
24+
</py-config>
1725
</head>
1826

1927
<body>
@@ -43,6 +51,8 @@
4351
else:
4452
out3.clear()
4553

54+
# close the global PyScript pyscript_loader
55+
pyscript_loader.close()
4656
pyscript.run_until_complete(foo())
4757
</py-script>
4858
</body>

pyscriptjs/src/App.svelte

Lines changed: 0 additions & 75 deletions
8
Original file line numberDiff line numberDiff line change
@@ -1,76 +1,5 @@
11
<script lang="ts">
22
import Tailwind from './Tailwind.svelte';
3-
import { loadInterpreter } from './interpreter';
4-
import type { AppConfig } from './components/pyconfig';
5-
import { initializers, loadedEnvironments, mode, postInitializers, pyodideLoaded, scriptsQueue, globalLoader, appConfig } from './stores';
6-
7-
let pyodideReadyPromise;
-
9-
let loader;
10-
let appConfig_: AppConfig = {
11-
autoclose_loader: true,
12-
};
13-
14-
globalLoader.subscribe(value => {
15-
loader = value;
16-
});
17-
18-
appConfig.subscribe( (value:AppConfig) => {
19-
if (value){
20-
appConfig_ = value;
21-
}
22-
console.log("config set!")
23-
});
24-
25-
const initializePyodide = async () => {
26-
loader.log("Loading runtime...")
27-
pyodideReadyPromise = loadInterpreter();
28-
const pyodide = await pyodideReadyPromise;
29-
const newEnv = {
30-
id: 'a',
31-
promise: pyodideReadyPromise,
32-
runtime: pyodide,
33-
state: 'loading',
34-
};
35-
pyodideLoaded.set(pyodide);
36-
37-
// Inject the loader into the runtime namespace
38-
pyodide.globals.set("pyscript_loader", loader);
39-
40-
loader.log("Runtime created...")
41-
loadedEnvironments.update((value: any): any => {
42-
value[newEnv['id']] = newEnv;
43-
});
44-
45-
// now we call all initializers before we actually executed all page scripts
46-
loader.log("Initializing components...")
47-
for (let initializer of $initializers) {
48-
await initializer();
49-
}
50-
51-
// now we can actually execute the page scripts if we are in play mode
52-
loader.log("Initializing scripts...")
53-
if ($mode == 'play') {
54-
for (let script of $scriptsQueue) {
55-
await script.evaluate();
56-
}
57-
scriptsQueue.set([]);
58-
}
59-
60-
// now we call all post initializers AFTER we actually executed all page scripts
61-
loader.log("Running post initializers...");
62-
63-
if (appConfig_ && appConfig_.autoclose_loader) {
64-
loader.close();
65-
console.log("------ loader closed ------");
66-
}
67-
68-
setTimeout(async () => {
69-
for (let initializer of $postInitializers) {
70-
await initializer();
71-
}
72-
}, 3000);
73-
};
743
</script>
754

765
<style global>
@@ -105,8 +34,4 @@
10534
}
10635
</style>
10736

108-
<svelte:head>
109-
<script src="https://cdn.jsdelivr.net/pyodide/v0.20.0/full/pyodide.js" on:load={initializePyodide}></script>
110-
</svelte:head>
111-
11237
<Tailwind />

pyscriptjs/src/components/pyconfig.ts

Lines changed: 143 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,133 @@
11
import * as jsyaml from 'js-yaml';
22
import { BaseEvalElement } from './base';
3-
import { appConfig } from '../stores';
3+
import { initializers, loadedEnvironments, mode, postInitializers, pyodideLoaded, scriptsQueue, globalLoader, appConfig, Initializer } from '../stores';
4+
import { loadInterpreter } from '../interpreter';
5+
import type { PyScript } from './pyscript';
46

5-
let appConfig_;
67

7-
appConfig.subscribe(value => {
8-
appConfig_ = value;
9-
});
8+
const DEFAULT_RUNTIME = {
9+
src: "https://cdn.jsdelivr.net/pyodide/v0.20.0/full/pyodide.js",
10+
name: "pyodide-default",
11+
lang: "python"
12+
}
13+
14+
export type Runtime = {
15+
src: string;
16+
name?: string;
17+
lang?: string;
18+
};
1019

1120
export type AppConfig = {
1221
autoclose_loader: boolean;
1322
name?: string;
1423
version?: string;
15-
};
24+
runtimes?: Array<Runtime>;
25+
};
26+
27+
let appConfig_: AppConfig = {
28+
autoclose_loader: true,
29+
};
30+
31+
appConfig.subscribe( (value:AppConfig) => {
32+
if (value){
33+
appConfig_ = value;
34+
}
35+
console.log("config set!")
36+
});
37+
38+
let initializers_: Initializer[];
39+
initializers.subscribe( (value:Initializer[]) => {
40+
initializers_ = value;
41+
console.log("initializers set")
42+
});
43+< EED3 div class="diff-text-inner">
44+
let postInitializers_: Initializer[];
45+
postInitializers.subscribe( (value:Initializer[]) => {
46+
postInitializers_ = value;
47+
console.log("post initializers set")
48+
});
49+
50+
let scriptsQueue_: PyScript[];
51+
scriptsQueue.subscribe( (value: PyScript[]) => {
52+
scriptsQueue_ = value;
53+
console.log("post initializers set")
54+
});
55+
56+
let mode_: string;
57+
mode.subscribe( (value:string) => {
58+
mode_ = value;
59+
console.log("post initializers set")
60+
});
61+
62+
63+
let pyodideReadyPromise;
64+
let loader;
65+
66+
67+
globalLoader.subscribe(value => {
68+
loader = value;
69+
});
70+
71+
72+
export class PyodideRuntime extends Object{
73+
src: string;
74+
75+
constructor(url:string) {
76+
super();
77+
this.src = url;
78+
}
79+
80+
async initialize(){
81+
loader.log("Loading runtime...")
82+
pyodideReadyPromise = loadInterpreter(this.src);
83+
const pyodide = await pyodideReadyPromise;
84+
const newEnv = {
85+
id: 'a',
86+
promise: pyodideReadyPromise,
87+
runtime: pyodide,
88+
state: 'loading',
89+
};
90+
pyodideLoaded.set(pyodide);
91+
92+
// Inject the loader into the runtime namespace
93+
pyodide.globals.set("pyscript_loader", loader);
94+
95+
loader.log("Runtime created...")
96+
loadedEnvironments.update((value: any): any => {
97+
value[newEnv['id']] = newEnv;
98+
});
99+
100+
// now we call all initializers before we actually executed all page scripts
101+
loader.log("Initializing components...")
102+
for (const initializer of initializers_) {
103+
await initializer();
104+
}
105+
106+
// now we can actually execute the page scripts if we are in play mode
107+
loader.log("Initializing scripts...")
108+
if (mode_ == 'play') {
109+
for (const script of scriptsQueue_) {
110+
script.evaluate();
111+
}
112+
scriptsQueue.set([]);
113+
}
114+
115+
// now we call all post initializers AFTER we actually executed all page scripts
116+
loader.log("Running post initializers...");
117+
118+
if (appConfig_ && appConfig_.autoclose_loader) {
119+
loader.close();
120+
console.log("------ loader closed ------");
121+
}
122+
123+
setTimeout(() => {
124+
for (const initializer of postInitializers_) {
125+
initializer();
126+
}
127+
}, 3000);
128+
}
129+
}
130+
16131

17132
export class PyConfig extends BaseEvalElement {
18133
shadow: ShadowRoot;
@@ -33,14 +148,21 @@ export class PyConfig extends BaseEvalElement {
33148
this.code = this.innerHTML;
34149
this.innerHTML = '';
35150

36-
this.values = jsyaml.load(this.code);
37-
if (this.values === undefined){
151+
const loadedValues = jsyaml.load(this.code);
152+
if (loadedValues === undefined){
38153
this.values = {
39154
autoclose_loader: true,
40155
};
156+
}else{
157+
this.values = Object.assign({}, ...loadedValues);
158+
}
159+
if (this.values.runtimes === undefined){
160+
this.values.runtimes = [DEFAULT_RUNTIME];
41161
}
42162
appConfig.set(this.values);
43163
console.log("config set", this.values);
164+
165+
this.loadRuntimes();
44166
}
45167

46168
log(msg: string){
@@ -52,4 +174,17 @@ export class PyConfig extends BaseEvalElement {
52174
close() {
53175
this.remove();
54176
}
177+
178+
loadRuntimes(){
179+
console.log("Initializing runtimes...")
180+
for (const runtime of this.values.runtimes) {
181+
const script = document.createElement("script"); // create a script DOM node
182+
const runtimeSpec = new PyodideRuntime(runtime.src);
183+
script.src = runtime.src; // set its src to the provided URL
184+
script.onload = () => {
185+
runtimeSpec.initialize();
186+
}
187+
document.head.appendChild(script);
188+
}
189+
}
55190
}

pyscriptjs/src/interpreter.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,12 @@ import { getLastPath } from './utils';
33
let pyodideReadyPromise;
44
let pyodide;
55

6-
const loadInterpreter = async function (): Promise<any> {
6+
const loadInterpreter = async function (indexUrl:string): Promise<any> {
77
console.log('creating pyodide runtime');
88
// eslint-disable-next-line
99
// @ts-ignore
1010
pyodide = await loadPyodide({
11+
// indexURL: indexUrl,
1112
stdout: console.log,
1213
stderr: console.log,
1314
fullStdLib: false

pyscriptjs/src/main.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,9 +23,8 @@ const xPyWidget = customElements.define('py-register-widget', PyWidget);
2323
const xPyLoader = customElements.define('py-loader', PyLoader);
2424
const xPyConfig = customElements.define('py-config', PyConfig);
2525

26-
2726
// As first thing, loop for application configs
28-
const config = document.querySelector('py-config');
27+
const config: PyConfig = document.querySelector('py-config');
2928
if (!config){
3029
const loader = document.createElement('py-config');
3130
document.body.append(loader);

pyscriptjs/src/stores.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { writable } from 'svelte/store';
22
import type { PyScript } from './components/pyscript';
33

4-
type Initializer = () => Promise<void>;
4+
export type Initializer = () => Promise<void>;
55

66
export const pyodideLoaded = writable({
77
loaded: false,

pyscriptjs/tsconfig.json

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,6 @@
2222
"sourceMap": true,
2323
/** Requests the runtime types from the svelte modules by default. Needed for TS files or else you get errors. */
2424
"types": ["svelte"],
25-
2625
"strict": false,
2726
"esModuleInterop": true,
2827
"skipLibCheck": true,

0 commit comments

Comments
 (0)
0