-
Notifications
You must be signed in to change notification settings - Fork 778
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
Support passing name and doc to new_closure. #2686
Conversation
023b3d4
to
6cef339
Compare
This is now done
On 15 October 2022 4:09:47 pm HKT, Adam Reichold ***@***.***> wrote:
***@***.*** commented on this pull request.
…
> /// py_run!(py, add_one, "assert add_one(42) == 43");
/// });
/// ```
- pub fn new_closure<F, R>(f: F, py: Python<'_>) -> PyResult<&PyCFunction>
+ pub fn new_closure<'a, F, R>(
I think it is also customary to move closure arguments to the end as this improves readability of the call sites.
--
Reply to this email directly or view it on GitHub:
#2686 (comment)
You are receiving this because you authored the thread.
Message ID: ***@***.***>
|
What about this signature? pub fn new_closure<'a, F, R>(
py: Python<'a>,
name: Option<&'static str,
doc: Option<&'static str>,
f: F,
) -> PyResult<&'a PyCFunction> iirc both name and doc can be null (?) and I think I prefer using |
I'm not sure if this PR caused this or not, but something like this use pyo3::prelude::*;
use pyo3::types::*;
fn main() {
Python::with_gil(|_py| loop {
let pool = unsafe { _py.new_pool() };
let py = pool.python();
let add_one = |args: &PyTuple, _kwargs: Option<&PyDict>| -> PyResult<_> {
let i = args.extract::<(i64,)>()?.0;
Ok(i + 1)
};
let closure_py = PyCFunction::new_closure(py, "blah", "blah", add_one).unwrap();
});
} leaks memory at a rate of 400MB/s. I'm not familiar with closures and capsules, but that doesn't sound right. |
We need to leak memory to convert a &'static str to a &'static cstr. If your name/doc is already null terminated I think we don't leak.
This is also the case for normal functions except we can't create them in a loop. I believe this also happens before the PR.
|
It leaks on pyo3 version 0.17 too 🤔 |
Also I don't think doc/name can be null. A PyMethodDef with null doc and name is used to mark the end of a PyMethodDef array.
|
If I read the CPython code correctly, at least The leak is easy to fix in 0.17 since we control the literals and can null-terminate them. For after this patch there are several possibilities:
|
Yes, the general use of leaking in current PyO3 is not ideal and it's definitely a bug that each call to It's been on the back of my mind to tidy up and I've personally wanted to go down the Maybe we should explore a solution like https://crates.io/crates/const-cstr ? |
I think there are two use cases of closures that have different requirements. If the goal is to define a module function but you find it more convenient to define it via a closure for whatever reason, you don't really care about leaks too much because it's going to leave it around forever.
The other use case is a short-lived function to feed into other python functions that require a function. In this case you probably don't care about name and doc.
Given this, it seems reasonable to have a default new_closure that does not take name/doc and does not leak, plus a version that takes name/doc and leaks if the user doesn't null-terminate.
|
Couldn't the signature proposed in #2686 (comment) fulfil this as well without having separate entry points? |
Let me see what I can come up with. 🙂 |
Sure. Two functions would preserve backwards compatibility though and we can make one redirect to the other
|
@mejrs Do you think this is blocked on #2690? Or can they proceed independently? (My understanding of the codebase is that if we use null-terminated static strings in |
I'll need to do some more thinking on that PR, so I'm happy to merge this one first.
That's true, but there is also a boxed PyMethodDef that is getting leaked. I don't mind that for this PR though. I'd still like the api as #2686 (comment) . It can default to a dummy name/doc if None. |
fa10d41
to
e84dd7f
Compare
I've updated the pull request to accept optional name/doc. |
e84dd7f
to
9201a7d
Compare
Is this still blocked on anything? Or are we waiting for the next breaking release? |
I just hadn't gotten around to it. Thanks ❤️ |
Thanks!
|
No description provided.