Use with_gil instead of acquire_gil in examples

This commit is contained in:
kngwyu 2021-03-20 16:44:28 +09:00
parent 3fa10a38d3
commit aedd6352e3
18 changed files with 266 additions and 288 deletions

View file

@ -85,25 +85,25 @@ struct MyClass {
num: i32, num: i32,
debug: bool, debug: bool,
} }
let gil = Python::acquire_gil(); Python::with_gil(|py| {
let py = gil.python(); let obj = PyCell::new(py, MyClass { num: 3, debug: true }).unwrap();
let obj = PyCell::new(py, MyClass { num: 3, debug: true }).unwrap(); {
{ let obj_ref = obj.borrow(); // Get PyRef
let obj_ref = obj.borrow(); // Get PyRef assert_eq!(obj_ref.num, 3);
assert_eq!(obj_ref.num, 3); // You cannot get PyRefMut unless all PyRefs are dropped
// You cannot get PyRefMut unless all PyRefs are dropped assert!(obj.try_borrow_mut().is_err());
assert!(obj.try_borrow_mut().is_err()); }
} {
{ let mut obj_mut = obj.borrow_mut(); // Get PyRefMut
let mut obj_mut = obj.borrow_mut(); // Get PyRefMut obj_mut.num = 5;
obj_mut.num = 5; // You cannot get any other refs until the PyRefMut is dropped
// You cannot get any other refs until the PyRefMut is dropped assert!(obj.try_borrow().is_err());
assert!(obj.try_borrow().is_err()); assert!(obj.try_borrow_mut().is_err());
assert!(obj.try_borrow_mut().is_err()); }
}
// You can convert `&PyCell` to a Python object // You can convert `&PyCell` to a Python object
pyo3::py_run!(py, obj, "assert obj.num == 5") pyo3::py_run!(py, obj, "assert obj.num == 5");
});
``` ```
`&PyCell<T>` is bounded by the same lifetime as a [`GILGuard`]. `&PyCell<T>` is bounded by the same lifetime as a [`GILGuard`].
@ -118,15 +118,14 @@ struct MyClass {
num: i32, num: i32,
} }
fn return_myclass() -> Py<MyClass> { fn return_myclass() -> Py<MyClass> {
let gil = Python::acquire_gil(); Python::with_gil(|py| Py::new(py, MyClass { num: 1 }).unwrap())
let py = gil.python();
Py::new(py, MyClass { num: 1 }).unwrap()
} }
let gil = Python::acquire_gil();
let obj = return_myclass(); let obj = return_myclass();
let cell = obj.as_ref(gil.python()); // Py<MyClass>::as_ref returns &PyCell<MyClass> Python::with_gil(|py|{
let obj_ref = cell.borrow(); // Get PyRef<T> let cell = obj.as_ref(py); // Py<MyClass>::as_ref returns &PyCell<MyClass>
assert_eq!(obj_ref.num, 1); let obj_ref = cell.borrow(); // Get PyRef<T>
assert_eq!(obj_ref.num, 1);
});
``` ```
## Customizing the class ## Customizing the class
@ -261,10 +260,10 @@ impl SubSubClass {
SubClass::method2(super_).map(|x| x * v) SubClass::method2(super_).map(|x| x * v)
} }
} }
# let gil = Python::acquire_gil(); # Python::with_gil(|py| {
# let py = gil.python(); # let subsub = pyo3::PyCell::new(py, SubSubClass::new()).unwrap();
# let subsub = pyo3::PyCell::new(py, SubSubClass::new()).unwrap(); # pyo3::py_run!(py, subsub, "assert subsub.method3() == 3000")
# pyo3::py_run!(py, subsub, "assert subsub.method3() == 3000") # });
``` ```
You can also inherit native types such as `PyDict`, if they implement You can also inherit native types such as `PyDict`, if they implement
@ -274,8 +273,7 @@ However, because of some technical problems, we don't currently provide safe upc
that inherit native types. Even in such cases, you can unsafely get a base class by raw pointer conversion. that inherit native types. Even in such cases, you can unsafely get a base class by raw pointer conversion.
```rust ```rust
# #[cfg(Py_LIMITED_API)] fn main() {} # #[cfg(not(Py_LIMITED_API))] {
# #[cfg(not(Py_LIMITED_API))] fn main() {
# use pyo3::prelude::*; # use pyo3::prelude::*;
use pyo3::types::PyDict; use pyo3::types::PyDict;
use pyo3::{AsPyPointer, PyNativeType}; use pyo3::{AsPyPointer, PyNativeType};
@ -300,10 +298,10 @@ impl DictWithCounter {
dict.set_item(key, value) dict.set_item(key, value)
} }
} }
# let gil = Python::acquire_gil(); # Python::with_gil(|py| {
# let py = gil.python(); # let cnt = pyo3::PyCell::new(py, DictWithCounter::new()).unwrap();
# let cnt = pyo3::PyCell::new(py, DictWithCounter::new()).unwrap(); # pyo3::py_run!(py, cnt, "cnt.set('abc', 10); assert cnt['abc'] == 10")
# pyo3::py_run!(py, cnt, "cnt.set('abc', 10); assert cnt['abc'] == 10") # });
# } # }
``` ```
@ -563,10 +561,10 @@ impl MyClass {
} }
} }
let gil = Python::acquire_gil(); Python::with_gil(|py| {
let py = gil.python(); let my_class = py.get_type::<MyClass>();
let my_class = py.get_type::<MyClass>(); pyo3::py_run!(py, my_class, "assert my_class.my_attribute == 'hello'")
pyo3::py_run!(py, my_class, "assert my_class.my_attribute == 'hello'") });
``` ```
Note that unlike class variables defined in Python code, class attributes defined in Rust cannot Note that unlike class variables defined in Python code, class attributes defined in Rust cannot
@ -712,8 +710,7 @@ This simple technique works for the case when there is zero or one implementatio
The `#[pyclass]` macro expands to roughly the code seen below. The `PyClassImplCollector` is the type used internally by PyO3 for dtolnay specialization: The `#[pyclass]` macro expands to roughly the code seen below. The `PyClassImplCollector` is the type used internally by PyO3 for dtolnay specialization:
```rust ```rust
# #[cfg(not(feature = "multiple-pymethods"))] # #[cfg(not(feature = "multiple-pymethods"))] {
# {
# use pyo3::prelude::*; # use pyo3::prelude::*;
// Note: the implementation differs slightly with the `multiple-pymethods` feature enabled. // Note: the implementation differs slightly with the `multiple-pymethods` feature enabled.
@ -808,10 +805,10 @@ impl pyo3::class::impl_::PyClassImpl for MyClass {
collector.buffer_procs() collector.buffer_procs()
} }
} }
# let gil = Python::acquire_gil(); # Python::with_gil(|py| {
# let py = gil.python(); # let cls = py.get_type::<MyClass>();
# let cls = py.get_type::<MyClass>(); # pyo3::py_run!(py, cls, "assert cls.__name__ == 'MyClass'")
# pyo3::py_run!(py, cls, "assert cls.__name__ == 'MyClass'") # });
# } # }
``` ```

