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,
debug: bool,
}
let gil = Python::acquire_gil();
let py = gil.python();
let obj = PyCell::new(py, MyClass { num: 3, debug: true }).unwrap();
{
let obj_ref = obj.borrow(); // Get PyRef
assert_eq!(obj_ref.num, 3);
// You cannot get PyRefMut unless all PyRefs are dropped
assert!(obj.try_borrow_mut().is_err());
}
{
let mut obj_mut = obj.borrow_mut(); // Get PyRefMut
obj_mut.num = 5;
// You cannot get any other refs until the PyRefMut is dropped
assert!(obj.try_borrow().is_err());
assert!(obj.try_borrow_mut().is_err());
}
Python::with_gil(|py| {
let obj = PyCell::new(py, MyClass { num: 3, debug: true }).unwrap();
{
let obj_ref = obj.borrow(); // Get PyRef
assert_eq!(obj_ref.num, 3);
// You cannot get PyRefMut unless all PyRefs are dropped
assert!(obj.try_borrow_mut().is_err());
}
{
let mut obj_mut = obj.borrow_mut(); // Get PyRefMut
obj_mut.num = 5;
// You cannot get any other refs until the PyRefMut is dropped
assert!(obj.try_borrow().is_err());
assert!(obj.try_borrow_mut().is_err());
}
// You can convert `&PyCell` to a Python object
pyo3::py_run!(py, obj, "assert obj.num == 5")
// You can convert `&PyCell` to a Python object
pyo3::py_run!(py, obj, "assert obj.num == 5");
});
```
`&PyCell<T>` is bounded by the same lifetime as a [`GILGuard`].
@ -118,15 +118,14 @@ struct MyClass {
num: i32,
}
fn return_myclass() -> Py<MyClass> {
let gil = Python::acquire_gil();
let py = gil.python();
Py::new(py, MyClass { num: 1 }).unwrap()
Python::with_gil(|py| Py::new(py, MyClass { num: 1 }).unwrap())
}
let gil = Python::acquire_gil();
let obj = return_myclass();
let cell = obj.as_ref(gil.python()); // Py<MyClass>::as_ref returns &PyCell<MyClass>
let obj_ref = cell.borrow(); // Get PyRef<T>
assert_eq!(obj_ref.num, 1);
Python::with_gil(|py|{
let cell = obj.as_ref(py); // Py<MyClass>::as_ref returns &PyCell<MyClass>
let obj_ref = cell.borrow(); // Get PyRef<T>
assert_eq!(obj_ref.num, 1);
});
```
## Customizing the class
@ -261,10 +260,10 @@ impl SubSubClass {
SubClass::method2(super_).map(|x| x * v)
}
}
# let gil = Python::acquire_gil();
# let py = gil.python();
# let subsub = pyo3::PyCell::new(py, SubSubClass::new()).unwrap();
# pyo3::py_run!(py, subsub, "assert subsub.method3() == 3000")
# Python::with_gil(|py| {
# let subsub = pyo3::PyCell::new(py, SubSubClass::new()).unwrap();
# pyo3::py_run!(py, subsub, "assert subsub.method3() == 3000")
# });
```
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.
```rust
# #[cfg(Py_LIMITED_API)] fn main() {}
# #[cfg(not(Py_LIMITED_API))] fn main() {
# #[cfg(not(Py_LIMITED_API))] {
# use pyo3::prelude::*;
use pyo3::types::PyDict;
use pyo3::{AsPyPointer, PyNativeType};
@ -300,10 +298,10 @@ impl DictWithCounter {
dict.set_item(key, value)
}
}
# let gil = Python::acquire_gil();
# let py = gil.python();
# let cnt = pyo3::PyCell::new(py, DictWithCounter::new()).unwrap();
# pyo3::py_run!(py, cnt, "cnt.set('abc', 10); assert cnt['abc'] == 10")
# Python::with_gil(|py| {
# let cnt = pyo3::PyCell::new(py, DictWithCounter::new()).unwrap();
# pyo3::py_run!(py, cnt, "cnt.set('abc', 10); assert cnt['abc'] == 10")
# });
# }
```
@ -563,10 +561,10 @@ impl MyClass {
}
}
let gil = Python::acquire_gil();
let py = gil.python();
let my_class = py.get_type::<MyClass>();
pyo3::py_run!(py, my_class, "assert my_class.my_attribute == 'hello'")
Python::with_gil(|py| {
let my_class = py.get_type::<MyClass>();
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
@ -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:
```rust
# #[cfg(not(feature = "multiple-pymethods"))]
# {
# #[cfg(not(feature = "multiple-pymethods"))] {
# use pyo3::prelude::*;
// 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()
}
}
# let gil = Python::acquire_gil();
# let py = gil.python();
# let cls = py.get_type::<MyClass>();
# pyo3::py_run!(py, cls, "assert cls.__name__ == 'MyClass'")
# Python::with_gil(|py| {
# let cls = py.get_type::<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();
# let py = gil.python();
# let inst = pyo3::PyCell::new(
# py,
# Container {
# 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]");
# Python::with_gil(|py| {
# let container = Container { iter: vec![1, 2, 3, 4] };
# let inst = pyo3::PyCell::new(py, container).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

