forked from pyodide/pyodide
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
This allows users to bind arbitrary JS objects as python modules. This is used to implement the `js` module. Fixes pyodide#960
- Loading branch information
Hood Chatham
authored
Jan 17, 2021
1 parent
a961851
commit 7374be5
Showing
13 changed files
with
335 additions
and
87 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
(js_api_pyodide_registerJsModule)= | ||
# pyodide.registerJsModule(name, module) | ||
|
||
Registers the Js object ``module`` as a Js module with ``name``. This module can then be imported from Python using the standard Python import system. If another module by the same name has already been imported, this won't have much effect unless you also delete the imported module from ``sys.modules``. This calls the ``pyodide_py`` api ``pyodide_py.register_js_module``. | ||
|
||
|
||
**Parameters** | ||
|
||
| name | type | description | | ||
|-----------|--------|--------------------------------------| | ||
| *name* | String | Name of js module | | ||
| *module* | object | Javascript object backing the module | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
(js_api_pyodide_unregisterJsModule)= | ||
# pyodide.unregisterJsModule(name) | ||
|
||
Unregisters a Js module with given name that has been previously registered with `js_api_pyodide_registerJsModule` or ``pyodide.register_js_module``. If a Js module with that name does not already exist, will throw an error. Note that if the module has already been imported, this won't have much effect unless you also delete the imported module from ``sys.modules``. This calls the ``pyodide_py`` api ``pyodide_py.unregister_js_module``. | ||
|
||
**Parameters** | ||
|
||
| name | type | description | | ||
|---------|--------|--------------------------------| | ||
| *name* | String | Name of js module | | ||
|
This file was deleted.
Oops, something went wrong.
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,96 @@ | ||
from ._core import JsProxy | ||
from importlib.abc import MetaPathFinder, Loader | ||
from importlib.util import spec_from_loader | ||
import sys | ||
|
||
|
||
class JsFinder(MetaPathFinder): | ||
def __init__(self): | ||
self.jsproxies = {} | ||
|
||
def find_spec(self, fullname, path, target=None): | ||
[parent, _, child] = fullname.rpartition(".") | ||
if parent: | ||
parent_module = sys.modules[parent] | ||
if not isinstance(parent_module, JsProxy): | ||
# Not one of us. | ||
return None | ||
try: | ||
jsproxy = getattr(parent_module, child) | ||
except AttributeError: | ||
raise ModuleNotFoundError( | ||
f"No module named {fullname!r}", name=fullname | ||
) from None | ||
if not isinstance(jsproxy, JsProxy): | ||
raise ModuleNotFoundError( | ||
f"No module named {fullname!r}", name=fullname | ||
) | ||
else: | ||
try: | ||
jsproxy = self.jsproxies[fullname] | ||
except KeyError: | ||
return None | ||
loader = JsLoader(jsproxy) | ||
return spec_from_loader(fullname, loader, origin="javascript") | ||
|
||
def register_js_module(self, name, jsproxy): | ||
""" | ||
Registers the Js object ``module`` as a Js module with ``name``. The module | ||
can then be imported from Python using the standard Python import system. | ||
If another module by the same name has already been imported, this won't | ||
have much effect unless you also delete the imported module from | ||
``sys.modules``. This is called by the javascript API | ||
``pyodide.registerJsModule``. | ||
Parameters | ||
---------- | ||
name : str | ||
Name of js module | ||
jsproxy : JsProxy | ||
Javascript object backing the module | ||
""" | ||
if not isinstance(name, str): | ||
raise TypeError( | ||
f"Argument 'name' must be a str, not {type(name).__name__!r}" | ||
) | ||
if not isinstance(jsproxy, JsProxy): | ||
raise TypeError( | ||
f"Argument 'jsproxy' must be a JsProxy, not {type(jsproxy).__name__!r}" | ||
) | ||
self.jsproxies[name] = jsproxy | ||
|
||
def unregister_js_module(self, name): | ||
""" | ||
Unregisters a Js module with given name that has been previously registered | ||
with `js_api_pyodide_registerJsModule` or ``pyodide.register_js_module``. If | ||
a Js module with that name does not already exist, will raise an error. Note | ||
that if the module has already been imported, this won't have much effect | ||
unless you also delete the imported module from ``sys.modules``. This is | ||
called by the javascript API ``pyodide.unregisterJsModule``. | ||
Parameters | ||
---------- | ||
name : str | ||
Name of js module | ||
""" | ||
try: | ||
del self.jsproxies[name] | ||
except KeyError: | ||
raise ValueError( | ||
f"Cannot unregister {name!r}: no javascript module with that name is registered" | ||
) from None | ||
|
||
|
||
class JsLoader(Loader): | ||
def __init__(self, jsproxy): | ||
self.jsproxy = jsproxy | ||
|
||
def create_module(self, spec): | ||
return self.jsproxy | ||
|
||
def exec_module(self, module): | ||
pass | ||
|
||
# used by importlib.util.spec_from_loader | ||
def is_package(self, fullname): | ||
return True |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.