DOC Refactor API reference documentation (#782)

This commit is contained in:
Roman Yurchak 2020-10-31 21:00:58 +01:00 committed by GitHub
parent a260ea3bbf
commit f1cc304717
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
21 changed files with 357 additions and 243 deletions

4
.gitignore vendored
View File

@ -35,3 +35,7 @@ packages/libxml/libxml*
packages/libxslt/libxslt*
packages/libiconv/libiconv*
packages/zlib/zlib*
docs/python-api/
docs/micropip-api/
docs/_build/

View File

@ -1,216 +1,62 @@
# API Reference
*pyodide version 0.1.0*
## Python API
Backward compatibility of the API is not guaranteed at this point.
## Python API
```{eval-rst}
.. currentmodule:: pyodide
.. autosummary::
:toctree: ./python-api/
### pyodide.open_url(url)
pyodide.as_nested_list
pyodide.eval_code
pyodide.find_imports
pyodide.get_completions
pyodide.open_url
```
Fetches a given *url* and returns a `io.StringIO` to access its contents.
*Parameters*
| name | type | description |
|-------|------|-----------------|
| *url* | str | the URL to open |
*Returns*
A `io.StringIO` object with the URL contents./
### pyodide.eval_code(code, ns)
Runs a string of code. The last part of the string may be an expression, in which case, its value is returned.
This function may be overridden to change how `pyodide.runPython` interprets code, for example to perform
some preprocessing on the Python code first.
*Parameters*
| name | type | description |
|--------|-------|-----------------------|
| *code* | str | the code to evaluate |
| *ns* | dict | evaluation name space |
*Returns*
Either the resulting object or `None`.
### pyodide.as_nested_list(obj)
Converts Javascript nested arrays to Python nested lists. This conversion can not
be performed automatically, because Javascript Arrays and Objects can be combined
in ways that are ambiguous.
*Parameters*
| name | type | description |
|--------|-------|-----------------------|
| *obj* | JS Object | The object to convert |
*Returns*
The object as nested Python lists.
## Javascript API
(api_pyodide_loadpackage)=
### pyodide.loadPackage(names, messageCallback, errorCallback)
Backward compatibility of the API is not guaranteed at this point.
Load a package or a list of packages over the network.
This makes the files for the package available in the virtual filesystem.
The package needs to be imported from Python before it can be used.
*Parameters*
| name | type | description |
|-------------------|-----------------|---------------------------------------|
| *names* | {String, Array} | package name, or URL. Can be either a single element, or an array. |
| *messageCallback* | function | A callback, called with progress messages. (optional) |
| *errorCallback* | function | A callback, called with error/warning messages. (optional) |
*Returns*
Loading is asynchronous, therefore, this returns a `Promise`.
| | |
|-|-|
| **{ref}`js_api_pyodide_globals`** | An alias to the global Python namespace |
| **{ref}`pyodide.loadPackage(names, ...) <js_api_pyodide_loadPackage>`** | Load a package or a list of packages over the network |
| **{ref}`js_api_pyodide_loadedPackages`** | `Object` with loaded packages. |
| **{ref}`js_api_pyodide_pyimport`** | Access a Python object in the global namespace from Javascript |
| **{ref}`js_api_pyodide_repr`** | Gets the Python's string representation of an object. |
| **{ref}`js_api_pyodide_runPython`** | Runs Python code from Javascript. |
| **{ref}`pyodide.runPythonAsync(code, ...) <js_api_pyodide_runPythonAsync>`** | Runs Python code with automatic preloading of imports. |
| **{ref}`js_api_pyodide_version`** | Returns the pyodide version. |
### pyodide.loadedPackages
```{eval-rst}
.. toctree::
:hidden:
`Object` with loaded packages.
Use `Object.keys(pyodide.loadedPackages)` to access the names of the
loaded packages, and `pyodide.loadedPackages[package_name]` to access
install location for a particular `package_name`.
### pyodide.pyimport(name)
Access a Python object from Javascript. The object must be in the global Python namespace.
For example, to access the `foo` Python object from Javascript:
`var foo = pyodide.pyimport('foo')`
*Parameters*
| name | type | description |
|---------|--------|----------------------|
| *names* | String | Python variable name |
*Returns*
| name | type | description |
|-----------|---------|---------------------------------------|
| *object* | *any* | If one of the basic types (string, number,<br>boolean, array, object), the Python<br> object is converted to Javascript and <br>returned. For other types, a Proxy<br> object to the Python object is returned. |
(api_pyodide_globals)=
### pyodide.globals
An object whose attributes are members of the Python global namespace. This is a
more convenient alternative to `pyodide.pyimport`.
For example, to access the `foo` Python object from Javascript:
`pyodide.globals.foo`
### pyodide.repr(obj)
Gets the Python's string representation of an object.
This is equivalent to calling `repr(obj)` in Python.
*Parameters*
| name | type | description |
|---------|--------|---------------------|
| *obj* | *any* | Input object |
*Returns*
| name | type | description |
|------------|---------|-------------------------------------------|
| *str_repr* | String | String representation of the input object |
### pyodide.runPython(code)
Runs a string of code. The last part of the string may be an expression, in which case, its value is returned.
*Parameters*
| name | type | description |
|---------|--------|--------------------------------|
| *code* | String | Python code to evaluate |
*Returns*
| name | type | description |
|------------|---------|---------------------------------|
| *jsresult* | *any* | Result, converted to Javascript |
(api_pyodide_runPythonAsync)=
### pyodide.runPythonAsync(code, messageCallback, errorCallback)
Runs Python code, possibly asynchronously loading any known packages that the code
chunk imports.
For example, given the following code chunk
```python
import numpy as np
x = np.array([1, 2, 3])
js-api/pyodide_globals.md
js-api/pyodide_loadPackage.md
js-api/pyodide_loadedPackages.md
js-api/pyodide_pyimport.md
js-api/pyodide_repr.md
js-api/pyodide_runPython.md
js-api/pyodide_runPythonAsync.md
js-api/pyodide_version.md
```
pyodide will first call `pyodide.loadPackage(['numpy'])`, and then run the code
chunk, returning the result. Since package fetching must happen asynchronously,
this function returns a `Promise` which resolves to the output. For example, to
use:
```javascript
pyodide.runPythonAsync(code, messageCallback)
.then((output) => handleOutput(output))
## Micropip API
```{eval-rst}
.. currentmodule:: micropip
.. autosummary::
:toctree: ./micropip-api/
micropip.install
```
*Parameters*
| name | type | description |
|-------------------|----------|--------------------------------|
| *code* | String | Python code to evaluate |
| *messageCallback* | function | A callback, called with progress messages. (optional) |
| *errorCallback* | function | A callback, called with error/warning messages. (optional) |
*Returns*
| name | type | description |
|------------|---------|------------------------------------------|
| *result* | Promise | Resolves to the result of the code chunk |
### pyodide.version()
Returns the pyodide version.
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 git hash of the current commit (e.g. `0.1.0-1-bd84646`).
*Parameters*
None
*Returns*
| name | type | description |
|-----------|--------|------------------------|
| *version* | String | Pyodide version string |

View File

@ -34,7 +34,8 @@
https://pyodide-cdn2.iodide.io/v0.15.0/full/pyodide.js
It now supports versioning and should provide faster downloads. The latest release
can be accessed via `https://pyodide-cdn2.iodide.io/latest/full/`
- Adds `messageCallback` and `errorCallback` to `pyodide.loadPackage`.
- Adds `messageCallback` and `errorCallback` to
{ref}`pyodide.loadPackage <js_api_pyodide_loadPackage>`.
- Reduces the initial memory footprint (`TOTAL_MEMORY`) from 1 GiB to 5 MiB. More
memory will be allocated as needed.
- When building from source, only a subset of packages can be built by setting

View File

@ -15,8 +15,12 @@
import os
import sys
sys.path.insert(0, os.path.abspath("."))
sys.path.insert(0, os.path.abspath(".."))
for base_path in [".", ".."]:
sys.path.insert(0, os.path.abspath(base_path))
sys.path.insert(1, os.path.abspath(os.path.join(base_path, "src")))
sys.path.insert(
2, os.path.abspath(os.path.join(base_path, "packages", "micropip", "micropip"))
)
# -- Project information -----------------------------------------------------
@ -24,7 +28,8 @@ project = "Pyodide"
copyright = "2019, Mozilla"
author = "Mozilla"
from src import pyodide
import pyodide
import micropip # noqa
# The full version, including alpha/beta/rc tags.
release = version = pyodide.__version__
@ -39,7 +44,15 @@ release = version = pyodide.__version__
# Add any Sphinx extension module names here, as strings. They can be
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
# ones.
extensions = ["sphinx.ext.autodoc", "myst_parser"]
extensions = [
"sphinx.ext.autodoc",
"sphinx.ext.autosummary",
"sphinxcontrib.napoleon",
"myst_parser",
]
autosummary_generate = True
autodoc_default_flags = ["members", "inherited-members"]
# Add any paths that contain templates here, relative to this directory.
templates_path = ["_templates"]

View File

@ -29,7 +29,7 @@ Although still experimental, additional packages may be installed from PyPI
to be used with Pyodide.
.. toctree::
:maxdepth: 1
:maxdepth: 2
:caption: Usage
using_pyodide_from_iodide.md

View File

@ -0,0 +1,13 @@
(js_api_pyodide_globals)=
# pyodide.globals
An alias to the global Python namespace.
An object whose attributes are members of the Python global namespace. This is a
more convenient alternative to {ref}`pyodide.pyimport <js_api_pyodide_pyimport>`.
For example, to access the `foo` Python object from Javascript:
```javascript
pyodide.globals.foo
```

View File

@ -0,0 +1,19 @@
(js_api_pyodide_loadpackage)=
# pyodide.loadPackage(names, messageCallback, errorCallback)
Load a package or a list of packages over the network.
This makes the files for the package available in the virtual filesystem.
The package needs to be imported from Python before it can be used.
*Parameters*
| name | type | description |
|-------------------|-----------------|---------------------------------------|
| *names* | {String, Array} | package name, or URL. Can be either a single element, or an array. |
| *messageCallback* | function | A callback, called with progress messages. (optional) |
| *errorCallback* | function | A callback, called with error/warning messages. (optional) |
*Returns*
Loading is asynchronous, therefore, this returns a `Promise`.

View File

@ -0,0 +1,8 @@
(js_api_pyodide_loadedPackages)=
# pyodide.loadedPackages
`Object` with loaded packages.
Use `Object.keys(pyodide.loadedPackages)` to access the names of the
loaded packages, and `pyodide.loadedPackages[package_name]` to access
install location for a particular `package_name`.

View File

@ -0,0 +1,22 @@
(js_api_pyodide_pyimport)=
# pyodide.pyimport(name)
Access a Python object in the global namespace from Javascript.
For example, to access the `foo` Python object from Javascript:
```javascript
var foo = pyodide.pyimport('foo')
```
*Parameters*
| name | type | description |
|---------|--------|----------------------|
| *names* | String | Python variable name |
*Returns*
| name | type | description |
|-----------|---------|---------------------------------------|
| *object* | *any* | If one of the basic types (string, number,<br>boolean, array, object), the Python<br> object is converted to Javascript and <br>returned. For other types, a Proxy<br> object to the Python object is returned. |

View File

@ -0,0 +1,19 @@
(js_api_pyodide_repr)=
# pyodide.repr(obj)
Gets the Python's string representation of an object.
This is equivalent to calling `repr(obj)` in Python.
*Parameters*
| name | type | description |
|---------|--------|---------------------|
| *obj* | *any* | Input object |
*Returns*
| name | type | description |
|------------|---------|-------------------------------------------|
| *str_repr* | String | String representation of the input object |

View File

@ -0,0 +1,19 @@
(js_api_pyodide_runPython)=
# pyodide.runPython(code)
Runs a string of Python code from Javascript.
The last part of the string may be an expression, in which case, its value is returned.
**Parameters**
| name | type | description |
|---------|--------|--------------------------------|
| *code* | String | Python code to evaluate |
**Returns**
| name | type | description |
|------------|---------|---------------------------------|
| *jsresult* | *any* | Result, converted to Javascript |

View File

@ -0,0 +1,36 @@
(js_api_pyodide_runPythonAsync)=
# pyodide.runPythonAsync(code, messageCallback, errorCallback)
Runs Python code, possibly asynchronously loading any known packages that the code
chunk imports.
For example, given the following code chunk
```python
import numpy as np
x = np.array([1, 2, 3])
```
pyodide will first call `pyodide.loadPackage(['numpy'])`, and then run the code
chunk, returning the result. Since package fetching must happen asynchronously,
this function returns a `Promise` which resolves to the output. For example, to
use:
```javascript
pyodide.runPythonAsync(code, messageCallback)
.then((output) => handleOutput(output))
```
*Parameters*
| name | type | description |
|-------------------|----------|--------------------------------|
| *code* | String | Python code to evaluate |
| *messageCallback* | function | A callback, called with progress messages. (optional) |
| *errorCallback* | function | A callback, called with error/warning messages. (optional) |
*Returns*
| name | type | description |
|------------|---------|------------------------------------------|
| *result* | Promise | Resolves to the result of the code chunk |

View File

@ -0,0 +1,18 @@
(js_api_pyodide_version)=
# pyodide.version()
Returns the pyodide version.
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 git hash of the current commit (e.g. `0.1.0-1-bd84646`).
**Parameters**
None
**Returns**
| name | type | description |
|-----------|--------|------------------------|
| *version* | String | Pyodide version string |

View File

@ -1,15 +1,24 @@
(loading_packages)=
# Loading Python packages
# Loading packages
Only the Python standard library and six are available after importing Pyodide. To use other libraries, youll need to load their package using either,
- `pyodide.loadPackage` for packages built with pyodide.
- `micropip.install` for pure Python packages with wheels available on PyPi or on other URLs.
Only the Python standard library and six are available after importing Pyodide.
To use other libraries, youll need to load their package using either,
- {ref}`pyodide.loadPackage <js_api_pyodide_loadPackage>` for packages built
with pyodide.
- `micropip.install` for pure Python packages with wheels available on PyPi or
on other URLs.
```{note}
Note that `micropip` can also be used to load packages built in pyodide (in which case it relies on `pyodide.loadPackage`).
Note that `micropip` can also be used to load packages built in pyodide (in
which case it relies on {ref}`pyodide.loadPackage
<js_api_pyodide_loadPackage>`).
```
Alternatively you can run Python code without manually pre-loading packages. You can do this with {ref}`pyodide.runPythonAsync <api_pyodide_runPythonAsync>`) function, which will automatically download all packages that the code snippet imports. It only supports packages included in Pyodide (not on PyPi) at present.
Alternatively you can run Python code without manually pre-loading packages.
You can do this with {ref}`pyodide.runPythonAsync
<api_pyodide_runPythonAsync>`) function, which will automatically download all
packages that the code snippet imports. It only supports packages included in
Pyodide (not on PyPi) at present.
## Loading packages with pyodide.loadPackage
@ -65,7 +74,7 @@ stemmer.stemWords('go goes going gone'.split())
```
For use outside of Iodide (just Python), you can use the `then` method on the
`Promise` that `micropip.install` returns to do work once the packages have
`Promise` that {func}`micropip.install` returns to do work once the packages have
finished loading:
```py