View file

@ -23,14 +23,11 @@ use pyo3::exceptions::PyException;
create_exception!(mymodule, CustomError, PyException);
fn main() {
let gil = Python::acquire_gil();
let py = gil.python();
Python::with_gil(|py| {
let ctx = [("CustomError", py.get_type::<CustomError>())].into_py_dict(py);
py.run("assert str(CustomError) == \"<class 'mymodule.CustomError'>\"", None, Some(&ctx)).unwrap();
py.run("assert CustomError('oops').args == ('oops',)", None, Some(&ctx)).unwrap();
}
pyo3::py_run!(py, *ctx, "assert str(CustomError) == \"<class 'mymodule.CustomError'>\"");
pyo3::py_run!(py, *ctx, "assert CustomError('oops').args == ('oops',)");
});
```
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::exceptions::PyTypeError;
fn main() {
let gil = Python::acquire_gil();
let py = gil.python();
Python::with_gil(|py| {
PyTypeError::new_err("Error").restore(py);
assert!(PyErr::occurred(py));
drop(PyErr::fetch(py));
}
});
```
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::types::{PyBool, PyList};
fn main() {
let gil = Python::acquire_gil();
let py = gil.python();
Python::with_gil(|py| {
assert!(PyBool::new(py, true).is_instance::<PyBool>().unwrap());
let list = PyList::new(py, &[1, 2, 3, 4]);
assert!(!list.is_instance::<PyBool>().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)
method to do the actual work.
@ -120,10 +113,10 @@ To check the type of an exception, you can similarly do:
```rust
# use pyo3::exceptions::PyTypeError;
# use pyo3::prelude::*;
# let gil = Python::acquire_gil();
# let py = gil.python();
# Python::with_gil(|py| {
# let err = PyTypeError::new_err(());
err.is_instance::<PyTypeError>(py);
# });
```
## Handling Rust errors

View file

@ -266,22 +266,16 @@ To migrate, just pass a `py` argument to any calls to these methods.
Before:
```rust,compile_fail
use pyo3::prelude::*;
let gil = Python::acquire_gil();
let py = gil.python();
# pyo3::Python::with_gil(|py| {
py.None().get_refcnt();
# })
```
After:
```rust
use pyo3::prelude::*;
let gil = Python::acquire_gil();
let py = gil.python();
# pyo3::Python::with_gil(|py| {
py.None().get_refcnt(py);
# })
```
## from 0.9.* to 0.10
@ -296,18 +290,20 @@ Before:
```rust,compile_fail
use pyo3::ObjectProtocol;
let gil = pyo3::Python::acquire_gil();
let obj = gil.python().eval("lambda: 'Hi :)'", None, None).unwrap();
# pyo3::Python::with_gil(|py| {
let obj = py.eval("lambda: 'Hi :)'", None, None).unwrap();
let hi: &pyo3::types::PyString = obj.call0().unwrap().downcast().unwrap();
assert_eq!(hi.len().unwrap(), 5);
# })
```
After:
```rust
let gil = pyo3::Python::acquire_gil();
let obj = gil.python().eval("lambda: 'Hi :)'", None, None).unwrap();
# pyo3::Python::with_gil(|py| {
let obj = py.eval("lambda: 'Hi :)'", None, None).unwrap();
let hi: &pyo3::types::PyString = obj.call0().unwrap().downcast().unwrap();
assert_eq!(hi.len().unwrap(), 5);
# })
```
### No `#![feature(specialization)]` in user code
@ -380,16 +376,16 @@ impl Names {
self.names.append(&mut other.names)
}
}
# let gil = Python::acquire_gil();
# let py = gil.python();
# let names = PyCell::new(py, Names::new()).unwrap();
# pyo3::py_run!(py, names, r"
# try:
# names.merge(names)
# assert False, 'Unreachable'
# except RuntimeError as e:
# assert str(e) == 'Already borrowed'
# ");
# Python::with_gil(|py| {
# let names = PyCell::new(py, Names::new()).unwrap();
# pyo3::py_run!(py, names, r"
# try:
# names.merge(names)
# assert False, 'Unreachable'
# except RuntimeError as e:
# assert str(e) == 'Already borrowed'
# ");
# })
```
`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
@ -410,9 +406,9 @@ Before:
# use pyo3::prelude::*;
# #[pyclass]
# struct MyClass {}
let gil = Python::acquire_gil();
let py = gil.python();
# Python::with_gil(|py| {
let obj_ref = PyRef::new(py, MyClass {}).unwrap();
# })
```
After:
@ -420,10 +416,10 @@ After:
# use pyo3::prelude::*;
# #[pyclass]
# struct MyClass {}
let gil = Python::acquire_gil();
let py = gil.python();
# Python::with_gil(|py| {
let obj = PyCell::new(py, MyClass {}).unwrap();
let obj_ref = obj.borrow();
# })
```
#### Object extraction
@ -445,8 +441,7 @@ After:
# use pyo3::types::IntoPyDict;
# #[pyclass] #[derive(Clone)] struct MyClass {}
# #[pymethods] impl MyClass { #[new]fn new() -> Self { MyClass {} }}
# let gil = Python::acquire_gil();
# let py = gil.python();
# Python::with_gil(|py| {
# let typeobj = py.get_type::<MyClass>();
# let d = [("c", typeobj)].into_py_dict(py);
# 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
}
let obj_ref_mut: PyRefMut<MyClass> = obj.extract().unwrap();
# })
```

View file

@ -38,21 +38,20 @@ fn main() {
let arg2 = "arg2";
let arg3 = "arg3";
let gil = Python::acquire_gil();
let py = gil.python();
Python::with_gil(|py| {
let obj = SomeObject::new(py);
let obj = SomeObject::new(py);
// call object without empty arguments
obj.call0(py);
// call object without empty arguments
obj.call0(py);
// call object with PyTuple
let args = PyTuple::new(py, &[arg1, arg2, arg3]);
obj.call1(py, args);
// call object with PyTuple
let args = PyTuple::new(py, &[arg1, arg2, arg3]);
obj.call1(py, args);
// pass arguments as rust tuple
let args = (arg1, arg2, arg3);
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 val2 = 2;
let gil = Python::acquire_gil();
let py = gil.python();
Python::with_gil(|py| {
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
let kwargs = [(key1, val1)].into_py_dict(py);
obj.call(py, (), Some(kwargs));
// pass arguments as Vec
let kwargs = vec![(key1, val1), (key2, val2)];
obj.call(py, (), Some(kwargs.into_py_dict(py)));
// pass arguments as Vec
let kwargs = vec![(key1, val1), (key2, val2)];
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)));
// 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
# use pyo3::prelude::*;
# use pyo3::types::PyList;
# let gil = Python::acquire_gil();
# let py = gil.python();
# Python::with_gil(|py| {
let list: Py<PyList> = PyList::empty(py).into();
// To &PyList with Py::as_ref() (borrows from the Py)
@ -184,14 +183,14 @@ let _: &PyList = list.into_ref(py);
# let list = list_clone;
// To Py<PyAny> (aka PyObject) with .into()
let _: Py<PyAny> = list.into();
# })
```
For a `#[pyclass] struct MyClass`, the conversions for `Py<MyClass>` are below:
```rust
# use pyo3::prelude::*;
# let gil = Python::acquire_gil();
# let py = gil.python();
# Python::with_gil(|py| {
# #[pyclass] struct MyClass { }
# Python::with_gil(|py| -> PyResult<()> {
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)?;
# Ok(())
# }).unwrap();
# });
```
### `PyCell<SomeType>`

View file

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

View file

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

View file

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

View file

@ -178,8 +178,11 @@ where
result
}
/// RAII type that represents the Global Interpreter Lock acquisition. To get hold of a value of
/// this type, see [`Python::acquire_gil`](struct.Python.html#method.acquire_gil).
/// RAII type that represents the Global Interpreter Lock acquisition.
///
/// 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
/// ```

View file

@ -286,6 +286,10 @@ macro_rules! wrap_pymodule {
/// 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
/// ```
/// 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.
///
/// # Examples
/// ```
/// use pyo3::{prelude::*, py_run, PyCell};
/// #[pyclass]

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

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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