Clean up doctests, deny some lints (#1900)

* Clean up doctests, deny some lints

* Apply suggestions from review.

* replace \" with '

* Fix some more doc examples

* Fix formatting

* Fix some more things

* Remove unused parentheses

* Only test class sig on supported abi/platforms

* Only test class signature on correct versions

* Fix tests to compile on msrv

* msrv strikes yet again

* Add feedback

* Pin `half` to 1.7.1 on msrv
This commit is contained in:
Bruno Kolenbrander 2021-10-14 23:15:25 +02:00 committed by GitHub
parent ae873698d4
commit 8a57fe2d20
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
37 changed files with 744 additions and 264 deletions

View File

@ -183,6 +183,7 @@ jobs:
cargo update -p indexmap --precise 1.6.2
cargo update -p hashbrown:0.11.2 --precise 0.9.1
cargo update -p bitflags --precise 1.2.1
cargo update -p half --precise 1.7.1
- name: Build docs
run: cargo doc --no-deps --no-default-features --features "${{ steps.settings.outputs.all_additive_features }}"

View File

@ -121,7 +121,7 @@ use pyo3::types::IntoPyDict;
fn main() -> PyResult<()> {
Python::with_gil(|py| {
let sys = py.import("sys")?;
let version: String = sys.get("version")?.extract()?;
let version: String = sys.getattr("version")?.extract()?;
let locals = [("os", py.import("os")?)].into_py_dict(py);
let code = "os.getenv('USER') or os.getenv('USERNAME') or 'Unknown'";

View File

@ -25,11 +25,12 @@ To define a custom Python class, a Rust struct needs to be annotated with the
`#[pyclass]` attribute.
```rust
# #![allow(dead_code)]
# use pyo3::prelude::*;
#[pyclass]
struct MyClass {
# #[pyo3(get)]
num: i32,
debug: bool,
}
```
@ -45,8 +46,8 @@ Custom Python classes can then be added to a module using `add_class()`.
# use pyo3::prelude::*;
# #[pyclass]
# struct MyClass {
# #[allow(dead_code)]
# num: i32,
# debug: bool,
# }
#[pymodule]
fn mymodule(_py: Python, m: &PyModule) -> PyResult<()> {
@ -78,15 +79,13 @@ For users who are not very familiar with `RefCell`, here is a reminder of Rust's
```rust
# use pyo3::prelude::*;
# use pyo3::types::PyDict;
#[pyclass]
struct MyClass {
#[pyo3(get)]
num: i32,
debug: bool,
}
Python::with_gil(|py| {
let obj = PyCell::new(py, MyClass { num: 3, debug: true }).unwrap();
let obj = PyCell::new(py, MyClass { num: 3}).unwrap();
{
let obj_ref = obj.borrow(); // Get PyRef
assert_eq!(obj_ref.num, 3);
@ -117,10 +116,13 @@ lifetime, and therefore needs a `Python<'_>` token to access.
struct MyClass {
num: i32,
}
fn return_myclass() -> Py<MyClass> {
Python::with_gil(|py| Py::new(py, MyClass { num: 1 }).unwrap())
}
let obj = return_myclass();
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>
@ -157,6 +159,7 @@ attribute. Only Python's `__new__` method can be specified, `__init__` is not av
# use pyo3::prelude::*;
#[pyclass]
struct MyClass {
# #[allow(dead_code)]
num: i32,
}
@ -174,6 +177,7 @@ Alternatively, if your `new` method may fail you can return `PyResult<Self>`.
# use pyo3::prelude::*;
#[pyclass]
struct MyClass {
# #[allow(dead_code)]
num: i32,
}
@ -323,7 +327,7 @@ impl DictWithCounter {
```
If `SubClass` does not provide a baseclass initialization, the compilation fails.
```compile_fail
```rust,compile_fail
# use pyo3::prelude::*;
#[pyclass]
@ -498,8 +502,8 @@ gets injected by the method wrapper, e.g.
# use pyo3::prelude::*;
# #[pyclass]
# struct MyClass {
# #[allow(dead_code)]
# num: i32,
# debug: bool,
# }
#[pymethods]
impl MyClass {
@ -522,8 +526,8 @@ This is the equivalent of the Python decorator `@classmethod`.
# use pyo3::types::PyType;
# #[pyclass]
# struct MyClass {
# #[allow(dead_code)]
# num: i32,
# debug: bool,
# }
#[pymethods]
impl MyClass {
@ -552,8 +556,8 @@ To create a static method for a custom class, the method needs to be annotated w
# use pyo3::prelude::*;
# #[pyclass]
# struct MyClass {
# #[allow(dead_code)]
# num: i32,
# debug: bool,
# }
#[pymethods]
impl MyClass {
@ -706,19 +710,17 @@ use pyo3::types::{PyDict, PyTuple};
# #[pyclass]
# struct MyClass {
# num: i32,
# debug: bool,
# }
#[pymethods]
impl MyClass {
#[new]
#[args(num = "-1", debug = "true")]
fn new(num: i32, debug: bool) -> Self {
MyClass { num, debug }
#[args(num = "-1")]
fn new(num: i32) -> Self {
MyClass { num }
}
#[args(
num = "10",
debug = "true",
py_args = "*",
name = "\"Hello\"",
py_kwargs = "**"
@ -726,23 +728,20 @@ impl MyClass {
fn method(
&mut self,
num: i32,
debug: bool,
name: &str,
py_args: &PyTuple,
py_kwargs: Option<&PyDict>,
) -> PyResult<String> {
self.debug = debug;
self.num = num;
Ok(format!(
"py_args={:?}, py_kwargs={:?}, name={}, num={}, debug={}",
py_args, py_kwargs, name, self.num, self.debug
"py_args={:?}, py_kwargs={:?}, name={}, num={}",
py_args, py_kwargs, name, self.num
))
}
fn make_change(&mut self, num: i32, debug: bool) -> PyResult<String> {
fn make_change(&mut self, num: i32) -> PyResult<String> {
self.num = num;
self.debug = debug;
Ok(format!("num={}, debug={}", self.num, self.debug))
Ok(format!("num={}", self.num))
}
}
```
@ -754,14 +753,13 @@ mc = mymodule.MyClass()
print(mc.method(44, False, "World", 666, x=44, y=55))
print(mc.method(num=-1, name="World"))
print(mc.make_change(44, False))
print(mc.make_change(debug=False, num=-1))
```
Produces output:
```text
py_args=('World', 666), py_kwargs=Some({'x': 44, 'y': 55}), name=Hello, num=44, debug=false
py_args=(), py_kwargs=None, name=World, num=-1, debug=true
num=44, debug=false
num=-1, debug=false
py_args=('World', 666), py_kwargs=Some({'x': 44, 'y': 55}), name=Hello, num=44
py_args=(), py_kwargs=None, name=World, num=-1
num=44
num=-1
```
## Implementation details
@ -781,8 +779,8 @@ The `#[pyclass]` macro expands to roughly the code seen below. The `PyClassImplC
/// Class for demonstration
struct MyClass {
# #[allow(dead_code)]
num: i32,
debug: bool,
}
unsafe impl pyo3::PyTypeInfo for MyClass {
@ -812,7 +810,7 @@ impl pyo3::IntoPy<PyObject> for MyClass {
}
impl pyo3::class::impl_::PyClassImpl for MyClass {
const DOC: &'static str = "Class for demonstration";
const DOC: &'static str = "Class for demonstration\u{0}";
const IS_GC: bool = false;
const IS_BASETYPE: bool = false;
const IS_SUBCLASS: bool = false;

View File

@ -300,7 +300,7 @@ use pyo3::PyIterProtocol;
#[pyclass]
struct MyIterator {
iter: Box<Iterator<Item = PyObject> + Send>,
iter: Box<dyn Iterator<Item = PyObject> + Send>,
}
#[pyproto]

View File

@ -32,6 +32,9 @@ structs is not supported.
#### Deriving [`FromPyObject`] for structs
The derivation generates code that will attempt to access the attribute `my_string` on
the Python object, i.e. `obj.getattr("my_string")`, and call `extract()` on the attribute.
```
use pyo3::prelude::*;
@ -39,20 +42,50 @@ use pyo3::prelude::*;
struct RustyStruct {
my_string: String,
}
#
# fn main() -> PyResult<()> {
# Python::with_gil(|py| -> PyResult<()> {
# let module = PyModule::from_code(
# py,
# "class Foo:
# def __init__(self):
# self.my_string = 'test'",
# "",
# "",
# )?;
#
# let class = module.getattr("Foo")?;
# let instance = class.call0()?;
# let rustystruct: RustyStruct = instance.extract()?;
# assert_eq!(rustystruct.my_string, "test");
# Ok(())
# })
# }
```
The derivation generates code that will per default access the attribute `my_string` on
the Python object, i.e. `obj.getattr("my_string")`, and call `extract()` on the attribute.
It is also possible to access the value on the Python object through `obj.get_item("my_string")`
by setting the attribute `pyo3(item)` on the field:
By setting the `#[pyo3(item)]` attribute on the field, PyO3 will attempt to extract the value by calling the `get_item` method on the Python object.
```
use pyo3::prelude::*;
#[derive(FromPyObject)]
struct RustyStruct {
#[pyo3(item)]
my_string: String,
}
#
# use pyo3::types::PyDict;
# fn main() -> PyResult<()> {
# Python::with_gil(|py| -> PyResult<()> {
# let dict = PyDict::new(py);
# dict.set_item("my_string", "test")?;
#
# let rustystruct: RustyStruct = dict.extract()?;
# assert_eq!(rustystruct.my_string, "test");
# Ok(())
# })
# }
```
The argument passed to `getattr` and `get_item` can also be configured:
@ -67,6 +100,28 @@ struct RustyStruct {
#[pyo3(attribute("name"))]
string_attr: String,
}
#
# fn main() -> PyResult<()> {
# Python::with_gil(|py| -> PyResult<()> {
# let module = PyModule::from_code(
# py,
# "class Foo(dict):
# def __init__(self):
# self.name = 'test'
# self['key'] = 'test2'",
# "",
# "",
# )?;
#
# let class = module.getattr("Foo")?;
# let instance = class.call0()?;
# let rustystruct: RustyStruct = instance.extract()?;
# assert_eq!(rustystruct.string_attr, "test");
# assert_eq!(rustystruct.string_in_mapping, "test2");
#
# Ok(())
# })
# }
```
This tries to extract `string_attr` from the attribute `name` and `string_in_mapping`
@ -85,6 +140,19 @@ use pyo3::prelude::*;
#[derive(FromPyObject)]
struct RustyTuple(String, String);
# use pyo3::types::PyTuple;
# fn main() -> PyResult<()> {
# Python::with_gil(|py| -> PyResult<()> {
# let tuple = PyTuple::new(py, vec!["test", "test2"]);
#
# let rustytuple: RustyTuple = tuple.extract()?;
# assert_eq!(rustytuple.0, "test");
# assert_eq!(rustytuple.1, "test2");
#
# Ok(())
# })
# }
```
Tuple structs with a single field are treated as wrapper types which are described in the
@ -95,6 +163,18 @@ use pyo3::prelude::*;
#[derive(FromPyObject)]
struct RustyTuple((String,));
# use pyo3::types::PyTuple;
# fn main() -> PyResult<()> {
# Python::with_gil(|py| -> PyResult<()> {
# let tuple = PyTuple::new(py, vec!["test"]);
#
# let rustytuple: RustyTuple = tuple.extract()?;
# assert_eq!((rustytuple.0).0, "test");
#
# Ok(())
# })
# }
```
#### Deriving [`FromPyObject`] for wrapper types
@ -115,6 +195,21 @@ struct RustyTransparentTupleStruct(String);
struct RustyTransparentStruct {
inner: String,
}
# use pyo3::types::PyString;
# fn main() -> PyResult<()> {
# Python::with_gil(|py| -> PyResult<()> {
# let s = PyString::new(py, "test");
#
# let tup: RustyTransparentTupleStruct = s.extract()?;
# assert_eq!(tup.0, "test");
#
# let stru: RustyTransparentStruct = s.extract()?;
# assert_eq!(stru.inner, "test");
#
# Ok(())
# })
# }
```
#### Deriving [`FromPyObject`] for enums
@ -132,6 +227,7 @@ attribute can be applied to single-field-variants.
use pyo3::prelude::*;
#[derive(FromPyObject)]
# #[derive(Debug)]
enum RustyEnum<'a> {
Int(usize), // input is a positive int
String(String), // input is a string
@ -151,23 +247,178 @@ enum RustyEnum<'a> {
#[pyo3(transparent)]
CatchAll(&'a PyAny), // This extraction never fails
}
#
# use pyo3::types::{PyBytes, PyString};
# fn main() -> PyResult<()> {
# Python::with_gil(|py| -> PyResult<()> {
# {
# let thing = 42_u8.to_object(py);
# let rust_thing: RustyEnum = thing.extract(py)?;
#
# assert_eq!(
# 42,
# match rust_thing {
# RustyEnum::Int(i) => i,
# other => unreachable!("Error extracting: {:?}", other),
# }
# );
# }
# {
# let thing = PyString::new(py, "text");
# let rust_thing: RustyEnum = thing.extract()?;
#
# assert_eq!(
# "text",
# match rust_thing {
# RustyEnum::String(i) => i,
# other => unreachable!("Error extracting: {:?}", other),
# }
# );
# }
# {
# let thing = (32_u8, 73_u8).to_object(py);
# let rust_thing: RustyEnum = thing.extract(py)?;
#
# assert_eq!(
# (32, 73),
# match rust_thing {
# RustyEnum::IntTuple(i, j) => (i, j),
# other => unreachable!("Error extracting: {:?}", other),
# }
# );
# }
# {
# let thing = ("foo", 73_u8).to_object(py);
# let rust_thing: RustyEnum = thing.extract(py)?;
#
# assert_eq!(
# (String::from("foo"), 73),
# match rust_thing {
# RustyEnum::StringIntTuple(i, j) => (i, j),
# other => unreachable!("Error extracting: {:?}", other),
# }
# );
# }
# {
# let module = PyModule::from_code(
# py,
# "class Foo(dict):
# def __init__(self):
# self.x = 0
# self.y = 1
# self.z = 2",
# "",
# "",
# )?;
#
# let class = module.getattr("Foo")?;
# let instance = class.call0()?;
# let rust_thing: RustyEnum = instance.extract()?;
#
# assert_eq!(
# (0, 1, 2),
# match rust_thing {
# RustyEnum::Coordinates3d { x, y, z } => (x, y, z),
# other => unreachable!("Error extracting: {:?}", other),
# }
# );
# }
#
# {
# let module = PyModule::from_code(
# py,
# "class Foo(dict):
# def __init__(self):
# self.x = 3
# self.y = 4",
# "",
# "",
# )?;
#
# let class = module.getattr("Foo")?;
# let instance = class.call0()?;
# let rust_thing: RustyEnum = instance.extract()?;
#
# assert_eq!(
# (3, 4),
# match rust_thing {
# RustyEnum::Coordinates2d { a, b } => (a, b),
# other => unreachable!("Error extracting: {:?}", other),
# }
# );
# }
#
# {
# let thing = PyBytes::new(py, b"text");
# let rust_thing: RustyEnum = thing.extract()?;
#
# assert_eq!(
# b"text",
# match rust_thing {
# RustyEnum::CatchAll(i) => i.downcast::<PyBytes>()?.as_bytes(),
# other => unreachable!("Error extracting: {:?}", other),
# }
# );
# }
# Ok(())
# })
# }
```
If none of the enum variants match, a `PyValueError` containing the names of the
If none of the enum variants match, a `PyTypeError` containing the names of the
tested variants is returned. The names reported in the error message can be customized
through the `pyo3(annotation = "name")` attribute, e.g. to use conventional Python type
through the `#[pyo3(annotation = "name")]` attribute, e.g. to use conventional Python type
names:
```
use pyo3::prelude::*;
#[derive(FromPyObject)]
# #[derive(Debug)]
enum RustyEnum {
#[pyo3(transparent, annotation = "str")]
String(String),
#[pyo3(transparent, annotation = "int")]
Int(isize),
}
#
# fn main() -> PyResult<()> {
# Python::with_gil(|py| -> PyResult<()> {
# {
# let thing = 42_u8.to_object(py);
# let rust_thing: RustyEnum = thing.extract(py)?;
#
# assert_eq!(
# 42,
# match rust_thing {
# RustyEnum::Int(i) => i,
# other => unreachable!("Error extracting: {:?}", other),
# }
# );
# }
#
# {
# let thing = "foo".to_object(py);
# let rust_thing: RustyEnum = thing.extract(py)?;
#
# assert_eq!(
# "foo",
# match rust_thing {
# RustyEnum::String(i) => i,
# other => unreachable!("Error extracting: {:?}", other),
# }
# );
# }
#
# {
# let thing = b"foo".to_object(py);
# let error = thing.extract::<RustyEnum>(py).unwrap_err();
# assert!(error.is_instance::<pyo3::exceptions::PyTypeError>(py));
# }
#
# Ok(())
# })
# }
```
If the input is neither a string nor an integer, the error message will be:

View File

@ -49,7 +49,35 @@ fn mymodule(py: Python, m: &PyModule) -> PyResult<()> {
## Raising an exception
To raise an exception, first you need to obtain an exception type and construct a new [`PyErr`], then call the [`PyErr::restore`]({{#PYO3_DOCS_URL}}/pyo3/struct.PyErr.html#method.restore) method to write the exception back to the Python interpreter's global state.
To raise an exception from `pyfunction`s and `pymethods`, you should return an `Err(PyErr)`.
If returned to Python code, this [`PyErr`] will then be raised as a Python exception. Many PyO3 APIs also return [`PyResult`].
If a Rust type exists for the exception, then it is possible to use the `new_err` method.
For example, each standard exception defined in the `pyo3::exceptions` module
has a corresponding Rust type and exceptions defined by [`create_exception!`] and [`import_exception!`] macro have Rust types as well.
```rust
use pyo3::exceptions::PyZeroDivisionError;
use pyo3::prelude::*;
#[pyfunction]
fn divide(a: i32, b: i32) -> PyResult<i32> {
match a.checked_div(b) {
Some(q) => Ok(q),
None => Err(PyZeroDivisionError::new_err("division by zero")),
}
}
#
# fn main(){
# Python::with_gil(|py|{
# let fun = pyo3::wrap_pyfunction!(divide, py).unwrap();
# fun.call1((1,0)).unwrap_err();
# fun.call1((1,1)).unwrap();
# });
# }
```
You can also manually write and fetch errors in the Python interpreter's global state:
```rust
use pyo3::{Python, PyErr};
@ -62,32 +90,12 @@ Python::with_gil(|py| {
});
```
From `pyfunction`s and `pyclass` methods, returning an `Err(PyErr)` is enough;
PyO3 will handle restoring the exception on the Python interpreter side.
If you already have a Python exception instance, you can simply call [`PyErr::from_instance`].
```rust,ignore
PyErr::from_instance(py, err).restore(py);
```
If a Rust type exists for the exception, then it is possible to use the `new_err` method.
For example, each standard exception defined in the `pyo3::exceptions` module
has a corresponding Rust type, exceptions defined by [`create_exception!`] and [`import_exception!`] macro
have Rust types as well.
```rust
# use pyo3::exceptions::PyValueError;
# use pyo3::prelude::*;
# fn check_for_error() -> bool {false}
fn my_func(arg: PyObject) -> PyResult<()> {
if check_for_error() {
Err(PyValueError::new_err("argument is wrong"))
} else {
Ok(())
}
}
```
## Checking exception types
@ -128,47 +136,62 @@ which is an alias for the type `Result<T, PyErr>`.
A [`PyErr`] represents a Python exception. Errors within the PyO3 library are also exposed as
Python exceptions.
If your code has a custom error type e.g. `MyError`, adding an implementation of
`std::convert::From<MyError> for PyErr` is usually enough. PyO3 will then automatically convert
your error to a Python exception when needed.
If your code has a custom error type, adding an implementation of `std::convert::From<MyError> for PyErr`
is usually enough. PyO3 will then automatically convert your error to a Python exception when needed.
The following code snippet defines a Rust error named `CustomIOError`. In its `From<CustomIOError> for PyErr`
implementation it returns a `PyErr` representing Python's `OSError`.
```rust
# use pyo3::prelude::*;
# use pyo3::exceptions::PyOSError;
# use std::error::Error;
# use std::fmt;
#
# #[derive(Debug)]
# struct CustomIOError;
#
# impl Error for CustomIOError {}
#
# impl fmt::Display for CustomIOError {
# fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
# write!(f, "Oh no!")
# }
# }
#
# fn bind(_addr: &str) -> Result<(), CustomIOError> {
# Err(CustomIOError)
# }
use pyo3::exceptions::PyOSError;
use pyo3::prelude::*;
use std::fmt;
#[derive(Debug)]
struct CustomIOError;
impl std::error::Error for CustomIOError {}
impl fmt::Display for CustomIOError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "Oh no!")
}
}
impl std::convert::From<CustomIOError> for PyErr {
fn from(err: CustomIOError) -> PyErr {
PyOSError::new_err(err.to_string())
}
}
pub struct Connection { /* ... */}
fn bind(addr: String) -> Result<Connection, CustomIOError> {
if &addr == "0.0.0.0"{
Err(CustomIOError)
} else {
Ok(Connection{ /* ... */})
}
}
#[pyfunction]
fn connect(s: String) -> Result<bool, CustomIOError> {
bind("127.0.0.1:80")?;
Ok(true)
fn connect(s: String) -> Result<(), CustomIOError> {
bind(s)?;
Ok(())
}
fn main() {
Python::with_gil(|py| {
let fun = pyo3::wrap_pyfunction!(connect, py).unwrap();
let err = fun.call1(("0.0.0.0",)).unwrap_err();
assert!(err.is_instance::<PyOSError>(py));
});
}
```
The code snippet above will raise an `OSError` in Python if `bind()` returns a `CustomIOError`.
The `std::convert::From<T>` trait is implemented for most of the Rust standard library's error
types so the `?` operator can be used.
This has been implemented for most of Rust's standard library errors, so that you can use the `?`
("try") operator with them. The following code snippet will raise a `ValueError` in Python if
`String::parse()` returns an error.
```rust
use pyo3::prelude::*;
@ -176,10 +199,27 @@ use pyo3::prelude::*;
fn parse_int(s: String) -> PyResult<usize> {
Ok(s.parse::<usize>()?)
}
#
# use pyo3::exceptions::PyValueError;
#
# fn main() {
# Python::with_gil(|py| {
# assert_eq!(parse_int(String::from("1")).unwrap(), 1);
# assert_eq!(parse_int(String::from("1337")).unwrap(), 1337);
#
# assert!(parse_int(String::from("-1"))
# .unwrap_err()
# .is_instance::<PyValueError>(py));
# assert!(parse_int(String::from("foo"))
# .unwrap_err()
# .is_instance::<PyValueError>(py));
# assert!(parse_int(String::from("13.37"))
# .unwrap_err()
# .is_instance::<PyValueError>(py));
# })
# }
```
The code snippet above will raise a `ValueError` in Python if `String::parse()` returns an error.
If lazy construction of the Python exception instance is desired, the
[`PyErrArguments`]({{#PYO3_DOCS_URL}}/pyo3/trait.PyErrArguments.html)
trait can be implemented. In that case, actual exception argument creation is delayed
@ -192,6 +232,7 @@ The `import_exception!` macro allows importing a specific exception class and de
for that exception.
```rust
#![allow(dead_code)]
use pyo3::prelude::*;
mod io {
@ -199,8 +240,6 @@ mod io {
}
fn tell(file: &PyAny) -> PyResult<u64> {
use pyo3::exceptions::*;
match file.call_method0("tell") {
Err(_) => Err(io::UnsupportedOperation::new_err("not supported: tell")),
Ok(x) => x.extract::<u64>(),
@ -216,6 +255,7 @@ defines exceptions for several standard library modules.
[`import_exception!`]: {{#PYO3_DOCS_URL}}/pyo3/macro.import_exception.html
[`PyErr`]: {{#PYO3_DOCS_URL}}/pyo3/struct.PyErr.html
[`PyResult`]: {{#PYO3_DOCS_URL}}/pyo3/type.PyResult.html
[`PyErr::from_instance`]: {{#PYO3_DOCS_URL}}/pyo3/struct.PyErr.html#method.from_instance
[`Python::is_instance`]: {{#PYO3_DOCS_URL}}/pyo3/struct.Python.html#method.is_instance
[`PyAny::is_instance`]: {{#PYO3_DOCS_URL}}/pyo3/struct.PyAny.html#method.is_instance

View File

@ -102,8 +102,6 @@ fn module_with_functions(py: Python, m: &PyModule) -> PyResult<()> {
m.add_function(wrap_pyfunction!(num_kwds, m)?).unwrap();
Ok(())
}
# fn main() {}
```
## Making the function signature available to Python
@ -123,16 +121,34 @@ use pyo3::prelude::*;
fn add(a: u64, b: u64) -> u64 {
a + b
}
#
# fn main() -> PyResult<()> {
# Python::with_gil(|py| {
# let fun = pyo3::wrap_pyfunction!(add, py)?;
#
# let doc: String = fun.getattr("__doc__")?.extract()?;
# assert_eq!(doc, "This function adds two unsigned 64-bit integers.");
#
# let inspect = PyModule::import(py, "inspect")?.getattr("signature")?;
# let sig: String = inspect
# .call1((fun,))?
# .call_method0("__str__")?
# .extract()?;
# assert_eq!(sig, "(a, b, /)");
#
# Ok(())
# })
# }
```
This also works for classes and methods:
```rust
# #![allow(dead_code)]
use pyo3::prelude::*;
use pyo3::types::PyType;
// it works even if the item is not documented:
#[pyclass]
#[pyo3(text_signature = "(c, d, /)")]
struct MyClass {}
@ -161,6 +177,69 @@ impl MyClass {
e + f
}
}
#
# fn main() -> PyResult<()> {
# Python::with_gil(|py| {
# let inspect = PyModule::import(py, "inspect")?.getattr("signature")?;
# let module = PyModule::new(py, "my_module")?;
# module.add_class::<MyClass>()?;
# let class = module.getattr("MyClass")?;
#
# if cfg!(not(Py_LIMITED_API)) || py.version_info() >= (3, 10) {
# let doc: String = class.getattr("__doc__")?.extract()?;
# assert_eq!(doc, "");
#
# let sig: String = inspect
# .call1((class,))?
# .call_method0("__str__")?
# .extract()?;
# assert_eq!(sig, "(c, d, /)");
# } else {
# let doc: String = class.getattr("__doc__")?.extract()?;
# assert_eq!(doc, "");
#
# inspect.call1((class,)).expect_err("`text_signature` on classes is not compatible with compilation in `abi3` mode until Python 3.10 or greater");
# }
#
# {
# let method = class.getattr("my_method")?;
#
# assert!(method.getattr("__doc__")?.is_none());
#
# let sig: String = inspect
# .call1((method,))?
# .call_method0("__str__")?
# .extract()?;
# assert_eq!(sig, "(self, /, e, f)");
# }
#
# {
# let method = class.getattr("my_class_method")?;
#
# assert!(method.getattr("__doc__")?.is_none());
#
# let sig: String = inspect
# .call1((method,))?
# .call_method0("__str__")?
# .extract()?;
# assert_eq!(sig, "(cls, e, f)");
# }
#
# {
# let method = class.getattr("my_static_method")?;
#
# assert!(method.getattr("__doc__")?.is_none());
#
# let sig: String = inspect
# .call1((method,))?
# .call_method0("__str__")?
# .extract()?;
# assert_eq!(sig, "(e, f)");
# }
#
# Ok(())
# })
# }
```
Note that `text_signature` on classes is not compatible with compilation in
@ -176,6 +255,7 @@ formatted like in the following example. Please note that the newline after the
generated signatures when those are added in a future version of PyO3.
```rust
# #![allow(dead_code)]
use pyo3::prelude::*;
/// add(a, b, /)
@ -262,8 +342,6 @@ fn pyfunction_with_module(module: &PyModule) -> PyResult<&str> {
fn module_with_fn(py: Python, m: &PyModule) -> PyResult<()> {
m.add_function(wrap_pyfunction!(pyfunction_with_module, m)?)
}
# fn main() {}
```
If `pass_module` is set, the first argument **must** be the `&PyModule`. It is then possible to use the module

View File

@ -146,7 +146,7 @@ let result: PyResult<()> = PyErr::new::<TypeError, _>("error message").into();
After (also using the new reworked exception types; see the following section):
```rust
# use pyo3::{PyErr, PyResult, exceptions::PyTypeError};
# use pyo3::{PyResult, exceptions::PyTypeError};
let result: PyResult<()> = Err(PyTypeError::new_err("error message"));
```
@ -292,6 +292,7 @@ There can be two fixes:
After:
```rust
# #![allow(dead_code)]
use pyo3::prelude::*;
use std::sync::{Arc, Mutex};
@ -323,6 +324,7 @@ There can be two fixes:
After:
```rust
# #![allow(dead_code)]
use pyo3::prelude::*;
#[pyclass(unsendable)]
@ -433,6 +435,7 @@ rules of references.
Here is an example.
```rust
# use pyo3::prelude::*;
#[pyclass]
struct Names {
names: Vec<String>

View File

@ -92,9 +92,7 @@ pub(crate) fn register(py: Python, m: &PyModule) -> PyResult<()> {
}
#[pyclass]
struct SomeClass {
x: usize,
}
struct SomeClass {/* ... */}
# }
// src/osutil.rs

View File

@ -20,38 +20,43 @@ Both of these APIs take `args` and `kwargs` arguments (for positional and keywor
For convenience the [`Py<T>`](types.html#pyt-and-pyobject) smart pointer also exposes these same six API methods, but needs a `Python` token as an additional first argument to prove the GIL is held.
The example below shows a calling Python functions behind a `PyObject` (aka `Py<PyAny>`) reference:
The example below calls a Python function behind a `PyObject` (aka `Py<PyAny>`) reference:
```rust
use pyo3::prelude::*;
use pyo3::types::{PyDict, PyTuple};
use pyo3::types::PyTuple;
struct SomeObject;
impl SomeObject {
fn new(py: Python) -> PyObject {
PyDict::new(py).to_object(py)
}
}
fn main() {
fn main() -> PyResult<()> {
let arg1 = "arg1";
let arg2 = "arg2";
let arg3 = "arg3";
Python::with_gil(|py| {
let obj = SomeObject::new(py);
let fun: Py<PyAny> = PyModule::from_code(
py,
"def example(*args, **kwargs):
if args != ():
print('called with args', args)
if kwargs != {}:
print('called with kwargs', kwargs)
if args == () and kwargs == {}:
print('called with no arguments')",
"",
"",
)?.getattr("example")?.into();
// call object without empty arguments
obj.call0(py);
fun.call0(py)?;
// call object with PyTuple
let args = PyTuple::new(py, &[arg1, arg2, arg3]);
obj.call1(py, args);
fun.call1(py, args)?;
// pass arguments as rust tuple
let args = (arg1, arg2, arg3);
obj.call1(py, args);
});
fun.call1(py, args)?;
Ok(())
})
}
```
@ -61,39 +66,45 @@ For the `call` and `call_method` APIs, `kwargs` can be `None` or `Some(&PyDict)`
```rust
use pyo3::prelude::*;
use pyo3::types::{IntoPyDict, PyDict};
use pyo3::types::IntoPyDict;
use std::collections::HashMap;
struct SomeObject;
impl SomeObject {
fn new(py: Python) -> PyObject {
PyDict::new(py).to_object(py)
}
}
fn main() {
fn main() -> PyResult<()> {
let key1 = "key1";
let val1 = 1;
let key2 = "key2";
let val2 = 2;
Python::with_gil(|py| {
let obj = SomeObject::new(py);
let fun: Py<PyAny> = PyModule::from_code(
py,
"def example(*args, **kwargs):
if args != ():
print('called with args', args)
if kwargs != {}:
print('called with kwargs', kwargs)
if args == () and kwargs == {}:
print('called with no arguments')",
"",
"",
)?.getattr("example")?.into();
// call object with PyDict
let kwargs = [(key1, val1)].into_py_dict(py);
obj.call(py, (), Some(kwargs));
fun.call(py, (), Some(kwargs))?;
// pass arguments as Vec
let kwargs = vec![(key1, val1), (key2, val2)];
obj.call(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);
obj.call(py, (), Some(kwargs.into_py_dict(py)));
});
fun.call(py, (), Some(kwargs.into_py_dict(py)))?;
Ok(())
})
}
```
@ -128,7 +139,6 @@ and return the evaluated value as a `&PyAny` object.
```rust
use pyo3::prelude::*;
use pyo3::types::IntoPyDict;
# fn main() -> Result<(), ()> {
Python::with_gil(|py| {

View File

@ -23,6 +23,7 @@ Let's say we have a function `solve` that operates on a model and mutates its st
The argument of the function can be any model that implements the `Model` trait :
```rust
# #![allow(dead_code)]
pub trait Model {
fn set_variables(&mut self, inputs: &Vec<f64>);
fn compute(&mut self);
@ -117,6 +118,7 @@ Now that this bit is implemented, let's expose the model wrapper to Python.
Let's add the PyO3 annotations and add a constructor:
```rust
# #![allow(dead_code)]
# pub trait Model {
# fn set_variables(&mut self, inputs: &Vec<f64>);
# fn compute(&mut self);

View File

@ -66,7 +66,7 @@ a list:
```rust
# use pyo3::prelude::*;
# use pyo3::{Py, Python, PyAny, PyResult, types::PyList};
# use pyo3::types::PyList;
# Python::with_gil(|py| -> PyResult<()> {
let obj: &PyAny = PyList::empty(py);
@ -86,7 +86,7 @@ For a `&PyAny` object reference `any` where the underlying object is a `#[pyclas
```rust
# use pyo3::prelude::*;
# use pyo3::{Py, Python, PyAny, PyResult, types::PyList};
# use pyo3::{Py, Python, PyAny, PyResult};
# #[pyclass] #[derive(Clone)] struct MyClass { }
# Python::with_gil(|py| -> PyResult<()> {
let obj: &PyAny = Py::new(py, MyClass { })?.into_ref(py);
@ -236,7 +236,6 @@ so it also exposes all of the methods on `PyAny`.
```rust
# use pyo3::prelude::*;
# use pyo3::types::PyList;
# #[pyclass] struct MyClass { }
# Python::with_gil(|py| -> PyResult<()> {
let cell: &PyCell<MyClass> = PyCell::new(py, MyClass { })?;
@ -257,7 +256,6 @@ let _: &mut MyClass = &mut *py_ref_mut;
```rust
# use pyo3::prelude::*;
# use pyo3::types::PyList;
# #[pyclass] struct MyClass { }
# Python::with_gil(|py| -> PyResult<()> {
let cell: &PyCell<MyClass> = PyCell::new(py, MyClass { })?;

View File

@ -431,7 +431,6 @@ impl Parse for FieldPyO3Attribute {
impl FieldPyO3Attributes {
/// Extract the field attributes.
///
fn from_attrs(attrs: &[Attribute]) -> Result<Self> {
let mut getter = None;
let mut from_py_with = None;

View File

@ -2,7 +2,6 @@
//! Context manager api
//! Trait and support implementation for context manager api
//!
use crate::callback::IntoPyCallbackOutput;
use crate::{PyClass, PyObject};

View File

@ -1,7 +1,6 @@
// Copyright (c) 2017-present PyO3 Project and Contributors
//! Python GC support
//!
use crate::{ffi, AsPyPointer, PyCell, PyClass, Python};
use std::os::raw::{c_int, c_void};

View File

@ -17,13 +17,13 @@ use crate::{ffi, IntoPy, IntoPyPointer, PyClass, PyObject, Python};
/// the integers 1 to 5, before raising `StopIteration("Ended")`.
///
/// ```rust
/// use pyo3::class::iter::IterNextOutput;
/// use pyo3::prelude::*;
/// use pyo3::PyIterProtocol;
/// use pyo3::class::iter::IterNextOutput;
///
/// #[pyclass]
/// struct Iter {
/// count: usize
/// count: usize,
/// }
///
/// #[pyproto]

View File

@ -6,7 +6,6 @@
//! https://docs.python.org/3/c-api/typeobj.html#async-object-structures)
//!
//! [PEP-0492](https://www.python.org/dev/peps/pep-0492/)
//!
use crate::callback::IntoPyCallbackOutput;
use crate::derive_utils::TryFromPyCell;

View File

@ -17,7 +17,7 @@ use std::ptr::NonNull;
/// # Examples
///
/// ```
/// use pyo3::{AsPyPointer, prelude::*};
/// use pyo3::{prelude::*, AsPyPointer};
/// Python::with_gil(|py| {
/// let dict = pyo3::types::PyDict::new(py);
/// // All native object wrappers implement AsPyPointer!!!
@ -147,8 +147,8 @@ where
///
/// #[pyclass]
/// struct Number {
/// #[pyo3(get, set)]
/// value: i32,
/// #[pyo3(get, set)]
/// value: i32,
/// }
/// ```
/// Python code will see this as an instance of the `Number` class with a `value` attribute.
@ -161,14 +161,14 @@ where
/// use pyo3::prelude::*;
///
/// struct Number {
/// value: i32,
/// value: i32,
/// }
///
/// impl IntoPy<PyObject> for Number {
/// fn into_py(self, py: Python) -> PyObject {
/// // delegates to i32's IntoPy implementation.
/// self.value.into_py(py)
/// }
/// }
/// }
/// ```
/// Python code will see this as an `int` object.
@ -183,7 +183,7 @@ where
/// enum Value {
/// Integer(i32),
/// String(String),
/// None
/// None,
/// }
///
/// impl IntoPy<PyObject> for Value {
@ -191,10 +191,22 @@ where
/// match self {
/// Self::Integer(val) => val.into_py(py),
/// Self::String(val) => val.into_py(py),
/// Self::None => py.None()
/// Self::None => py.None(),
/// }
/// }
/// }
/// }
/// # fn main() {
/// # Python::with_gil(|py| {
/// # let v = Value::Integer(73).into_py(py);
/// # let v = v.extract::<i32>(py).unwrap();
/// #
/// # let v = Value::String("foo".into()).into_py(py);
/// # let v = v.extract::<String>(py).unwrap();
/// #
/// # let v = Value::None.into_py(py);
/// # let v = v.extract::<Option<Vec<i32>>>(py).unwrap();
/// # });
/// # }
/// ```
/// Python code will see this as any of the `int`, `string` or `None` objects.
#[cfg_attr(docsrs, doc(alias = "IntoPyCallbackOutput"))]

View File

@ -35,7 +35,6 @@
//! Using [indexmap](https://docs.rs/indexmap) to return a dictionary with some statistics
//! about a list of numbers. Because of the insertion order guarantees, the Python code will
//! always print the same result, matching users' expectations about Python's dict.
//!
//! ```rust
//! use indexmap::{indexmap, IndexMap};
//! use pyo3::prelude::*;
@ -43,7 +42,7 @@
//! fn median(data: &Vec<i32>) -> f32 {
//! let sorted_data = data.clone().sort();
//! let mid = data.len() / 2;
//! if (data.len() % 2 == 0) {
//! if data.len() % 2 == 0 {
//! data[mid] as f32
//! }
//! else {

View File

@ -35,7 +35,6 @@
//! Using [`BigInt`] to correctly increment an arbitrary precision integer.
//! This is not possible with Rust's native integers if the Python integer is too large,
//! in which case it will fail its conversion and raise `OverflowError`.
//!
//! ```rust
//! use num_bigint::BigInt;
//! use pyo3::prelude::*;

View File

@ -29,7 +29,6 @@
//!
//! Using [num-complex](https://docs.rs/num-complex) and [nalgebra](https://docs.rs/nalgebra)
//! to create a pyfunction that calculates the eigenvalues of a 2x2 matrix.
//!
//! ```ignore
//! # // not tested because nalgebra isn't supported on msrv
//! # // please file an issue if it breaks!

View File

@ -114,10 +114,10 @@ impl PyErr {
///
/// # Examples
/// ```rust
/// use pyo3::{Python, PyErr, IntoPy, exceptions::PyTypeError, types::PyType};
/// use pyo3::{exceptions::PyTypeError, types::PyType, IntoPy, PyErr, Python};
/// Python::with_gil(|py| {
/// // Case #1: Exception instance
/// let err = PyErr::from_instance(PyTypeError::new_err("some type error",).instance(py));
/// let err = PyErr::from_instance(PyTypeError::new_err("some type error").instance(py));
/// assert_eq!(err.to_string(), "TypeError: some type error");
///
/// // Case #2: Exception type
@ -126,7 +126,10 @@ impl PyErr {
///
/// // Case #3: Invalid exception value
/// let err = PyErr::from_instance("foo".into_py(py).as_ref(py));
/// assert_eq!(err.to_string(), "TypeError: exceptions must derive from BaseException");
/// assert_eq!(
/// err.to_string(),
/// "TypeError: exceptions must derive from BaseException"
/// );
/// });
/// ```
pub fn from_instance(obj: &PyAny) -> PyErr {
@ -159,9 +162,10 @@ impl PyErr {
///
/// # Examples
/// ```rust
/// use pyo3::{Python, PyErr, exceptions::PyTypeError, types::PyType};
/// use pyo3::{exceptions::PyTypeError, types::PyType, PyErr, Python};
///
/// Python::with_gil(|py| {
/// let err = PyTypeError::new_err(("some type error",));
/// let err: PyErr = PyTypeError::new_err(("some type error",));
/// assert_eq!(err.ptype(py), PyType::new::<PyTypeError>(py));
/// });
/// ```
@ -174,10 +178,12 @@ impl PyErr {
/// The object will be normalized first if needed.
///
/// # Examples
///
/// ```rust
/// use pyo3::{Python, PyErr, exceptions::PyTypeError, types::PyType};
/// use pyo3::{exceptions::PyTypeError, PyErr, Python};
///
/// Python::with_gil(|py| {
/// let err = PyTypeError::new_err(("some type error",));
/// let err: PyErr = PyTypeError::new_err(("some type error",));
/// assert!(err.is_instance::<PyTypeError>(py));
/// assert_eq!(err.pvalue(py).to_string(), "some type error");
/// });
@ -192,7 +198,8 @@ impl PyErr {
///
/// # Examples
/// ```rust
/// use pyo3::{Python, PyErr, exceptions::PyTypeError, types::PyType};
/// use pyo3::{exceptions::PyTypeError, Python};
///
/// Python::with_gil(|py| {
/// let err = PyTypeError::new_err(("some type error",));
/// assert_eq!(err.ptraceback(py), None);
@ -403,9 +410,9 @@ impl PyErr {
///
/// # Examples
/// ```rust
/// use pyo3::{Python, PyErr, exceptions::PyTypeError, types::PyType};
/// use pyo3::{exceptions::PyTypeError, PyErr, Python};
/// Python::with_gil(|py| {
/// let err = PyTypeError::new_err(("some type error",));
/// let err: PyErr = PyTypeError::new_err(("some type error",));
/// let err_clone = err.clone_ref(py);
/// assert_eq!(err.ptype(py), err_clone.ptype(py));
/// assert_eq!(err.pvalue(py), err_clone.pvalue(py));

View File

@ -80,7 +80,7 @@ mod bufferinfo {
/* Flags for getting buffers */
pub const PyBUF_SIMPLE: c_int = 0;
pub const PyBUF_WRITABLE: c_int = 0x0001;
/* we used to include an E, backwards compatible alias */
/* we used to include an E, backwards compatible alias */
pub const PyBUF_WRITEABLE: c_int = PyBUF_WRITABLE;
pub const PyBUF_FORMAT: c_int = 0x0004;
pub const PyBUF_ND: c_int = 0x0008;

View File

@ -63,13 +63,10 @@ pub(crate) fn gil_is_acquired() -> bool {
/// ```rust
/// use pyo3::prelude::*;
///
/// # #[allow(clippy::needless_doctest_main)]
/// fn main() {
/// pyo3::prepare_freethreaded_python();
/// Python::with_gil(|py| {
/// py.run("print('Hello World')", None, None)
/// });
/// }
/// # fn main() -> PyResult<()>{
/// pyo3::prepare_freethreaded_python();
/// Python::with_gil(|py| py.run("print('Hello World')", None, None))
/// # }
/// ```
#[cfg(not(PyPy))]
#[cfg_attr(docsrs, doc(cfg(not(PyPy))))]
@ -131,14 +128,11 @@ pub fn prepare_freethreaded_python() {
/// ```rust
/// use pyo3::prelude::*;
///
/// # #[allow(clippy::needless_doctest_main)]
/// fn main() {
/// unsafe {
/// pyo3::with_embedded_python_interpreter(|py| {
/// py.run("print('Hello World')", None, None)
/// });
/// }
/// # fn main() -> PyResult<()>{
/// unsafe {
/// pyo3::with_embedded_python_interpreter(|py| py.run("print('Hello World')", None, None))
/// }
/// # }
/// ```
#[cfg(not(PyPy))]
#[cfg_attr(docsrs, doc(cfg(not(PyPy))))]

View File

@ -84,44 +84,74 @@ pub unsafe trait PyNativeType: Sized {
/// [`Py`]`<T>` can be used to get around this by converting `dict` into a GIL-independent reference:
///
/// ```rust
/// # use pyo3::prelude::*;
/// # use pyo3::types::PyDict;
/// #
/// use pyo3::prelude::*;
/// use pyo3::types::PyDict;
///
/// #[pyclass]
/// struct Foo {
/// inner: Py<PyDict>,
/// }
///
/// #[pymethods]
/// impl Foo {
/// fn new() -> Foo {
/// #[new]
/// fn __new__() -> Foo {
/// Python::with_gil(|py| {
/// let dict: Py<PyDict> = PyDict::new(py).into();
/// Foo { inner: dict }
/// })
/// }
/// }
/// #
/// # fn main() -> PyResult<()> {
/// # Python::with_gil(|py| {
/// # let m = pyo3::types::PyModule::new(py, "test")?;
/// # m.add_class::<Foo>()?;
/// #
/// # let foo: &PyCell<Foo> = pyo3::PyTryFrom::try_from(m.getattr("Foo")?.call0()?)?;
/// # let dict = &foo.borrow().inner;
/// # let dict: &PyDict = dict.as_ref(py);
/// #
/// # Ok(())
/// # })
/// # }
/// ```
///
/// This can also be done with other pyclasses:
/// ```rust
/// # use pyo3::prelude::*;
/// #
/// use pyo3::prelude::*;
///
/// #[pyclass]
/// struct Bar {/* fields omitted */}
/// struct Bar {/* ... */}
///
/// #[pyclass]
/// struct Foo {
/// inner: Py<Bar>,
/// }
///
/// #[pymethods]
/// impl Foo {
/// fn new() -> PyResult<Foo> {
/// #[new]
/// fn __new__() -> PyResult<Foo> {
/// Python::with_gil(|py| {
/// let bar: Py<Bar> = Py::new(py, Bar {})?;
/// Ok(Foo { inner: bar })
/// })
/// }
/// }
/// #
/// # fn main() -> PyResult<()> {
/// # Python::with_gil(|py| {
/// # let m = pyo3::types::PyModule::new(py, "test")?;
/// # m.add_class::<Foo>()?;
/// #
/// # let foo: &PyCell<Foo> = pyo3::PyTryFrom::try_from(m.getattr("Foo")?.call0()?)?;
/// # let bar = &foo.borrow().inner;
/// # let bar: &Bar = &*bar.borrow(py);
/// #
/// # Ok(())
/// # })
/// # }
/// ```
///
/// # Example: Shared ownership of Python objects
@ -134,9 +164,9 @@ pub unsafe trait PyNativeType: Sized {
/// [`Py::clone_ref`] will be faster if you happen to be already holding the GIL.
///
/// ```rust
/// use pyo3::conversion::AsPyPointer;
/// use pyo3::prelude::*;
/// use pyo3::types::PyDict;
/// use pyo3::conversion::AsPyPointer;
///
/// # fn main() {
/// Python::with_gil(|py| {
@ -259,10 +289,10 @@ where
/// # use pyo3::prelude::*;
/// #
/// #[pyclass]
/// struct MyClass { }
/// struct MyClass {}
///
/// Python::with_gil(|py| {
/// let my_class: Py<MyClass> = Py::new(py, MyClass { }).unwrap();
/// let my_class: Py<MyClass> = Py::new(py, MyClass {}).unwrap();
/// let my_class_cell: &PyCell<MyClass> = my_class.as_ref(py);
/// assert!(my_class_cell.try_borrow().is_ok());
/// });
@ -304,7 +334,7 @@ where
///
/// ```rust
/// # use pyo3::prelude::*;
/// #
/// # #[allow(dead_code)] // This is just to show it compiles.
/// fn new_py_any<'py>(py: Python<'py>, value: impl IntoPy<Py<PyAny>>) -> &'py PyAny {
/// let obj: Py<PyAny> = value.into_py(py);
///
@ -441,9 +471,9 @@ impl<T> Py<T> {
/// # Examples
///
/// ```rust
/// use pyo3::conversion::AsPyPointer;
/// use pyo3::prelude::*;
/// use pyo3::types::PyDict;
/// use pyo3::conversion::AsPyPointer;
///
/// # fn main() {
/// Python::with_gil(|py| {

View File

@ -8,6 +8,9 @@
rustdoc::bare_urls
)
)]
// Deny some lints in doctests.
// Use `#[allow(...)]` locally to override.
#![doc(test(attr(deny(warnings), allow(unused_variables, unused_assignments))))]
//! Rust bindings to the Python interpreter.
//!
@ -143,7 +146,6 @@
//! ```
//!
//! **`src/lib.rs`**
//!
//! ```rust
//! use pyo3::prelude::*;
//!
@ -165,7 +167,6 @@
//! With those two files in place, now `maturin` needs to be installed. This can be done using
//! Python's package manager `pip`. First, load up a new Python `virtualenv`, and install `maturin`
//! into it:
//!
//! ```bash
//! $ cd string_sum
//! $ python -m venv .env
@ -174,7 +175,6 @@
//! ```
//!
//! Now build and execute the module:
//!
//! ```bash
//! $ maturin develop
//! # lots of progress output as maturin runs the compilation...
@ -195,13 +195,11 @@
//! some example code which runs an embedded Python interpreter.
//!
//! To install the Python shared library on Ubuntu:
//!
//! ```bash
//! sudo apt install python3-dev
//! ```
//!
//! Start a new project with `cargo new` and add `pyo3` to the `Cargo.toml` like this:
//!
//! ```toml
//! [dependencies.pyo3]
// workaround for `extended_key_value_attributes`: https://github.com/rust-lang/rust/issues/82768#issuecomment-803935643
@ -212,7 +210,6 @@
//! ```
//!
//! Example program displaying the value of `sys.version` and the current user name:
//!
//! ```rust
//! use pyo3::prelude::*;
//! use pyo3::types::IntoPyDict;
@ -220,7 +217,7 @@
//! fn main() -> PyResult<()> {
//! Python::with_gil(|py| {
//! let sys = py.import("sys")?;
//! let version: String = sys.get("version")?.extract()?;
//! let version: String = sys.getattr("version")?.extract()?;
//!
//! let locals = [("os", py.import("os")?)].into_py_dict(py);
//! let code = "os.getenv('USER') or os.getenv('USERNAME') or 'Unknown'";
@ -390,6 +387,7 @@ pub mod doc_test {
"guide/src/conversions/tables.md",
guide_conversions_tables_md
);
doctest!(
"guide/src/conversions/traits.md",
guide_conversions_traits_md

View File

@ -97,12 +97,14 @@ macro_rules! wrap_pymodule {
/// #[pymethods]
/// impl MyClass {
/// #[new]
/// fn new() -> Self { MyClass {} }
/// fn new() -> Self {
/// MyClass {}
/// }
/// }
///
/// Python::with_gil(|py| {
/// let locals = [("C", py.get_type::<MyClass>())].into_py_dict(py);
/// pyo3::py_run!(py, *locals, "c = C()");
/// let locals = [("C", py.get_type::<MyClass>())].into_py_dict(py);
/// pyo3::py_run!(py, *locals, "c = C()");
/// });
/// ```
#[macro_export]

View File

@ -15,9 +15,9 @@ use std::cell::UnsafeCell;
/// between threads:
///
/// ```
/// use pyo3::once_cell::GILOnceCell;
/// use pyo3::prelude::*;
/// use pyo3::types::PyList;
/// use pyo3::once_cell::GILOnceCell;
///
/// static LIST_CELL: GILOnceCell<Py<PyList>> = GILOnceCell::new();
///

View File

@ -107,6 +107,16 @@
//! fn swap_numbers(a: &mut Number, b: &mut Number) {
//! std::mem::swap(&mut a.inner, &mut b.inner);
//! }
//! # use pyo3::AsPyPointer;
//! # fn main() {
//! # Python::with_gil(|py|{
//! # let n = Py::new(py, Number{inner: 35}).unwrap();
//! # let n2 = n.clone_ref(py);
//! # assert_eq!(n.as_ptr(), n2.as_ptr());
//! # let fun = pyo3::wrap_pyfunction!(swap_numbers, py).unwrap();
//! # fun.call1((n, n2)).expect_err("Managed to create overlapping mutable references. Note: this is undefined behaviour.");
//! # });
//! # }
//! ```
//! When users pass in the same `Number` as both arguments, one of the mutable borrows will
//! fail and raise a `RuntimeError`:
@ -119,7 +129,7 @@
//! ```
//!
//! It is better to write that function like this:
//! ```
//! ```rust
//! # use pyo3::prelude::*;
//! # #[pyclass]
//! # pub struct Number {
@ -128,12 +138,36 @@
//! #[pyfunction]
//! fn swap_numbers(a: &PyCell<Number>, b: &PyCell<Number>) {
//! // Check that the pointers are unequal
//! if a.as_ref() != b.as_ref() {
//! if a.as_ptr() != b.as_ptr() {
//! std::mem::swap(&mut a.borrow_mut().inner, &mut b.borrow_mut().inner);
//! } else {
//! // Do nothing - they are the same object, so don't need swapping.
//! }
//! }
//! # use pyo3::AsPyPointer;
//! # fn main() {
//! # // With duplicate numbers
//! # Python::with_gil(|py|{
//! # let n = Py::new(py, Number{inner: 35}).unwrap();
//! # let n2 = n.clone_ref(py);
//! # assert_eq!(n.as_ptr(), n2.as_ptr());
//! # let fun = pyo3::wrap_pyfunction!(swap_numbers, py).unwrap();
//! # fun.call1((n, n2)).unwrap();
//! # });
//! #
//! # // With two different numbers
//! # Python::with_gil(|py|{
//! # let n = Py::new(py, Number{inner: 35}).unwrap();
//! # let n2 = Py::new(py, Number{inner: 42}).unwrap();
//! # assert_ne!(n.as_ptr(), n2.as_ptr());
//! # let fun = pyo3::wrap_pyfunction!(swap_numbers, py).unwrap();
//! # fun.call1((&n, &n2)).unwrap();
//! # let n: u32 = n.borrow(py).inner;
//! # let n2: u32 = n2.borrow(py).inner;
//! # assert_eq!(n, 42);
//! # assert_eq!(n2, 35);
//! # });
//! # }
//! ```
//! See the [guide] for more information.
//!
@ -607,18 +641,18 @@ where
/// #[pyclass(extends=Base1, subclass)]
/// struct Base2 {
/// name2: &'static str,
/// }
/// }
///
/// #[pyclass(extends=Base2)]
/// struct Sub {
/// name3: &'static str,
/// }
/// }
///
/// #[pymethods]
/// impl Sub {
/// #[new]
/// fn new() -> PyClassInitializer<Self> {
/// PyClassInitializer::from(Base1{ name1: "base1" })
/// PyClassInitializer::from(Base1 { name1: "base1" })
/// .add_subclass(Base2 { name2: "base2" })
/// .add_subclass(Self { name3: "sub" })
/// }

View File

@ -85,7 +85,6 @@ 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)]
@ -108,7 +107,9 @@ impl<T: PyTypeInfo> PyObjectInit<T> for PyNativeTypeInitializer<T> {
/// fn new() -> PyClassInitializer<Self> {
/// PyClassInitializer::from(BaseClass { basename: "base" })
/// .add_subclass(SubClass { subname: "sub" })
/// .add_subclass(SubSubClass { subsubname: "subsub" })
/// .add_subclass(SubSubClass {
/// subsubname: "subsub",
/// })
/// }
/// }
/// Python::with_gil(|py| {
@ -141,19 +142,20 @@ impl<T: PyClass> PyClassInitializer<T> {
///
/// # Examples
/// ```
/// # use pyo3::prelude::*;
/// #[pyclass]
/// use pyo3::prelude::*;
///
/// #[pyclass(subclass)]
/// struct BaseClass {
/// value: u32,
/// #[pyo3(get)]
/// value: i32,
/// }
///
/// impl BaseClass {
/// fn new(value: i32) -> PyResult<Self> {
/// Ok(Self {
/// value: std::convert::TryFrom::try_from(value)?,
/// })
/// Ok(Self { value })
/// }
/// }
///
/// #[pyclass(extends=BaseClass)]
/// struct SubClass {}
///
@ -165,6 +167,22 @@ impl<T: PyClass> PyClassInitializer<T> {
/// Ok(base_init.add_subclass(SubClass {}))
/// }
/// }
///
/// fn main() -> PyResult<()> {
/// Python::with_gil(|py| {
/// let m = PyModule::new(py, "example")?;
/// m.add_class::<SubClass>()?;
/// m.add_class::<BaseClass>()?;
///
/// let instance = m.getattr("SubClass")?.call1((92,))?;
///
/// // `SubClass` does not have a `value` attribute, but `BaseClass` does.
/// let n = instance.getattr("value")?.extract::<i32>()?;
/// assert_eq!(n, 92);
///
/// Ok(())
/// })
/// }
/// ```
pub fn add_subclass<S>(self, subclass_value: S) -> PyClassInitializer<S>
where

View File

@ -180,11 +180,14 @@ impl Python<'_> {
/// # Examples
/// ```
/// use pyo3::prelude::*;
///
/// # fn main() -> PyResult<()> {
/// Python::with_gil(|py| -> PyResult<()> {
/// let x: i32 = py.eval("5", None, None)?.extract()?;
/// assert_eq!(x, 5);
/// Ok(())
/// });
/// })
/// # }
/// ```
#[inline]
pub fn with_gil<F, R>(f: F) -> R
@ -250,18 +253,18 @@ impl<'p> Python<'p> {
/// Temporarily releases the `GIL`, thus allowing other Python threads to run.
///
/// # Examples
///
/// ```
/// # use pyo3::prelude::*; use pyo3::types::IntoPyDict;
/// use pyo3::exceptions::PyRuntimeError;
/// use std::sync::Arc;
/// use std::thread;
///
/// #[pyfunction]
/// fn parallel_count(py: Python<'_>, strings: Vec<String>, query: String) -> PyResult<usize> {
/// let query = query.chars().next().unwrap();
/// py.allow_threads(move || {
/// let threads: Vec<_> = strings
/// .into_iter()
/// .map(|s| thread::spawn(move || s.chars().filter(|&c| c == query).count()))
/// .map(|s| std::thread::spawn(move || s.chars().filter(|&c| c == query).count()))
/// .collect();
/// let mut sum = 0;
/// for t in threads {
@ -273,12 +276,17 @@ impl<'p> Python<'p> {
///
/// Python::with_gil(|py| {
/// 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);
/// pyo3::py_run!(py, *locals, r#"
/// pyo3::py_run!(
/// py,
/// *locals,
/// r#"
/// s = ["Flow", "my", "tears", "the", "Policeman", "Said"]
/// assert pcount.parallel_count(s, "a") == 3
/// "#);
/// "#
/// );
/// });
/// ```
///
@ -341,8 +349,9 @@ impl<'p> Python<'p> {
/// If `locals` is `None`, it defaults to the value of `globals`.
///
/// # Examples
///
/// ```
/// # use pyo3::{types::{PyBytes, PyDict}, prelude::*};
/// # use pyo3::prelude::*;
/// # 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();
@ -365,7 +374,10 @@ impl<'p> Python<'p> {
///
/// # Examples
/// ```
/// use pyo3::{types::{PyBytes, PyDict}, prelude::*};
/// use pyo3::{
/// prelude::*,
/// types::{PyBytes, PyDict},
/// };
/// Python::with_gil(|py| {
/// let locals = PyDict::new(py);
/// py.run(
@ -374,8 +386,8 @@ impl<'p> Python<'p> {
/// s = 'Hello Rust!'
/// ret = base64.b64encode(s.encode('utf-8'))
/// "#,
/// None,
/// Some(locals),
/// None,
/// Some(locals),
/// )
/// .unwrap();
/// let ret = locals.get_item("ret").unwrap();
@ -631,7 +643,9 @@ impl<'p> Python<'p> {
/// # Example
///
/// ```rust
/// # #![allow(dead_code)] // this example is quite impractical to test
/// use pyo3::prelude::*;
///
/// # fn main(){
/// #[pyfunction]
/// fn loop_forever(py: Python) -> PyResult<()> {
@ -699,7 +713,7 @@ impl<'p> Python<'p> {
///
/// // 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() };
/// let py = pool.python();
///
/// // do stuff...
/// # break; // Exit the loop so that doctest terminates!

View File

@ -219,25 +219,21 @@ impl PyAny {
/// Depending on the value of `compare_op`, this is equivalent to one of the
/// following Python expressions:
///
/// <div style="width:1px">
///
/// | `compare_op` | <span style="white-space: pre">Python expression</span> |
/// | `compare_op` | Python expression |
/// | :---: | :----: |
/// | [`CompareOp::Eq`] | <span style="white-space: pre">`self == other`</span> |
/// | [`CompareOp::Ne`] | <span style="white-space: pre">`self != other`</span> |
/// | [`CompareOp::Lt`] | <span style="white-space: pre">`self < other`</span> |
/// | [`CompareOp::Le`] | <span style="white-space: pre">`self <= other`</span> |
/// | [`CompareOp::Gt`] | <span style="white-space: pre">`self > other`</span> |
/// | [`CompareOp::Ge`] | <span style="white-space: pre">`self >= other`</span> |
///
/// </div>
/// | [`CompareOp::Eq`] | `self == other` |
/// | [`CompareOp::Ne`] | `self != other` |
/// | [`CompareOp::Lt`] | `self < other` |
/// | [`CompareOp::Le`] | `self <= other` |
/// | [`CompareOp::Gt`] | `self > other` |
/// | [`CompareOp::Ge`] | `self >= other` |
///
/// # Examples
///
/// ```rust
/// use pyo3::class::basic::CompareOp;
/// use pyo3::prelude::*;
/// use pyo3::types::PyInt;
/// use pyo3::class::basic::CompareOp;
///
/// # fn main() -> PyResult<()> {
/// Python::with_gil(|py| -> PyResult<()> {
@ -245,7 +241,7 @@ impl PyAny {
/// let b: &PyInt = 42_u8.into_py(py).into_ref(py).downcast()?;
/// assert!(a.rich_compare(b, CompareOp::Le)?.is_true()?);
/// Ok(())
/// })?;
/// })?;
/// # Ok(())}
/// ```
pub fn rich_compare<O>(&self, other: O, compare_op: CompareOp) -> PyResult<&PyAny>
@ -274,10 +270,10 @@ impl PyAny {
///
/// # fn main() -> PyResult<()> {
/// Python::with_gil(|py| -> PyResult<()> {
/// let builtins = PyModule::import(py, "builtins")?;
/// let print = builtins.getattr("print")?;
/// assert!(print.is_callable());
/// Ok(())
/// let builtins = PyModule::import(py, "builtins")?;
/// let print = builtins.getattr("print")?;
/// assert!(print.is_callable());
/// Ok(())
/// })?;
/// # Ok(())}
/// ```
@ -363,7 +359,7 @@ impl PyAny {
/// Python::with_gil(|py| -> PyResult<()> {
/// let module = PyModule::import(py, "operator")?;
/// let add = module.getattr("add")?;
/// let args = (1,2);
/// let args = (1, 2);
/// let value = add.call1(args)?;
/// assert_eq!(value.extract::<i32>()?, 3);
/// Ok(())
@ -391,8 +387,7 @@ impl PyAny {
///
/// ```rust
/// use pyo3::prelude::*;
/// use pyo3::types::{PyDict, PyList};
/// use crate::pyo3::types::IntoPyDict;
/// use pyo3::types::{IntoPyDict, PyList};
///
/// # fn main() -> PyResult<()> {
/// Python::with_gil(|py| -> PyResult<()> {

View File

@ -28,8 +28,11 @@ impl PyByteArray {
/// * If `init` returns `Ok(())`, `new_with` will return `Ok(&PyByteArray)`.
///
/// # Examples
///
/// ```
/// use pyo3::{prelude::*, types::PyByteArray};
///
/// # fn main() -> PyResult<()> {
/// Python::with_gil(|py| -> PyResult<()> {
/// let py_bytearray = PyByteArray::new_with(py, 10, |bytes: &mut [u8]| {
/// bytes.copy_from_slice(b"Hello Rust");
@ -38,7 +41,8 @@ impl PyByteArray {
/// let bytearray: &[u8] = unsafe { py_bytearray.as_bytes() };
/// assert_eq!(bytearray, b"Hello Rust");
/// Ok(())
/// });
/// })
/// # }
/// ```
pub fn new_with<F>(py: Python, len: usize, init: F) -> PyResult<&PyByteArray>
where

View File

@ -34,8 +34,11 @@ impl PyBytes {
/// * If `init` returns `Ok(())`, `new_with` will return `Ok(&PyBytes)`.
///
/// # Examples
///
/// ```
/// use pyo3::{prelude::*, types::PyBytes};
///
/// # fn main() -> PyResult<()> {
/// Python::with_gil(|py| -> PyResult<()> {
/// let py_bytes = PyBytes::new_with(py, 10, |bytes: &mut [u8]| {
/// bytes.copy_from_slice(b"Hello Rust");
@ -44,7 +47,8 @@ impl PyBytes {
/// let bytes: &[u8] = FromPyObject::extract(py_bytes)?;
/// assert_eq!(bytes, b"Hello Rust");
/// Ok(())
/// });
/// })
/// # }
/// ```
pub fn new_with<F>(py: Python, len: usize, init: F) -> PyResult<&PyBytes>
where

View File

@ -11,18 +11,19 @@ use crate::{PyDowncastError, PyTryFrom};
/// # Examples
///
/// ```rust
/// # use pyo3::prelude::*;
/// use pyo3::types::PyIterator;
/// use pyo3::prelude::*;
///
/// # fn main() -> PyResult<()> {
/// Python::with_gil(|py| -> PyResult<()> {
/// Python::with_gil(|py| -> PyResult<()> {
/// let list = py.eval("iter([1, 2, 3, 4])", None, None)?;
/// let numbers: PyResult<Vec<usize>> = list.iter()?.map(|i| i.and_then(PyAny::extract::<usize>)).collect();
/// let numbers: PyResult<Vec<usize>> = list
/// .iter()?
/// .map(|i| i.and_then(PyAny::extract::<usize>))
/// .collect();
/// let sum: usize = numbers?.iter().sum();
/// assert_eq!(sum, 10);
/// Ok(())
/// });
/// # Ok(())
/// })
/// # }
/// ```
#[repr(transparent)]

View File

@ -64,7 +64,6 @@ impl PyModule {
/// ```
///
/// This is equivalent to the following Python expression:
///
/// ```python
/// import antigravity
/// ```
@ -99,12 +98,7 @@ impl PyModule {
///
/// # fn main() -> PyResult<()> {
/// Python::with_gil(|py| -> PyResult<()> {
/// let module = PyModule::from_code(
/// py,
/// "print(__file__, __name__)",
/// "my_file",
/// "my_module"
/// )?;
/// let module = PyModule::from_code(py, "print(__file__, __name__)", "my_file", "my_module")?;
/// Ok(())
/// })?;
/// # Ok(())}
@ -254,7 +248,6 @@ impl PyModule {
/// ```
///
/// Python code can see this class as such:
///
/// ```python
/// from my_module import Foo
///
@ -262,7 +255,6 @@ impl PyModule {
/// ```
///
/// This will result in the following output:
///
/// ```text
/// Foo is <class 'builtins.Foo'>
/// ```

View File

@ -110,13 +110,16 @@ impl PyTuple {
/// # Example
/// ```
/// use pyo3::{prelude::*, types::PyTuple};
///
/// # fn main() -> PyResult<()> {
/// Python::with_gil(|py| -> PyResult<()> {
/// let ob = (1, 2, 3).to_object(py);
/// let tuple = <PyTuple as PyTryFrom>::try_from(ob.as_ref(py)).unwrap();
/// let obj = tuple.get_item(0);
/// assert_eq!(obj.unwrap().extract::<i32>().unwrap(), 1);
/// Ok(())
/// });
/// })
/// # }
/// ```
pub fn get_item(&self, index: usize) -> PyResult<&PyAny> {
unsafe {