1
0
mirror of https://github.com/pyscript/pyscript.git synced 2022-05-01 19:47:48 +03:00

add array of initializers, to run after the python runtime has loaded

This commit is contained in:
Fabio Pliger
2022-03-25 16:57:54 -05:00
parent 3d613b8904
commit 2b7cbe0129
5 changed files with 141 additions and 17 deletions

View File

@@ -4,7 +4,7 @@
import { faPlusCircle } from '@fortawesome/free-solid-svg-icons' import { faPlusCircle } from '@fortawesome/free-solid-svg-icons'
import Tailwind from "./Tailwind.svelte"; import Tailwind from "./Tailwind.svelte";
import { loadInterpreter } from './interpreter'; import { loadInterpreter } from './interpreter';
import { pyodideLoaded, loadedEnvironments, navBarOpen, componentsNavOpen, mode, scriptsQueue } from './stores'; import { pyodideLoaded, loadedEnvironments, navBarOpen, componentsNavOpen, mode, scriptsQueue, initializers } from './stores';
import Main from "./Main.svelte"; import Main from "./Main.svelte";
import Header from "./Header.svelte"; import Header from "./Header.svelte";
import SideNav from "./SideNav.svelte"; import SideNav from "./SideNav.svelte";
@@ -47,6 +47,12 @@
for (let script of $scriptsQueue) { for (let script of $scriptsQueue) {
script.evaluate(); script.evaluate();
} }
scriptsQueue.set([])
}
// now we call all initializers AFTER we actually executed all page scripts
for (let initializer of $initializers){
initializer();
} }
} }

View File

