Add a nox task to rustfmt code in the guide.
Also apply it. Two caveats: 1) needs nightly rustfmt to be available 2) not all reformat diffs have been applied; using best judgment for readability.
This commit is contained in:
parent
8ca41be87b
commit
a7a53d6c0d
|
@ -24,12 +24,12 @@ more accompanying `#[pyo3(...)]` annotations, e.g.:
|
||||||
```rust,ignore
|
```rust,ignore
|
||||||
// Argument supplied directly to the `#[pyclass]` annotation.
|
// Argument supplied directly to the `#[pyclass]` annotation.
|
||||||
#[pyclass(name = "SomeName", subclass)]
|
#[pyclass(name = "SomeName", subclass)]
|
||||||
struct MyClass { }
|
struct MyClass {}
|
||||||
|
|
||||||
// Argument supplied as a separate annotation.
|
// Argument supplied as a separate annotation.
|
||||||
#[pyclass]
|
#[pyclass]
|
||||||
#[pyo3(name = "SomeName", subclass)]
|
#[pyo3(name = "SomeName", subclass)]
|
||||||
struct MyClass { }
|
struct MyClass {}
|
||||||
```
|
```
|
||||||
|
|
||||||
[params-1]: https://docs.rs/pyo3/latest/pyo3/struct.PyAny.html
|
[params-1]: https://docs.rs/pyo3/latest/pyo3/struct.PyAny.html
|
||||||
|
|
|
@ -115,7 +115,7 @@ The easiest way to set the correct linker arguments is to add a [`build.rs`](htt
|
||||||
|
|
||||||
```rust,ignore
|
```rust,ignore
|
||||||
fn main() {
|
fn main() {
|
||||||
pyo3_build_config::add_extension_module_link_args();
|
pyo3_build_config::add_extension_module_link_args();
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
|
@ -14,13 +14,13 @@ This allows us to write code like the following
|
||||||
|
|
||||||
```rust,ignore
|
```rust,ignore
|
||||||
#[cfg(Py_3_7)]
|
#[cfg(Py_3_7)]
|
||||||
fn function_only_supported_on_python_3_7_and_up() { }
|
fn function_only_supported_on_python_3_7_and_up() {}
|
||||||
|
|
||||||
#[cfg(not(Py_3_8))]
|
#[cfg(not(Py_3_8))]
|
||||||
fn function_only_supported_before_python_3_8() { }
|
fn function_only_supported_before_python_3_8() {}
|
||||||
|
|
||||||
#[cfg(not(Py_LIMITED_API))]
|
#[cfg(not(Py_LIMITED_API))]
|
||||||
fn function_incompatible_with_abi3_feature() { }
|
fn function_incompatible_with_abi3_feature() {}
|
||||||
```
|
```
|
||||||
|
|
||||||
The following sections first show how to add these `#[cfg]` flags to your build process, and then cover some common patterns flags in a little more detail.
|
The following sections first show how to add these `#[cfg]` flags to your build process, and then cover some common patterns flags in a little more detail.
|
||||||
|
@ -98,11 +98,10 @@ PyO3 provides the APIs [`Python::version()`] and [`Python::version_info()`] to q
|
||||||
use pyo3::Python;
|
use pyo3::Python;
|
||||||
|
|
||||||
Python::with_gil(|py| {
|
Python::with_gil(|py| {
|
||||||
// PyO3 supports Python 3.7 and up.
|
// PyO3 supports Python 3.7 and up.
|
||||||
assert!(py.version_info() >= (3, 7));
|
assert!(py.version_info() >= (3, 7));
|
||||||
assert!(py.version_info() >= (3, 7, 0));
|
assert!(py.version_info() >= (3, 7, 0));
|
||||||
});
|
});
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
[`Python::version()`]: {{#PYO3_DOCS_URL}}/pyo3/struct.Python.html#method.version
|
[`Python::version()`]: {{#PYO3_DOCS_URL}}/pyo3/struct.Python.html#method.version
|
||||||
|
|
|
@ -26,8 +26,8 @@ To define a custom Python class, add the `#[pyclass]` attribute to a Rust struct
|
||||||
use pyo3::prelude::*;
|
use pyo3::prelude::*;
|
||||||
|
|
||||||
#[pyclass]
|
#[pyclass]
|
||||||
struct Integer{
|
struct Integer {
|
||||||
inner: i32
|
inner: i32,
|
||||||
}
|
}
|
||||||
|
|
||||||
// A "tuple" struct
|
// A "tuple" struct
|
||||||
|
@ -166,7 +166,7 @@ struct MyClass {
|
||||||
num: i32,
|
num: i32,
|
||||||
}
|
}
|
||||||
Python::with_gil(|py| {
|
Python::with_gil(|py| {
|
||||||
let obj = PyCell::new(py, MyClass { num: 3}).unwrap();
|
let obj = PyCell::new(py, MyClass { num: 3 }).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);
|
||||||
|
@ -204,7 +204,7 @@ fn return_myclass() -> Py<MyClass> {
|
||||||
|
|
||||||
let obj = return_myclass();
|
let obj = return_myclass();
|
||||||
|
|
||||||
Python::with_gil(|py|{
|
Python::with_gil(|py| {
|
||||||
let cell = obj.as_ref(py); // Py<MyClass>::as_ref returns &PyCell<MyClass>
|
let cell = obj.as_ref(py); // Py<MyClass>::as_ref returns &PyCell<MyClass>
|
||||||
let obj_ref = cell.borrow(); // Get PyRef<T>
|
let obj_ref = cell.borrow(); // Get PyRef<T>
|
||||||
assert_eq!(obj_ref.num, 1);
|
assert_eq!(obj_ref.num, 1);
|
||||||
|
@ -279,7 +279,7 @@ impl SubClass {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn method2(self_: PyRef<'_, Self>) -> PyResult<usize> {
|
fn method2(self_: PyRef<'_, Self>) -> PyResult<usize> {
|
||||||
let super_ = self_.as_ref(); // Get &BaseClass
|
let super_ = self_.as_ref(); // Get &BaseClass
|
||||||
super_.method().map(|x| x * self_.val2)
|
super_.method().map(|x| x * self_.val2)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -293,13 +293,12 @@ struct SubSubClass {
|
||||||
impl SubSubClass {
|
impl SubSubClass {
|
||||||
#[new]
|
#[new]
|
||||||
fn new() -> PyClassInitializer<Self> {
|
fn new() -> PyClassInitializer<Self> {
|
||||||
PyClassInitializer::from(SubClass::new())
|
PyClassInitializer::from(SubClass::new()).add_subclass(SubSubClass { val3: 20 })
|
||||||
.add_subclass(SubSubClass{val3: 20})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn method3(self_: PyRef<'_, Self>) -> PyResult<usize> {
|
fn method3(self_: PyRef<'_, Self>) -> PyResult<usize> {
|
||||||
let v = self_.val3;
|
let v = self_.val3;
|
||||||
let super_ = self_.into_super(); // Get PyRef<'_, SubClass>
|
let super_ = self_.into_super(); // Get PyRef<'_, SubClass>
|
||||||
SubClass::method2(super_).map(|x| x * v)
|
SubClass::method2(super_).map(|x| x * v)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -426,7 +425,7 @@ For simple cases where a member variable is just read and written with no side e
|
||||||
#[pyclass]
|
#[pyclass]
|
||||||
struct MyClass {
|
struct MyClass {
|
||||||
#[pyo3(get, set)]
|
#[pyo3(get, set)]
|
||||||
num: i32
|
num: i32,
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -937,7 +936,7 @@ You may not use enums as a base class or let enums inherit from other classes.
|
||||||
```rust,compile_fail
|
```rust,compile_fail
|
||||||
# use pyo3::prelude::*;
|
# use pyo3::prelude::*;
|
||||||
#[pyclass(subclass)]
|
#[pyclass(subclass)]
|
||||||
enum BadBase{
|
enum BadBase {
|
||||||
Var1,
|
Var1,
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
@ -949,7 +948,7 @@ enum BadBase{
|
||||||
struct Base;
|
struct Base;
|
||||||
|
|
||||||
#[pyclass(extends=Base)]
|
#[pyclass(extends=Base)]
|
||||||
enum BadSubclass{
|
enum BadSubclass {
|
||||||
Var1,
|
Var1,
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
|
@ -395,7 +395,6 @@ fn my_module(_py: Python<'_>, m: &PyModule) -> PyResult<()> {
|
||||||
# Ok(())
|
# Ok(())
|
||||||
# })
|
# })
|
||||||
# }
|
# }
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
## Appendix: Writing some unsafe code
|
## Appendix: Writing some unsafe code
|
||||||
|
|
|
@ -40,10 +40,10 @@ print(n)
|
||||||
### String representations
|
### String representations
|
||||||
|
|
||||||
It can't even print an user-readable representation of itself! We can fix that by defining the
|
It can't even print an user-readable representation of itself! We can fix that by defining the
|
||||||
`__repr__` and `__str__` methods inside a `#[pymethods]` block. We do this by accessing the value
|
`__repr__` and `__str__` methods inside a `#[pymethods]` block. We do this by accessing the value
|
||||||
contained inside `Number`.
|
contained inside `Number`.
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
# use pyo3::prelude::*;
|
# use pyo3::prelude::*;
|
||||||
#
|
#
|
||||||
# #[pyclass]
|
# #[pyclass]
|
||||||
|
@ -114,13 +114,13 @@ impl Number {
|
||||||
> ```rust
|
> ```rust
|
||||||
> # use pyo3::prelude::*;
|
> # use pyo3::prelude::*;
|
||||||
> #[pyclass]
|
> #[pyclass]
|
||||||
> struct NotHashable { }
|
> struct NotHashable {}
|
||||||
>
|
>
|
||||||
> #[pymethods]
|
> #[pymethods]
|
||||||
> impl NotHashable {
|
> impl NotHashable {
|
||||||
> #[classattr]
|
> #[classattr]
|
||||||
> const __hash__: Option<Py<PyAny>> = None;
|
> const __hash__: Option<Py<PyAny>> = None;
|
||||||
>}
|
> }
|
||||||
> ```
|
> ```
|
||||||
|
|
||||||
### Comparisons
|
### Comparisons
|
||||||
|
|
|
@ -48,7 +48,7 @@ given signatures should be interpreted as follows:
|
||||||
# use pyo3::prelude::*;
|
# use pyo3::prelude::*;
|
||||||
#
|
#
|
||||||
#[pyclass]
|
#[pyclass]
|
||||||
struct NotHashable { }
|
struct NotHashable {}
|
||||||
|
|
||||||
#[pymethods]
|
#[pymethods]
|
||||||
impl NotHashable {
|
impl NotHashable {
|
||||||
|
@ -229,7 +229,7 @@ Use the `#[pyclass(sequence)]` annotation to instruct PyO3 to fill the `sq_lengt
|
||||||
# use pyo3::prelude::*;
|
# use pyo3::prelude::*;
|
||||||
#
|
#
|
||||||
#[pyclass]
|
#[pyclass]
|
||||||
struct NoContains { }
|
struct NoContains {}
|
||||||
|
|
||||||
#[pymethods]
|
#[pymethods]
|
||||||
impl NoContains {
|
impl NoContains {
|
||||||
|
|
|
@ -62,7 +62,7 @@ struct RustyStruct {
|
||||||
# "",
|
# "",
|
||||||
# "",
|
# "",
|
||||||
# )?;
|
# )?;
|
||||||
#
|
#
|
||||||
# let class = module.getattr("Foo")?;
|
# let class = module.getattr("Foo")?;
|
||||||
# let instance = class.call0()?;
|
# let instance = class.call0()?;
|
||||||
# let rustystruct: RustyStruct = instance.extract()?;
|
# let rustystruct: RustyStruct = instance.extract()?;
|
||||||
|
@ -77,7 +77,6 @@ By setting the `#[pyo3(item)]` attribute on the field, PyO3 will attempt to extr
|
||||||
```rust
|
```rust
|
||||||
use pyo3::prelude::*;
|
use pyo3::prelude::*;
|
||||||
|
|
||||||
|
|
||||||
#[derive(FromPyObject)]
|
#[derive(FromPyObject)]
|
||||||
struct RustyStruct {
|
struct RustyStruct {
|
||||||
#[pyo3(item)]
|
#[pyo3(item)]
|
||||||
|
@ -89,7 +88,7 @@ struct RustyStruct {
|
||||||
# Python::with_gil(|py| -> PyResult<()> {
|
# Python::with_gil(|py| -> PyResult<()> {
|
||||||
# let dict = PyDict::new(py);
|
# let dict = PyDict::new(py);
|
||||||
# dict.set_item("my_string", "test")?;
|
# dict.set_item("my_string", "test")?;
|
||||||
#
|
#
|
||||||
# let rustystruct: RustyStruct = dict.extract()?;
|
# let rustystruct: RustyStruct = dict.extract()?;
|
||||||
# assert_eq!(rustystruct.my_string, "test");
|
# assert_eq!(rustystruct.my_string, "test");
|
||||||
# Ok(())
|
# Ok(())
|
||||||
|
@ -109,7 +108,7 @@ struct RustyStruct {
|
||||||
#[pyo3(attribute("name"))]
|
#[pyo3(attribute("name"))]
|
||||||
string_attr: String,
|
string_attr: String,
|
||||||
}
|
}
|
||||||
#
|
#
|
||||||
# fn main() -> PyResult<()> {
|
# fn main() -> PyResult<()> {
|
||||||
# Python::with_gil(|py| -> PyResult<()> {
|
# Python::with_gil(|py| -> PyResult<()> {
|
||||||
# let module = PyModule::from_code(
|
# let module = PyModule::from_code(
|
||||||
|
@ -121,13 +120,13 @@ struct RustyStruct {
|
||||||
# "",
|
# "",
|
||||||
# "",
|
# "",
|
||||||
# )?;
|
# )?;
|
||||||
#
|
#
|
||||||
# let class = module.getattr("Foo")?;
|
# let class = module.getattr("Foo")?;
|
||||||
# let instance = class.call0()?;
|
# let instance = class.call0()?;
|
||||||
# let rustystruct: RustyStruct = instance.extract()?;
|
# let rustystruct: RustyStruct = instance.extract()?;
|
||||||
# assert_eq!(rustystruct.string_attr, "test");
|
# assert_eq!(rustystruct.string_attr, "test");
|
||||||
# assert_eq!(rustystruct.string_in_mapping, "test2");
|
# assert_eq!(rustystruct.string_in_mapping, "test2");
|
||||||
#
|
#
|
||||||
# Ok(())
|
# Ok(())
|
||||||
# })
|
# })
|
||||||
# }
|
# }
|
||||||
|
@ -154,11 +153,11 @@ struct RustyTuple(String, String);
|
||||||
# fn main() -> PyResult<()> {
|
# fn main() -> PyResult<()> {
|
||||||
# Python::with_gil(|py| -> PyResult<()> {
|
# Python::with_gil(|py| -> PyResult<()> {
|
||||||
# let tuple = PyTuple::new(py, vec!["test", "test2"]);
|
# let tuple = PyTuple::new(py, vec!["test", "test2"]);
|
||||||
#
|
#
|
||||||
# let rustytuple: RustyTuple = tuple.extract()?;
|
# let rustytuple: RustyTuple = tuple.extract()?;
|
||||||
# assert_eq!(rustytuple.0, "test");
|
# assert_eq!(rustytuple.0, "test");
|
||||||
# assert_eq!(rustytuple.1, "test2");
|
# assert_eq!(rustytuple.1, "test2");
|
||||||
#
|
#
|
||||||
# Ok(())
|
# Ok(())
|
||||||
# })
|
# })
|
||||||
# }
|
# }
|
||||||
|
@ -177,10 +176,10 @@ struct RustyTuple((String,));
|
||||||
# fn main() -> PyResult<()> {
|
# fn main() -> PyResult<()> {
|
||||||
# Python::with_gil(|py| -> PyResult<()> {
|
# Python::with_gil(|py| -> PyResult<()> {
|
||||||
# let tuple = PyTuple::new(py, vec!["test"]);
|
# let tuple = PyTuple::new(py, vec!["test"]);
|
||||||
#
|
#
|
||||||
# let rustytuple: RustyTuple = tuple.extract()?;
|
# let rustytuple: RustyTuple = tuple.extract()?;
|
||||||
# assert_eq!((rustytuple.0).0, "test");
|
# assert_eq!((rustytuple.0).0, "test");
|
||||||
#
|
#
|
||||||
# Ok(())
|
# Ok(())
|
||||||
# })
|
# })
|
||||||
# }
|
# }
|
||||||
|
@ -209,13 +208,13 @@ struct RustyTransparentStruct {
|
||||||
# fn main() -> PyResult<()> {
|
# fn main() -> PyResult<()> {
|
||||||
# Python::with_gil(|py| -> PyResult<()> {
|
# Python::with_gil(|py| -> PyResult<()> {
|
||||||
# let s = PyString::new(py, "test");
|
# let s = PyString::new(py, "test");
|
||||||
#
|
#
|
||||||
# let tup: RustyTransparentTupleStruct = s.extract()?;
|
# let tup: RustyTransparentTupleStruct = s.extract()?;
|
||||||
# assert_eq!(tup.0, "test");
|
# assert_eq!(tup.0, "test");
|
||||||
#
|
#
|
||||||
# let stru: RustyTransparentStruct = s.extract()?;
|
# let stru: RustyTransparentStruct = s.extract()?;
|
||||||
# assert_eq!(stru.inner, "test");
|
# assert_eq!(stru.inner, "test");
|
||||||
#
|
#
|
||||||
# Ok(())
|
# Ok(())
|
||||||
# })
|
# })
|
||||||
# }
|
# }
|
||||||
|
@ -256,14 +255,14 @@ enum RustyEnum<'a> {
|
||||||
#[pyo3(transparent)]
|
#[pyo3(transparent)]
|
||||||
CatchAll(&'a PyAny), // This extraction never fails
|
CatchAll(&'a PyAny), // This extraction never fails
|
||||||
}
|
}
|
||||||
#
|
#
|
||||||
# use pyo3::types::{PyBytes, PyString};
|
# use pyo3::types::{PyBytes, PyString};
|
||||||
# fn main() -> PyResult<()> {
|
# fn main() -> PyResult<()> {
|
||||||
# Python::with_gil(|py| -> PyResult<()> {
|
# Python::with_gil(|py| -> PyResult<()> {
|
||||||
# {
|
# {
|
||||||
# let thing = 42_u8.to_object(py);
|
# let thing = 42_u8.to_object(py);
|
||||||
# let rust_thing: RustyEnum<'_> = thing.extract(py)?;
|
# let rust_thing: RustyEnum<'_> = thing.extract(py)?;
|
||||||
#
|
#
|
||||||
# assert_eq!(
|
# assert_eq!(
|
||||||
# 42,
|
# 42,
|
||||||
# match rust_thing {
|
# match rust_thing {
|
||||||
|
@ -275,7 +274,7 @@ enum RustyEnum<'a> {
|
||||||
# {
|
# {
|
||||||
# let thing = PyString::new(py, "text");
|
# let thing = PyString::new(py, "text");
|
||||||
# let rust_thing: RustyEnum<'_> = thing.extract()?;
|
# let rust_thing: RustyEnum<'_> = thing.extract()?;
|
||||||
#
|
#
|
||||||
# assert_eq!(
|
# assert_eq!(
|
||||||
# "text",
|
# "text",
|
||||||
# match rust_thing {
|
# match rust_thing {
|
||||||
|
@ -287,7 +286,7 @@ enum RustyEnum<'a> {
|
||||||
# {
|
# {
|
||||||
# let thing = (32_u8, 73_u8).to_object(py);
|
# let thing = (32_u8, 73_u8).to_object(py);
|
||||||
# let rust_thing: RustyEnum<'_> = thing.extract(py)?;
|
# let rust_thing: RustyEnum<'_> = thing.extract(py)?;
|
||||||
#
|
#
|
||||||
# assert_eq!(
|
# assert_eq!(
|
||||||
# (32, 73),
|
# (32, 73),
|
||||||
# match rust_thing {
|
# match rust_thing {
|
||||||
|
@ -299,7 +298,7 @@ enum RustyEnum<'a> {
|
||||||
# {
|
# {
|
||||||
# let thing = ("foo", 73_u8).to_object(py);
|
# let thing = ("foo", 73_u8).to_object(py);
|
||||||
# let rust_thing: RustyEnum<'_> = thing.extract(py)?;
|
# let rust_thing: RustyEnum<'_> = thing.extract(py)?;
|
||||||
#
|
#
|
||||||
# assert_eq!(
|
# assert_eq!(
|
||||||
# (String::from("foo"), 73),
|
# (String::from("foo"), 73),
|
||||||
# match rust_thing {
|
# match rust_thing {
|
||||||
|
@ -319,11 +318,11 @@ enum RustyEnum<'a> {
|
||||||
# "",
|
# "",
|
||||||
# "",
|
# "",
|
||||||
# )?;
|
# )?;
|
||||||
#
|
#
|
||||||
# let class = module.getattr("Foo")?;
|
# let class = module.getattr("Foo")?;
|
||||||
# let instance = class.call0()?;
|
# let instance = class.call0()?;
|
||||||
# let rust_thing: RustyEnum<'_> = instance.extract()?;
|
# let rust_thing: RustyEnum<'_> = instance.extract()?;
|
||||||
#
|
#
|
||||||
# assert_eq!(
|
# assert_eq!(
|
||||||
# (0, 1, 2),
|
# (0, 1, 2),
|
||||||
# match rust_thing {
|
# match rust_thing {
|
||||||
|
@ -332,7 +331,7 @@ enum RustyEnum<'a> {
|
||||||
# }
|
# }
|
||||||
# );
|
# );
|
||||||
# }
|
# }
|
||||||
#
|
#
|
||||||
# {
|
# {
|
||||||
# let module = PyModule::from_code(
|
# let module = PyModule::from_code(
|
||||||
# py,
|
# py,
|
||||||
|
@ -343,11 +342,11 @@ enum RustyEnum<'a> {
|
||||||
# "",
|
# "",
|
||||||
# "",
|
# "",
|
||||||
# )?;
|
# )?;
|
||||||
#
|
#
|
||||||
# let class = module.getattr("Foo")?;
|
# let class = module.getattr("Foo")?;
|
||||||
# let instance = class.call0()?;
|
# let instance = class.call0()?;
|
||||||
# let rust_thing: RustyEnum<'_> = instance.extract()?;
|
# let rust_thing: RustyEnum<'_> = instance.extract()?;
|
||||||
#
|
#
|
||||||
# assert_eq!(
|
# assert_eq!(
|
||||||
# (3, 4),
|
# (3, 4),
|
||||||
# match rust_thing {
|
# match rust_thing {
|
||||||
|
@ -356,11 +355,11 @@ enum RustyEnum<'a> {
|
||||||
# }
|
# }
|
||||||
# );
|
# );
|
||||||
# }
|
# }
|
||||||
#
|
#
|
||||||
# {
|
# {
|
||||||
# let thing = PyBytes::new(py, b"text");
|
# let thing = PyBytes::new(py, b"text");
|
||||||
# let rust_thing: RustyEnum<'_> = thing.extract()?;
|
# let rust_thing: RustyEnum<'_> = thing.extract()?;
|
||||||
#
|
#
|
||||||
# assert_eq!(
|
# assert_eq!(
|
||||||
# b"text",
|
# b"text",
|
||||||
# match rust_thing {
|
# match rust_thing {
|
||||||
|
@ -396,7 +395,7 @@ enum RustyEnum {
|
||||||
# {
|
# {
|
||||||
# let thing = 42_u8.to_object(py);
|
# let thing = 42_u8.to_object(py);
|
||||||
# let rust_thing: RustyEnum = thing.extract(py)?;
|
# let rust_thing: RustyEnum = thing.extract(py)?;
|
||||||
#
|
#
|
||||||
# assert_eq!(
|
# assert_eq!(
|
||||||
# 42,
|
# 42,
|
||||||
# match rust_thing {
|
# match rust_thing {
|
||||||
|
@ -405,11 +404,11 @@ enum RustyEnum {
|
||||||
# }
|
# }
|
||||||
# );
|
# );
|
||||||
# }
|
# }
|
||||||
#
|
#
|
||||||
# {
|
# {
|
||||||
# let thing = "foo".to_object(py);
|
# let thing = "foo".to_object(py);
|
||||||
# let rust_thing: RustyEnum = thing.extract(py)?;
|
# let rust_thing: RustyEnum = thing.extract(py)?;
|
||||||
#
|
#
|
||||||
# assert_eq!(
|
# assert_eq!(
|
||||||
# "foo",
|
# "foo",
|
||||||
# match rust_thing {
|
# match rust_thing {
|
||||||
|
@ -418,13 +417,13 @@ enum RustyEnum {
|
||||||
# }
|
# }
|
||||||
# );
|
# );
|
||||||
# }
|
# }
|
||||||
#
|
#
|
||||||
# {
|
# {
|
||||||
# let thing = b"foo".to_object(py);
|
# let thing = b"foo".to_object(py);
|
||||||
# let error = thing.extract::<RustyEnum>(py).unwrap_err();
|
# let error = thing.extract::<RustyEnum>(py).unwrap_err();
|
||||||
# assert!(error.is_instance_of::<pyo3::exceptions::PyTypeError>(py));
|
# assert!(error.is_instance_of::<pyo3::exceptions::PyTypeError>(py));
|
||||||
# }
|
# }
|
||||||
#
|
#
|
||||||
# Ok(())
|
# Ok(())
|
||||||
# })
|
# })
|
||||||
# }
|
# }
|
||||||
|
|
|
@ -131,7 +131,6 @@ fn my_async_module(py: Python<'_>, m: &PyModule) -> PyResult<()> {
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
If you want to use `tokio` instead, here's what your module should look like:
|
If you want to use `tokio` instead, here's what your module should look like:
|
||||||
|
|
|
@ -25,7 +25,11 @@ create_exception!(mymodule, CustomError, PyException);
|
||||||
|
|
||||||
Python::with_gil(|py| {
|
Python::with_gil(|py| {
|
||||||
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'>\"");
|
pyo3::py_run!(
|
||||||
|
py,
|
||||||
|
*ctx,
|
||||||
|
"assert str(CustomError) == \"<class 'mymodule.CustomError'>\""
|
||||||
|
);
|
||||||
pyo3::py_run!(py, *ctx, "assert CustomError('oops').args == ('oops',)");
|
pyo3::py_run!(py, *ctx, "assert CustomError('oops').args == ('oops',)");
|
||||||
});
|
});
|
||||||
```
|
```
|
||||||
|
@ -47,7 +51,6 @@ fn mymodule(py: Python<'_>, m: &PyModule) -> PyResult<()> {
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
## Raising an exception
|
## Raising an exception
|
||||||
|
@ -115,7 +118,6 @@ fn tell(file: &PyAny) -> PyResult<u64> {
|
||||||
Ok(x) => x.extract::<u64>(),
|
Ok(x) => x.extract::<u64>(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
[`pyo3::exceptions`]({{#PYO3_DOCS_URL}}/pyo3/exceptions/index.html)
|
[`pyo3::exceptions`]({{#PYO3_DOCS_URL}}/pyo3/exceptions/index.html)
|
||||||
|
|
|
@ -86,7 +86,7 @@ You may have a nested struct similar to this:
|
||||||
# use pyo3::prelude::*;
|
# use pyo3::prelude::*;
|
||||||
#[pyclass]
|
#[pyclass]
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
struct Inner { /* fields omitted */ }
|
struct Inner {/* fields omitted */}
|
||||||
|
|
||||||
#[pyclass]
|
#[pyclass]
|
||||||
struct Outer {
|
struct Outer {
|
||||||
|
@ -126,7 +126,7 @@ If you don't want that cloning to happen, a workaround is to allocate the field
|
||||||
# use pyo3::prelude::*;
|
# use pyo3::prelude::*;
|
||||||
#[pyclass]
|
#[pyclass]
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
struct Inner { /* fields omitted */ }
|
struct Inner {/* fields omitted */}
|
||||||
|
|
||||||
#[pyclass]
|
#[pyclass]
|
||||||
struct Outer {
|
struct Outer {
|
||||||
|
|
|
@ -138,14 +138,14 @@ This allows to use [`#[derive(Serialize, Deserialize)`](https://serde.rs/derive.
|
||||||
#[pyclass]
|
#[pyclass]
|
||||||
#[derive(Serialize, Deserialize)]
|
#[derive(Serialize, Deserialize)]
|
||||||
struct Permission {
|
struct Permission {
|
||||||
name: String
|
name: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[pyclass]
|
#[pyclass]
|
||||||
#[derive(Serialize, Deserialize)]
|
#[derive(Serialize, Deserialize)]
|
||||||
struct User {
|
struct User {
|
||||||
username: String,
|
username: String,
|
||||||
permissions: Vec<Py<Permission>>
|
permissions: Vec<Py<Permission>>,
|
||||||
}
|
}
|
||||||
# }
|
# }
|
||||||
```
|
```
|
||||||
|
|
|
@ -50,7 +50,9 @@ The `#[pyo3]` attribute can be used to modify properties of the generated Python
|
||||||
|
|
||||||
#[pyfunction]
|
#[pyfunction]
|
||||||
#[pyo3(name = "no_args")]
|
#[pyo3(name = "no_args")]
|
||||||
fn no_args_py() -> usize { 42 }
|
fn no_args_py() -> usize {
|
||||||
|
42
|
||||||
|
}
|
||||||
|
|
||||||
#[pymodule]
|
#[pymodule]
|
||||||
fn module_with_functions(py: Python<'_>, m: &PyModule) -> PyResult<()> {
|
fn module_with_functions(py: Python<'_>, m: &PyModule) -> PyResult<()> {
|
||||||
|
@ -185,8 +187,6 @@ fn add(a: u64, b: u64) -> u64 {
|
||||||
|
|
||||||
/// sub(a, b, /)
|
/// sub(a, b, /)
|
||||||
/// --
|
/// --
|
||||||
///
|
|
||||||
///
|
|
||||||
#[pyfunction]
|
#[pyfunction]
|
||||||
fn sub(a: u64, b: u64) -> u64 {
|
fn sub(a: u64, b: u64) -> u64 {
|
||||||
a - b
|
a - b
|
||||||
|
@ -255,7 +255,6 @@ use pyo3::prelude::*;
|
||||||
|
|
||||||
#[pymodule]
|
#[pymodule]
|
||||||
fn my_extension(py: Python<'_>, m: &PyModule) -> PyResult<()> {
|
fn my_extension(py: Python<'_>, m: &PyModule) -> PyResult<()> {
|
||||||
|
|
||||||
#[pyfn(m)]
|
#[pyfn(m)]
|
||||||
fn double(x: usize) -> usize {
|
fn double(x: usize) -> usize {
|
||||||
x * 2
|
x * 2
|
||||||
|
@ -273,7 +272,6 @@ use pyo3::prelude::*;
|
||||||
|
|
||||||
#[pymodule]
|
#[pymodule]
|
||||||
fn my_extension(py: Python<'_>, m: &PyModule) -> PyResult<()> {
|
fn my_extension(py: Python<'_>, m: &PyModule) -> PyResult<()> {
|
||||||
|
|
||||||
#[pyfunction]
|
#[pyfunction]
|
||||||
fn double(x: usize) -> usize {
|
fn double(x: usize) -> usize {
|
||||||
x * 2
|
x * 2
|
||||||
|
|
|
@ -112,10 +112,10 @@ impl std::convert::From<CustomIOError> for PyErr {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Connection { /* ... */}
|
pub struct Connection {/* ... */}
|
||||||
|
|
||||||
fn bind(addr: String) -> Result<Connection, CustomIOError> {
|
fn bind(addr: String) -> Result<Connection, CustomIOError> {
|
||||||
if &addr == "0.0.0.0"{
|
if &addr == "0.0.0.0" {
|
||||||
Err(CustomIOError)
|
Err(CustomIOError)
|
||||||
} else {
|
} else {
|
||||||
Ok(Connection{ /* ... */})
|
Ok(Connection{ /* ... */})
|
||||||
|
|
|
@ -120,7 +120,7 @@ Below are the same examples as above which using the deprecated syntax:
|
||||||
use pyo3::prelude::*;
|
use pyo3::prelude::*;
|
||||||
use pyo3::types::PyDict;
|
use pyo3::types::PyDict;
|
||||||
|
|
||||||
#[pyfunction(kwds="**")]
|
#[pyfunction(kwds = "**")]
|
||||||
fn num_kwds(kwds: Option<&PyDict>) -> usize {
|
fn num_kwds(kwds: Option<&PyDict>) -> usize {
|
||||||
kwds.map_or(0, |dict| dict.len())
|
kwds.map_or(0, |dict| dict.len())
|
||||||
}
|
}
|
||||||
|
@ -166,12 +166,7 @@ impl MyClass {
|
||||||
MyClass { num }
|
MyClass { num }
|
||||||
}
|
}
|
||||||
|
|
||||||
#[args(
|
#[args(num = "10", py_args = "*", name = "\"Hello\"", py_kwargs = "**")]
|
||||||
num = "10",
|
|
||||||
py_args = "*",
|
|
||||||
name = "\"Hello\"",
|
|
||||||
py_kwargs = "**"
|
|
||||||
)]
|
|
||||||
fn method(
|
fn method(
|
||||||
&mut self,
|
&mut self,
|
||||||
num: i32,
|
num: i32,
|
||||||
|
|
|
@ -44,7 +44,6 @@ impl Mapping {
|
||||||
// ...
|
// ...
|
||||||
// truncated implementation of this mapping pyclass - basically a wrapper around a HashMap
|
// truncated implementation of this mapping pyclass - basically a wrapper around a HashMap
|
||||||
}
|
}
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
You must register the class with `collections.abc.Mapping` before the downcast will work:
|
You must register the class with `collections.abc.Mapping` before the downcast will work:
|
||||||
|
@ -155,7 +154,7 @@ use pyo3::class::{PyBasicProtocol, PyIterProtocol};
|
||||||
use pyo3::types::PyString;
|
use pyo3::types::PyString;
|
||||||
|
|
||||||
#[pyclass]
|
#[pyclass]
|
||||||
struct MyClass { }
|
struct MyClass {}
|
||||||
|
|
||||||
#[pyproto]
|
#[pyproto]
|
||||||
impl PyBasicProtocol for MyClass {
|
impl PyBasicProtocol for MyClass {
|
||||||
|
@ -179,7 +178,7 @@ use pyo3::prelude::*;
|
||||||
use pyo3::types::PyString;
|
use pyo3::types::PyString;
|
||||||
|
|
||||||
#[pyclass]
|
#[pyclass]
|
||||||
struct MyClass { }
|
struct MyClass {}
|
||||||
|
|
||||||
#[pymethods]
|
#[pymethods]
|
||||||
impl MyClass {
|
impl MyClass {
|
||||||
|
@ -343,7 +342,7 @@ use pyo3::prelude::*;
|
||||||
use pyo3::class::basic::PyBasicProtocol;
|
use pyo3::class::basic::PyBasicProtocol;
|
||||||
|
|
||||||
#[pyclass]
|
#[pyclass]
|
||||||
struct MyClass { }
|
struct MyClass {}
|
||||||
|
|
||||||
#[pyproto]
|
#[pyproto]
|
||||||
impl PyBasicProtocol for MyClass {
|
impl PyBasicProtocol for MyClass {
|
||||||
|
@ -359,7 +358,7 @@ After:
|
||||||
use pyo3::prelude::*;
|
use pyo3::prelude::*;
|
||||||
|
|
||||||
#[pyclass]
|
#[pyclass]
|
||||||
struct MyClass { }
|
struct MyClass {}
|
||||||
|
|
||||||
#[pymethods]
|
#[pymethods]
|
||||||
impl MyClass {
|
impl MyClass {
|
||||||
|
@ -457,7 +456,10 @@ assert_eq!(err.to_string(), "TypeError: error message");
|
||||||
|
|
||||||
// Now possible to interact with exception instances, new for PyO3 0.12
|
// Now possible to interact with exception instances, new for PyO3 0.12
|
||||||
let instance: &PyBaseException = err.instance(py);
|
let instance: &PyBaseException = err.instance(py);
|
||||||
assert_eq!(instance.getattr("__class__")?, PyTypeError::type_object(py).as_ref());
|
assert_eq!(
|
||||||
|
instance.getattr("__class__")?,
|
||||||
|
PyTypeError::type_object(py).as_ref()
|
||||||
|
);
|
||||||
# Ok(())
|
# Ok(())
|
||||||
# }).unwrap();
|
# }).unwrap();
|
||||||
```
|
```
|
||||||
|
@ -568,7 +570,7 @@ There can be two fixes:
|
||||||
#[pyclass]
|
#[pyclass]
|
||||||
struct NotThreadSafe {
|
struct NotThreadSafe {
|
||||||
shared_bools: Rc<RefCell<Vec<bool>>>,
|
shared_bools: Rc<RefCell<Vec<bool>>>,
|
||||||
closure: Box<dyn Fn()>
|
closure: Box<dyn Fn()>,
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -581,7 +583,7 @@ There can be two fixes:
|
||||||
#[pyclass]
|
#[pyclass]
|
||||||
struct ThreadSafe {
|
struct ThreadSafe {
|
||||||
shared_bools: Arc<Mutex<Vec<bool>>>,
|
shared_bools: Arc<Mutex<Vec<bool>>>,
|
||||||
closure: Box<dyn Fn() + Send>
|
closure: Box<dyn Fn() + Send>,
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -679,10 +681,10 @@ struct MyClass {}
|
||||||
|
|
||||||
#[pymethods]
|
#[pymethods]
|
||||||
impl MyClass {
|
impl MyClass {
|
||||||
#[new]
|
#[new]
|
||||||
fn new(obj: &PyRawObject) {
|
fn new(obj: &PyRawObject) {
|
||||||
obj.init(MyClass { })
|
obj.init(MyClass {})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -694,10 +696,10 @@ struct MyClass {}
|
||||||
|
|
||||||
#[pymethods]
|
#[pymethods]
|
||||||
impl MyClass {
|
impl MyClass {
|
||||||
#[new]
|
#[new]
|
||||||
fn new() -> Self {
|
fn new() -> Self {
|
||||||
MyClass {}
|
MyClass {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -720,7 +722,7 @@ Here is an example.
|
||||||
|
|
||||||
#[pyclass]
|
#[pyclass]
|
||||||
struct Names {
|
struct Names {
|
||||||
names: Vec<String>
|
names: Vec<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[pymethods]
|
#[pymethods]
|
||||||
|
|
|
@ -43,7 +43,7 @@ But let's assume you have a long running Rust function which you would like to e
|
||||||
# }
|
# }
|
||||||
# total
|
# total
|
||||||
# }
|
# }
|
||||||
#
|
#
|
||||||
fn search_sequential(contents: &str, needle: &str) -> usize {
|
fn search_sequential(contents: &str, needle: &str) -> usize {
|
||||||
contents.lines().map(|line| count_line(line, needle)).sum()
|
contents.lines().map(|line| count_line(line, needle)).sum()
|
||||||
}
|
}
|
||||||
|
@ -63,7 +63,7 @@ To enable parallel execution of this function, the [`Python::allow_threads`] met
|
||||||
# }
|
# }
|
||||||
# total
|
# total
|
||||||
# }
|
# }
|
||||||
#
|
#
|
||||||
# fn search_sequential(contents: &str, needle: &str) -> usize {
|
# fn search_sequential(contents: &str, needle: &str) -> usize {
|
||||||
# contents.lines().map(|line| count_line(line, needle)).sum()
|
# contents.lines().map(|line| count_line(line, needle)).sum()
|
||||||
# }
|
# }
|
||||||
|
|
|
@ -43,7 +43,9 @@ fn main() -> PyResult<()> {
|
||||||
print('called with no arguments')",
|
print('called with no arguments')",
|
||||||
"",
|
"",
|
||||||
"",
|
"",
|
||||||
)?.getattr("example")?.into();
|
)?
|
||||||
|
.getattr("example")?
|
||||||
|
.into();
|
||||||
|
|
||||||
// call object without any arguments
|
// call object without any arguments
|
||||||
fun.call0(py)?;
|
fun.call0(py)?;
|
||||||
|
@ -87,8 +89,9 @@ fn main() -> PyResult<()> {
|
||||||
print('called with no arguments')",
|
print('called with no arguments')",
|
||||||
"",
|
"",
|
||||||
"",
|
"",
|
||||||
)?.getattr("example")?.into();
|
)?
|
||||||
|
.getattr("example")?
|
||||||
|
.into();
|
||||||
|
|
||||||
// call object with PyDict
|
// call object with PyDict
|
||||||
let kwargs = [(key1, val1)].into_py_dict(py);
|
let kwargs = [(key1, val1)].into_py_dict(py);
|
||||||
|
@ -104,7 +107,7 @@ fn main() -> PyResult<()> {
|
||||||
fun.call(py, (), Some(kwargs.into_py_dict(py)))?;
|
fun.call(py, (), Some(kwargs.into_py_dict(py)))?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -124,7 +127,10 @@ use pyo3::prelude::*;
|
||||||
fn main() -> PyResult<()> {
|
fn main() -> PyResult<()> {
|
||||||
Python::with_gil(|py| {
|
Python::with_gil(|py| {
|
||||||
let builtins = PyModule::import(py, "builtins")?;
|
let builtins = PyModule::import(py, "builtins")?;
|
||||||
let total: i32 = builtins.getattr("sum")?.call1((vec![1, 2, 3],))?.extract()?;
|
let total: i32 = builtins
|
||||||
|
.getattr("sum")?
|
||||||
|
.call1((vec![1, 2, 3],))?
|
||||||
|
.extract()?;
|
||||||
assert_eq!(total, 6);
|
assert_eq!(total, 6);
|
||||||
Ok(())
|
Ok(())
|
||||||
})
|
})
|
||||||
|
@ -142,9 +148,11 @@ use pyo3::prelude::*;
|
||||||
|
|
||||||
# fn main() -> Result<(), ()> {
|
# fn main() -> Result<(), ()> {
|
||||||
Python::with_gil(|py| {
|
Python::with_gil(|py| {
|
||||||
let result = py.eval("[i * 10 for i in range(5)]", None, None).map_err(|e| {
|
let result = py
|
||||||
e.print_and_set_sys_last_vars(py);
|
.eval("[i * 10 for i in range(5)]", None, None)
|
||||||
})?;
|
.map_err(|e| {
|
||||||
|
e.print_and_set_sys_last_vars(py);
|
||||||
|
})?;
|
||||||
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]);
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@ -228,7 +236,8 @@ def leaky_relu(x, slope=0.01):
|
||||||
|
|
||||||
let kwargs = [("slope", 0.2)].into_py_dict(py);
|
let kwargs = [("slope", 0.2)].into_py_dict(py);
|
||||||
let lrelu_result: f64 = activators
|
let lrelu_result: f64 = activators
|
||||||
.getattr("leaky_relu")?.call((-1.0,), Some(kwargs))?
|
.getattr("leaky_relu")?
|
||||||
|
.call((-1.0,), Some(kwargs))?
|
||||||
.extract()?;
|
.extract()?;
|
||||||
assert_eq!(lrelu_result, -0.2);
|
assert_eq!(lrelu_result, -0.2);
|
||||||
# Ok(())
|
# Ok(())
|
||||||
|
|
|
@ -27,7 +27,7 @@ use pyo3::prelude::*;
|
||||||
|
|
||||||
#[pyclass]
|
#[pyclass]
|
||||||
struct MyClass {
|
struct MyClass {
|
||||||
num: u32,
|
num: u32,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[pymethods]
|
#[pymethods]
|
||||||
|
|
|
@ -25,13 +25,13 @@ The argument of the function can be any model that implements the `Model` trait
|
||||||
```rust
|
```rust
|
||||||
# #![allow(dead_code)]
|
# #![allow(dead_code)]
|
||||||
pub trait Model {
|
pub trait Model {
|
||||||
fn set_variables(&mut self, inputs: &Vec<f64>);
|
fn set_variables(&mut self, inputs: &Vec<f64>);
|
||||||
fn compute(&mut self);
|
fn compute(&mut self);
|
||||||
fn get_results(&self) -> Vec<f64>;
|
fn get_results(&self) -> Vec<f64>;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn solve<T: Model>(model: &mut T) {
|
pub fn solve<T: Model>(model: &mut T) {
|
||||||
println!("Magic solver that mutates the model into a resolved state");
|
println!("Magic solver that mutates the model into a resolved state");
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
Let's assume we have the following constraints:
|
Let's assume we have the following constraints:
|
||||||
|
@ -152,7 +152,7 @@ Now we add the PyO3 annotations to the trait implementation:
|
||||||
```rust,ignore
|
```rust,ignore
|
||||||
#[pymethods]
|
#[pymethods]
|
||||||
impl Model for UserModel {
|
impl Model for UserModel {
|
||||||
// the previous trait implementation
|
// the previous trait implementation
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -411,7 +411,10 @@ impl Model for UserModel {
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
if py_result.get_type().name().unwrap() != "list" {
|
if py_result.get_type().name().unwrap() != "list" {
|
||||||
panic!("Expected a list for the get_results() method signature, got {}", py_result.get_type().name().unwrap());
|
panic!(
|
||||||
|
"Expected a list for the get_results() method signature, got {}",
|
||||||
|
py_result.get_type().name().unwrap()
|
||||||
|
);
|
||||||
}
|
}
|
||||||
py_result.extract()
|
py_result.extract()
|
||||||
})
|
})
|
||||||
|
@ -472,7 +475,7 @@ pub trait Model {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn solve<T: Model>(model: &mut T) {
|
pub fn solve<T: Model>(model: &mut T) {
|
||||||
println!("Magic solver that mutates the model into a resolved state");
|
println!("Magic solver that mutates the model into a resolved state");
|
||||||
}
|
}
|
||||||
|
|
||||||
#[pyfunction]
|
#[pyfunction]
|
||||||
|
@ -538,7 +541,10 @@ impl Model for UserModel {
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
if py_result.get_type().name().unwrap() != "list" {
|
if py_result.get_type().name().unwrap() != "list" {
|
||||||
panic!("Expected a list for the get_results() method signature, got {}", py_result.get_type().name().unwrap());
|
panic!(
|
||||||
|
"Expected a list for the get_results() method signature, got {}",
|
||||||
|
py_result.get_type().name().unwrap()
|
||||||
|
);
|
||||||
}
|
}
|
||||||
py_result.extract()
|
py_result.extract()
|
||||||
})
|
})
|
||||||
|
|
|
@ -89,7 +89,7 @@ For a `&PyAny` object reference `any` where the underlying object is a `#[pyclas
|
||||||
# use pyo3::{Py, Python, PyAny, PyResult};
|
# use pyo3::{Py, Python, PyAny, PyResult};
|
||||||
# #[pyclass] #[derive(Clone)] struct MyClass { }
|
# #[pyclass] #[derive(Clone)] struct MyClass { }
|
||||||
# Python::with_gil(|py| -> PyResult<()> {
|
# Python::with_gil(|py| -> PyResult<()> {
|
||||||
let obj: &PyAny = Py::new(py, MyClass { })?.into_ref(py);
|
let obj: &PyAny = Py::new(py, MyClass {})?.into_ref(py);
|
||||||
|
|
||||||
// To &PyCell<MyClass> with PyAny::downcast
|
// To &PyCell<MyClass> with PyAny::downcast
|
||||||
let _: &PyCell<MyClass> = obj.downcast()?;
|
let _: &PyCell<MyClass> = obj.downcast()?;
|
||||||
|
@ -238,7 +238,7 @@ so it also exposes all of the methods on `PyAny`.
|
||||||
# use pyo3::prelude::*;
|
# use pyo3::prelude::*;
|
||||||
# #[pyclass] struct MyClass { }
|
# #[pyclass] struct MyClass { }
|
||||||
# Python::with_gil(|py| -> PyResult<()> {
|
# Python::with_gil(|py| -> PyResult<()> {
|
||||||
let cell: &PyCell<MyClass> = PyCell::new(py, MyClass { })?;
|
let cell: &PyCell<MyClass> = PyCell::new(py, MyClass {})?;
|
||||||
|
|
||||||
// To PyRef<T> with .borrow() or .try_borrow()
|
// To PyRef<T> with .borrow() or .try_borrow()
|
||||||
let py_ref: PyRef<'_, MyClass> = cell.try_borrow()?;
|
let py_ref: PyRef<'_, MyClass> = cell.try_borrow()?;
|
||||||
|
@ -258,7 +258,7 @@ let _: &mut MyClass = &mut *py_ref_mut;
|
||||||
# use pyo3::prelude::*;
|
# use pyo3::prelude::*;
|
||||||
# #[pyclass] struct MyClass { }
|
# #[pyclass] struct MyClass { }
|
||||||
# Python::with_gil(|py| -> PyResult<()> {
|
# Python::with_gil(|py| -> PyResult<()> {
|
||||||
let cell: &PyCell<MyClass> = PyCell::new(py, MyClass { })?;
|
let cell: &PyCell<MyClass> = PyCell::new(py, MyClass {})?;
|
||||||
|
|
||||||
// Use methods from PyAny on PyCell<T> with Deref implementation
|
// Use methods from PyAny on PyCell<T> with Deref implementation
|
||||||
let _ = cell.repr()?;
|
let _ = cell.repr()?;
|
||||||
|
|
53
noxfile.py
53
noxfile.py
|
@ -2,6 +2,7 @@ import os
|
||||||
import re
|
import re
|
||||||
import subprocess
|
import subprocess
|
||||||
import sys
|
import sys
|
||||||
|
import tempfile
|
||||||
import time
|
import time
|
||||||
from glob import glob
|
from glob import glob
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
@ -231,6 +232,58 @@ def build_guide(session: nox.Session):
|
||||||
_run(session, "mdbook", "build", "-d", "../target/guide", "guide", *session.posargs)
|
_run(session, "mdbook", "build", "-d", "../target/guide", "guide", *session.posargs)
|
||||||
|
|
||||||
|
|
||||||
|
@nox.session(name="format-guide", venv_backend="none")
|
||||||
|
def format_guide(session: nox.Session):
|
||||||
|
fence_line = "//! ```\n"
|
||||||
|
|
||||||
|
for path in Path("guide").glob("**/*.md"):
|
||||||
|
session.log("Working on %s", path)
|
||||||
|
content = path.read_text()
|
||||||
|
|
||||||
|
lines = iter(path.read_text().splitlines(True))
|
||||||
|
new_lines = []
|
||||||
|
|
||||||
|
for line in lines:
|
||||||
|
new_lines.append(line)
|
||||||
|
if not re.search("```rust(,.*)?$", line):
|
||||||
|
continue
|
||||||
|
|
||||||
|
# Found a code block fence, gobble up its lines and write to temp. file
|
||||||
|
prefix = line[: line.index("```")]
|
||||||
|
with tempfile.NamedTemporaryFile("w", delete=False) as file:
|
||||||
|
tempname = file.name
|
||||||
|
file.write(fence_line)
|
||||||
|
for line in lines:
|
||||||
|
if line == prefix + "```\n":
|
||||||
|
break
|
||||||
|
file.write(("//! " + line[len(prefix) :]).rstrip() + "\n")
|
||||||
|
file.write(fence_line)
|
||||||
|
|
||||||
|
# Format it (needs nightly rustfmt for `format_code_in_doc_comments`)
|
||||||
|
_run(
|
||||||
|
session,
|
||||||
|
"rustfmt",
|
||||||
|
"+nightly",
|
||||||
|
"--config",
|
||||||
|
"format_code_in_doc_comments=true",
|
||||||
|
"--config",
|
||||||
|
"reorder_imports=false",
|
||||||
|
tempname,
|
||||||
|
)
|
||||||
|
|
||||||
|
# Re-read the formatted file, add its lines, and delete it
|
||||||
|
with open(tempname, "r") as file:
|
||||||
|
for line in file:
|
||||||
|
if line == fence_line:
|
||||||
|
continue
|
||||||
|
new_lines.append((prefix + line[4:]).rstrip() + "\n")
|
||||||
|
os.unlink(tempname)
|
||||||
|
|
||||||
|
new_lines.append(prefix + "```\n")
|
||||||
|
|
||||||
|
path.write_text("".join(new_lines))
|
||||||
|
|
||||||
|
|
||||||
@nox.session(name="address-sanitizer", venv_backend="none")
|
@nox.session(name="address-sanitizer", venv_backend="none")
|
||||||
def address_sanitizer(session: nox.Session):
|
def address_sanitizer(session: nox.Session):
|
||||||
_run(
|
_run(
|
||||||
|
|
Loading…
Reference in New Issue