From 528763d493f649cffcd2e0979a7b7e0fa882e64b Mon Sep 17 00:00:00 2001 From: Fabio Pliger Date: Wed, 4 May 2022 19:56:13 -0500 Subject: [PATCH 01/15] make copy of .py files part of build process --- pyscriptjs/rollup.config.js | 33 ++++++++++++++++++++++++++++++++- 1 file changed, 32 insertions(+), 1 deletion(-) diff --git a/pyscriptjs/rollup.config.js b/pyscriptjs/rollup.config.js index e5a976276cb..e3085960365 100644 --- a/pyscriptjs/rollup.config.js +++ b/pyscriptjs/rollup.config.js @@ -6,7 +6,36 @@ import { terser } from "rollup-plugin-terser"; import sveltePreprocess from "svelte-preprocess"; import typescript from "@rollup/plugin-typescript"; import css from "rollup-plugin-css-only"; -import serve from 'rollup-plugin-serve' +import serve from 'rollup-plugin-serve'; + +import path from "path"; +import fs from "fs"; + +function copyPythonFiles(from, to, overwrite = false) { + return { + name: 'copy-files', + generateBundle() { + const log = msg => console.log('\x1b[36m%s\x1b[0m', msg) + log(`copy files: ${from} → ${to}`) + fs.readdirSync(from).forEach(file => { + const fromFile = `${from}/${file}` + const toFile = `${to}/${file}` + if (fromFile.endsWith(`.py`)){ + log(`----> ${fromFile} → ${toFile}`) + if (fs.existsSync(toFile) && !overwrite){ + log(`skipping ${fromFile} → ${toFile}`) + return + }else{ + fs.copyFileSync( + path.resolve(fromFile), + path.resolve(toFile) + ); + } + } + }) + } + } +} const production = !process.env.ROLLUP_WATCH || (process.env.NODE_ENV === "production"); @@ -68,6 +97,8 @@ export default { sourceMap: !production, inlineSources: !production, }), + // Copy all the python files from source to the build folder + copyPythonFiles("./src/", "./examples/build", true), !production && serve(), !production && livereload("public"), production && terser(), From a2ed2f8b021baa6b803f402ee8481e57f5e8d22b Mon Sep 17 00:00:00 2001 From: Fabio Pliger Date: Wed, 4 May 2022 19:56:54 -0500 Subject: [PATCH 02/15] move code out ofinterpreter file and make it download and load code during initialization --- pyscriptjs/src/interpreter.ts | 428 ++-------------------------------- pyscriptjs/src/pyscript.py | 240 ++++++++++++++++++- 2 files changed, 251 insertions(+), 417 deletions(-) diff --git a/pyscriptjs/src/interpreter.ts b/pyscriptjs/src/interpreter.ts index 578e732a506..47adcaf96a2 100644 --- a/pyscriptjs/src/interpreter.ts +++ b/pyscriptjs/src/interpreter.ts @@ -3,415 +3,6 @@ import { getLastPath } from './utils'; let pyodideReadyPromise; let pyodide; -const additional_definitions = ` -from js import document, setInterval, console, setTimeout -import micropip -import time -import asyncio -import io, base64, sys - -loop = asyncio.get_event_loop() - -MIME_METHODS = { - '__repr__': 'text/plain', - '_repr_html_': 'text/html', - '_repr_markdown_': 'text/markdown', - '_repr_svg_': 'image/svg+xml', - '_repr_png_': 'image/png', - '_repr_pdf_': 'application/pdf', - '_repr_jpeg_': 'image/jpeg', - '_repr_latex': 'text/latex', - '_repr_json_': 'application/json', - '_repr_javascript_': 'application/javascript', - 'savefig': 'image/png' -} - -def render_image(mime, value, meta): - data = f'data:{mime};charset=utf-8;base64,{value}' - attrs = ' '.join(['{k}="{v}"' for k, v in meta.items()]) - return f'' - -def identity(value, meta): - return value - - -MIME_RENDERERS = { - 'text/plain': identity, - 'text/html' : identity, - 'image/png' : lambda value, meta: render_image('image/png', value, meta), - 'image/jpeg': lambda value, meta: render_image('image/jpeg', value, meta), - 'image/svg+xml': identity, - 'application/json': identity, - 'application/javascript': lambda value, meta: f'' -} - - -def eval_formatter(obj, print_method): - """ - Evaluates a formatter method. - """ - if print_method == '__repr__': - return repr(obj) - elif hasattr(obj, print_method): - if print_method == 'savefig': - buf = io.BytesIO() - obj.savefig(buf, format='png') - buf.seek(0) - return base64.b64encode(buf.read()).decode('utf-8') - return getattr(obj, print_method)() - elif print_method == '_repr_mimebundle_': - return {}, {} - return None - - -def format_mime(obj): - """ - Formats object using _repr_x_ methods. - """ - if isinstance(obj, str): - return obj, 'text/plain' - - mimebundle = eval_formatter(obj, '_repr_mimebundle_') - if isinstance(mimebundle, tuple): - format_dict, md_dict = mimebundle - else: - format_dict = mimebundle - md_dict = {} - - output, not_available = None, [] - for method, mime_type in reversed(MIME_METHODS.items()): - if mime_type in format_dict: - output = format_dict[mime_type] - else: - output = eval_formatter(obj, method) - - if output is None: - continue - elif mime_type not in MIME_RENDERERS: - not_available.append(mime_type) - continue - break - if output is None: - if not_available: - console.warning(f'Rendered object requested unavailable MIME renderers: {not_available}') - output = repr(output) - mime_type = 'text/plain' - elif isinstance(output, tuple): - output, meta = output - else: - meta = {} - return MIME_RENDERERS[mime_type](output, meta), mime_type - - -class PyScript: - loop = loop - - @staticmethod - def write(element_id, value, append=False, exec_id=0): - """Writes value to the element with id "element_id""" - console.log(f"APPENDING: {append} ==> {element_id} --> {value}") - if append: - child = document.createElement('div'); - element = document.querySelector(f'#{element_id}'); - if not element: - return - exec_id = exec_id or element.childElementCount + 1 - element_id = child.id = f"{element_id}-{exec_id}"; - element.appendChild(child); - - element = document.getElementById(element_id) - html, mime_type = format_mime(value) - if mime_type in ('application/javascript', 'text/html'): - scriptEl = document.createRange().createContextualFragment(html) - element.appendChild(scriptEl) - else: - element.innerHTML = html - - @staticmethod - def run_until_complete(f): - p = loop.run_until_complete(f) - - -class Element: - def __init__(self, element_id, element=None): - self._id = element_id - self._element = element - - @property - def id(self): - return self._id - - @property - def element(self): - """Return the dom element""" - if not self._element: - self._element = document.querySelector(f'#{self._id}'); - return self._element - - @property - def value(self): - return self.element.value - - @property - def innerHtml(self): - return self.element.innerHtml - - def write(self, value, append=False): - 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) - - def clear(self): - if hasattr(self.element, 'value'): - self.element.value = '' - else: - self.write("", append=False) - - 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: - new_id = self.element.id - - clone = self.element.cloneNode(True); - clone.id = new_id; - - if to: - to.element.appendChild(clone) - - # Inject it into the DOM - self.element.after(clone); - - return Element(clone.id, clone) - - def remove_class(self, classname): - if isinstance(classname, list): - for cl in classname: - self.remove_class(cl) - else: - self.element.classList.remove(classname) - - def add_class(self, classname): - self.element.classList.add(classname) - -def add_classes(element, class_list): - for klass in class_list.split(' '): - element.classList.add(klass) - -def create(what, id_=None, classes=''): - element = document.createElement(what) - if id_: - element.id = id_ - add_classes(element, classes) - return Element(id_, element) - - -class PyWidgetTheme: - def __init__(self, main_style_classes): - self.main_style_classes = main_style_classes - - def theme_it(self, widget): - for klass in self.main_style_classes.split(' '): - widget.classList.add(klass) - - -class PyItemTemplate(Element): - label_fields = None - - def __init__(self, data, labels=None, state_key=None, parent=None): - self.data = data - - self.register_parent(parent) - - if not labels: - labels = list(self.data.keys()) - self.labels = labels - - self.state_key = state_key - - super().__init__(self._id) - - def register_parent(self, parent): - self._parent = parent - if parent: - self._id = f"{self._parent._id}-c-{len(self._parent._children)}" - self.data['id'] = self._id - else: - self._id = None - - def create(self): - console.log('creating section') - new_child = create('section', self._id, "task bg-white my-1") - console.log('creating values') - - console.log('creating innerHtml') - new_child._element.innerHTML = f""" - - """ - - console.log('returning') - return new_child - - def on_click(self, evt): - pass - - def pre_append(self): - pass - - def post_append(self): - self.element.click = self.on_click - self.element.onclick = self.on_click - - self._post_append() - - def _post_append(self): - pass - - def strike(self, value, extra=None): - if value: - self.add_class("line-through") - else: - self.remove_class("line-through") - - def render_content(self): - return ' - '.join([self.data[f] for f in self.labels]) - -class PyListTemplate: - theme = PyWidgetTheme("flex flex-col-reverse mt-8 mx-8") - item_class = PyItemTemplate - - def __init__(self, parent): - self.parent = parent - self._children = [] - self._id = self.parent.id - - @property - def children(self): - return self._children - - @property - def data(self): - return [c.data for c in self._children] - - def render_children(self): - out = [] - binds = {} - for i, c in enumerate(self._children): - txt = c.element.innerHTML - rnd = str(time.time()).replace(".", "")[-5:] - new_id = f"{c.element.id}-{i}-{rnd}" - binds[new_id] = c.element.id - txt = txt.replace(">", f" id='{new_id}'>") - print(txt) - - def foo(evt): - console.log(evt) - evtEl = evt.srcElement - srcEl = Element(binds[evtEl.id]) - srcEl.element.onclick() - evtEl.classList = srcEl.element.classList - - for new_id, old_id in binds.items(): - Element(new_id).element.onclick = foo - - def connect(self): - self.md = main_div = document.createElement('div') - main_div.id = self._id + "-list-tasks-container" - - if self.theme: - self.theme.theme_it(main_div) - - self.parent.appendChild(main_div) - - def add(self, *args, **kws): - if not isinstance(args[0], self.item_class): - child = self.item_class(*args, **kws) - else: - child = args[0] - child.register_parent(self) - return self._add(child) - - def _add(self, child_elem): - console.log("appending child", child_elem.element) - self.pre_child_append(child_elem) - child_elem.pre_append() - self._children.append(child_elem) - self.md.appendChild(child_elem.create().element) - child_elem.post_append() - self.child_appended(child_elem) - return child_elem - - def pre_child_append(self, child): - pass - - def child_appended(self, child): - """Overwrite me to define logic""" - pass - - -class OutputCtxManager: - def __init__(self, out=None, output_to_console=True, append=True): - self._out = out - self._prev = out - self.output_to_console = output_to_console - self._append = append - - def change(self, out=None, err=None, output_to_console=True, append=True): - self._prev = self._out - self._out = out - self.output_to_console = output_to_console - self._append = append - console.log("----> changed out to", self._out, self._append) - - def revert(self): - console.log("----> reverted") - self._out = self._prev - - def write(self, txt): - console.log('writing to', self._out, txt, self._append) - if self._out: - pyscript.write(self._out, txt, append=self._append) - if self.output_to_console: - console.log(self._out, txt) - -class OutputManager: - def __init__(self, out=None, err=None, output_to_console=True, append=True): - sys.stdout = self._out_manager = OutputCtxManager(out, output_to_console, append) - sys.stderr = self._err_manager = OutputCtxManager(err, output_to_console, append) - self.output_to_console = output_to_console - self._append = append - - def change(self, out=None, err=None, output_to_console=True, append=True): - self._out_manager.change(out, output_to_console, append) - sys.stdout = self._out_manager - self._err_manager.change(err, output_to_console, append) - sys.stderr = self._err_manager - self.output_to_console = output_to_console - self.append = append - - def revert(self): - self._out_manager.revert() - self._err_manager.revert() - sys.stdout = self._out_manager - sys.stderr = self._err_manager - console.log("----> reverted") - -pyscript = PyScript() -output_manager = OutputManager() -`; const loadInterpreter = async function (): Promise { console.log('creating pyodide runtime'); @@ -425,14 +16,22 @@ const loadInterpreter = async function (): Promise { // now that we loaded, add additional convenience functions console.log('loading micropip'); await pyodide.loadPackage('micropip'); - console.log('loading pyscript module'); - console.log('creating additional definitions'); - const output = pyodide.runPython(additional_definitions); + console.log('loading pyscript...'); + + // let's get the full path of where PyScript is running from so we can load the pyscript.py + // file from the same location + const loadedScript:HTMLScriptElement = document.querySelector(`script[src$='pyscript.js']`); + const scriptPath = loadedScript.src.substr(0, loadedScript.src.lastIndexOf("/")) + await pyodide.runPythonAsync(await (await fetch(`${scriptPath}/pyscript.py`)).text()); + + console.log(scriptPath);; + console.log('done setting up environment'); return pyodide; }; + const loadPackage = async function (package_name: string[] | string, runtime: any): Promise { const micropip = pyodide.globals.get('micropip'); await micropip.install(package_name); @@ -444,11 +43,14 @@ const loadFromFile = async function (s: string, runtime: any): Promise { await runtime.runPythonAsync( ` from pyodide.http import pyfetch - + from js import console response = await pyfetch("` + s + `") content = await response.bytes() + console.log("writing", ` + + filename + + `) with open("` + filename + `", "wb") as f: diff --git a/pyscriptjs/src/pyscript.py b/pyscriptjs/src/pyscript.py index f9673c208a4..f56af1e9f6e 100644 --- a/pyscriptjs/src/pyscript.py +++ b/pyscriptjs/src/pyscript.py @@ -1,6 +1,8 @@ -from js import document, console +from js import document, setInterval, console, setTimeout +import micropip +import time import asyncio -import io, base64 +import io, base64, sys loop = asyncio.get_event_loop() @@ -35,7 +37,7 @@ def identity(value, meta): 'image/svg+xml': identity, 'application/json': identity, 'application/javascript': lambda value, meta: f'' -} +} def eval_formatter(obj, print_method): @@ -129,6 +131,10 @@ def __init__(self, element_id, element=None): self._id = element_id self._element = element + @property + def id(self): + return self._id + @property def element(self): """Return the dom element""" @@ -136,6 +142,14 @@ def element(self): self._element = document.querySelector(f'#{self._id}'); return self._element + @property + def value(self): + return self.element.value + + @property + def innerHtml(self): + return self.element.innerHtml + def write(self, value, append=False): console.log(f"Element.write: {value} --> {append}") # TODO: it should be the opposite... pyscript.write should use the Element.write @@ -171,5 +185,223 @@ def clone(self, new_id=None, to=None): # Inject it into the DOM self.element.after(clone); - + return Element(clone.id, clone) + + def remove_class(self, classname): + if isinstance(classname, list): + for cl in classname: + self.remove_class(cl) + else: + self.element.classList.remove(classname) + + def add_class(self, classname): + self.element.classList.add(classname) + +def add_classes(element, class_list): + for klass in class_list.split(' '): + element.classList.add(klass) + +def create(what, id_=None, classes=''): + element = document.createElement(what) + if id_: + element.id = id_ + add_classes(element, classes) + return Element(id_, element) + + +class PyWidgetTheme: + def __init__(self, main_style_classes): + self.main_style_classes = main_style_classes + + def theme_it(self, widget): + for klass in self.main_style_classes.split(' '): + widget.classList.add(klass) + + +class PyItemTemplate(Element): + label_fields = None + + def __init__(self, data, labels=None, state_key=None, parent=None): + self.data = data + + self.register_parent(parent) + + if not labels: + labels = list(self.data.keys()) + self.labels = labels + + self.state_key = state_key + + super().__init__(self._id) + + def register_parent(self, parent): + self._parent = parent + if parent: + self._id = f"{self._parent._id}-c-{len(self._parent._children)}" + self.data['id'] = self._id + else: + self._id = None + + def create(self): + console.log('creating section') + new_child = create('section', self._id, "task bg-white my-1") + console.log('creating values') + + console.log('creating innerHtml') + new_child._element.innerHTML = f""" + + """ + + console.log('returning') + return new_child + + def on_click(self, evt): + pass + + def pre_append(self): + pass + + def post_append(self): + self.element.click = self.on_click + self.element.onclick = self.on_click + + self._post_append() + + def _post_append(self): + pass + + def strike(self, value, extra=None): + if value: + self.add_class("line-through") + else: + self.remove_class("line-through") + + def render_content(self): + return ' - '.join([self.data[f] for f in self.labels]) + +class PyListTemplate: + theme = PyWidgetTheme("flex flex-col-reverse mt-8 mx-8") + item_class = PyItemTemplate + + def __init__(self, parent): + self.parent = parent + self._children = [] + self._id = self.parent.id + + @property + def children(self): + return self._children + + @property + def data(self): + return [c.data for c in self._children] + + def render_children(self): + out = [] + binds = {} + for i, c in enumerate(self._children): + txt = c.element.innerHTML + rnd = str(time.time()).replace(".", "")[-5:] + new_id = f"{c.element.id}-{i}-{rnd}" + binds[new_id] = c.element.id + txt = txt.replace(">", f" id='{new_id}'>") + print(txt) + + def foo(evt): + console.log(evt) + evtEl = evt.srcElement + srcEl = Element(binds[evtEl.id]) + srcEl.element.onclick() + evtEl.classList = srcEl.element.classList + + for new_id, old_id in binds.items(): + Element(new_id).element.onclick = foo + + def connect(self): + self.md = main_div = document.createElement('div') + main_div.id = self._id + "-list-tasks-container" + + if self.theme: + self.theme.theme_it(main_div) + + self.parent.appendChild(main_div) + + def add(self, *args, **kws): + if not isinstance(args[0], self.item_class): + child = self.item_class(*args, **kws) + else: + child = args[0] + child.register_parent(self) + return self._add(child) + + def _add(self, child_elem): + console.log("appending child", child_elem.element) + self.pre_child_append(child_elem) + child_elem.pre_append() + self._children.append(child_elem) + self.md.appendChild(child_elem.create().element) + child_elem.post_append() + self.child_appended(child_elem) + return child_elem + + def pre_child_append(self, child): + pass + + def child_appended(self, child): + """Overwrite me to define logic""" + pass + + +class OutputCtxManager: + def __init__(self, out=None, output_to_console=True, append=True): + self._out = out + self._prev = out + self.output_to_console = output_to_console + self._append = append + + def change(self, out=None, err=None, output_to_console=True, append=True): + self._prev = self._out + self._out = out + self.output_to_console = output_to_console + self._append = append + console.log("----> changed out to", self._out, self._append) + + def revert(self): + console.log("----> reverted") + self._out = self._prev + + def write(self, txt): + console.log('writing to', self._out, txt, self._append) + if self._out: + pyscript.write(self._out, txt, append=self._append) + if self.output_to_console: + console.log(self._out, txt) + +class OutputManager: + def __init__(self, out=None, err=None, output_to_console=True, append=True): + sys.stdout = self._out_manager = OutputCtxManager(out, output_to_console, append) + sys.stderr = self._err_manager = OutputCtxManager(err, output_to_console, append) + self.output_to_console = output_to_console + self._append = append + + def change(self, out=None, err=None, output_to_console=True, append=True): + self._out_manager.change(out, output_to_console, append) + sys.stdout = self._out_manager + self._err_manager.change(err, output_to_console, append) + sys.stderr = self._err_manager + self.output_to_console = output_to_console + self.append = append + + def revert(self): + self._out_manager.revert() + self._err_manager.revert() + sys.stdout = self._out_manager + sys.stderr = self._err_manager + console.log("----> reverted") + +pyscript = PyScript() +output_manager = OutputManager() \ No newline at end of file From a17d047f952b8222c84b8cd7279876a97ea23c84 Mon Sep 17 00:00:00 2001 From: Fabio Pliger Date: Wed, 4 May 2022 21:48:04 -0500 Subject: [PATCH 03/15] fix double ; in interpreter --- pyscriptjs/src/interpreter.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pyscriptjs/src/interpreter.ts b/pyscriptjs/src/interpreter.ts index 47adcaf96a2..da313bde10d 100644 --- a/pyscriptjs/src/interpreter.ts +++ b/pyscriptjs/src/interpreter.ts @@ -22,10 +22,10 @@ const loadInterpreter = async function (): Promise { // let's get the full path of where PyScript is running from so we can load the pyscript.py // file from the same location const loadedScript:HTMLScriptElement = document.querySelector(`script[src$='pyscript.js']`); - const scriptPath = loadedScript.src.substr(0, loadedScript.src.lastIndexOf("/")) + const scriptPath = loadedScript.src.substr(0, loadedScript.src.lastIndexOf("/")); await pyodide.runPythonAsync(await (await fetch(`${scriptPath}/pyscript.py`)).text()); - console.log(scriptPath);; + console.log(scriptPath); console.log('done setting up environment'); return pyodide; From ec7f7a67457969e892f0eaf792cc6caf2b40b41e Mon Sep 17 00:00:00 2001 From: Fabio Pliger Date: Wed, 4 May 2022 22:20:32 -0500 Subject: [PATCH 04/15] remove debugging print --- pyscriptjs/src/components/pyenv.ts | 2 +- pyscriptjs/src/interpreter.ts | 3 --- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/pyscriptjs/src/components/pyenv.ts b/pyscriptjs/src/components/pyenv.ts index 55c9416d572..6456c67c9f5 100644 --- a/pyscriptjs/src/components/pyenv.ts +++ b/pyscriptjs/src/components/pyenv.ts @@ -54,8 +54,8 @@ export class PyEnv extends HTMLElement { } async function loadPaths() { - const pyodide = await pyodideReadyPromise; for (const singleFile of paths) { + console.log(`loading ${singleFile}`); await loadFromFile(singleFile, runtime); } console.log('paths loaded'); diff --git a/pyscriptjs/src/interpreter.ts b/pyscriptjs/src/interpreter.ts index da313bde10d..36869e9645f 100644 --- a/pyscriptjs/src/interpreter.ts +++ b/pyscriptjs/src/interpreter.ts @@ -48,9 +48,6 @@ const loadFromFile = async function (s: string, runtime: any): Promise { s + `") content = await response.bytes() - console.log("writing", ` + - filename + - `) with open("` + filename + `", "wb") as f: From fd41bc9e149ee92b6d5497c8f84e863a838e051b Mon Sep 17 00:00:00 2001 From: Fabio Pliger Date: Wed, 4 May 2022 22:20:38 -0500 Subject: [PATCH 05/15] update dependencies --- pyscriptjs/package-lock.json | 102 +++++++++++++++++------------------ pyscriptjs/package.json | 20 +++---- 2 files changed, 61 insertions(+), 61 deletions(-) diff --git a/pyscriptjs/package-lock.json b/pyscriptjs/package-lock.json index 018b0459b73..ae2be62d575 100644 --- a/pyscriptjs/package-lock.json +++ b/pyscriptjs/package-lock.json @@ -145,9 +145,9 @@ } }, "@codemirror/lang-python": { - "version": "0.19.4", - "resolved": "https://registry.npmjs.org/@codemirror/lang-python/-/lang-python-0.19.4.tgz", - "integrity": "sha512-eSH1JXbf0D30y+f3nWy/+bTLAIV8RmcQbbVD8DsBxkxOHMVKcILgxFRHCovba8YEMtmq45I1DoWcNt1CeKnrYQ==", + "version": "0.19.5", + "resolved": "https://registry.npmjs.org/@codemirror/lang-python/-/lang-python-0.19.5.tgz", + "integrity": "sha512-MQf7t0k6+i9KCzlFCI8EY+jjwyXLy5AwjmXsMyMCMbOw/97j70jFZYrs7Mm7RJakNE2rypWhnLGlyBTSYMqR5g==", "requires": { "@codemirror/highlight": "^0.19.7", "@codemirror/language": "^0.19.0", @@ -404,9 +404,9 @@ } }, "@rollup/plugin-typescript": { - "version": "8.3.1", - "resolved": "https://registry.npmjs.org/@rollup/plugin-typescript/-/plugin-typescript-8.3.1.tgz", - "integrity": "sha512-84rExe3ICUBXzqNX48WZV2Jp3OddjTMX97O2Py6D1KJaGSwWp0mDHXj+bCGNJqWHIEKDIT2U0sDjhP4czKi6cA==", + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/@rollup/plugin-typescript/-/plugin-typescript-8.3.2.tgz", + "integrity": "sha512-MtgyR5LNHZr3GyN0tM7gNO9D0CS+Y+vflS4v/PHmrX17JCkHUYKvQ5jN5o3cz1YKllM3duXUqu3yOHwMPUxhDg==", "dev": true, "requires": { "@rollup/pluginutils": "^3.1.0", @@ -683,13 +683,13 @@ "dev": true }, "autoprefixer": { - "version": "10.4.4", - "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.4.tgz", - "integrity": "sha512-Tm8JxsB286VweiZ5F0anmbyGiNI3v3wGv3mz9W+cxEDYB/6jbnj6GM9H9mK3wIL8ftgl+C07Lcwb8PG5PCCPzA==", + "version": "10.4.7", + "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.7.tgz", + "integrity": "sha512-ypHju4Y2Oav95SipEcCcI5J7CGPuvz8oat7sUtYj3ClK44bldfvtvcxK6IEK++7rqB7YchDGzweZIBG+SD0ZAA==", "dev": true, "requires": { - "browserslist": "^4.20.2", - "caniuse-lite": "^1.0.30001317", + "browserslist": "^4.20.3", + "caniuse-lite": "^1.0.30001335", "fraction.js": "^4.2.0", "normalize-range": "^0.1.2", "picocolors": "^1.0.0", @@ -728,15 +728,15 @@ } }, "browserslist": { - "version": "4.20.2", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.20.2.tgz", - "integrity": "sha512-CQOBCqp/9pDvDbx3xfMi+86pr4KXIf2FDkTTdeuYw8OxS9t898LA1Khq57gtufFILXpfgsSx5woNgsBgvGjpsA==", + "version": "4.20.3", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.20.3.tgz", + "integrity": "sha512-NBhymBQl1zM0Y5dQT/O+xiLP9/rzOIQdKM/eMJBAq7yBgaB6krIYLGejrwVYnSHZdqjscB1SPuAjHwxjvN6Wdg==", "dev": true, "requires": { - "caniuse-lite": "^1.0.30001317", - "electron-to-chromium": "^1.4.84", + "caniuse-lite": "^1.0.30001332", + "electron-to-chromium": "^1.4.118", "escalade": "^3.1.1", - "node-releases": "^2.0.2", + "node-releases": "^2.0.3", "picocolors": "^1.0.0" } }, @@ -777,9 +777,9 @@ "dev": true }, "caniuse-lite": { - "version": "1.0.30001323", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001323.tgz", - "integrity": "sha512-e4BF2RlCVELKx8+RmklSEIVub1TWrmdhvA5kEUueummz1XyySW0DVk+3x9HyhU9MuWTa2BhqLgEuEmUwASAdCA==", + "version": "1.0.30001335", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001335.tgz", + "integrity": "sha512-ddP1Tgm7z2iIxu6QTtbZUv6HJxSaV/PZeSrWFZtbY4JZ69tOeNhBCl3HyRQgeNZKE5AOn1kpV7fhljigy0Ty3w==", "dev": true }, "chalk": { @@ -810,9 +810,9 @@ } }, "codemirror": { - "version": "5.65.2", - "resolved": "https://registry.npmjs.org/codemirror/-/codemirror-5.65.2.tgz", - "integrity": "sha512-SZM4Zq7XEC8Fhroqe3LxbEEX1zUPWH1wMr5zxiBuiUF64iYOUH/JI88v4tBag8MiBS8B8gRv8O1pPXGYXQ4ErA==" + "version": "5.65.3", + "resolved": "https://registry.npmjs.org/codemirror/-/codemirror-5.65.3.tgz", + "integrity": "sha512-kCC0iwGZOVZXHEKW3NDTObvM7pTIyowjty4BUqeREROc/3I6bWbgZDA3fGDwlA+rbgRjvnRnfqs9SfXynel1AQ==" }, "color": { "version": "4.2.1", @@ -1019,9 +1019,9 @@ } }, "electron-to-chromium": { - "version": "1.4.103", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.103.tgz", - "integrity": "sha512-c/uKWR1Z/W30Wy/sx3dkZoj4BijbXX85QKWu9jJfjho3LBAXNEGAEW3oWiGb+dotA6C6BzCTxL2/aLes7jlUeg==", + "version": "1.4.134", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.134.tgz", + "integrity": "sha512-OdD7M2no4Mi8PopfvoOuNcwYDJ2mNFxaBfurA6okG3fLBaMcFah9S+si84FhX+FIWLKkdaiHfl4A+5ep/gOVrg==", "dev": true }, "error-ex": { @@ -1832,9 +1832,9 @@ "dev": true }, "nanoid": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.2.tgz", - "integrity": "sha512-CuHBogktKwpm5g2sRgv83jEy2ijFzBwMoYA60orPDR7ynsLijJDqgsi4RDGj3OJpy3Ieb+LYwiRmIOGyytgITA==", + "version": "3.3.4", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.4.tgz", + "integrity": "sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw==", "dev": true }, "natural-compare": { @@ -1853,9 +1853,9 @@ } }, "node-releases": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.2.tgz", - "integrity": "sha512-XxYDdcQ6eKqp/YjI+tb2C5WM2LgjnZrfYg4vgQt49EK268b6gYCHsBLrK2qvJo4FmCtqmKezb0WZFK4fkrZNsg==", + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.4.tgz", + "integrity": "sha512-gbMzqQtTtDz/00jQzZ21PQzdI9PyLYqUSvD0p3naOhX4odFji0ZxYdnVwPTxmSwkmxhcFImpozceidSG+AgoPQ==", "dev": true }, "normalize-path": { @@ -1969,12 +1969,12 @@ "dev": true }, "postcss": { - "version": "8.4.12", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.12.tgz", - "integrity": "sha512-lg6eITwYe9v6Hr5CncVbK70SoioNQIq81nsaG86ev5hAidQvmOeETBqs7jm43K2F5/Ley3ytDtriImV6TpNiSg==", + "version": "8.4.13", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.13.tgz", + "integrity": "sha512-jtL6eTBrza5MPzy8oJLFuUscHDXTV5KcLlqAWHl5q5WYRfnNRGSmOZmOZ1T6Gy7A99mOZfqungmZMpMmCVJ8ZA==", "dev": true, "requires": { - "nanoid": "^3.3.1", + "nanoid": "^3.3.3", "picocolors": "^1.0.0", "source-map-js": "^1.0.2" } @@ -2179,9 +2179,9 @@ } }, "rollup": { - "version": "2.70.1", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.70.1.tgz", - "integrity": "sha512-CRYsI5EuzLbXdxC6RnYhOuRdtz4bhejPMSWjsFLfVM/7w/85n2szZv6yExqUXsBdz5KT8eoubeyDUDjhLHEslA==", + "version": "2.71.1", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.71.1.tgz", + "integrity": "sha512-lMZk3XfUBGjrrZQpvPSoXcZSfKcJ2Bgn+Z0L1MoW2V8Wh7BVM+LOBJTPo16yul2MwL59cXedzW1ruq3rCjSRgw==", "dev": true, "requires": { "fsevents": "~2.3.2" @@ -2480,9 +2480,9 @@ "dev": true }, "svelte": { - "version": "3.46.6", - "resolved": "https://registry.npmjs.org/svelte/-/svelte-3.46.6.tgz", - "integrity": "sha512-o9nNft/OzCz/9kJpmWa1S52GAM+huCjPIsNWydYmgei74ZWlOA9/hN9+Z12INdklghu31seEXZMRHhS1+8DETw==" + "version": "3.48.0", + "resolved": "https://registry.npmjs.org/svelte/-/svelte-3.48.0.tgz", + "integrity": "sha512-fN2YRm/bGumvjUpu6yI3BpvZnpIm9I6A7HR4oUNYd7ggYyIwSA/BX7DJ+UXXffLp6XNcUijyLvttbPVCYa/3xQ==" }, "svelte-check": { "version": "1.6.0", @@ -2558,9 +2558,9 @@ "integrity": "sha512-0bnbMGbsE1LUnlioDcf27tl2O8kjuXlTXMXzIxC7LoIOWmqn0D+zd539HfLiQbdLuOHGTaynwN9V+4ehhEu1Jw==" }, "svelte-preprocess": { - "version": "4.10.4", - "resolved": "https://registry.npmjs.org/svelte-preprocess/-/svelte-preprocess-4.10.4.tgz", - "integrity": "sha512-fuwol0N4UoHsNQolLFbMqWivqcJ9N0vfWO9IuPAiX/5okfoGXURyJ6nECbuEIv0nU3M8Xe2I1ONNje2buk7l6A==", + "version": "4.10.6", + "resolved": "https://registry.npmjs.org/svelte-preprocess/-/svelte-preprocess-4.10.6.tgz", + "integrity": "sha512-I2SV1w/AveMvgIQlUF/ZOO3PYVnhxfcpNyGt8pxpUVhPfyfL/CZBkkw/KPfuFix5FJ9TnnNYMhACK3DtSaYVVQ==", "dev": true, "requires": { "@types/pug": "^2.0.4", @@ -2751,9 +2751,9 @@ "integrity": "sha512-gduQwd1rOdDMGxFG1gEvhV88Oirdo2p+KjoYFU7k2g+i7n6AFFbDQ5kMPUsW0pNbfQsB/cwXvT1i4Bue0s9g5g==" }, "tslib": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.1.tgz", - "integrity": "sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw==", + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz", + "integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==", "dev": true }, "tsutils": { @@ -2789,9 +2789,9 @@ "dev": true }, "typescript": { - "version": "4.6.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.6.3.tgz", - "integrity": "sha512-yNIatDa5iaofVozS/uQJEl3JRWLKKGJKh6Yaiv0GLGSuhpFJe7P3SbHZ8/yjAHRQwKRoA6YZqlfjXWmVzoVSMw==", + "version": "4.6.4", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.6.4.tgz", + "integrity": "sha512-9ia/jWHIEbo49HfjrLGfKbZSuWo9iTMwXO+Ca3pRsSpbsMbc7/IU8NKdCZVRRBafVPGnoJeFL76ZOAA84I9fEg==", "dev": true }, "universalify": { diff --git a/pyscriptjs/package.json b/pyscriptjs/package.json index d1f39de9d69..47d6d19312d 100644 --- a/pyscriptjs/package.json +++ b/pyscriptjs/package.json @@ -15,36 +15,36 @@ "devDependencies": { "@rollup/plugin-commonjs": "^17.0.0", "@rollup/plugin-node-resolve": "^11.0.0", - "@rollup/plugin-typescript": "^8.1.0", + "@rollup/plugin-typescript": "^8.3.2", "@tsconfig/svelte": "^1.0.0", "@typescript-eslint/eslint-plugin": "^5.20.0", "@typescript-eslint/parser": "^5.20.0", - "autoprefixer": "^10.2.3", + "autoprefixer": "^10.4.7", "eslint": "^8.14.0", "eslint-plugin-svelte3": "^3.4.1", - "postcss": "^8.2.4", + "postcss": "^8.4.13", "prettier": "^2.6.2", "prettier-plugin-svelte": "^2.7.0", - "rollup": "^2.3.4", + "rollup": "^2.71.1", "rollup-plugin-css-only": "^3.1.0", "rollup-plugin-livereload": "^2.0.0", "rollup-plugin-serve": "^1.1.0", "rollup-plugin-svelte": "^7.0.0", "rollup-plugin-terser": "^7.0.0", - "svelte": "^3.0.0", + "svelte": "^3.48.0", "svelte-check": "^1.0.0", - "svelte-preprocess": "^4.6.3", + "svelte-preprocess": "^4.10.6", "tailwindcss": "^2.0.2", - "tslib": "^2.0.0", - "typescript": "^4.1.3" + "tslib": "^2.4.0", + "typescript": "^4.6.4" }, "dependencies": { "@codemirror/basic-setup": "^0.19.1", - "@codemirror/lang-python": "^0.19.4", + "@codemirror/lang-python": "^0.19.5", "@codemirror/state": "^0.19.9", "@codemirror/theme-one-dark": "^0.19.1", "@fortawesome/free-solid-svg-icons": "^6.0.0", - "codemirror": "^5.65.2", + "codemirror": "^5.65.3", "js-yaml": "^4.1.0", "sirv-cli": "^1.0.0", "svelte-fa": "^2.4.0", From 822ae0dc83277de696cdc0c4bb667fc0f07d2e37 Mon Sep 17 00:00:00 2001 From: Fabio Pliger Date: Thu, 5 May 2022 09:14:28 -0500 Subject: [PATCH 06/15] fix project name and version --- pyscriptjs/package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pyscriptjs/package.json b/pyscriptjs/package.json index 47d6d19312d..e426b053b05 100644 --- a/pyscriptjs/package.json +++ b/pyscriptjs/package.json @@ -1,6 +1,6 @@ { - "name": "svelte-app", - "version": "1.0.0", + "name": "pyscript", + "version": "0.0.1", "scripts": { "build": "NODE_ENV=production rollup -c", "dev": "rollup -c -w", From 85a85becaa80363b43cef21f652873d21df46874 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Thu, 5 May 2022 22:16:13 +0000 Subject: [PATCH 07/15] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- pyscriptjs/examples/micrograd_ai.py | 111 +++++++----- pyscriptjs/src/pyscript.py | 270 +++++++++++++++------------- 2 files changed, 205 insertions(+), 176 deletions(-) diff --git a/pyscriptjs/examples/micrograd_ai.py b/pyscriptjs/examples/micrograd_ai.py index 05a0af3ee7a..ea7317919bd 100644 --- a/pyscriptjs/examples/micrograd_ai.py +++ b/pyscriptjs/examples/micrograd_ai.py @@ -1,45 +1,48 @@ -#Credit: https://github.com/karpathy/micrograd/blob/master/demo.ipynb -#cell -import random -import numpy as np -import matplotlib.pyplot as plt +# Credit: https://github.com/karpathy/micrograd/blob/master/demo.ipynb +# cell import datetime +import random -#cell +import matplotlib.pyplot as plt +import numpy as np +# cell from micrograd.engine import Value -from micrograd.nn import Neuron, Layer, MLP +from micrograd.nn import MLP, Layer, Neuron print_statements = [] -def run_all_micrograd_demo(*args,**kwargs): + +def run_all_micrograd_demo(*args, **kwargs): result = micrograd_demo() - pyscript.write('micrograd-run-all-fig2-div', result) + pyscript.write("micrograd-run-all-fig2-div", result) + def print_div(o): o = str(o) - print_statements.append(o + ' \n
') - pyscript.write('micrograd-run-all-print-div', ''.join(print_statements)) + print_statements.append(o + " \n
") + pyscript.write("micrograd-run-all-print-div", "".join(print_statements)) + -#All code is wrapped in this run_all function so it optionally executed (called) -#from pyscript when a button is pressed. -def micrograd_demo(*args,**kwargs): +# All code is wrapped in this run_all function so it optionally executed (called) +# from pyscript when a button is pressed. +def micrograd_demo(*args, **kwargs): """ Runs the micrograd demo. *args and **kwargs do nothing and are only there to capture any parameters passed from pyscript when this function is called when a button is clicked. """ - - #cell + + # cell start = datetime.datetime.now() - print_div('Starting...') + print_div("Starting...") - #cell + # cell np.random.seed(1337) random.seed(1337) -#cell -#An adaptation of sklearn's make_moons function https://scikit-learn.org/stable/modules/generated/sklearn.datasets.make_moons.html + # cell + # An adaptation of sklearn's make_moons function https://scikit-learn.org/stable/modules/generated/sklearn.datasets.make_moons.html def make_moons(n_samples=100, noise=None): n_samples_out, n_samples_in = n_samples, n_samples @@ -48,26 +51,38 @@ def make_moons(n_samples=100, noise=None): inner_circ_x = 1 - np.cos(np.linspace(0, np.pi, n_samples_in)) inner_circ_y = 1 - np.sin(np.linspace(0, np.pi, n_samples_in)) - 0.5 - X = np.vstack([np.append(outer_circ_x, inner_circ_x), np.append(outer_circ_y, inner_circ_y)]).T - y = np.hstack([np.zeros(n_samples_out, dtype=np.intp), np.ones(n_samples_in, dtype=np.intp)]) - if noise is not None: X += np.random.normal(loc=0.0, scale=noise, size=X.shape) + X = np.vstack( + [ + np.append(outer_circ_x, inner_circ_x), + np.append(outer_circ_y, inner_circ_y), + ] + ).T + y = np.hstack( + [ + np.zeros(n_samples_out, dtype=np.intp), + np.ones(n_samples_in, dtype=np.intp), + ] + ) + if noise is not None: + X += np.random.normal(loc=0.0, scale=noise, size=X.shape) return X, y + X, y = make_moons(n_samples=100, noise=0.1) - #cell - y = y*2 - 1 # make y be -1 or 1 + # cell + y = y * 2 - 1 # make y be -1 or 1 # visualize in 2D - plt.figure(figsize=(5,5)) - plt.scatter(X[:,0], X[:,1], c=y, s=20, cmap='jet') + plt.figure(figsize=(5, 5)) + plt.scatter(X[:, 0], X[:, 1], c=y, s=20, cmap="jet") plt - pyscript.write('micrograd-run-all-fig1-div', plt) + pyscript.write("micrograd-run-all-fig1-div", plt) - #cell - model = MLP(2, [16, 16, 1]) # 2-layer neural network + # cell + model = MLP(2, [16, 16, 1]) # 2-layer neural network print_div(model) print_div(("number of parameters", len(model.parameters()))) - #cell + # cell # loss function def loss(batch_size=None): # inline DataLoader :) @@ -77,51 +92,53 @@ def loss(batch_size=None): ri = np.random.permutation(X.shape[0])[:batch_size] Xb, yb = X[ri], y[ri] inputs = [list(map(Value, xrow)) for xrow in Xb] - + # forward the model to get scores scores = list(map(model, inputs)) - + # svm "max-margin" loss - losses = [(1 + -yi*scorei).relu() for yi, scorei in zip(yb, scores)] + losses = [(1 + -yi * scorei).relu() for yi, scorei in zip(yb, scores)] data_loss = sum(losses) * (1.0 / len(losses)) # L2 regularization alpha = 1e-4 - reg_loss = alpha * sum((p*p for p in model.parameters())) + reg_loss = alpha * sum((p * p for p in model.parameters())) total_loss = data_loss + reg_loss - + # also get accuracy - accuracy = [((yi).__gt__(0)) == ((scorei.data).__gt__(0)) for yi, scorei in zip(yb, scores)] + accuracy = [ + ((yi).__gt__(0)) == ((scorei.data).__gt__(0)) + for yi, scorei in zip(yb, scores) + ] return total_loss, sum(accuracy) / len(accuracy) total_loss, acc = loss() print((total_loss, acc)) - #cell + # cell # optimization - for k in range(20): #was 100 - + for k in range(20): # was 100 + # forward total_loss, acc = loss() - + # backward model.zero_grad() total_loss.backward() - + # update (sgd) - learning_rate = 1.0 - 0.9*k/100 + learning_rate = 1.0 - 0.9 * k / 100 for p in model.parameters(): p.data -= learning_rate * p.grad - + if k % 1 == 0: # print(f"step {k} loss {total_loss.data}, accuracy {acc*100}%") print_div(f"step {k} loss {total_loss.data}, accuracy {acc*100}%") - #cell + # cell h = 0.25 x_min, x_max = X[:, 0].min() - 1, X[:, 0].max() + 1 y_min, y_max = X[:, 1].min() - 1, X[:, 1].max() + 1 - xx, yy = np.meshgrid(np.arange(x_min, x_max, h), - np.arange(y_min, y_max, h)) + xx, yy = np.meshgrid(np.arange(x_min, x_max, h), np.arange(y_min, y_max, h)) Xmesh = np.c_[xx.ravel(), yy.ravel()] inputs = [list(map(Value, xrow)) for xrow in Xmesh] scores = list(map(model, inputs)) diff --git a/pyscriptjs/src/pyscript.py b/pyscriptjs/src/pyscript.py index b2b0fe7a319..b1d45e4c5a9 100644 --- a/pyscriptjs/src/pyscript.py +++ b/pyscriptjs/src/pyscript.py @@ -1,8 +1,11 @@ -from js import document, setInterval, console, setTimeout -import micropip -import time import asyncio -import io, base64, sys +import base64 +import io +import sys +import time + +import micropip +from js import console, document, setInterval, setTimeout loop = asyncio.get_event_loop() @@ -202,162 +205,165 @@ def remove_class(self, classname): def add_class(self, classname): self.element.classList.add(classname) + def add_classes(element, class_list): - for klass in class_list.split(' '): - element.classList.add(klass) + for klass in class_list.split(" "): + element.classList.add(klass) -def create(what, id_=None, classes=''): - element = document.createElement(what) - if id_: - element.id = id_ - add_classes(element, classes) - return Element(id_, element) + +def create(what, id_=None, classes=""): + element = document.createElement(what) + if id_: + element.id = id_ + add_classes(element, classes) + return Element(id_, element) class PyWidgetTheme: - def __init__(self, main_style_classes): - self.main_style_classes = main_style_classes + def __init__(self, main_style_classes): + self.main_style_classes = main_style_classes - def theme_it(self, widget): - for klass in self.main_style_classes.split(' '): - widget.classList.add(klass) + def theme_it(self, widget): + for klass in self.main_style_classes.split(" "): + widget.classList.add(klass) class PyItemTemplate(Element): - label_fields = None + label_fields = None - def __init__(self, data, labels=None, state_key=None, parent=None): - self.data = data + def __init__(self, data, labels=None, state_key=None, parent=None): + self.data = data - self.register_parent(parent) + self.register_parent(parent) - if not labels: - labels = list(self.data.keys()) - self.labels = labels + if not labels: + labels = list(self.data.keys()) + self.labels = labels - self.state_key = state_key + self.state_key = state_key - super().__init__(self._id) + super().__init__(self._id) - def register_parent(self, parent): - self._parent = parent - if parent: - self._id = f"{self._parent._id}-c-{len(self._parent._children)}" - self.data['id'] = self._id - else: - self._id = None + def register_parent(self, parent): + self._parent = parent + if parent: + self._id = f"{self._parent._id}-c-{len(self._parent._children)}" + self.data["id"] = self._id + else: + self._id = None - def create(self): - console.log('creating section') - new_child = create('section', self._id, "task bg-white my-1") - console.log('creating values') + def create(self): + console.log("creating section") + new_child = create("section", self._id, "task bg-white my-1") + console.log("creating values") - console.log('creating innerHtml') - new_child._element.innerHTML = f""" + console.log("creating innerHtml") + new_child._element.innerHTML = f""" """ - console.log('returning') - return new_child + console.log("returning") + return new_child - def on_click(self, evt): - pass + def on_click(self, evt): + pass - def pre_append(self): - pass + def pre_append(self): + pass - def post_append(self): - self.element.click = self.on_click - self.element.onclick = self.on_click + def post_append(self): + self.element.click = self.on_click + self.element.onclick = self.on_click - self._post_append() + self._post_append() - def _post_append(self): - pass + def _post_append(self): + pass - def strike(self, value, extra=None): - if value: - self.add_class("line-through") - else: - self.remove_class("line-through") + def strike(self, value, extra=None): + if value: + self.add_class("line-through") + else: + self.remove_class("line-through") + + def render_content(self): + return " - ".join([self.data[f] for f in self.labels]) - def render_content(self): - return ' - '.join([self.data[f] for f in self.labels]) class PyListTemplate: - theme = PyWidgetTheme("flex flex-col-reverse mt-8 mx-8") - item_class = PyItemTemplate - - def __init__(self, parent): - self.parent = parent - self._children = [] - self._id = self.parent.id - - @property - def children(self): - return self._children - - @property - def data(self): - return [c.data for c in self._children] - - def render_children(self): - out = [] - binds = {} - for i, c in enumerate(self._children): - txt = c.element.innerHTML - rnd = str(time.time()).replace(".", "")[-5:] - new_id = f"{c.element.id}-{i}-{rnd}" - binds[new_id] = c.element.id - txt = txt.replace(">", f" id='{new_id}'>") - print(txt) - - def foo(evt): - console.log(evt) - evtEl = evt.srcElement - srcEl = Element(binds[evtEl.id]) - srcEl.element.onclick() - evtEl.classList = srcEl.element.classList - - for new_id, old_id in binds.items(): - Element(new_id).element.onclick = foo - - def connect(self): - self.md = main_div = document.createElement('div') - main_div.id = self._id + "-list-tasks-container" - - if self.theme: - self.theme.theme_it(main_div) - - self.parent.appendChild(main_div) - - def add(self, *args, **kws): - if not isinstance(args[0], self.item_class): - child = self.item_class(*args, **kws) - else: - child = args[0] - child.register_parent(self) - return self._add(child) + theme = PyWidgetTheme("flex flex-col-reverse mt-8 mx-8") + item_class = PyItemTemplate + + def __init__(self, parent): + self.parent = parent + self._children = [] + self._id = self.parent.id + + @property + def children(self): + return self._children - def _add(self, child_elem): - console.log("appending child", child_elem.element) - self.pre_child_append(child_elem) - child_elem.pre_append() - self._children.append(child_elem) - self.md.appendChild(child_elem.create().element) - child_elem.post_append() - self.child_appended(child_elem) - return child_elem + @property + def data(self): + return [c.data for c in self._children] + + def render_children(self): + out = [] + binds = {} + for i, c in enumerate(self._children): + txt = c.element.innerHTML + rnd = str(time.time()).replace(".", "")[-5:] + new_id = f"{c.element.id}-{i}-{rnd}" + binds[new_id] = c.element.id + txt = txt.replace(">", f" id='{new_id}'>") + print(txt) + + def foo(evt): + console.log(evt) + evtEl = evt.srcElement + srcEl = Element(binds[evtEl.id]) + srcEl.element.onclick() + evtEl.classList = srcEl.element.classList + + for new_id, old_id in binds.items(): + Element(new_id).element.onclick = foo + + def connect(self): + self.md = main_div = document.createElement("div") + main_div.id = self._id + "-list-tasks-container" + + if self.theme: + self.theme.theme_it(main_div) + + self.parent.appendChild(main_div) + + def add(self, *args, **kws): + if not isinstance(args[0], self.item_class): + child = self.item_class(*args, **kws) + else: + child = args[0] + child.register_parent(self) + return self._add(child) + + def _add(self, child_elem): + console.log("appending child", child_elem.element) + self.pre_child_append(child_elem) + child_elem.pre_append() + self._children.append(child_elem) + self.md.appendChild(child_elem.create().element) + child_elem.post_append() + self.child_appended(child_elem) + return child_elem - def pre_child_append(self, child): - pass + def pre_child_append(self, child): + pass - def child_appended(self, child): - """Overwrite me to define logic""" - pass + def child_appended(self, child): + """Overwrite me to define logic""" + pass class OutputCtxManager: @@ -379,16 +385,21 @@ def revert(self): self._out = self._prev def write(self, txt): - console.log('writing to', self._out, txt, self._append) + console.log("writing to", self._out, txt, self._append) if self._out: pyscript.write(self._out, txt, append=self._append) if self.output_to_console: console.log(self._out, txt) + class OutputManager: def __init__(self, out=None, err=None, output_to_console=True, append=True): - sys.stdout = self._out_manager = OutputCtxManager(out, output_to_console, append) - sys.stderr = self._err_manager = OutputCtxManager(err, output_to_console, append) + sys.stdout = self._out_manager = OutputCtxManager( + out, output_to_console, append + ) + sys.stderr = self._err_manager = OutputCtxManager( + err, output_to_console, append + ) self.output_to_console = output_to_console self._append = append @@ -407,5 +418,6 @@ def revert(self): sys.stderr = self._err_manager console.log("----> reverted") + pyscript = PyScript() -output_manager = OutputManager() \ No newline at end of file +output_manager = OutputManager() From d0d2635f44e7e8b479310bbf579e9799d46db66b Mon Sep 17 00:00:00 2001 From: Fabio Pliger Date: Thu, 5 May 2022 18:23:57 -0500 Subject: [PATCH 08/15] lint --- pyscriptjs/examples/micrograd_ai.py | 1 + pyscriptjs/src/App.svelte | 9 +--- pyscriptjs/src/components/base.ts | 10 ++-- pyscriptjs/src/components/pybox.ts | 7 ++- pyscriptjs/src/components/pyenv.ts | 2 +- pyscriptjs/src/components/pyrepl.ts | 67 ++++++++++++++------------- pyscriptjs/src/components/pyscript.ts | 2 - pyscriptjs/src/interpreter.ts | 6 +-- 8 files changed, 46 insertions(+), 58 deletions(-) diff --git a/pyscriptjs/examples/micrograd_ai.py b/pyscriptjs/examples/micrograd_ai.py index ea7317919bd..37cfc881b8a 100644 --- a/pyscriptjs/examples/micrograd_ai.py +++ b/pyscriptjs/examples/micrograd_ai.py @@ -5,6 +5,7 @@ import matplotlib.pyplot as plt import numpy as np + # cell from micrograd.engine import Value from micrograd.nn import MLP, Layer, Neuron diff --git a/pyscriptjs/src/App.svelte b/pyscriptjs/src/App.svelte index f60e2f4b0d1..6fd83ba1641 100644 --- a/pyscriptjs/src/App.svelte +++ b/pyscriptjs/src/App.svelte @@ -1,14 +1,7 @@