From 8657dfb5da0d7b5c2b130c02ae9485040bd40179 Mon Sep 17 00:00:00 2001 From: Jeff Glass Date: Mon, 12 Sep 2022 03:29:25 -0500 Subject: [PATCH] Docs: How To Pass Objects between JavaScript and PyScript (#753) * Begin writeup * Draft full howto * Correct code errors in writeup, swap sections * Add introduction, clarification * Add link to howto:js in index * Copyedit, update examples to Pyodide 21 * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * Add toc tree context * Use print instead of js console in python examples Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> Co-authored-by: mariana --- docs/howtos/index.md | 2 +- docs/howtos/passing-objects.md | 140 +++++++++++++++++++++++++++++++++ docs/index.md | 4 +- 3 files changed, 144 insertions(+), 2 deletions(-) create mode 100644 docs/howtos/passing-objects.md diff --git a/docs/howtos/index.md b/docs/howtos/index.md index 5c4261fe..557de8cf 100644 --- a/docs/howtos/index.md +++ b/docs/howtos/index.md @@ -14,5 +14,5 @@ maxdepth: 2 glob: caption: 'Contents:' --- -* +passing-objects ``` diff --git a/docs/howtos/passing-objects.md b/docs/howtos/passing-objects.md new file mode 100644 index 00000000..024c42fc --- /dev/null +++ b/docs/howtos/passing-objects.md @@ -0,0 +1,140 @@ +# How to Pass Objects from PyScript to Javascript (and Vice Versa) + +[Pyodide](https://pyodide.org), the runtime that underlies PyScript, does a lot of work under the hood to translate objects between Python and JavaScript. This allows code in one language to access objects defined in the other. + +This guide discusses how to pass objects between JavaScript and Python within PyScript. For more details on how Pyodide handles translating and proxying objects between the two languages, see the [Pyodide Type Translations Page](https://pyodide.org/en/stable/usage/type-conversions.html). + +For our purposes, an 'object' is anything that can be bound to a variable (a number, string, object, [function](https://developer.mozilla.org/en-US/docs/Glossary/First-class_Function), etc). + +## JavaScript to PyScript + +We can use the syntax `from js import ...` to import JavaScript objects directly into PyScript. Simple JavaScript objects are converted to equivalent Python types; these are called [implicit conversions](https://pyodide.org/en/stable/usage/type-conversions.html#implicit-conversions). More complicated objects are wrapped in [JSProxy](https://pyodide.org/en/stable/usage/type-conversions.html) objects to make them behave like Python objects. + +`import js` and `from js import ...` [in Pyodide](https://pyodide.org/en/stable/usage/type-conversions.html#type-translations-using-js-obj-from-py) get objects from the [JavaScript globalThis scope](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/globalThis), so keep the[ rules of JavaScript variable scoping](https://www.freecodecamp.org/news/var-let-and-const-whats-the-difference/) in mind. + +```html + +``` +```python + + # Import and use JS function and variable into Python + from js import name, addTwoNumbers + + print(f"Hello {name}") + print("Adding 1 and 2 in Javascript: " + str(addTwoNumbers(1, 2))) + +``` + +## PyScript to JavaScript + +Since [PyScript doesn't export its instance of Pyodide](https://github.com/pyscript/pyscript/issues/494) and only one instance of Pyodide can be running in a browser window at a time, there isn't currently a way for Javascript to access Objects defined inside PyScript tags "directly". + +We can work around this limitation using [JavaScript's eval() function](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/eval), which executes a string as code much like [Python's eval()](https://docs.python.org/3/library/functions.html#eval). First, we create a JS function `createObject` which takes an object and a string, then uses `eval()` to create a variable named after the string and bind it to that object. By calling this function from PyScript (where we have access to the Pyodide global namespace), we can bind JavaScript variables to Python objects without having direct access to that global namespace. + +Include the following script tag anywhere in your html document: + +```html + +``` + +This function takes a Python Object and creates a variable pointing to it in the JavaScript global scope. + +### Exporting all Global Python Objects + +We can use our new `createObject` function to "export" the entire Python global object dictionary as a JavaScript object: + +```python + + from js import createObject + from pyodide.ffi import create_proxy + createObject(create_proxy(globals()), "pyodideGlobals") + +``` +This will make all Python global variables available in JavaScript with `pyodideGlobals.get('my_variable_name')`. + +(Since PyScript tags evaluate _after_ all JavaScript on the page, we can't just dump a `console.log(...)` into a ` +``` + + +### Exporting Individual Python Objects + +We can also export individual Python objects to the JavaScript global scope if we wish. + +(As above, the following example uses a button to delay the execution of the ` +``` diff --git a/docs/index.md b/docs/index.md index 6c4051c7..696db28c 100644 --- a/docs/index.md +++ b/docs/index.md @@ -24,7 +24,9 @@ Check out our [getting started guide](tutorials/getting-started.md)! ::: :::{grid-item-card} [How-to guides](howtos/index.md) -**Coming soon!** +You already know the basics and want to learn specifics! + +[Passing Objects between JavaScript and Python](howtos/passing-objects.md) ::: :::{grid-item-card} [Concepts](concepts/index.md)