@@ -6,7 +6,7 @@ import { keymap, ViewUpdate } from "@codemirror/view";
import { defaultKeymap } from "@codemirror/commands"; import { defaultKeymap } from "@codemirror/commands";
import { oneDarkTheme } from "@codemirror/theme-one-dark"; import { oneDarkTheme } from "@codemirror/theme-one-dark";
import { pyodideLoaded, loadedEnvironments, componentDetailsNavOpen, currentComponentDetails, mode, addToScriptsQueue } from '../stores'; import { pyodideLoaded, loadedEnvironments, componentDetailsNavOpen, currentComponentDetails, mode } from '../stores';
import { addClasses } from '../utils'; import { addClasses } from '../utils';
// Premise used to connect to the first available pyodide interpreter // Premise used to connect to the first available pyodide interpreter
@@ -208,7 +208,7 @@ export class PyRepl extends HTMLElement {
let source = this.editor.state.doc.toString(); let source = this.editor.state.doc.toString();
let output; let output;
if (source.includes("asyncio")){ if (source.includes("asyncio")){
output = pyodide.runPythonAsync(source); output = await pyodide.runPythonAsync(source);
}else{ }else{
output = pyodide.runPython(source); output = pyodide.runPython(source);
} }

View File

@@ -6,13 +6,14 @@ import { keymap, ViewUpdate } from "@codemirror/view";
import { defaultKeymap } from "@codemirror/commands"; import { defaultKeymap } from "@codemirror/commands";
import { oneDarkTheme } from "@codemirror/theme-one-dark"; import { oneDarkTheme } from "@codemirror/theme-one-dark";
import { pyodideLoaded, loadedEnvironments, componentDetailsNavOpen, currentComponentDetails, mode, addToScriptsQueue } from '../stores'; import { pyodideLoaded, loadedEnvironments, componentDetailsNavOpen, currentComponentDetails, mode, addToScriptsQueue, addInitializer } from '../stores';
import { addClasses } from '../utils'; import { addClasses } from '../utils';
// Premise used to connect to the first available pyodide interpreter // Premise used to connect to the first available pyodide interpreter
let pyodideReadyPromise; let pyodideReadyPromise;
let environments; let environments;
let currentMode; let currentMode;
let handlersCollected = false;
pyodideLoaded.subscribe(value => { pyodideLoaded.subscribe(value => {
pyodideReadyPromise = value; pyodideReadyPromise = value;
@@ -40,6 +41,46 @@ function createCmdHandler(el){
} }
class Script {
source: string;
state: string;
target: string;
constructor(source: string, target: string) {
this.target = target;
this.source = source;
this.state = 'waiting';
}
async evaluate() {
console.log('evaluate');
let pyodide = await pyodideReadyPromise;
// debugger
try {
// @ts-ignore
// let source = this.editor.state.doc.toString();
let output;
if (this.source.includes("asyncio")){
output = await pyodide.runPythonAsync(this.source);
}else{
output = pyodide.runPython(this.source);
}
if (this.target){
// this.editorOut.innerHTML = s;
}
// if (output !== undefined){
// this.addToOutput(output);
// }
} catch (err) {
console.log("OOOPS, this happened: " + err);
// this.addToOutput(err);
}
}
}
export class PyScript extends HTMLElement { export class PyScript extends HTMLElement {
shadow: ShadowRoot; shadow: ShadowRoot;
wrapper: HTMLElement; wrapper: HTMLElement;
@@ -176,11 +217,10 @@ export class PyScript extends HTMLElement {
let source = this.editor.state.doc.toString(); let source = this.editor.state.doc.toString();
let output; let output;
if (source.includes("asyncio")){ if (source.includes("asyncio")){
output = pyodide.runPythonAsync(source); output = await pyodide.runPythonAsync(source);
}else{ }else{
output = pyodide.runPython(source); output = pyodide.runPython(source);
} }
if (output !== undefined){ if (output !== undefined){
this.addToOutput(output); this.addToOutput(output);
} }
@@ -200,3 +240,47 @@ export class PyScript extends HTMLElement {
} }
} }
async function initHandlers() {
if( handlersCollected == true ) return;
console.log('Collecting nodes...');
let pyodide = await pyodideReadyPromise;
let matches : NodeListOf<HTMLElement> = document.querySelectorAll('[pys-onClick]');
let output;
let source;
for (var el of matches) {
let handlerCode = el.getAttribute('pys-onClick');
source = `Element("${ el.id }").element.onclick = ${ handlerCode }`;
output = await pyodide.runPythonAsync(source);
// el.onclick = (evt: any) => {
// console.log("click");
// new Promise((resolve, reject) => {
// setTimeout(() => {
// console.log('Inside')
// }, 300);
// }).then(() => {
// console.log("resolved")
// });
// // let handlerCode = el.getAttribute('pys-onClick');
// // pyodide.runPython(handlerCode);
// }
}
handlersCollected = true;
matches = document.querySelectorAll('[pys-onKeyDown]');
for (var el of matches) {
let handlerCode = el.getAttribute('pys-onKeyDown');
source = `Element("${ el.id }").element.addEventListener("keydown", ${ handlerCode })`;
output = await pyodide.runPythonAsync(source);
}
}
addInitializer(initHandlers)
// if( document.readyState === 'loading' ) {
// document.addEventListener( 'DOMContentLoaded', initHandlers );
// }
// else if( document.readyState === 'interactive' || document.readyState === 'complete' ) {
// initHandlers();
// }

View File

@@ -47,30 +47,54 @@ pyscript = PyScript()
class Element: class Element:
def __init__(self, element_id): def __init__(self, element_id, element=None):
self._id = element_id self._id = element_id
self._element = element
@property @property
def element(self): def element(self):
"""Return the dom element""" """Return the dom element"""
return document.querySelector(f'#{self._id}'); if not self._element:
self._element = document.querySelector(f'#{self._id}');
return self._element
def write(self, value, append=False): def write(self, value, append=False):
console.log(f"Element.write: {value} --> {append}") console.log(f"Element.write: {value} --> {append}")
# TODO: it should be the opposite... pyscript.write should use the Element.write
# so we can consolidate on how we write depending on the element type
pyscript.write(self._id, value, append=append) pyscript.write(self._id, value, append=append)
def clear(self): def clear(self):
self.write("", append=False) if hasattr(self.element, 'value'):
self.element.value = ''
else:
self.write("", append=False)
def clone(self, new_id=None): def select(self, query, from_content=False):
el = self.element
if from_content:
el = el.content
_el = el.querySelector(query)
if _el:
return Element(_el.id, _el)
else:
console.log(f"WARNING: can't find element matching query {query}")
def clone(self, new_id=None, to=None):
if new_id is None: if new_id is None:
new_id = self.element.id new_id = self.element.id
clone = self.element.cloneNode(true); clone = self.element.cloneNode(True);
clone.id = new_id; clone.id = new_id;
if to:
to.element.appendChild(clone)
# Inject it into the DOM # Inject it into the DOM
self.element.after(clone); self.element.after(clone);
return Element(clone.id, clone)
` `
@@ -81,13 +105,13 @@ let loadInterpreter = async function(): any {
}); });
// now that we loaded, add additional convenience fuctions // now that we loaded, add additional convenience fuctions
pyodide.loadPackage(['matplotlib', 'numpy']) // pyodide.loadPackage(['matplotlib', 'numpy'])
await pyodide.loadPackage("micropip"); await pyodide.loadPackage("micropip");
await pyodide.runPythonAsync(` // await pyodide.runPythonAsync(`
import micropip // import micropip
await micropip.install("ipython") // await micropip.install("ipython")
`); // `);
let output = pyodide.runPython(additional_definitions); let output = pyodide.runPython(additional_definitions);

View File

@@ -23,8 +23,10 @@ export const mainDiv = writable(null);
export const currentComponentDetails = writable([]); export const currentComponentDetails = writable([]);
export const mode = writable(DEFAULT_MODE) export const mode = writable(DEFAULT_MODE)
export const scriptsQueue = writable([]) export const scriptsQueue = writable([])
export const initializers = writable([])
let scriptsQueue_ = [] let scriptsQueue_ = [];
let initializers_ = [];
scriptsQueue.subscribe(value => { scriptsQueue.subscribe(value => {
scriptsQueue_ = value; scriptsQueue_ = value;
@@ -33,3 +35,11 @@ scriptsQueue.subscribe(value => {
export const addToScriptsQueue = (script) => { export const addToScriptsQueue = (script) => {
scriptsQueue.set([...scriptsQueue_, script]); scriptsQueue.set([...scriptsQueue_, script]);
}; };
scriptsQueue.subscribe(value => {
scriptsQueue_ = value;
});
export const addInitializer = (initializer) => {
initializers.set([...initializers_, initializer]);
};