View file

@ -275,17 +275,12 @@ impl PyIterProtocol for Container {
} }
} }
# let gil = Python::acquire_gil(); # Python::with_gil(|py| {
# let py = gil.python(); # let container = Container { iter: vec![1, 2, 3, 4] };
# let inst = pyo3::PyCell::new( # let inst = pyo3::PyCell::new(py, container).unwrap();
# py, # pyo3::py_run!(py, inst, "assert list(inst) == [1, 2, 3, 4]");
# Container { # pyo3::py_run!(py, inst, "assert list(iter(iter(inst))) == [1, 2, 3, 4]");
# iter: vec![1, 2, 3, 4], # });
# },
# )
# .unwrap();
# pyo3::py_run!(py, inst, "assert list(inst) == [1, 2, 3, 4]");
# pyo3::py_run!(py, inst, "assert list(iter(iter(inst))) == [1, 2, 3, 4]");
``` ```
For more details on Python's iteration protocols, check out [the "Iterator Types" section of the library For more details on Python's iteration protocols, check out [the "Iterator Types" section of the library

View file

@ -23,14 +23,11 @@ use pyo3::exceptions::PyException;
create_exception!(mymodule, CustomError, PyException); create_exception!(mymodule, CustomError, PyException);
fn main() { Python::with_gil(|py| {
let gil = Python::acquire_gil();
let py = gil.python();
let ctx = [("CustomError", py.get_type::<CustomError>())].into_py_dict(py); let ctx = [("CustomError", py.get_type::<CustomError>())].into_py_dict(py);
pyo3::py_run!(py, *ctx, "assert str(CustomError) == \"<class 'mymodule.CustomError'>\"");
py.run("assert str(CustomError) == \"<class 'mymodule.CustomError'>\"", None, Some(&ctx)).unwrap(); pyo3::py_run!(py, *ctx, "assert CustomError('oops').args == ('oops',)");
py.run("assert CustomError('oops').args == ('oops',)", None, Some(&ctx)).unwrap(); });
}
``` ```
When using PyO3 to create an extension module, you can add the new exception to When using PyO3 to create an extension module, you can add the new exception to
@ -58,13 +55,11 @@ To raise an exception, first you need to obtain an exception type and construct
use pyo3::{Python, PyErr}; use pyo3::{Python, PyErr};
use pyo3::exceptions::PyTypeError; use pyo3::exceptions::PyTypeError;
fn main() { Python::with_gil(|py| {
let gil = Python::acquire_gil();
let py = gil.python();
PyTypeError::new_err("Error").restore(py); PyTypeError::new_err("Error").restore(py);
assert!(PyErr::occurred(py)); assert!(PyErr::occurred(py));
drop(PyErr::fetch(py)); drop(PyErr::fetch(py));
} });
``` ```
From `pyfunction`s and `pyclass` methods, returning an `Err(PyErr)` is enough; From `pyfunction`s and `pyclass` methods, returning an `Err(PyErr)` is enough;
@ -103,14 +98,12 @@ In PyO3 every native type has access to the [`PyAny::is_instance`] method which
use pyo3::Python; use pyo3::Python;
use pyo3::types::{PyBool, PyList}; use pyo3::types::{PyBool, PyList};
fn main() { Python::with_gil(|py| {
let gil = Python::acquire_gil();
let py = gil.python();
assert!(PyBool::new(py, true).is_instance::<PyBool>().unwrap()); assert!(PyBool::new(py, true).is_instance::<PyBool>().unwrap());
let list = PyList::new(py, &[1, 2, 3, 4]); let list = PyList::new(py, &[1, 2, 3, 4]);
assert!(!list.is_instance::<PyBool>().unwrap()); assert!(!list.is_instance::<PyBool>().unwrap());
assert!(list.is_instance::<PyList>().unwrap()); assert!(list.is_instance::<PyList>().unwrap());
} });
``` ```
[`PyAny::is_instance`] calls the underlying [`PyType::is_instance`](https://docs.rs/pyo3/latest/pyo3/types/struct.PyType.html#method.is_instance) [`PyAny::is_instance`] calls the underlying [`PyType::is_instance`](https://docs.rs/pyo3/latest/pyo3/types/struct.PyType.html#method.is_instance)
method to do the actual work. method to do the actual work.
@ -120,10 +113,10 @@ To check the type of an exception, you can similarly do:
```rust ```rust
# use pyo3::exceptions::PyTypeError; # use pyo3::exceptions::PyTypeError;
# use pyo3::prelude::*; # use pyo3::prelude::*;
# let gil = Python::acquire_gil(); # Python::with_gil(|py| {
# let py = gil.python();
# let err = PyTypeError::new_err(()); # let err = PyTypeError::new_err(());
err.is_instance::<PyTypeError>(py); err.is_instance::<PyTypeError>(py);
# });
``` ```
## Handling Rust errors ## Handling Rust errors

View file

@ -266,22 +266,16 @@ To migrate, just pass a `py` argument to any calls to these methods.
Before: Before:
```rust,compile_fail ```rust,compile_fail
use pyo3::prelude::*; # pyo3::Python::with_gil(|py| {
let gil = Python::acquire_gil();
let py = gil.python();
py.None().get_refcnt(); py.None().get_refcnt();
# })
``` ```
After: After:
```rust ```rust
use pyo3::prelude::*; # pyo3::Python::with_gil(|py| {
let gil = Python::acquire_gil();
let py = gil.python();
py.None().get_refcnt(py); py.None().get_refcnt(py);
# })
``` ```
## from 0.9.* to 0.10 ## from 0.9.* to 0.10
@ -296,18 +290,20 @@ Before:
```rust,compile_fail ```rust,compile_fail
use pyo3::ObjectProtocol; use pyo3::ObjectProtocol;
let gil = pyo3::Python::acquire_gil(); # pyo3::Python::with_gil(|py| {
let obj = gil.python().eval("lambda: 'Hi :)'", None, None).unwrap(); let obj = py.eval("lambda: 'Hi :)'", None, None).unwrap();
let hi: &pyo3::types::PyString = obj.call0().unwrap().downcast().unwrap(); let hi: &pyo3::types::PyString = obj.call0().unwrap().downcast().unwrap();
assert_eq!(hi.len().unwrap(), 5); assert_eq!(hi.len().unwrap(), 5);
# })
``` ```
After: After:
```rust ```rust
let gil = pyo3::Python::acquire_gil(); # pyo3::Python::with_gil(|py| {
let obj = gil.python().eval("lambda: 'Hi :)'", None, None).unwrap(); let obj = py.eval("lambda: 'Hi :)'", None, None).unwrap();
let hi: &pyo3::types::PyString = obj.call0().unwrap().downcast().unwrap(); let hi: &pyo3::types::PyString = obj.call0().unwrap().downcast().unwrap();
assert_eq!(hi.len().unwrap(), 5); assert_eq!(hi.len().unwrap(), 5);
# })
``` ```
### No `#![feature(specialization)]` in user code ### No `#![feature(specialization)]` in user code
@ -380,16 +376,16 @@ impl Names {
self.names.append(&mut other.names) self.names.append(&mut other.names)
} }
} }
# let gil = Python::acquire_gil(); # Python::with_gil(|py| {
# let py = gil.python(); # let names = PyCell::new(py, Names::new()).unwrap();
# let names = PyCell::new(py, Names::new()).unwrap(); # pyo3::py_run!(py, names, r"
# pyo3::py_run!(py, names, r" # try:
# try: # names.merge(names)
# names.merge(names) # assert False, 'Unreachable'
# assert False, 'Unreachable' # except RuntimeError as e:
# except RuntimeError as e: # assert str(e) == 'Already borrowed'
# assert str(e) == 'Already borrowed' # ");
# "); # })
``` ```
`Names` has a `merge` method, which takes `&mut self` and another argument of type `&mut Self`. `Names` has a `merge` method, which takes `&mut self` and another argument of type `&mut Self`.
Given this `#[pyclass]`, calling `names.merge(names)` in Python raises Given this `#[pyclass]`, calling `names.merge(names)` in Python raises
@ -410,9 +406,9 @@ Before:
# use pyo3::prelude::*; # use pyo3::prelude::*;
# #[pyclass] # #[pyclass]
# struct MyClass {} # struct MyClass {}
let gil = Python::acquire_gil(); # Python::with_gil(|py| {
let py = gil.python();
let obj_ref = PyRef::new(py, MyClass {}).unwrap(); let obj_ref = PyRef::new(py, MyClass {}).unwrap();
# })
``` ```
After: After:
@ -420,10 +416,10 @@ After:
# use pyo3::prelude::*; # use pyo3::prelude::*;
# #[pyclass] # #[pyclass]
# struct MyClass {} # struct MyClass {}
let gil = Python::acquire_gil(); # Python::with_gil(|py| {
let py = gil.python();
let obj = PyCell::new(py, MyClass {}).unwrap(); let obj = PyCell::new(py, MyClass {}).unwrap();
let obj_ref = obj.borrow(); let obj_ref = obj.borrow();
# })
``` ```
#### Object extraction #### Object extraction
@ -445,8 +441,7 @@ After:
# use pyo3::types::IntoPyDict; # use pyo3::types::IntoPyDict;
# #[pyclass] #[derive(Clone)] struct MyClass {} # #[pyclass] #[derive(Clone)] struct MyClass {}
# #[pymethods] impl MyClass { #[new]fn new() -> Self { MyClass {} }} # #[pymethods] impl MyClass { #[new]fn new() -> Self { MyClass {} }}
# let gil = Python::acquire_gil(); # Python::with_gil(|py| {
# let py = gil.python();
# let typeobj = py.get_type::<MyClass>(); # let typeobj = py.get_type::<MyClass>();
# let d = [("c", typeobj)].into_py_dict(py); # let d = [("c", typeobj)].into_py_dict(py);
# let create_obj = || py.eval("c()", None, Some(d)).unwrap(); # let create_obj = || py.eval("c()", None, Some(d)).unwrap();
@ -458,6 +453,7 @@ let obj_cloned: MyClass = obj.extract().unwrap(); // extracted by cloning the ob
// we need to drop obj_ref before we can extract a PyRefMut due to Rust's rules of references // we need to drop obj_ref before we can extract a PyRefMut due to Rust's rules of references
} }
let obj_ref_mut: PyRefMut<MyClass> = obj.extract().unwrap(); let obj_ref_mut: PyRefMut<MyClass> = obj.extract().unwrap();
# })
``` ```

