Add isPyProxy to public API (#1456)

This commit is contained in:
Hood Chatham 2021-04-12 17:49:43 -04:00 committed by GitHub
parent 6fd605e436
commit ed935df143
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 40 additions and 31 deletions

View File

@ -133,7 +133,7 @@ class SeleniumWrapper:
let result = pyodide.runPython({code!r});
if(result && result.toJs){{
let converted_result = result.toJs();
if(pyodide._module.PyProxy.isPyProxy(converted_result)){{
if(pyodide.isPyProxy(converted_result)){{
converted_result = undefined;
}}
result.destroy();
@ -149,7 +149,7 @@ class SeleniumWrapper:
let result = await pyodide.runPythonAsync({code!r});
if(result && result.toJs){{
let converted_result = result.toJs();
if(pyodide._module.PyProxy.isPyProxy(converted_result)){{
if(pyodide.isPyProxy(converted_result)){{
converted_result = undefined;
}}
result.destroy();

View File

@ -23,37 +23,36 @@ substitutions:
- {{ Feature }} A `JsProxy` of a Javascript `Promise` or other awaitable object is now a
Python awaitable.
[#880](https://github.com/pyodide/pyodide/pull/880)
- {{ API }} Instead of automatically converting Python lists and dicts into Javascript, they
are now wrapped in `PyProxy`. Added a new `toJs` API to `PyProxy` to request the
conversion behavior that used to be implicit.
- {{ API }} Instead of automatically converting Python lists and dicts into
Javascript, they are now wrapped in `PyProxy`. Added a new {any}`PyProxy.toJs`
API to request the conversion behavior that used to be implicit.
[#1167](https://github.com/pyodide/pyodide/pull/1167)
- {{ API }} Added `JsProxy.to_py` API to convert a Javascript object to Python.
- {{ API }} Added {any}`JsProxy.to_py` API to convert a Javascript object to Python.
[#1244](https://github.com/pyodide/pyodide/pull/1244)
- {{ Feature }} Flexible jsimports: it now possible to add custom Python
"packages" backed by Javascript code, like the `js` package. The `js` package
is now implemented using this system.
[#1146](https://github.com/pyodide/pyodide/pull/1146)
- {{ Feature }} A `PyProxy` of a Python coroutine or awaitable is now an awaitable Javascript
object. Awaiting a coroutine will schedule it to run on the Python event loop
using `asyncio.ensure_future`.
- {{ Feature }} A `PyProxy` of a Python coroutine or awaitable is now an
awaitable Javascript object. Awaiting a coroutine will schedule it to run on
the Python event loop using `asyncio.ensure_future`.
[#1170](https://github.com/pyodide/pyodide/pull/1170)
- {{ Feature }} A `JsProxy` of a Javascript `Promise` or other awaitable object is now a
Python awaitable.
[#880](https://github.com/pyodide/pyodide/pull/880)
- {{ Enhancement }} Made `PyProxy` of an iterable Python object an iterable Js object: defined the
`[Symbol.iterator]` method, can be used like `for(let x of proxy)`.
Made a `PyProxy` of a Python iterator an iterator: `proxy.next()` is
translated to `next(it)`.
Made a `PyProxy` of a Python generator into a Javascript generator:
`proxy.next(val)` is translated to `gen.send(val)`.
- {{ Enhancement }} Made `PyProxy` of an iterable Python object an iterable Js
object: defined the `[Symbol.iterator]` method, can be used like `for(let x of
proxy)`. Made a `PyProxy` of a Python iterator an iterator: `proxy.next()` is
translated to `next(it)`. Made a `PyProxy` of a Python generator into a
Javascript generator: `proxy.next(val)` is translated to `gen.send(val)`.
[#1180](https://github.com/pyodide/pyodide/pull/1180)
- {{ API }} Updated `PyProxy` so that if the wrapped Python object supports `__getitem__`
access, then the wrapper has `get`, `set`, `has`, and `delete` methods which do
`obj[key]`, `obj[key] = val`, `key in obj` and `del obj[key]` respectively.
[#1175](https://github.com/pyodide/pyodide/pull/1175)
- {{ API }} The `pyodide.pyimport` function is deprecated in favor of using
- {{ API }} The {any}`pyodide.pyimport` function is deprecated in favor of using
`pyodide.globals.get('key')`. [#1367](https://github.com/pyodide/pyodide/pull/1367)
- {{ API }} Added `PyProxy.getBuffer` API to allow direct access to Python
- {{ API }} Added {any}`PyProxy.getBuffer` API to allow direct access to Python
buffers as Javascript TypedArrays.
[1215](https://github.com/pyodide/pyodide/pull/1215)
- {{ API }} The innermost level of a buffer converted to Javascript used to be a
@ -65,6 +64,8 @@ substitutions:
- {{ Enhancement }} Javascript `BigInt`s are converted into Python `int` and
Python `int`s larger than 2^53 are converted into `BigInt`.
[1407](https://github.com/pyodide/pyodide/pull/1407)
- {{ API }} Added {any}`pyodide.isPyProxy` to test if an object is a `PyProxy`.
[1456](https://github.com/pyodide/pyodide/pull/1456)
### Fixed
- {{ Fix }} getattr and dir on JsProxy now report consistent results and include all
@ -89,6 +90,9 @@ substitutions:
[#1126](https://github.com/pyodide/pyodide/pull/1126)
- {{ Fix }} Javascript bound method calls now work correctly with keyword arguments.
[#1138](https://github.com/pyodide/pyodide/pull/1138)
- {{ Fix }} Javascript constructor calls now work correctly with keyword
arguments.
[#1433](https://github.com/pyodide/pyodide/pull/1433)
### pyodide-py package

View File

@ -308,13 +308,13 @@ function destroyToJsResult(x){
if(!x){
return;
}
if(x.destroy){
if(pyodide.isPyProxy(x)){
x.destroy();
return;
}
if(x[Symbol.iterator]){
for(let k of x){
freeToJsResult(k);
destroyToJsResult(k);
}
}
}

View File

@ -515,7 +515,7 @@ EM_JS_NUM(errcode, hiwire_call_delete_method, (JsRef idobj, JsRef idkey), {
});
EM_JS_NUM(bool, hiwire_is_pyproxy, (JsRef idobj), {
return Module.PyProxy.isPyProxy(Module.hiwire.get_value(idobj));
return Module.isPyProxy(Module.hiwire.get_value(idobj));
});
EM_JS_NUM(bool, hiwire_is_function, (JsRef idobj), {

View File

@ -156,8 +156,8 @@ EM_JS_NUM(errcode, js2python_init, (), {
return __js2python_true();
} else if (value === false) {
return __js2python_false();
} else if (Module.PyProxy.isPyProxy(value)) {
return __js2python_pyproxy(Module.PyProxy._getPtr(value));
} else if (Module.isPyProxy(value)) {
return __js2python_pyproxy(Module.PyProxy_getPtr(value));
}
// clang-format on
return 0;

View File

@ -53,12 +53,7 @@ JS_FILE(pyproxy_init_js, () => {0,0; /* Magic, see include_js_file.h */
};
// Static methods
Module.PyProxy = {
_getPtr,
isPyProxy : function(jsobj) {
return !!jsobj && jsobj.$$ !== undefined && jsobj.$$.type === 'PyProxy';
},
};
Module.PyProxy_getPtr = _getPtr;
Module.callPyObject = function(ptrobj, ...jsargs) {
let idargs = Module.hiwire.new_value(jsargs);

View File

@ -387,6 +387,7 @@ globalThis.loadPyodide = async function(config = {}) {
'loadPackage',
'loadPackagesFromImports',
'loadedPackages',
'isPyProxy',
'pyimport',
'runPython',
'runPythonAsync',
@ -441,7 +442,7 @@ globalThis.loadPyodide = async function(config = {}) {
}
// Have to do this case first because typeof(some_pyproxy) ===
// "function".
if (Module.PyProxy.isPyProxy(value)) {
if (Module.isPyProxy(value)) {
value.destroy();
continue;
}
@ -711,6 +712,15 @@ globalThis.loadPyodide = async function(config = {}) {
};
// clang-format on
/**
* Is the argument a :any:`PyProxy`?
* @param jsobj {any} Object to test.
* @returns {bool} Is ``jsobj`` a :any:`PyProxy`?
*/
Module.isPyProxy = function(jsobj) {
return !!jsobj && jsobj.$$ !== undefined && jsobj.$$.type === 'PyProxy';
};
Module.locateFile = (path) => baseURL + path;
let moduleLoaded = new Promise(r => Module.postRun = r);

View File

@ -621,7 +621,7 @@ def test_python2js_with_depth(selenium):
assert(Array.isArray(x), `i: ${i}, j: ${j}`);
x = x[1];
}
assert(pyodide._module.PyProxy.isPyProxy(x), `i: ${i}, j: ${i}`);
assert(pyodide.isPyProxy(x), `i: ${i}, j: ${i}`);
}
"""
)
@ -641,7 +641,7 @@ def test_python2js_with_depth(selenium):
assert(Array.isArray(x), `i: ${i}, j: ${j}`);
x = x[1];
}
assert(pyodide._module.PyProxy.isPyProxy(x), `i: ${i}, j: ${i}`);
assert(pyodide.isPyProxy(x), `i: ${i}, j: ${i}`);
}
"""
)