Skip to content

Commit

Permalink
reintroduce Py::call and Py::call_method
Browse files Browse the repository at this point in the history
  • Loading branch information
Icxolu committed Aug 30, 2024
1 parent c77b853 commit f09f992
Show file tree
Hide file tree
Showing 4 changed files with 42 additions and 21 deletions.
2 changes: 1 addition & 1 deletion examples/decorator/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ impl PyCounter {
println!("{} has been called {} time(s).", name, new_count);

// After doing something, we finally forward the call to the wrapped function
let ret = self.wraps.call_bound(py, args, kwargs)?;
let ret = self.wraps.call(py, args, kwargs)?;

// We could do something with the return value of
// the function before returning it
Expand Down
16 changes: 4 additions & 12 deletions guide/src/python-from-rust/function-calls.md
Original file line number Diff line number Diff line change
Expand Up @@ -91,26 +91,18 @@ fn main() -> PyResult<()> {

// call object with PyDict
let kwargs = [(key1, val1)].into_py_dict(py);
fun.call_bound(py, (), Some(&kwargs))?;
fun.call(py, (), Some(&kwargs))?;

// pass arguments as Vec
let kwargs = vec![(key1, val1), (key2, val2)];
fun.call_bound(py, (), Some(&kwargs.into_py_dict(py)))?;
fun.call(py, (), Some(&kwargs.into_py_dict(py)))?;

// pass arguments as HashMap
let mut kwargs = HashMap::<&str, i32>::new();
kwargs.insert(key1, 1);
fun.call_bound(py, (), Some(&kwargs.into_py_dict(py)))?;
fun.call(py, (), Some(&kwargs.into_py_dict(py)))?;

Ok(())
})
}
```

<div class="warning">

During PyO3's [migration from "GIL Refs" to the `Bound<T>` smart pointer](../migration.md#migrating-from-the-gil-refs-api-to-boundt), `Py<T>::call` is temporarily named [`Py<T>::call_bound`]({{#PYO3_DOCS_URL}}/pyo3/struct.Py.html#method.call_bound) (and `call_method` is temporarily `call_method_bound`).

(This temporary naming is only the case for the `Py<T>` smart pointer. The methods on the `&PyAny` GIL Ref such as `call` have not been given replacements, and the methods on the `Bound<PyAny>` smart pointer such as [`Bound<PyAny>::call`]({{#PYO3_DOCS_URL}}/pyo3/types/trait.PyAnyMethods.html#tymethod.call) already use follow the newest API conventions.)

</div>
```
43 changes: 36 additions & 7 deletions src/instance.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1449,18 +1449,30 @@ impl<T> Py<T> {
/// Calls the object.
///
/// This is equivalent to the Python expression `self(*args, **kwargs)`.
pub fn call_bound<'py, N>(
pub fn call<'py, A>(
&self,
py: Python<'py>,
args: N,
args: A,
kwargs: Option<&Bound<'py, PyDict>>,
) -> PyResult<PyObject>
where
N: IntoPy<Py<PyTuple>>,
A: IntoPy<Py<PyTuple>>,
{
self.bind(py).as_any().call(args, kwargs).map(Bound::unbind)
}

/// Deprecated name for [`Py::call`].
#[deprecated(since = "0.23.0", note = "renamed to `Py::call`")]
#[inline]
pub fn call_bound(
&self,
py: Python<'_>,
args: impl IntoPy<Py<PyTuple>>,
kwargs: Option<&Bound<'_, PyDict>>,
) -> PyResult<PyObject> {
self.call(py, args, kwargs)
}

/// Calls the object with only positional arguments.
///
/// This is equivalent to the Python expression `self(*args)`.
Expand All @@ -1484,7 +1496,7 @@ impl<T> Py<T> {
///
/// To avoid repeated temporary allocations of Python strings, the [`intern!`](crate::intern)
/// macro can be used to intern `name`.
pub fn call_method_bound<'py, N, A>(
pub fn call_method<'py, N, A>(
&self,
py: Python<'py>,
name: N,
Expand All @@ -1501,6 +1513,23 @@ impl<T> Py<T> {
.map(Bound::unbind)
}

/// Deprecated name for [`Py::call_method`].
#[deprecated(since = "0.23.0", note = "renamed to `Py::call_method`")]
#[inline]
pub fn call_method_bound<N, A>(
&self,
py: Python<'_>,
name: N,
args: A,
kwargs: Option<&Bound<'_, PyDict>>,
) -> PyResult<PyObject>
where
N: IntoPy<Py<PyString>>,
A: IntoPy<Py<PyTuple>>,
{
self.call_method(py, name.into_py(py), args, kwargs)
}

/// Calls a method on the object with only positional arguments.
///
/// This is equivalent to the Python expression `self.name(*args)`.
Expand Down Expand Up @@ -1904,11 +1933,11 @@ mod tests {

assert_repr(obj.call0(py).unwrap().bind(py), "{}");
assert_repr(obj.call1(py, ()).unwrap().bind(py), "{}");
assert_repr(obj.call_bound(py, (), None).unwrap().bind(py), "{}");
assert_repr(obj.call(py, (), None).unwrap().bind(py), "{}");

assert_repr(obj.call1(py, ((('x', 1),),)).unwrap().bind(py), "{'x': 1}");
assert_repr(
obj.call_bound(py, (), Some(&[('x', 1)].into_py_dict(py)))
obj.call(py, (), Some(&[('x', 1)].into_py_dict(py)))
.unwrap()
.bind(py),
"{'x': 1}",
Expand All @@ -1922,7 +1951,7 @@ mod tests {
let obj: PyObject = PyDict::new(py).into();
assert!(obj.call_method0(py, "asdf").is_err());
assert!(obj
.call_method_bound(py, "nonexistent_method", (1,), None)
.call_method(py, "nonexistent_method", (1,), None)
.is_err());
assert!(obj.call_method0(py, "nonexistent_method").is_err());
assert!(obj.call_method1(py, "nonexistent_method", (1,)).is_err());
Expand Down
2 changes: 1 addition & 1 deletion src/types/any.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1699,7 +1699,7 @@ class NonHeapNonDescriptorInt:
Python::with_gil(|py| {
let list = vec![3, 6, 5, 4, 7].to_object(py);
let dict = vec![("reverse", true)].into_py_dict(py);
list.call_method_bound(py, "sort", (), Some(&dict)).unwrap();
list.call_method(py, "sort", (), Some(&dict)).unwrap();
assert_eq!(list.extract::<Vec<i32>>(py).unwrap(), vec![7, 6, 5, 4, 3]);
});
}
Expand Down

0 comments on commit f09f992

Please sign in to comment.