View File

@ -21,8 +21,8 @@ libraries to the build. We automate the following steps:
the virtual filesystem.
Lastly, a `packages.json` file is output containing the dependency tree of all
packages, so `pyodide.loadPackage` can load a package's dependencies
automatically.
packages, so {ref}`pyodide.loadPackage <js_api_pyodide_loadPackage>` can
load a package's dependencies automatically.
## mkpkg

View File

@ -1,3 +1,5 @@
# Temporarly commented as a workaround for pypa/pip#9031
# sphinx
sphinx_rtd_theme
myst-parser
sphinxcontrib-napoleon

View File

@ -3,8 +3,10 @@
Python to Javascript conversions occur:
- when returning the final expression from a `pyodide.runPython` call (evaluating a Python cell in Iodide)
- using `pyodide.pyimport`
- when returning the final expression from a
{ref}`pyodide.runPython <js_api_pyodide_runPython>` call
(evaluating a Python cell in Iodide)
- using {ref}`pyodide.pyimport <js_api_pyodide_pyimport>`
- passing arguments to a Javascript function from Python
Javascript to Python conversions occur:
@ -146,8 +148,9 @@ foo.call_method(); // This will raise an exception, since the object has been
## Using Python objects from Javascript
A Python object (in global scope) can be brought over to Javascript using the
`pyodide.pyimport` function. It takes a string giving the name of the variable,
and returns the object, converted to Javascript.
{ref}`pyodide.pyimport <js_api_pyodide_pyimport>` function. It takes a string
giving the name of the variable, and returns the object, converted to
Javascript.
```javascript
var sys = pyodide.pyimport('sys');

View File

@ -44,8 +44,8 @@ np.arange(10)
For most uses, that is all you need to know.
However, if you want to use your own custom package or load a package from
another provider, you'll need to use the `pyodide.loadPackage` function from a
Javascript chunk. For example, to load a special distribution of Numpy from
another provider, you'll need to use the {ref}`pyodide.loadPackage <js_api_pyodide_loadPackage>`
function from a Javascript chunk. For example, to load a special distribution of Numpy from
`custom.com`:
```js

