DOCS Edits to Javascript API docs (#1427)

This commit is contained in:
Hood Chatham 2021-04-09 14:30:40 -04:00 committed by GitHub
parent 31d10d1705
commit 1781b8760f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 181 additions and 99 deletions

View File

@ -2,3 +2,7 @@
margin-right: 5px; margin-right: 5px;
opacity: 0.7; opacity: 0.7;
} }
code {
font-size: 100% !important;
}

View File

@ -7,9 +7,10 @@ browser.
Pyodide brings the Python 3.8 runtime to the browser via WebAssembly, along with Pyodide brings the Python 3.8 runtime to the browser via WebAssembly, along with
the Python scientific stack including NumPy, Pandas, Matplotlib, SciPy, and the Python scientific stack including NumPy, Pandas, Matplotlib, SciPy, and
scikit-learn. The [packages directory](packages) lists over 75 packages which scikit-learn. The [packages
are currently available. In addition it's possible to install pure Python wheels directory](https://github.com/pyodide/pyodide/tree/master/packages) lists over
from PyPi. 75 packages which are currently available. In addition it's possible to install
pure Python wheels from PyPi.
Pyodide provides transparent conversion of objects between Javascript and Pyodide provides transparent conversion of objects between Javascript and
Python. When used inside a browser, Python has full access to the Web APIs. Python. When used inside a browser, Python has full access to the Web APIs.

View File

@ -1,5 +1,5 @@
from docutils import nodes from docutils import nodes
from docutils.parsers.rst import Directive, Parser as RstParser from docutils.parsers.rst import Directive, Parser as RstParser, directives
from docutils.statemachine import StringList from docutils.statemachine import StringList
from docutils.utils import new_document from docutils.utils import new_document
@ -10,6 +10,7 @@ from sphinx import addnodes
from sphinx.util import rst from sphinx.util import rst
from sphinx.util.docutils import switch_source_input from sphinx.util.docutils import switch_source_input
from sphinx.ext.autosummary import autosummary_table, extract_summary from sphinx.ext.autosummary import autosummary_table, extract_summary
from sphinx.domains.javascript import JSCallable, JavaScriptDomain
from sphinx_js.jsdoc import Analyzer as JsAnalyzer from sphinx_js.jsdoc import Analyzer as JsAnalyzer
from sphinx_js.ir import Class, Function from sphinx_js.ir import Class, Function
@ -21,6 +22,21 @@ from sphinx_js.renderers import (
) )
class JSFuncMaybeAsync(JSCallable):
option_spec = {
**JSCallable.option_spec,
"async": directives.flag,
}
def handle_signature(self, sig, signode):
if "async" in self.options:
self.display_prefix = "async"
return super().handle_signature(sig, signode)
JavaScriptDomain.directives["function"] = JSFuncMaybeAsync
class PyodideAnalyzer: class PyodideAnalyzer:
"""JsDoc automatically instantiates the JsAnalyzer. Rather than subclassing """JsDoc automatically instantiates the JsAnalyzer. Rather than subclassing
or monkey patching it, we use composition (see getattr impl). or monkey patching it, we use composition (see getattr impl).
@ -85,11 +101,14 @@ class PyodideAnalyzer:
if key[0] == "pyproxy.": if key[0] == "pyproxy.":
items["PyProxy"] += group items["PyProxy"] += group
from operator import itemgetter
for key, value in items.items(): for key, value in items.items():
for json in value: for json in sorted(value, key=itemgetter("name")):
if json.get("access", None) == "private": if json.get("access", None) == "private":
continue continue
obj = self.get_object_from_json(json) obj = self.get_object_from_json(json)
obj.async_ = json.get("async", False)
if isinstance(obj, Class): if isinstance(obj, Class):
# sphinx-jsdoc messes up array types. Fix them. # sphinx-jsdoc messes up array types. Fix them.
for x in obj.members: for x in obj.members:
@ -121,9 +140,20 @@ def get_jsdoc_content_directive(app):
renderer = AutoClassRenderer renderer = AutoClassRenderer
else: else:
renderer = AutoAttributeRenderer renderer = AutoAttributeRenderer
return renderer( rst = renderer(
self, app, arguments=["dummy"], options={"members": ["*"]} self, app, arguments=["dummy"], options={"members": ["*"]}
).rst([obj.name], obj, use_short_name=False) ).rst([obj.name], obj, use_short_name=False)
if obj.async_:
rst = self.add_async_option_to_rst(rst)
return rst
def add_async_option_to_rst(self, rst):
rst_lines = rst.split("\n")
for i, line in enumerate(rst_lines):
if line.startswith(".."):
break
rst_lines.insert(i + 1, " :async:")
return "\n".join(rst_lines)
def get_rst_for_group(self, objects): def get_rst_for_group(self, objects):
return [self.get_rst(obj) for obj in objects] return [self.get_rst(obj) for obj in objects]
@ -215,9 +245,10 @@ def get_jsdoc_summary_directive(app):
""" """
sig = self.get_sig(obj) sig = self.get_sig(obj)
display_name = obj.name display_name = obj.name
prefix = "*async* " if obj.async_ else ""
summary = self.extract_summary(obj.description) summary = self.extract_summary(obj.description)
link_name = pkgname + "." + display_name link_name = pkgname + "." + display_name
return (display_name, sig, summary, link_name) return (prefix, display_name, sig, summary, link_name)
def get_summary_table(self, pkgname, group): def get_summary_table(self, pkgname, group):
"""Get the data for a summary table. Return value is set up to be an """Get the data for a summary table. Return value is set up to be an
@ -266,17 +297,18 @@ def get_jsdoc_summary_directive(app):
row.append(nodes.entry("", node)) row.append(nodes.entry("", node))
body.append(row) body.append(row)
for name, sig, summary, real_name in items: for prefix, name, sig, summary, real_name in items:
qualifier = "any" # <== Only thing changed from autosummary version qualifier = "any" # <== Only thing changed from autosummary version
if "nosignatures" not in self.options: if "nosignatures" not in self.options:
col1 = ":%s:`%s <%s>`\\ %s" % ( col1 = "%s:%s:`%s <%s>`\\ %s" % (
prefix,
qualifier, qualifier,
name, name,
real_name, real_name,
rst.escape(sig), rst.escape(sig),
) )
else: else:
col1 = ":%s:`%s <%s>`" % (qualifier, name, real_name) col1 = "%s:%s:`%s <%s>`" % (prefix, qualifier, name, real_name)
col2 = summary col2 = summary
append_row(col1, col2) append_row(col1, col2)