View file

@ -38,21 +38,20 @@ fn main() {
let arg2 = "arg2"; let arg2 = "arg2";
let arg3 = "arg3"; let arg3 = "arg3";
let gil = Python::acquire_gil(); Python::with_gil(|py| {
let py = gil.python(); let obj = SomeObject::new(py);
let obj = SomeObject::new(py); // call object without empty arguments
obj.call0(py);
// call object without empty arguments // call object with PyTuple
obj.call0(py); let args = PyTuple::new(py, &[arg1, arg2, arg3]);
obj.call1(py, args);
// call object with PyTuple // pass arguments as rust tuple
let args = PyTuple::new(py, &[arg1, arg2, arg3]); let args = (arg1, arg2, arg3);
obj.call1(py, args); obj.call1(py, args);
});
// pass arguments as rust tuple
let args = (arg1, arg2, arg3);
obj.call1(py, args);
} }
``` ```
@ -79,23 +78,22 @@ fn main() {
let key2 = "key2"; let key2 = "key2";
let val2 = 2; let val2 = 2;
let gil = Python::acquire_gil(); Python::with_gil(|py| {
let py = gil.python(); let obj = SomeObject::new(py);
let obj = SomeObject::new(py); // call object with PyDict
let kwargs = [(key1, val1)].into_py_dict(py);
obj.call(py, (), Some(kwargs));
// call object with PyDict // pass arguments as Vec
let kwargs = [(key1, val1)].into_py_dict(py); let kwargs = vec![(key1, val1), (key2, val2)];
obj.call(py, (), Some(kwargs)); obj.call(py, (), Some(kwargs.into_py_dict(py)));
// pass arguments as Vec // pass arguments as HashMap
let kwargs = vec![(key1, val1), (key2, val2)]; let mut kwargs = HashMap::<&str, i32>::new();
obj.call(py, (), Some(kwargs.into_py_dict(py))); kwargs.insert(key1, 1);
obj.call(py, (), Some(kwargs.into_py_dict(py)));
// pass arguments as HashMap });
let mut kwargs = HashMap::<&str, i32>::new();
kwargs.insert(key1, 1);
obj.call(py, (), Some(kwargs.into_py_dict(py)));
} }
``` ```

View file

@ -170,8 +170,7 @@ For a `Py<PyList>`, the conversions are as below:
```rust ```rust
# use pyo3::prelude::*; # use pyo3::prelude::*;
# use pyo3::types::PyList; # use pyo3::types::PyList;
# let gil = Python::acquire_gil(); # Python::with_gil(|py| {
# let py = gil.python();
let list: Py<PyList> = PyList::empty(py).into(); let list: Py<PyList> = PyList::empty(py).into();
// To &PyList with Py::as_ref() (borrows from the Py) // To &PyList with Py::as_ref() (borrows from the Py)
@ -184,14 +183,14 @@ let _: &PyList = list.into_ref(py);
# let list = list_clone; # let list = list_clone;
// To Py<PyAny> (aka PyObject) with .into() // To Py<PyAny> (aka PyObject) with .into()
let _: Py<PyAny> = list.into(); let _: Py<PyAny> = list.into();
# })
``` ```
For a `#[pyclass] struct MyClass`, the conversions for `Py<MyClass>` are below: For a `#[pyclass] struct MyClass`, the conversions for `Py<MyClass>` are below:
```rust ```rust
# use pyo3::prelude::*; # use pyo3::prelude::*;
# let gil = Python::acquire_gil(); # Python::with_gil(|py| {
# let py = gil.python();
# #[pyclass] struct MyClass { } # #[pyclass] struct MyClass { }
# Python::with_gil(|py| -> PyResult<()> { # Python::with_gil(|py| -> PyResult<()> {
let my_class: Py<MyClass> = Py::new(py, MyClass { })?; let my_class: Py<MyClass> = Py::new(py, MyClass { })?;
@ -215,6 +214,7 @@ let _: PyRef<MyClass> = my_class.try_borrow(py)?;
let _: PyRefMut<MyClass> = my_class.try_borrow_mut(py)?; let _: PyRefMut<MyClass> = my_class.try_borrow_mut(py)?;
# Ok(()) # Ok(())
# }).unwrap(); # }).unwrap();
# });
``` ```
### `PyCell<SomeType>` ### `PyCell<SomeType>`

View file

@ -38,11 +38,10 @@ use crate::{ffi, IntoPy, IntoPyPointer, PyClass, PyObject, Python};
/// } /// }
/// } /// }
/// ///
/// # let gil = Python::acquire_gil(); /// # Python::with_gil(|py| {
/// # let py = gil.python(); /// # let inst = Py::new(py, Iter { count: 0 }).unwrap();
/// # let inst = Py::new(py, Iter { count: 0 }).unwrap(); /// # pyo3::py_run!(py, inst, "assert next(inst) == 1");
/// # pyo3::py_run!(py, inst, "assert next(inst) == 1"); /// # }); // test of StopIteration is done in examples/rustapi_module/pyclass_iter.rs
/// # // test of StopIteration is done in examples/rustapi_module/pyclass_iter.rs
/// ``` /// ```
#[allow(unused_variables)] #[allow(unused_variables)]
pub trait PyIterProtocol<'p>: PyClass { pub trait PyIterProtocol<'p>: PyClass {

View file

@ -18,10 +18,11 @@ use std::ptr::NonNull;
/// ///
/// ``` /// ```
/// use pyo3::{AsPyPointer, prelude::*}; /// use pyo3::{AsPyPointer, prelude::*};
/// let gil = Python::acquire_gil(); /// Python::with_gil(|py| {
/// let dict = pyo3::types::PyDict::new(gil.python()); /// let dict = pyo3::types::PyDict::new(py);
/// // All native object wrappers implement AsPyPointer!!! /// // All native object wrappers implement AsPyPointer!!!
/// assert_ne!(dict.as_ptr(), std::ptr::null_mut()); /// assert_ne!(dict.as_ptr(), std::ptr::null_mut());
/// });
/// ``` /// ```
pub trait AsPyPointer { pub trait AsPyPointer {
/// Retrieves the underlying FFI pointer (as a borrowed pointer). /// Retrieves the underlying FFI pointer (as a borrowed pointer).

View file

@ -60,16 +60,10 @@ macro_rules! impl_exception_boilerplate {
/// import_exception!(socket, gaierror); /// import_exception!(socket, gaierror);
/// ///
/// fn main() { /// fn main() {
/// let gil = Python::acquire_gil(); /// Python::with_gil(|py| {
/// let py = gil.python(); /// let ctx = [("gaierror", py.get_type::<gaierror>())].into_py_dict(py);
/// /// pyo3::py_run!(py, *ctx, "import socket; assert gaierror is socket.gaierror");
/// let ctx = [("gaierror", py.get_type::<gaierror>())].into_py_dict(py); /// });
/// py.run(
/// "import socket; assert gaierror is socket.gaierror",
/// None,
/// Some(ctx),
/// )
/// .unwrap();
/// } /// }
/// ///
/// ``` /// ```
@ -137,22 +131,17 @@ macro_rules! import_exception {
/// create_exception!(mymodule, CustomError, PyException); /// create_exception!(mymodule, CustomError, PyException);
/// ///
/// fn main() { /// fn main() {
/// let gil = Python::acquire_gil(); /// Python::with_gil(|py| {
/// let py = gil.python(); /// let error_type = py.get_type::<CustomError>();
/// let error_type = py.get_type::<CustomError>(); /// let ctx = [("CustomError", error_type)].into_py_dict(py);
/// let ctx = [("CustomError", error_type)].into_py_dict(py); /// let type_description: String = py
/// let type_description: String = py /// .eval("str(CustomError)", None, Some(&ctx))
/// .eval("str(CustomError)", None, Some(&ctx)) /// .unwrap()
/// .unwrap() /// .extract()
/// .extract() /// .unwrap();
/// .unwrap(); /// assert_eq!(type_description, "<class 'mymodule.CustomError'>");
/// assert_eq!(type_description, "<class 'mymodule.CustomError'>"); /// pyo3::py_run!(py, *ctx, "assert CustomError('oops').args == ('oops',)");
/// py.run( /// });
/// "assert CustomError('oops').args == ('oops',)",
/// None,
/// Some(ctx),
/// )
/// .unwrap();
/// } /// }
/// ``` /// ```
#[macro_export] #[macro_export]

View file

@ -178,8 +178,11 @@ where
result result
} }
/// RAII type that represents the Global Interpreter Lock acquisition. To get hold of a value of /// RAII type that represents the Global Interpreter Lock acquisition.
/// this type, see [`Python::acquire_gil`](struct.Python.html#method.acquire_gil). ///
/// Users are strongly encouraged to [`Python::with_gil`](struct.Python.html#method.with_gil)
/// instead of directly constructing this type.
/// See [`Python::acquire_gil`](struct.Python.html#method.acquire_gil) for more.
/// ///
/// # Examples /// # Examples
/// ``` /// ```

View file

@ -286,6 +286,10 @@ macro_rules! wrap_pymodule {
/// A convenient macro to execute a Python code snippet, with some local variables set. /// A convenient macro to execute a Python code snippet, with some local variables set.
/// ///
/// # Panics
/// This macro internally calls [`Python::run`](struct.Python.html#method.run) and panics
/// if it returns `Err`, after printing the error to stdout.
///
/// # Examples /// # Examples
/// ``` /// ```
/// use pyo3::{prelude::*, py_run, types::PyList}; /// use pyo3::{prelude::*, py_run, types::PyList};
@ -297,7 +301,6 @@ macro_rules! wrap_pymodule {
/// ///
/// You can use this macro to test pyfunctions or pyclasses quickly. /// You can use this macro to test pyfunctions or pyclasses quickly.
/// ///
/// # Examples
/// ``` /// ```
/// use pyo3::{prelude::*, py_run, PyCell}; /// use pyo3::{prelude::*, py_run, PyCell};
/// #[pyclass] /// #[pyclass]

5
src/marshal.rs Normal file → Executable file
View file

@ -21,15 +21,14 @@ pub const VERSION: i32 = 4;
/// # Examples /// # Examples
/// ``` /// ```
/// # use pyo3::{marshal, types::PyDict}; /// # use pyo3::{marshal, types::PyDict};
/// # let gil = pyo3::Python::acquire_gil(); /// # pyo3::Python::with_gil(|py| {
/// # let py = gil.python();
/// #
/// let dict = PyDict::new(py); /// let dict = PyDict::new(py);
/// dict.set_item("aap", "noot").unwrap(); /// dict.set_item("aap", "noot").unwrap();
/// dict.set_item("mies", "wim").unwrap(); /// dict.set_item("mies", "wim").unwrap();
/// dict.set_item("zus", "jet").unwrap(); /// dict.set_item("zus", "jet").unwrap();
/// ///
/// let bytes = marshal::dumps(py, dict, marshal::VERSION); /// let bytes = marshal::dumps(py, dict, marshal::VERSION);
/// # });
/// ``` /// ```
pub fn dumps<'a>(py: Python<'a>, object: &impl AsPyPointer, version: i32) -> PyResult<&'a PyBytes> { pub fn dumps<'a>(py: Python<'a>, object: &impl AsPyPointer, version: i32) -> PyResult<&'a PyBytes> {
unsafe { unsafe {

View file

@ -25,9 +25,7 @@ use std::cell::UnsafeCell;
/// .get_or_init(py, || PyList::empty(py).into()) /// .get_or_init(py, || PyList::empty(py).into())
/// .as_ref(py) /// .as_ref(py)
/// } /// }
/// # let gil = Python::acquire_gil(); /// # Python::with_gil(|py| assert_eq!(get_shared_list(py).len(), 0));
/// # let py = gil.python();
/// # assert_eq!(get_shared_list(py).len(), 0 );
/// ``` /// ```
pub struct GILOnceCell<T>(UnsafeCell<Option<T>>); pub struct GILOnceCell<T>(UnsafeCell<Option<T>>);

View file

@ -121,15 +121,15 @@ impl<T: PyClass> PyCellInner<T> {
/// name: &'static str, /// name: &'static str,
/// author: &'static str, /// author: &'static str,
/// } /// }
/// let gil = Python::acquire_gil();
/// let py = gil.python();
/// let book = Book { /// let book = Book {
/// name: "The Man in the High Castle", /// name: "The Man in the High Castle",
/// author: "Philip Kindred Dick", /// author: "Philip Kindred Dick",
/// }; /// };
/// let book_cell = PyCell::new(py, book).unwrap(); /// Python::with_gil(|py| {
/// // you can expose PyCell to Python snippets /// let book_cell = PyCell::new(py, book).unwrap();
/// pyo3::py_run!(py, book_cell, "assert book_cell.name[-6:] == 'Castle'"); /// // `&PyCell` implements `ToPyObject`, so you can use it in a Python snippet
/// pyo3::py_run!(py, book_cell, "assert book_cell.name[-6:] == 'Castle'");
/// });
/// ``` /// ```
/// You can use `slf: &PyCell<Self>` as an alternative `self` receiver of `#[pymethod]`, /// You can use `slf: &PyCell<Self>` as an alternative `self` receiver of `#[pymethod]`,
/// though you rarely need it. /// though you rarely need it.
@ -154,10 +154,10 @@ impl<T: PyClass> PyCellInner<T> {
/// Ok(*counter) /// Ok(*counter)
/// } /// }
/// } /// }
/// # let gil = Python::acquire_gil(); /// # Python::with_gil(|py| {
/// # let py = gil.python(); /// # let counter = PyCell::new(py, Counter::default()).unwrap();
/// # let counter = PyCell::new(py, Counter::default()).unwrap(); /// # pyo3::py_run!(py, counter, "assert counter.increment('cat') == 1");
/// # pyo3::py_run!(py, counter, "assert counter.increment('cat') == 1"); /// # });
/// ``` /// ```
#[repr(C)] #[repr(C)]
pub struct PyCell<T: PyClass> { pub struct PyCell<T: PyClass> {
@ -245,18 +245,18 @@ impl<T: PyClass> PyCell<T> {
/// # use pyo3::prelude::*; /// # use pyo3::prelude::*;
/// #[pyclass] /// #[pyclass]
/// struct Class {} /// struct Class {}
/// let gil = Python::acquire_gil(); /// Python::with_gil(|py| {
/// let py = gil.python(); /// let c = PyCell::new(py, Class {}).unwrap();
/// let c = PyCell::new(py, Class {}).unwrap(); /// {
/// { /// let m = c.borrow_mut();
/// let m = c.borrow_mut(); /// assert!(c.try_borrow().is_err());
/// assert!(c.try_borrow().is_err()); /// }
/// }
/// ///
/// { /// {
/// let m = c.borrow(); /// let m = c.borrow();
/// assert!(c.try_borrow().is_ok()); /// assert!(c.try_borrow().is_ok());
/// } /// }
/// });
/// ``` /// ```
pub fn try_borrow(&self) -> Result<PyRef<'_, T>, PyBorrowError> { pub fn try_borrow(&self) -> Result<PyRef<'_, T>, PyBorrowError> {
self.thread_checker.ensure(); self.thread_checker.ensure();
@ -280,15 +280,15 @@ impl<T: PyClass> PyCell<T> {
/// # use pyo3::prelude::*; /// # use pyo3::prelude::*;
/// #[pyclass] /// #[pyclass]
/// struct Class {} /// struct Class {}
/// let gil = Python::acquire_gil(); /// Python::with_gil(|py| {
/// let py = gil.python(); /// let c = PyCell::new(py, Class {}).unwrap();
/// let c = PyCell::new(py, Class {}).unwrap(); /// {
/// { /// let m = c.borrow();
/// let m = c.borrow(); /// assert!(c.try_borrow_mut().is_err());
/// assert!(c.try_borrow_mut().is_err()); /// }
/// }
/// ///
/// assert!(c.try_borrow_mut().is_ok()); /// assert!(c.try_borrow_mut().is_ok());
/// });
/// ``` /// ```
pub fn try_borrow_mut(&self) -> Result<PyRefMut<'_, T>, PyBorrowMutError> { pub fn try_borrow_mut(&self) -> Result<PyRefMut<'_, T>, PyBorrowMutError> {
self.thread_checker.ensure(); self.thread_checker.ensure();
@ -315,19 +315,19 @@ impl<T: PyClass> PyCell<T> {
/// # use pyo3::prelude::*; /// # use pyo3::prelude::*;
/// #[pyclass] /// #[pyclass]
/// struct Class {} /// struct Class {}
/// let gil = Python::acquire_gil(); /// Python::with_gil(|py| {
/// let py = gil.python(); /// let c = PyCell::new(py, Class {}).unwrap();
/// let c = PyCell::new(py, Class {}).unwrap();
/// ///
/// { /// {
/// let m = c.borrow_mut(); /// let m = c.borrow_mut();
/// assert!(unsafe { c.try_borrow_unguarded() }.is_err()); /// assert!(unsafe { c.try_borrow_unguarded() }.is_err());
/// } /// }
/// ///
/// { /// {
/// let m = c.borrow(); /// let m = c.borrow();
/// assert!(unsafe { c.try_borrow_unguarded() }.is_ok()); /// assert!(unsafe { c.try_borrow_unguarded() }.is_ok());
/// } /// }
/// });
/// ``` /// ```
pub unsafe fn try_borrow_unguarded(&self) -> Result<&T, PyBorrowError> { pub unsafe fn try_borrow_unguarded(&self) -> Result<&T, PyBorrowError> {
self.thread_checker.ensure(); self.thread_checker.ensure();
@ -485,10 +485,10 @@ impl<T: PyClass + fmt::Debug> fmt::Debug for PyCell<T> {
/// format!("{}(base: {}, cnt: {})", slf.name, basename, refcnt) /// format!("{}(base: {}, cnt: {})", slf.name, basename, refcnt)
/// } /// }
/// } /// }
/// # let gil = Python::acquire_gil(); /// # Python::with_gil(|py| {
/// # let py = gil.python(); /// # let sub = PyCell::new(py, Child::new()).unwrap();
/// # let sub = PyCell::new(py, Child::new()).unwrap(); /// # pyo3::py_run!(py, sub, "assert sub.format() == 'Caterpillar(base: Butterfly, cnt: 3)'");
/// # pyo3::py_run!(py, sub, "assert sub.format() == 'Caterpillar(base: Butterfly, cnt: 3)'"); /// # });
/// ``` /// ```
pub struct PyRef<'p, T: PyClass> { pub struct PyRef<'p, T: PyClass> {
inner: &'p PyCellInner<T>, inner: &'p PyCellInner<T>,
@ -549,10 +549,10 @@ where
/// format!("{} {} {}", super_.as_ref().name1, super_.name2, subname) /// format!("{} {} {}", super_.as_ref().name1, super_.name2, subname)
/// } /// }
/// } /// }
/// # let gil = Python::acquire_gil(); /// # Python::with_gil(|py| {
/// # let py = gil.python(); /// # let sub = PyCell::new(py, Sub::new()).unwrap();
/// # let sub = PyCell::new(py, Sub::new()).unwrap(); /// # pyo3::py_run!(py, sub, "assert sub.name() == 'base1 base2 sub'")
/// # pyo3::py_run!(py, sub, "assert sub.name() == 'base1 base2 sub'") /// # });
/// ``` /// ```
pub fn into_super(self) -> PyRef<'p, U> { pub fn into_super(self) -> PyRef<'p, U> {
let PyRef { inner } = self; let PyRef { inner } = self;

View file

@ -30,6 +30,7 @@ impl<T: PyTypeInfo> PyObjectInit<T> for PyNativeTypeInitializer<T> {
/// ``` /// ```
/// # use pyo3::prelude::*; /// # use pyo3::prelude::*;
/// # use pyo3::py_run; /// # use pyo3::py_run;
/// # use pyo3::types::IntoPyDict;
/// #[pyclass(subclass)] /// #[pyclass(subclass)]
/// struct BaseClass { /// struct BaseClass {
/// #[pyo3(get)] /// #[pyo3(get)]
@ -55,14 +56,18 @@ impl<T: PyTypeInfo> PyObjectInit<T> for PyNativeTypeInitializer<T> {
/// .add_subclass(SubSubClass { subsubname: "subsub" }) /// .add_subclass(SubSubClass { subsubname: "subsub" })
/// } /// }
/// } /// }
/// let gil = Python::acquire_gil(); /// Python::with_gil(|py| {
/// let py = gil.python(); /// let typeobj = py.get_type::<SubSubClass>();
/// let typeobj = py.get_type::<SubSubClass>(); /// let sub_sub_class = typeobj.call((), None).unwrap();
/// let inst = typeobj.call((), None).unwrap(); /// py_run!(
/// py_run!(py, inst, r#" /// py,
/// assert inst.basename == 'base' /// sub_sub_class,
/// assert inst.subname == 'sub' /// r#"
/// assert inst.subsubname == 'subsub'"#); /// assert sub_sub_class.basename == 'base'
/// assert sub_sub_class.subname == 'sub'
/// assert sub_sub_class.subsubname == 'subsub'"#
/// );
/// });
/// ``` /// ```
pub struct PyClassInitializer<T: PyClass> { pub struct PyClassInitializer<T: PyClass> {
init: T, init: T,

View file

@ -208,15 +208,16 @@ impl<'p> Python<'p> {
/// Ok(sum) /// Ok(sum)
/// }) /// })
/// } /// }
/// let gil = Python::acquire_gil(); ///
/// let py = gil.python(); /// Python::with_gil(|py| {
/// let m = PyModule::new(py, "pcount").unwrap(); /// let m = PyModule::new(py, "pcount").unwrap();
/// m.add_function(wrap_pyfunction!(parallel_count, m).unwrap()).unwrap(); /// m.add_function(wrap_pyfunction!(parallel_count, m).unwrap()).unwrap();
/// let locals = [("pcount", m)].into_py_dict(py); /// let locals = [("pcount", m)].into_py_dict(py);
/// py.run(r#" /// pyo3::py_run!(py, *locals, r#"
/// s = ["Flow", "my", "tears", "the", "Policeman", "Said"] /// s = ["Flow", "my", "tears", "the", "Policeman", "Said"]
/// assert pcount.parallel_count(s, "a") == 3 /// assert pcount.parallel_count(s, "a") == 3
/// "#, None, Some(locals)); /// "#);
/// });
/// ``` /// ```
/// ///
/// **Note:** /// **Note:**
@ -280,11 +281,11 @@ impl<'p> Python<'p> {
/// # Examples /// # Examples
/// ``` /// ```
/// # use pyo3::{types::{PyBytes, PyDict}, prelude::*}; /// # use pyo3::{types::{PyBytes, PyDict}, prelude::*};
/// # let gil = pyo3::Python::acquire_gil(); /// # Python::with_gil(|py| {
/// # let py = gil.python();
/// let result = py.eval("[i * 10 for i in range(5)]", None, None).unwrap(); /// let result = py.eval("[i * 10 for i in range(5)]", None, None).unwrap();
/// let res: Vec<i64> = result.extract().unwrap(); /// let res: Vec<i64> = result.extract().unwrap();
/// assert_eq!(res, vec![0, 10, 20, 30, 40]) /// assert_eq!(res, vec![0, 10, 20, 30, 40])
/// # });
/// ``` /// ```
pub fn eval( pub fn eval(
self, self,
@ -303,22 +304,26 @@ impl<'p> Python<'p> {
/// # Examples /// # Examples
/// ``` /// ```
/// use pyo3::{types::{PyBytes, PyDict}, prelude::*}; /// use pyo3::{types::{PyBytes, PyDict}, prelude::*};
/// let gil = pyo3::Python::acquire_gil(); /// Python::with_gil(|py| {
/// let py = gil.python(); /// let locals = PyDict::new(py);
/// let locals = PyDict::new(py); /// py.run(
/// py.run( /// r#"
/// r#"
/// import base64 /// import base64
/// s = 'Hello Rust!' /// s = 'Hello Rust!'
/// ret = base64.b64encode(s.encode('utf-8')) /// ret = base64.b64encode(s.encode('utf-8'))
/// "#, /// "#,
/// None, /// None,
/// Some(locals), /// Some(locals),
/// ).unwrap(); /// )
/// let ret = locals.get_item("ret").unwrap(); /// .unwrap();
/// let b64: &PyBytes = ret.downcast().unwrap(); /// let ret = locals.get_item("ret").unwrap();
/// assert_eq!(b64.as_bytes(), b"SGVsbG8gUnVzdCE="); /// let b64: &PyBytes = ret.downcast().unwrap();
/// assert_eq!(b64.as_bytes(), b"SGVsbG8gUnVzdCE=");
/// });
/// ``` /// ```
///
/// You can use [`py_run!`](macro.py_run.html) for a handy alternative of `run`
/// if you don't need `globals` and unwrapping is OK.
pub fn run( pub fn run(
self, self,
code: &str, code: &str,
@ -602,21 +607,20 @@ impl<'p> Python<'p> {
/// # Examples /// # Examples
/// ```rust /// ```rust
/// # use pyo3::prelude::*; /// # use pyo3::prelude::*;
/// let gil = Python::acquire_gil(); /// Python::with_gil(|py| {
/// let py = gil.python(); /// // Some long-running process like a webserver, which never releases the GIL.
/// loop {
/// // Create a new pool, so that PyO3 can clear memory at the end of the loop.
/// let pool = unsafe { py.new_pool() };
/// ///
/// // Some long-running process like a webserver, which never releases the GIL. /// // It is recommended to *always* immediately set py to the pool's Python, to help
/// loop { /// // avoid creating references with invalid lifetimes.
/// // Create a new pool, so that PyO3 can clear memory at the end of the loop. /// let py = unsafe { pool.python() };
/// let pool = unsafe { py.new_pool() };
/// ///
/// // It is recommended to *always* immediately set py to the pool's Python, to help /// // do stuff...
/// // avoid creating references with invalid lifetimes. /// # break; // Exit the loop so that doctest terminates!
/// let py = unsafe { pool.python() }; /// }
/// /// });
/// // do stuff...
/// # break; // Exit the loop so that doctest terminates!
/// }
/// ``` /// ```
/// ///
/// # Safety /// # Safety

View file

@ -28,12 +28,13 @@ use std::os::raw::c_int;
/// ``` /// ```
/// use pyo3::prelude::*; /// use pyo3::prelude::*;
/// use pyo3::types::{PyAny, PyDict, PyList}; /// use pyo3::types::{PyAny, PyDict, PyList};
/// let gil = Python::acquire_gil(); /// Python::with_gil(|py| {
/// let dict = PyDict::new(gil.python()); /// let dict = PyDict::new(py);
/// assert!(dict.is_instance::<PyAny>().unwrap()); /// assert!(dict.is_instance::<PyAny>().unwrap());
/// let any: &PyAny = dict.as_ref(); /// let any: &PyAny = dict.as_ref();
/// assert!(any.downcast::<PyDict>().is_ok()); /// assert!(any.downcast::<PyDict>().is_ok());
/// assert!(any.downcast::<PyList>().is_err()); /// assert!(any.downcast::<PyList>().is_err());
/// });
/// ``` /// ```
#[repr(transparent)] #[repr(transparent)]
pub struct PyAny(UnsafeCell<ffi::PyObject>); pub struct PyAny(UnsafeCell<ffi::PyObject>);
@ -255,16 +256,16 @@ impl PyAny {
/// # use pyo3::prelude::*; /// # use pyo3::prelude::*;
/// use pyo3::types::IntoPyDict; /// use pyo3::types::IntoPyDict;
/// ///
/// let gil = Python::acquire_gil(); /// Python::with_gil(|py| {
/// let py = gil.python(); /// let list = vec![3, 6, 5, 4, 7].to_object(py);
/// let list = vec![3, 6, 5, 4, 7].to_object(py); /// let dict = vec![("reverse", true)].into_py_dict(py);
/// let dict = vec![("reverse", true)].into_py_dict(py); /// list.call_method(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]);
/// assert_eq!(list.extract::<Vec<i32>>(py).unwrap(), vec![7, 6, 5, 4, 3]);
/// ///
/// let new_element = 1.to_object(py); /// let new_element = 1.to_object(py);
/// list.call_method(py, "append", (new_element,), None).unwrap(); /// list.call_method(py, "append", (new_element,), None).unwrap();
/// assert_eq!(list.extract::<Vec<i32>>(py).unwrap(), vec![7, 6, 5, 4, 3, 1]); /// assert_eq!(list.extract::<Vec<i32>>(py).unwrap(), vec![7, 6, 5, 4, 3, 1]);
/// });
/// ``` /// ```
pub fn call_method( pub fn call_method(
&self, &self,

View file

@ -133,10 +133,7 @@ impl PyByteArray {
/// ``` /// ```
/// # use pyo3::prelude::*; /// # use pyo3::prelude::*;
/// # use pyo3::types::PyByteArray; /// # use pyo3::types::PyByteArray;
/// # use pyo3::types::IntoPyDict; /// # Python::with_gil(|py| {
/// # let gil = Python::acquire_gil();
/// # let py = gil.python();
/// #
/// let bytearray = PyByteArray::new(py, b"Hello World."); /// let bytearray = PyByteArray::new(py, b"Hello World.");
/// let mut copied_message = bytearray.to_vec(); /// let mut copied_message = bytearray.to_vec();
/// assert_eq!(b"Hello World.", copied_message.as_slice()); /// assert_eq!(b"Hello World.", copied_message.as_slice());
@ -144,8 +141,8 @@ impl PyByteArray {
/// copied_message[11] = b'!'; /// copied_message[11] = b'!';
/// assert_eq!(b"Hello World!", copied_message.as_slice()); /// assert_eq!(b"Hello World!", copied_message.as_slice());
/// ///
/// let locals = [("bytearray", bytearray)].into_py_dict(py); /// pyo3::py_run!(py, bytearray, "assert bytearray == b'Hello World.'");
/// py.run("assert bytearray == b'Hello World.'", None, Some(locals)).unwrap(); /// # });
/// ``` /// ```
pub fn to_vec(&self) -> Vec<u8> { pub fn to_vec(&self) -> Vec<u8> {
unsafe { self.as_bytes() }.to_vec() unsafe { self.as_bytes() }.to_vec()