View File

@ -31,9 +31,10 @@ languagePluginLoader.then(() => {
## Running Python code
Python code is run using the `pyodide.runPython` function. It takes as input a
string of Python code. If the code ends in an expression, it returns the result
of the expression, converted to Javascript objects (see {ref}`type_conversions`).
Python code is run using the {ref}`pyodide.runPython <js_api_pyodide_runPython>`
function. It takes as input a string of Python
code. If the code ends in an expression, it returns the result of the
expression, converted to Javascript objects (see {ref}`type_conversions`).
```javascript
pyodide.runPython(`
@ -123,7 +124,7 @@ Create and save a test `index.html` page with the following contents:
## Accessing Python scope from JavaScript
You can also access from JavaScript all functions and variables defined in Python using the {ref}`pyodide.globals <api_pyodide_globals>`) object.
You can also access from JavaScript all functions and variables defined in Python using the {ref}`pyodide.globals <js_api_pyodide_globals>`) object.
For example, if you initialize the variable `x = numpy.ones([3,3])` in Python, you can access it from JavaScript in your browser's developer console as follows: `pyodide.globals.x`. The same goes for functions and imports. See {ref}`type_conversions` for more details.

View File

@ -262,11 +262,25 @@ del _PackageManager
def install(requirements: Union[str, List[str]]):
"""
Install the given package and all of its dependencies.
"""Install the given package and all of its dependencies.
Returns a Promise that resolves when all packages have downloaded and
installed.
This only works for pure Python wheels or for packages built
in pyodide. If a package is not found in the pyodide repository
it will be loaded from PyPi.
Parameters
----------
requirements
a requirements or a list of requirements to install.
Can be composed either of
- package names, as defined in pyodide repository or on PyPi
- URLs pointing to pure Python wheels. The file name of such wheels
end with ``none-any.whl``.
Returns
-------
a Promise that resolves when all packages have downloaded and installed.
"""
def do_install(resolve, reject):

View File

@ -3,28 +3,50 @@ A library of helper utilities for connecting Python to the browser environment.
"""
import ast
import io
from io import StringIO
from textwrap import dedent
from typing import Dict, List, Optional, Any
__version__ = "0.15.0"
def open_url(url):
def open_url(url: str) -> StringIO:
"""
Fetches a given *url* and returns a io.StringIO to access its contents.
Fetches a given URL
Parameters
----------
url
URL to fetch
Returns
-------
a io.StringIO object with the contents of the URL.
"""
from js import XMLHttpRequest
req = XMLHttpRequest.new()
req.open("GET", url, False)
req.send(None)
return io.StringIO(req.response)
return StringIO(req.response)
def eval_code(code, ns):
"""
Runs a string of code, the last part of which may be an expression.
def eval_code(code: str, ns: Dict[str, Any]) -> None:
"""Runs a code string
The last part of the provided code may be an expression.
Parameters
----------
code
the Python code to run.
ns
`locals()` or `globals()` context where to execute code.
Returns
-------
None
"""
# handle mis-indented input from multi-line strings
code = dedent(code)
@ -33,6 +55,7 @@ def eval_code(code, ns):
if len(mod.body) == 0:
return None
expr: Any
if isinstance(mod.body[-1], ast.Expr):
expr = ast.Expression(mod.body[-1].value)
del mod.body[-1]
@ -47,10 +70,25 @@ def eval_code(code, ns):
return None
def find_imports(code):
def find_imports(code: str) -> List[str]:
"""
Finds the imports in a string of code and returns a list of their package
names.
Finds the imports in a string of code
Parameters
----------
code
the Python code to run.
Returns
-------
A list of module names that are imported in the code.
Examples
--------
>>> from pyodide import find_imports
>>> code = "import numpy as np; import scipy.stats"
>>> find_imports(code)
['numpy', 'scipy']
"""
# handle mis-indented input from multi-line strings
code = dedent(code)
@ -60,18 +98,30 @@ def find_imports(code):
for node in ast.walk(mod):
if isinstance(node, ast.Import):
for name in node.names:
name = name.name
imports.add(name.split(".")[0])
node_name = name.name
imports.add(node_name.split(".")[0])
elif isinstance(node, ast.ImportFrom):
name = node.module
imports.add(name.split(".")[0])
module_name = node.module
if module_name is None:
continue
imports.add(module_name.split(".")[0])
return list(imports)
def as_nested_list(obj):
"""
def as_nested_list(obj) -> List:
"""Convert a nested JS array to nested Python list.
Assumes a Javascript object is made of (possibly nested) arrays and
converts them to nested Python lists.
Parameters
----------
obj
a Javscript object made of nested arrays.
Returns
-------
Python list, or a nested Python list
"""
try:
it = iter(obj)
@ -80,9 +130,26 @@ def as_nested_list(obj):
return obj
def get_completions(code, cursor=None, namespaces=None):
def get_completions(
code: str, cursor: Optional[int] = None, namespaces: Optional[List] = None
) -> List[str]:
"""
Get code autocompletion candidates.
Get code autocompletion candidates
Note that this function requires to have the jedi module loaded.
Parameters
----------
code
the Python code to complete.
cursor
optional position in the code at which to autocomplete
namespaces
a list of namespaces
Returns
-------
a list of autocompleted modules
"""
import jedi
import __main__