File diff suppressed because one or more lines are too long

View File

@ -119,6 +119,7 @@ def test_summary():
) )
assert set(globals) == { assert set(globals) == {
( (
"",
"languagePluginLoader", "languagePluginLoader",
"", "",
"A promise that resolves to ``undefined`` when Pyodide is finished loading.", "A promise that resolves to ``undefined`` when Pyodide is finished loading.",
@ -128,12 +129,14 @@ def test_summary():
assert set(attributes).issuperset( assert set(attributes).issuperset(
{ {
( (
"",
"loadedPackages", "loadedPackages",
"", "",
"The list of packages that Pyodide has loaded.", "The list of packages that Pyodide has loaded.",
"pyodide.loadedPackages", "pyodide.loadedPackages",
), ),
( (
"",
"pyodide_py", "pyodide_py",
"", "",
"An alias to the Python pyodide package.", "An alias to the Python pyodide package.",
@ -141,15 +144,18 @@ def test_summary():
), ),
} }
) )
print(functions)
assert set(functions).issuperset( assert set(functions).issuperset(
{ {
( (
"*async* ",
"loadPackagesFromImports", "loadPackagesFromImports",
"(code, messageCallback, errorCallback)", "(code, messageCallback, errorCallback)",
"Inspect a Python code chunk and use :js:func:`pyodide.loadPackage` to load any known \npackages that the code chunk imports.", "Inspect a Python code chunk and use :js:func:`pyodide.loadPackage` to load any known \npackages that the code chunk imports.",
"pyodide.loadPackagesFromImports", "pyodide.loadPackagesFromImports",
), ),
( (
"",
"registerJsModule", "registerJsModule",
"(name, module)", "(name, module)",
"Registers the Js object ``module`` as a Js module with ``name``.", "Registers the Js object ``module`` as a Js module with ``name``.",

View File

@ -14,7 +14,7 @@ By default there are two Javascript modules. More can be added with
* - ``js`` * - ``js``
- The global Javascript scope. - The global Javascript scope.
* - :js:mod:`pyodide_js <pyodide>` * - :js:mod:`pyodide_js <pyodide>`
- The Javascript pyodide module. - The Javascript Pyodide module.
``` ```
```{eval-rst} ```{eval-rst}

View File

@ -167,7 +167,7 @@ JS_FILE(pyproxy_init_js, () => {0,0; /* Magic, see include_js_file.h */
/** /**
* The length of the object. * The length of the object.
* *
* Present only if ``type(obj)`` has a `__len__` method. * Present only if the proxied Python object has a ``__len__`` method.
*/ */
get length() { get length() {
let ptrobj = _getPtr(this); let ptrobj = _getPtr(this);
@ -190,7 +190,7 @@ JS_FILE(pyproxy_init_js, () => {0,0; /* Magic, see include_js_file.h */
/** /**
* This translates to the Python code ``obj[key]``. * This translates to the Python code ``obj[key]``.
* *
* Present only if ``type(obj)`` has a ``__getitem__`` method. * Present only if the proxied Python object has a ``__getitem__`` method.
* *
* @param {any} key The key to look up. * @param {any} key The key to look up.
* @returns The corresponding value. * @returns The corresponding value.
@ -223,7 +223,7 @@ JS_FILE(pyproxy_init_js, () => {0,0; /* Magic, see include_js_file.h */
/** /**
* This translates to the Python code ``obj[key] = value``. * This translates to the Python code ``obj[key] = value``.
* *
* Present only if ``type(obj)`` has a ``__setitem__`` method. * Present only if the proxied Python object has a ``__setitem__`` method.
* *
* @param {any} key The key to set. * @param {any} key The key to set.
* @param {any} value The value to set it to. * @param {any} value The value to set it to.
@ -248,7 +248,7 @@ JS_FILE(pyproxy_init_js, () => {0,0; /* Magic, see include_js_file.h */
/** /**
* This translates to the Python code ``del obj[key]``. * This translates to the Python code ``del obj[key]``.
* *
* Present only if ``type(obj)`` has a ``__delitem__`` method. * Present only if the proxied Python object has a ``__delitem__`` method.
* *
* @param {any} key The key to delete. * @param {any} key The key to delete.
*/ */
@ -275,7 +275,7 @@ JS_FILE(pyproxy_init_js, () => {0,0; /* Magic, see include_js_file.h */
/** /**
* This translates to the Python code ``key in obj``. * This translates to the Python code ``key in obj``.
* *
* Present only if ``type(obj)`` has a ``__contains__`` method. * Present only if the proxied Python object has a ``__contains__`` method.
* *
* @param {*} key The key to check for. * @param {*} key The key to check for.
* @returns {bool} Is ``key`` present? * @returns {bool} Is ``key`` present?
@ -308,12 +308,12 @@ JS_FILE(pyproxy_init_js, () => {0,0; /* Magic, see include_js_file.h */
* associated to the proxy. See the documentation for `Symbol.iterator * associated to the proxy. See the documentation for `Symbol.iterator
* <https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Symbol/iterator>`_. * <https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Symbol/iterator>`_.
* *
* Present only if the Python object is iterable (i.e., ``type(obj)`` has an * Present only if the proxied Python object is iterable (i.e., has an
* ``__iter__`` method). * ``__iter__`` method).
* *
* This will be used implicitly by ``for(let x of proxy){}``. * This will be used implicitly by ``for(let x of proxy){}``.
* *
* @returns {Iterator} An iterator for ``obj``. * @returns {Iterator} An iterator for the proxied Python object.
*/ */
[Symbol.iterator] : function*() { [Symbol.iterator] : function*() {
let iterptr = _PyObject_GetIter(_getPtr(this)); let iterptr = _PyObject_GetIter(_getPtr(this));
@ -343,16 +343,16 @@ JS_FILE(pyproxy_init_js, () => {0,0; /* Magic, see include_js_file.h */
* *
* This will be used implicitly by ``for(let x of proxy){}``. * This will be used implicitly by ``for(let x of proxy){}``.
* *
* Present only if ``obj`` is a Python generator or iterator (i.e., * Present only if the proxied Python object is a generator or iterator
* ``type(obj)`` has an ``__iter__`` method). * (i.e., has a ``send`` or ``__next__`` method).
* *
* @param {*} value The value to send to the generator. The value will be * @param {*} value The value to send to the generator. The value will be
* assigned as a result of a yield expression. * assigned as a result of a yield expression.
* @returns {Object} An Object with two properties, ``done`` and ``value``. * @returns {Object} An Object with two properties: ``done`` and ``value``.
* If the generator returned ``some_value``, will return ``{done : false, * When the generator yields ``some_value``, ``next`` returns ``{done :
* value : some_value}``. If the Python generator raised a * false, value : some_value}``. When the generator raises a
* ``StopIteration(result_value)`` exception, then we return ``{done : true, * ``StopIteration(result_value)`` exception, ``next`` returns ``{done :
* value : result_value}``. * true, value : result_value}``.
*/ */
next : function(arg) { next : function(arg) {
let idresult; let idresult;
@ -599,7 +599,8 @@ JS_FILE(pyproxy_init_js, () => {0,0; /* Magic, see include_js_file.h */
* `Promise.then * `Promise.then
* <https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/then>`_ * <https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/then>`_
* *
* Only present on awaitable Python objects. * Present only if the proxied Python object is `awaitable
* <https://docs.python.org/3/library/asyncio-task.html?highlight=awaitable#awaitables>`_.
* *
* @param {Function} onFulfilled A handler called with the result as an * @param {Function} onFulfilled A handler called with the result as an
* argument if the awaitable succeeds. * argument if the awaitable succeeds.
@ -619,7 +620,8 @@ JS_FILE(pyproxy_init_js, () => {0,0; /* Magic, see include_js_file.h */
* `Promise.catch * `Promise.catch
* <https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/catch>`_. * <https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/catch>`_.
* *
* Only present on awaitable Python objects. * Present only if the proxied Python object is `awaitable
* <https://docs.python.org/3/library/asyncio-task.html?highlight=awaitable#awaitables>`_.
* *
* @param {Function} onRejected A handler called with the error as an * @param {Function} onRejected A handler called with the error as an
* argument if the awaitable fails. * argument if the awaitable fails.
@ -637,9 +639,9 @@ JS_FILE(pyproxy_init_js, () => {0,0; /* Magic, see include_js_file.h */
* `Promise.finally * `Promise.finally
* <https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/finally>`_. * <https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/finally>`_.
* *
* Only present on `awaitable * Present only if the proxied Python object is `awaitable
* <https://docs.python.org/3/library/asyncio-task.html?highlight=awaitable#awaitables>`_ * <https://docs.python.org/3/library/asyncio-task.html?highlight=awaitable#awaitables>`_.
* Python objects. *
* *
* @param {Function} onFinally A handler that is called with zero arguments * @param {Function} onFinally A handler that is called with zero arguments
* when the awaitable resolves. * when the awaitable resolves.
@ -681,18 +683,31 @@ JS_FILE(pyproxy_init_js, () => {0,0; /* Magic, see include_js_file.h */
* Get a view of the buffer data which is usable from Javascript. No copy is * Get a view of the buffer data which is usable from Javascript. No copy is
* ever performed. * ever performed.
* *
* The return value is a :any:`PyBuffer` object. See the documentation for * Present only if the proxied Python object supports the `Python Buffer
* :any:`PyBuffer` for details on how to use it. * Protocol <https://docs.python.org/3/c-api/buffer.html>`_.
* *
* We do not support suboffsets, if the buffer requires suboffsets we will * We do not support suboffsets, if the buffer requires suboffsets we will
* throw an error. Javascript nd array libraries can't handle suboffsets * throw an error. Javascript nd array libraries can't handle suboffsets
* anyways. In this case, you should copy the buffer to one that doesn't use * anyways. In this case, you should use the :any:`toJs` api or copy the
* suboffets (using e.g., ``np.ascontiguousarray``). * buffer to one that doesn't use suboffets (using e.g.,
* `numpy.ascontiguousarray
* <https://numpy.org/doc/stable/reference/generated/numpy.ascontiguousarray.html>`_).
* *
* @param {string} type The type of the desired output. Should be one of: * If the buffer stores big endian data or half floats, this function will
* "i8", "u8", "u8clamped", "i16", "u16", "i32", "u32", "i32", "u32", * fail without an explicit type argument. For big endian data you can use
* "i64", "u64", "f32", "f64, or "dataview". * ``toJs``. `DataViews
* @returns PyBuffer * <https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/DataView>`_
* have support for big endian data, so you might want to pass
* ``'dataview'`` as the type argument in that case.
*
* @param {string} [type] The type of :any:`PyBuffer.data` field in the
* output. Should be one of: ``"i8"``, ``"u8"``, ``"u8clamped"``, ``"i16"``,
* ``"u16"``, ``"i32"``, ``"u32"``, ``"i32"``, ``"u32"``, ``"i64"``,
* ``"u64"``, ``"f32"``, ``"f64``, or ``"dataview"``. This argument is
* optional, if absent ``getBuffer`` will try to determine the appropriate
* output type based on the buffer `format string
* <https://docs.python.org/3/library/struct.html#format-strings>`_.
* @returns :any:`PyBuffer`
*/ */
getBuffer : function(type) { getBuffer : function(type) {
let ArrayType = undefined; let ArrayType = undefined;
@ -789,6 +804,7 @@ JS_FILE(pyproxy_init_js, () => {0,0; /* Magic, see include_js_file.h */
} }
}; };
// clang-format off
/** /**
* A class to allow access to a Python data buffers from Javascript. These are * A class to allow access to a Python data buffers from Javascript. These are
* produced by :any:`PyProxy.getBuffer` and cannot be constructed directly. * produced by :any:`PyProxy.getBuffer` and cannot be constructed directly.
@ -817,8 +833,7 @@ JS_FILE(pyproxy_init_js, () => {0,0; /* Magic, see include_js_file.h */
* } * }
* return idx; * return idx;
* } * }
* console.log("entry is", pybuff.data[multiIndexToIndex(pybuff, [2, 0, * console.log("entry is", pybuff.data[multiIndexToIndex(pybuff, [2, 0, -1])]);
* -1])]);
* *
* .. admonition:: Contiguity * .. admonition:: Contiguity
* :class: warning * :class: warning
@ -856,6 +871,7 @@ JS_FILE(pyproxy_init_js, () => {0,0; /* Magic, see include_js_file.h */
* buffer.data.byteLength * buffer.data.byteLength
* ); * );
*/ */
// clang-format on
Module.PyBuffer = class PyBuffer { Module.PyBuffer = class PyBuffer {
constructor() { constructor() {
// FOR_JSDOC_ONLY is a macro that deletes its argument. // FOR_JSDOC_ONLY is a macro that deletes its argument.
@ -923,6 +939,11 @@ JS_FILE(pyproxy_init_js, () => {0,0; /* Magic, see include_js_file.h */
/** /**
* The actual data. A typed array of an appropriate size backed by a * The actual data. A typed array of an appropriate size backed by a
* segment of the WASM memory. * segment of the WASM memory.
*
* The ``type`` argument of :any:`getBuffer`
* determines which sort of `TypedArray` this is, by default
* :any:`getBuffer` will look at the format string to determine the most
* appropriate option.
* @type {TypedArray} * @type {TypedArray}
*/ */
this.data; this.data;

View File

@ -51,7 +51,7 @@ try:
"""The ``Promise.then`` API, wrapped to manage the lifetimes of the """The ``Promise.then`` API, wrapped to manage the lifetimes of the
handlers. handlers.
Only available if the wrapped Javascript object has a "then" method. Present only if the wrapped Javascript object has a "then" method.
Pyodide will automatically release the references to the handlers Pyodide will automatically release the references to the handlers
when the promise resolves. when the promise resolves.
""" """
@ -60,7 +60,7 @@ try:
"""The ``Promise.catch`` API, wrapped to manage the lifetimes of the """The ``Promise.catch`` API, wrapped to manage the lifetimes of the
handler. handler.
Only available if the wrapped Javascript object has a "then" method. Present only if the wrapped Javascript object has a "then" method.
Pyodide will automatically release the references to the handler Pyodide will automatically release the references to the handler
when the promise resolves. when the promise resolves.
""" """
@ -69,7 +69,7 @@ try:
"""The ``Promise.finally`` API, wrapped to manage the lifetimes of """The ``Promise.finally`` API, wrapped to manage the lifetimes of
the handler. the handler.
Only available if the wrapped Javascript object has a "then" method. Present only if the wrapped Javascript object has a "then" method.
Pyodide will automatically release the references to the handler Pyodide will automatically release the references to the handler
when the promise resolves. Note the trailing underscore in the name; when the promise resolves. Note the trailing underscore in the name;
this is needed because ``finally`` is a reserved keyword in Python. this is needed because ``finally`` is a reserved keyword in Python.

View File

@ -13,11 +13,11 @@ globalThis.pyodide = {};
/** /**
* Load the main Pyodide wasm module and initialize it. When finished stores the * Load the main Pyodide wasm module and initialize it. When finished stores the
* pyodide module as a global object called ``pyodide``. * Pyodide module as a global object called ``pyodide``.
* @async
* @param {string} config.indexURL - The URL from which Pyodide will load * @param {string} config.indexURL - The URL from which Pyodide will load
* packages * packages
* @returns The pyodide module. * @returns The Pyodide module.
* @async
*/ */
globalThis.loadPyodide = async function(config = {}) { globalThis.loadPyodide = async function(config = {}) {
if (globalThis.__pyodideLoading) { if (globalThis.__pyodideLoading) {
@ -273,18 +273,18 @@ globalThis.loadPyodide = async function(config = {}) {
Module.loadedPackages = {}; Module.loadedPackages = {};
/** /**
* Load a package or a list of packages over the network. This makes the files * Load a package or a list of packages over the network. This installs the
* for the package available in the virtual filesystem. The package needs to * package in the virtual filesystem. The package needs to be imported from
* be imported from Python before it can be used. * Python before it can be used.
* @param {String | Array} names Package name or URL. Can be either a single * @param {String | Array} names Either a single package name or URL or a list
* element, or an array. URLs can be absolute or relative. URLs must have * of them. URLs can be absolute or relative. The URLs must have file name
* file name `<package-name>.js` and there must be a file called * ``<package-name>.js`` and there must be a file called
* `<package-name>.data` in the same directory. * ``<package-name>.data`` in the same directory.
* @param {function} messageCallback A callback, called with progress messages * @param {function} messageCallback A callback, called with progress messages
* (optional) * (optional)
* @param {function} errorCallback A callback, called with error/warning * @param {function} errorCallback A callback, called with error/warning
* messages (optional) * messages (optional)
* @returns {Promise} Resolves to ``undefined`` when loading is complete * @async
*/ */
Module.loadPackage = async function(names, messageCallback, errorCallback) { Module.loadPackage = async function(names, messageCallback, errorCallback) {
if (!Array.isArray(names)) { if (!Array.isArray(names)) {
@ -455,7 +455,10 @@ globalThis.loadPyodide = async function(config = {}) {
}; };
/** /**
* An alias to the Python pyodide package. * An alias to the Python :py:mod:`pyodide` package.
*
* You can use this to call functions defined in the Pyodide Python package
* from Javascript.
* *
* @type {PyProxy} * @type {PyProxy}
*/ */
@ -465,9 +468,8 @@ globalThis.loadPyodide = async function(config = {}) {
* *
* An alias to the global Python namespace. * An alias to the global Python namespace.
* *
* An object whose attributes are members of the Python global namespace. * For example, to access a variable called ``foo`` in the Python global
* For example, to access the ``foo`` Python object from Javascript use * scope, use ``pyodide.globals.get("foo")``
* ``pyodide.globals.get("foo")``
* *
* @type {PyProxy} * @type {PyProxy}
*/ */
@ -487,11 +489,11 @@ globalThis.loadPyodide = async function(config = {}) {
* .. admonition:: Avoid Stack Frames * .. admonition:: Avoid Stack Frames
* :class: warning * :class: warning
* *
* If you make a ``PyProxy`` of ``sys.last_value``, you should be * If you make a :any:`PyProxy` of ``sys.last_value``, you should be
* especially careful to :any:`destroy() <PyProxy.destroy>`. You may leak a * especially careful to :any:`destroy() <PyProxy.destroy>` it when you are
* large amount of memory including the local variables of all the stack * done. You may leak a large amount of memory including the local
* frames in the traceback if you don't. The easiest way is to only handle * variables of all the stack frames in the traceback if you don't. The
* the exception in Python. * easiest way is to only handle the exception in Python.
* *
* @class * @class
*/ */
@ -510,7 +512,7 @@ globalThis.loadPyodide = async function(config = {}) {
/** /**
* *
* The pyodide version. * The Pyodide version.
* *
* It can be either the exact release version (e.g. ``0.1.0``), or * It can be either the exact release version (e.g. ``0.1.0``), or
* the latest release version followed by the number of commits since, and * the latest release version followed by the number of commits since, and
@ -531,7 +533,7 @@ globalThis.loadPyodide = async function(config = {}) {
* 1. `runPythonSimple` doesn't return anything (and so won't leak * 1. `runPythonSimple` doesn't return anything (and so won't leak
* PyProxies) * PyProxies)
* 2. `runPythonSimple` doesn't require access to any state on the * 2. `runPythonSimple` doesn't require access to any state on the
* `pyodide_js` module. * Javascript `pyodide` module.
* 3. `runPython` uses `pyodide.eval_code`, whereas `runPythonSimple` uses * 3. `runPython` uses `pyodide.eval_code`, whereas `runPythonSimple` uses
* `PyRun_String` which is the C API for `eval` / `exec`. * `PyRun_String` which is the C API for `eval` / `exec`.
* 4. `runPythonSimple` runs with `globals` a separate dict which is called * 4. `runPythonSimple` runs with `globals` a separate dict which is called
@ -560,8 +562,10 @@ globalThis.loadPyodide = async function(config = {}) {
* *
* @param {string} code Python code to evaluate * @param {string} code Python code to evaluate
* @param {dict} globals An optional Python dictionary to use as the globals. * @param {dict} globals An optional Python dictionary to use as the globals.
* Defaults to ``pyodide.globals``. * Defaults to :any:`pyodide.globals`. Uses the Python API
* @returns The result of the python code converted to Javascript * :any:`pyodide.eval_code` to evaluate the code.
* @returns The result of the Python code translated to Javascript. See the
* documentation for :any:`pyodide.eval_code` for more info.
*/ */
Module.runPython = function(code, globals = Module.globals) { Module.runPython = function(code, globals = Module.globals) {
return Module.pyodide_py.eval_code(code, globals); return Module.pyodide_py.eval_code(code, globals);
@ -569,23 +573,25 @@ globalThis.loadPyodide = async function(config = {}) {
// clang-format off // clang-format off
/** /**
* Inspect a Python code chunk and use :js:func:`pyodide.loadPackage` to load any known * Inspect a Python code chunk and use :js:func:`pyodide.loadPackage` to
* packages that the code chunk imports. Uses * install any known packages that the code chunk imports. Uses the Python API
* :func:`pyodide_py.find_imports <pyodide.find\_imports>` to inspect the code. * :func:`pyodide.find\_imports` to inspect the code.
* *
* For example, given the following code as input * For example, given the following code as input
* *
* .. code-block:: python * .. code-block:: python
* *
* import numpy as np * import numpy as np x = np.array([1, 2, 3])
* x = np.array([1, 2, 3])
* *
* :js:func:`loadPackagesFromImports` will call ``pyodide.loadPackage(['numpy'])``. * :js:func:`loadPackagesFromImports` will call
* See also :js:func:`runPythonAsync`. * ``pyodide.loadPackage(['numpy'])``. See also :js:func:`runPythonAsync`.
* *
* @param {*} code * @param {string} code The code to inspect.
* @param {*} messageCallback * @param {Function} messageCallback The ``messageCallback`` argument of
* @param {*} errorCallback * :any:`pyodide.loadPackage` (optional).
* @param {Function} errorCallback The ``errorCallback`` argument of
* :any:`pyodide.loadPackage` (optional).
* @async
*/ */
Module.loadPackagesFromImports = async function(code, messageCallback, errorCallback) { Module.loadPackagesFromImports = async function(code, messageCallback, errorCallback) {
let imports = Module.pyodide_py.find_imports(code).toJs(); let imports = Module.pyodide_py.find_imports(code).toJs();
@ -610,13 +616,11 @@ globalThis.loadPyodide = async function(config = {}) {
/** /**
* Access a Python object in the global namespace from Javascript. * Access a Python object in the global namespace from Javascript.
* *
* Note: this function is deprecated and will be removed in version 0.18.0. * @deprecated This function will be removed in version 0.18.0. Use
* Use pyodide.globals.get('key') instead. * :any:`pyodide.globals.get('key') <pyodide.globals>` instead.
* *
* @param {string} name Python variable name * @param {string} name Python variable name
* @returns If the Python object is an immutable type (string, number, * @returns The Python object translated to Javascript.
* boolean), it is converted to Javascript and returned. For other types, a
* ``PyProxy`` object is returned.
*/ */
Module.pyimport = name => { Module.pyimport = name => {
console.warn( console.warn(
@ -634,21 +638,35 @@ globalThis.loadPyodide = async function(config = {}) {
* import numpy as np * import numpy as np
* x = np.array([1, 2, 3]) * x = np.array([1, 2, 3])
* *
* pyodide will first call ``pyodide.loadPackage(['numpy'])``, and then run * Pyodide will first call :any:`pyodide.loadPackage(['numpy'])
* the code, returning the result. Since package fetching must happen * <pyodide.loadPackage>`, and then run the code using the Python API
* asynchronously, this function returns a `Promise` which resolves to the * :any:`pyodide.eval_code_async`, returning the result. The code is compiled
* output. For example: * with `PyCF_ALLOW_TOP_LEVEL_AWAIT
* <https://docs.python.org/3/library/ast.html?highlight=pycf_allow_top_level_await#ast.PyCF_ALLOW_TOP_LEVEL_AWAIT>`_.
* *
* .. code-block:: javascript * For example:
* *
* pyodide.runPythonAsync(code, messageCallback) * .. code-block:: pyodide
* .then((output) => handleOutput(output)) *
* let result = await pyodide.runPythonAsync(`
* # numpy will automatically be loaded by loadPackagesFromImports
* import numpy as np
* # we can use top level await
* from js import fetch
* response = await fetch("./packages.json")
* packages = await response.json()
* # If final statement is an expression, its value is returned to
* Javascript len(packages.dependencies.object_keys())
* `);
* console.log(result); // 72
* *
* @param {string} code Python code to evaluate * @param {string} code Python code to evaluate
* @param {Function} messageCallback A callback, called with progress * @param {Function} messageCallback The ``messageCallback`` argument of
* messages. (optional) * :any:`pyodide.loadPackage`.
* @param {Function} errorCallback A callback, called with error/warning * @param {Function} errorCallback The ``errorCallback`` argument of
* messages. (optional) * :any:`pyodide.loadPackage`.
* @returns The result of the Python code translated to Javascript.
* @async
*/ */
Module.runPythonAsync = async function(code, messageCallback, errorCallback) { Module.runPythonAsync = async function(code, messageCallback, errorCallback) {
await Module.loadPackagesFromImports(code, messageCallback, errorCallback); await Module.loadPackagesFromImports(code, messageCallback, errorCallback);
@ -755,12 +773,12 @@ if (globalThis.languagePluginUrl) {
"instead use loadPyodide({ indexURL : <some_url>})"); "instead use loadPyodide({ indexURL : <some_url>})");
/** /**
* A deprecated parameter that specifies the Pyodide indexURL. If present, * A deprecated parameter that specifies the Pyodide ``indexURL``. If present,
* Pyodide will automatically invoke * Pyodide will automatically invoke
* ``initializePyodide({indexURL : languagePluginUrl})`` * ``loadPyodide({indexURL : languagePluginUrl})``
* and will store the resulting promise in * and will store the resulting promise in
* :any:`globalThis.languagePluginLoader`. Instead, use :any:`loadPyodide` * :any:`globalThis.languagePluginLoader`. Use :any:`loadPyodide`
* directly. * directly instead of defining this.
* *
* @type String * @type String
* @deprecated Will be removed in version 0.18.0 * @deprecated Will be removed in version 0.18.0