-
Notifications
You must be signed in to change notification settings - Fork 769
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Introduce a PyFunction? #1156
Comments
I pushed a branch on my fork that implements the first half of what I discsussed above: sebpuetz@fd37b21
|
Interesting idea! I haven't thought too hard this morning, so apologies if any of the below is stupid / obvious...
Would we actually need want two types? Also worth considering is #684 - last time I looked at that I think I concluded we might want to consider making our own function type. (But I can't remember clearly why.) |
I think we'd need two function types if we'd want to be able to take (and construct) regular Python functions. From my understanding they're just (rightfully so) different types, a
Although we could provide preliminary |
Via |
The idea is to construct a PyFunction the same way we currently offer a way to construct PyModules. This is currently achieved with the wrap_pyfunction!(ident)(module), but the return type is underspecified as PyObject. The linked commit above shows how this could look like if we add a PyFunction as a native type. |
Yeah, but I think we can do that by casting PyObject to PyCFunction. |
I think we need to define some words to figure this out: there's the PyCFunction alias in pyo3 that describes the function type that's being called by Python. Then there's PyCFunction which describes the Python object that's used to call the actual C function. I'm interested in exposing the latter as a native type which is currently not part of the API. With the current implementations there is no (Rust) type that we can cast the PyObject to. That's why I linked the commit on my fork which adds such a type and also makes the change to the proc macro and the add_function wrapper argument. |
I'm sorry for the confusion and misunderstanding: I agree with adding |
Once #1143 goes in, I'll also open a PR to get a basic |
I think the Rust API for |
Yep, that was also my plan. I'll probably get around to open a PR later today. I'll also look into the non-extension If that's not straight forward to implement, we might consider restricting to |
#1163, I'll open a new issue to track building an API for the function types... |
Inspired by the discussion in #1149 I thought it might be nice to add a native
PyFunction
in Rust. It seems like functions come in two flavours in CPython:PyCFunction
(defined in https://github.com/python/cpython/blob/master/Objects/methodobject.c already bound inffi::methodobject.rs
, type objectPyCFunction_Type
) andPyFunction
(defined in https://github.com/python/cpython/blob/3.7/Objects/funcobject.c afaic unbound in pyo3) which are distinct types.PyCFunction
seems to relate to built-ins and methods defined in extension modules whilePyFunction
is a regularlydef
'd Python function.I'm not sure how we could bind
PyFunction
in Rust, but e.g. this would allow extracting built-in / extension functions in Rust:and we would be able to change
PyModule::add_function
to takeFn(python: &PyModule) -> PyResult<&PyFunction>
instead of the generic-> PyResult<PyObject>
since we'd have a proper Rust type for functions.I have also been looking for ways to construct such
PyFunction
s in Rust at runtime but didn't get too far:The issue is that we (as far as I can tell) need an
extern "C"
function that we put in theMethodDef
, if we define this wrapper as a local method inside thefn new
, we can't access it since local functions don't capture their context. To call the proper implementation, we'd need to get the correct function identifier into the method body at compile time, which is how we currently do it through proc-macros.A (probably) possible way is to pass the function wrapper instead of building it locally as
ffi::PyCFunctionWithKeywords
which would mean we'd have to offer an API / macro to produce such functions. As of now we're producing these wrappers inside of__pyo3_get_function_X
, so they're hidden from the user.Then there's also the construction that we already offer:
wrap_pyfunction!(function_name)(module)
which returns aPyObject
thats actually a&PyFunction
.The text was updated successfully, but these errors were encountered: