PyCFunction bound api
This commit is contained in:
parent
5dbb51b9ce
commit
aa3c938b5e
|
@ -6,5 +6,5 @@ pub fn _wrap_pyfunction<'a>(
|
||||||
method_def: &PyMethodDef,
|
method_def: &PyMethodDef,
|
||||||
py_or_module: impl Into<PyFunctionArguments<'a>>,
|
py_or_module: impl Into<PyFunctionArguments<'a>>,
|
||||||
) -> PyResult<&'a PyCFunction> {
|
) -> PyResult<&'a PyCFunction> {
|
||||||
PyCFunction::internal_new(method_def, py_or_module.into())
|
PyCFunction::internal_new(method_def, py_or_module.into()).map(|x| x.into_gil_ref())
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
use crate::derive_utils::PyFunctionArguments;
|
use crate::derive_utils::PyFunctionArguments;
|
||||||
|
use crate::ffi_ptr_ext::FfiPtrExt;
|
||||||
use crate::methods::PyMethodDefDestructor;
|
use crate::methods::PyMethodDefDestructor;
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
|
use crate::py_result_ext::PyResultExt;
|
||||||
use crate::types::capsule::PyCapsuleMethods;
|
use crate::types::capsule::PyCapsuleMethods;
|
||||||
use crate::{
|
use crate::{
|
||||||
ffi,
|
ffi,
|
||||||
|
@ -17,13 +19,30 @@ pub struct PyCFunction(PyAny);
|
||||||
pyobject_native_type_core!(PyCFunction, pyobject_native_static_type_object!(ffi::PyCFunction_Type), #checkfunction=ffi::PyCFunction_Check);
|
pyobject_native_type_core!(PyCFunction, pyobject_native_static_type_object!(ffi::PyCFunction_Type), #checkfunction=ffi::PyCFunction_Check);
|
||||||
|
|
||||||
impl PyCFunction {
|
impl PyCFunction {
|
||||||
/// Create a new built-in function with keywords (*args and/or **kwargs).
|
/// Deprecated form of [`PyCFunction::new_with_keywords_bound`]
|
||||||
|
#[cfg_attr(
|
||||||
|
not(feature = "gil-refs"),
|
||||||
|
deprecated(
|
||||||
|
since = "0.21.0",
|
||||||
|
note = "`PyCFunction::new_with_keywords` will be replaced by `PyCFunction::new_with_keywords_bound` in a future PyO3 version"
|
||||||
|
)
|
||||||
|
)]
|
||||||
pub fn new_with_keywords<'a>(
|
pub fn new_with_keywords<'a>(
|
||||||
fun: ffi::PyCFunctionWithKeywords,
|
fun: ffi::PyCFunctionWithKeywords,
|
||||||
name: &'static str,
|
name: &'static str,
|
||||||
doc: &'static str,
|
doc: &'static str,
|
||||||
py_or_module: PyFunctionArguments<'a>,
|
py_or_module: PyFunctionArguments<'a>,
|
||||||
) -> PyResult<&'a Self> {
|
) -> PyResult<&'a Self> {
|
||||||
|
Self::new_with_keywords_bound(fun, name, doc, py_or_module).map(Bound::into_gil_ref)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Create a new built-in function with keywords (*args and/or **kwargs).
|
||||||
|
pub fn new_with_keywords_bound<'a>(
|
||||||
|
fun: ffi::PyCFunctionWithKeywords,
|
||||||
|
name: &'static str,
|
||||||
|
doc: &'static str,
|
||||||
|
py_or_module: PyFunctionArguments<'a>,
|
||||||
|
) -> PyResult<Bound<'a, Self>> {
|
||||||
Self::internal_new(
|
Self::internal_new(
|
||||||
&PyMethodDef::cfunction_with_keywords(
|
&PyMethodDef::cfunction_with_keywords(
|
||||||
name,
|
name,
|
||||||
|
@ -34,19 +53,57 @@ impl PyCFunction {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Create a new built-in function which takes no arguments.
|
/// Deprecated form of [`PyCFunction::new`]
|
||||||
|
#[cfg_attr(
|
||||||
|
not(feature = "gil-refs"),
|
||||||
|
deprecated(
|
||||||
|
since = "0.21.0",
|
||||||
|
note = "`PyCFunction::new` will be replaced by `PyCFunction::new_bound` in a future PyO3 version"
|
||||||
|
)
|
||||||
|
)]
|
||||||
pub fn new<'a>(
|
pub fn new<'a>(
|
||||||
fun: ffi::PyCFunction,
|
fun: ffi::PyCFunction,
|
||||||
name: &'static str,
|
name: &'static str,
|
||||||
doc: &'static str,
|
doc: &'static str,
|
||||||
py_or_module: PyFunctionArguments<'a>,
|
py_or_module: PyFunctionArguments<'a>,
|
||||||
) -> PyResult<&'a Self> {
|
) -> PyResult<&'a Self> {
|
||||||
|
Self::new_bound(fun, name, doc, py_or_module).map(Bound::into_gil_ref)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Create a new built-in function which takes no arguments.
|
||||||
|
pub fn new_bound<'a>(
|
||||||
|
fun: ffi::PyCFunction,
|
||||||
|
name: &'static str,
|
||||||
|
doc: &'static str,
|
||||||
|
py_or_module: PyFunctionArguments<'a>,
|
||||||
|
) -> PyResult<Bound<'a, Self>> {
|
||||||
Self::internal_new(
|
Self::internal_new(
|
||||||
&PyMethodDef::noargs(name, pymethods::PyCFunction(fun), doc),
|
&PyMethodDef::noargs(name, pymethods::PyCFunction(fun), doc),
|
||||||
py_or_module,
|
py_or_module,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Deprecated form of [`PyCFunction::new_closure`]
|
||||||
|
#[cfg_attr(
|
||||||
|
not(feature = "gil-refs"),
|
||||||
|
deprecated(
|
||||||
|
since = "0.21.0",
|
||||||
|
note = "`PyCFunction::new_closure` will be replaced by `PyCFunction::new_closure_bound` in a future PyO3 version"
|
||||||
|
)
|
||||||
|
)]
|
||||||
|
pub fn new_closure<'a, F, R>(
|
||||||
|
py: Python<'a>,
|
||||||
|
name: Option<&'static str>,
|
||||||
|
doc: Option<&'static str>,
|
||||||
|
closure: F,
|
||||||
|
) -> PyResult<&'a PyCFunction>
|
||||||
|
where
|
||||||
|
F: Fn(&PyTuple, Option<&PyDict>) -> R + Send + 'static,
|
||||||
|
R: crate::callback::IntoPyCallbackOutput<*mut ffi::PyObject>,
|
||||||
|
{
|
||||||
|
Self::new_closure_bound(py, name, doc, closure).map(Bound::into_gil_ref)
|
||||||
|
}
|
||||||
|
|
||||||
/// Create a new function from a closure.
|
/// Create a new function from a closure.
|
||||||
///
|
///
|
||||||
/// # Examples
|
/// # Examples
|
||||||
|
@ -60,16 +117,16 @@ impl PyCFunction {
|
||||||
/// let i = args.extract::<(i64,)>()?.0;
|
/// let i = args.extract::<(i64,)>()?.0;
|
||||||
/// Ok(i+1)
|
/// Ok(i+1)
|
||||||
/// };
|
/// };
|
||||||
/// let add_one = PyCFunction::new_closure(py, None, None, add_one).unwrap();
|
/// let add_one = PyCFunction::new_closure_bound(py, None, None, add_one).unwrap();
|
||||||
/// py_run!(py, add_one, "assert add_one(42) == 43");
|
/// py_run!(py, add_one, "assert add_one(42) == 43");
|
||||||
/// });
|
/// });
|
||||||
/// ```
|
/// ```
|
||||||
pub fn new_closure<'a, F, R>(
|
pub fn new_closure_bound<'a, F, R>(
|
||||||
py: Python<'a>,
|
py: Python<'a>,
|
||||||
name: Option<&'static str>,
|
name: Option<&'static str>,
|
||||||
doc: Option<&'static str>,
|
doc: Option<&'static str>,
|
||||||
closure: F,
|
closure: F,
|
||||||
) -> PyResult<&'a PyCFunction>
|
) -> PyResult<Bound<'a, Self>>
|
||||||
where
|
where
|
||||||
F: Fn(&PyTuple, Option<&PyDict>) -> R + Send + 'static,
|
F: Fn(&PyTuple, Option<&PyDict>) -> R + Send + 'static,
|
||||||
R: crate::callback::IntoPyCallbackOutput<*mut ffi::PyObject>,
|
R: crate::callback::IntoPyCallbackOutput<*mut ffi::PyObject>,
|
||||||
|
@ -95,11 +152,9 @@ impl PyCFunction {
|
||||||
let data = unsafe { capsule.reference::<ClosureDestructor<F>>() };
|
let data = unsafe { capsule.reference::<ClosureDestructor<F>>() };
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
py.from_owned_ptr_or_err::<PyCFunction>(ffi::PyCFunction_NewEx(
|
ffi::PyCFunction_NewEx(data.def.get(), capsule.as_ptr(), std::ptr::null_mut())
|
||||||
data.def.get(),
|
.assume_owned_or_err(py)
|
||||||
capsule.as_ptr(),
|
.downcast_into_unchecked()
|
||||||
std::ptr::null_mut(),
|
|
||||||
))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -107,7 +162,7 @@ impl PyCFunction {
|
||||||
pub fn internal_new<'py>(
|
pub fn internal_new<'py>(
|
||||||
method_def: &PyMethodDef,
|
method_def: &PyMethodDef,
|
||||||
py_or_module: PyFunctionArguments<'py>,
|
py_or_module: PyFunctionArguments<'py>,
|
||||||
) -> PyResult<&'py Self> {
|
) -> PyResult<Bound<'py, Self>> {
|
||||||
let (py, module) = py_or_module.into_py_and_maybe_module();
|
let (py, module) = py_or_module.into_py_and_maybe_module();
|
||||||
let (mod_ptr, module_name): (_, Option<Py<PyString>>) = if let Some(m) = module {
|
let (mod_ptr, module_name): (_, Option<Py<PyString>>) = if let Some(m) = module {
|
||||||
let mod_ptr = m.as_ptr();
|
let mod_ptr = m.as_ptr();
|
||||||
|
@ -126,11 +181,9 @@ impl PyCFunction {
|
||||||
.map_or(std::ptr::null_mut(), Py::as_ptr);
|
.map_or(std::ptr::null_mut(), Py::as_ptr);
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
py.from_owned_ptr_or_err::<PyCFunction>(ffi::PyCFunction_NewEx(
|
ffi::PyCFunction_NewEx(def, mod_ptr, module_name_ptr)
|
||||||
def,
|
.assume_owned_or_err(py)
|
||||||
mod_ptr,
|
.downcast_into_unchecked()
|
||||||
module_name_ptr,
|
|
||||||
))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -323,7 +323,7 @@ fn test_pycfunction_new() {
|
||||||
ffi::PyLong_FromLong(4200)
|
ffi::PyLong_FromLong(4200)
|
||||||
}
|
}
|
||||||
|
|
||||||
let py_fn = PyCFunction::new(
|
let py_fn = PyCFunction::new_bound(
|
||||||
c_fn,
|
c_fn,
|
||||||
"py_fn",
|
"py_fn",
|
||||||
"py_fn for test (this is the docstring)",
|
"py_fn for test (this is the docstring)",
|
||||||
|
@ -380,7 +380,7 @@ fn test_pycfunction_new_with_keywords() {
|
||||||
ffi::PyLong_FromLong(foo * bar)
|
ffi::PyLong_FromLong(foo * bar)
|
||||||
}
|
}
|
||||||
|
|
||||||
let py_fn = PyCFunction::new_with_keywords(
|
let py_fn = PyCFunction::new_with_keywords_bound(
|
||||||
c_fn,
|
c_fn,
|
||||||
"py_fn",
|
"py_fn",
|
||||||
"py_fn for test (this is the docstring)",
|
"py_fn for test (this is the docstring)",
|
||||||
|
@ -422,7 +422,7 @@ fn test_closure() {
|
||||||
})
|
})
|
||||||
};
|
};
|
||||||
let closure_py =
|
let closure_py =
|
||||||
PyCFunction::new_closure(py, Some("test_fn"), Some("test_fn doc"), f).unwrap();
|
PyCFunction::new_closure_bound(py, Some("test_fn"), Some("test_fn doc"), f).unwrap();
|
||||||
|
|
||||||
py_assert!(py, closure_py, "closure_py(42) == [43]");
|
py_assert!(py, closure_py, "closure_py(42) == [43]");
|
||||||
py_assert!(py, closure_py, "closure_py.__name__ == 'test_fn'");
|
py_assert!(py, closure_py, "closure_py.__name__ == 'test_fn'");
|
||||||
|
@ -445,7 +445,7 @@ fn test_closure_counter() {
|
||||||
*counter += 1;
|
*counter += 1;
|
||||||
Ok(*counter)
|
Ok(*counter)
|
||||||
};
|
};
|
||||||
let counter_py = PyCFunction::new_closure(py, None, None, counter_fn).unwrap();
|
let counter_py = PyCFunction::new_closure_bound(py, None, None, counter_fn).unwrap();
|
||||||
|
|
||||||
py_assert!(py, counter_py, "counter_py() == 1");
|
py_assert!(py, counter_py, "counter_py() == 1");
|
||||||
py_assert!(py, counter_py, "counter_py() == 2");
|
py_assert!(py, counter_py, "counter_py() == 2");
|
||||||
|
|
|
@ -10,7 +10,9 @@ fn main() {
|
||||||
println!("This is five: {:?}", ref_.len());
|
println!("This is five: {:?}", ref_.len());
|
||||||
Ok(())
|
Ok(())
|
||||||
};
|
};
|
||||||
PyCFunction::new_closure(py, None, None, closure_fn).unwrap().into()
|
PyCFunction::new_closure_bound(py, None, None, closure_fn)
|
||||||
|
.unwrap()
|
||||||
|
.into()
|
||||||
});
|
});
|
||||||
|
|
||||||
Python::with_gil(|py| {
|
Python::with_gil(|py| {
|
||||||
|
|
|
@ -6,7 +6,8 @@ error[E0597]: `local_data` does not live long enough
|
||||||
7 | let ref_: &[u8] = &local_data;
|
7 | let ref_: &[u8] = &local_data;
|
||||||
| ^^^^^^^^^^^ borrowed value does not live long enough
|
| ^^^^^^^^^^^ borrowed value does not live long enough
|
||||||
...
|
...
|
||||||
13 | PyCFunction::new_closure(py, None, None, closure_fn).unwrap().into()
|
13 | PyCFunction::new_closure_bound(py, None, None, closure_fn)
|
||||||
| ---------------------------------------------------- argument requires that `local_data` is borrowed for `'static`
|
| ---------------------------------------------------------- argument requires that `local_data` is borrowed for `'static`
|
||||||
14 | });
|
...
|
||||||
|
16 | });
|
||||||
| - `local_data` dropped here while still borrowed
|
| - `local_data` dropped here while still borrowed
|
||||||
|
|
Loading…
Reference in New Issue