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
|
||||
// Argument supplied directly to the `#[pyclass]` annotation.
|
||||
#[pyclass(name = "SomeName", subclass)]
|
||||
struct MyClass { }
|
||||
struct MyClass {}
|
||||
|
||||
// Argument supplied as a separate annotation.
|
||||
#[pyclass]
|
||||
#[pyo3(name = "SomeName", subclass)]
|
||||
struct MyClass { }
|
||||
struct MyClass {}
|
||||
```
|
||||
|
||||
[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
|
||||
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
|
||||
#[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))]
|
||||
fn function_only_supported_before_python_3_8() { }
|
||||
fn function_only_supported_before_python_3_8() {}
|
||||
|
||||
#[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.
|
||||
|
@ -98,11 +98,10 @@ PyO3 provides the APIs [`Python::version()`] and [`Python::version_info()`] to q
|
|||
use pyo3::Python;
|
||||
|
||||
Python::with_gil(|py| {
|
||||
// PyO3 supports Python 3.7 and up.
|
||||
assert!(py.version_info() >= (3, 7));
|
||||
assert!(py.version_info() >= (3, 7, 0));
|
||||
// PyO3 supports Python 3.7 and up.
|
||||
assert!(py.version_info() >= (3, 7));
|
||||
assert!(py.version_info() >= (3, 7, 0));
|
||||
});
|
||||
|
||||
```
|
||||
|
||||
[`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::*;
|
||||
|
||||
#[pyclass]
|
||||
struct Integer{
|
||||
inner: i32
|
||||
struct Integer {
|
||||
inner: i32,
|
||||
}
|
||||
|
||||
// A "tuple" struct
|
||||
|
@ -166,7 +166,7 @@ struct MyClass {
|
|||
num: i32,
|
||||
}
|
||||
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
|
||||
assert_eq!(obj_ref.num, 3);
|
||||
|
@ -204,7 +204,7 @@ fn return_myclass() -> Py<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 obj_ref = cell.borrow(); // Get PyRef<T>
|
||||
assert_eq!(obj_ref.num, 1);
|
||||
|
@ -279,7 +279,7 @@ impl SubClass {
|
|||
}
|
||||
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
@ -293,13 +293,12 @@ struct SubSubClass {
|
|||
impl SubSubClass {
|
||||
#[new]
|
||||
fn new() -> PyClassInitializer<Self> {
|
||||
PyClassInitializer::from(SubClass::new())
|
||||
.add_subclass(SubSubClass{val3: 20})
|
||||
PyClassInitializer::from(SubClass::new()).add_subclass(SubSubClass { val3: 20 })
|
||||
}
|
||||
|
||||
fn method3(self_: PyRef<'_, Self>) -> PyResult<usize> {
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
@ -426,7 +425,7 @@ For simple cases where a member variable is just read and written with no side e
|
|||
#[pyclass]
|
||||
struct MyClass {
|
||||
#[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
|
||||
# use pyo3::prelude::*;
|
||||
#[pyclass(subclass)]
|
||||
enum BadBase{
|
||||
enum BadBase {
|
||||
Var1,
|
||||
}
|
||||
```
|
||||
|
@ -949,7 +948,7 @@ enum BadBase{
|
|||
struct Base;
|
||||
|
||||
#[pyclass(extends=Base)]
|
||||
enum BadSubclass{
|
||||
enum BadSubclass {
|
||||
Var1,
|
||||
}
|
||||
```
|
||||
|
|
|
@ -395,7 +395,6 @@ fn my_module(_py: Python<'_>, m: &PyModule) -> PyResult<()> {
|
|||
# Ok(())
|
||||
# })
|
||||
# }
|
||||
|
||||
```
|
||||
|
||||
## Appendix: Writing some unsafe code
|
||||
|
|
|
@ -40,10 +40,10 @@ print(n)
|
|||
### String representations
|
||||
|
||||
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
|
||||
contained inside `Number`.
|
||||
`__repr__` and `__str__` methods inside a `#[pymethods]` block. We do this by accessing the value
|
||||
contained inside `Number`.
|
||||
|
||||
```rust
|
||||
```rust
|
||||
# use pyo3::prelude::*;
|
||||
#
|
||||
# #[pyclass]
|
||||
|
@ -114,13 +114,13 @@ impl Number {
|
|||
> ```rust
|
||||
> # use pyo3::prelude::*;
|
||||
> #[pyclass]
|
||||
> struct NotHashable { }
|
||||
> struct NotHashable {}
|
||||
>
|
||||
> #[pymethods]
|
||||
> impl NotHashable {
|
||||
> #[classattr]
|
||||
> const __hash__: Option<Py<PyAny>> = None;
|
||||
>}
|
||||
> #[classattr]
|
||||
> const __hash__: Option<Py<PyAny>> = None;
|
||||
> }
|
||||
> ```
|
||||
|
||||
### Comparisons
|
||||
|
|
|
@ -48,7 +48,7 @@ given signatures should be interpreted as follows:
|
|||
# use pyo3::prelude::*;
|
||||
#
|
||||
#[pyclass]
|
||||
struct NotHashable { }
|
||||
struct NotHashable {}
|
||||
|
||||
#[pymethods]
|
||||
impl NotHashable {
|
||||
|
@ -229,7 +229,7 @@ Use the `#[pyclass(sequence)]` annotation to instruct PyO3 to fill the `sq_lengt
|
|||
# use pyo3::prelude::*;
|
||||
#
|
||||
#[pyclass]
|
||||
struct NoContains { }
|
||||
struct NoContains {}
|
||||
|
||||
#[pymethods]
|
||||
impl NoContains {
|
||||
|
|
|
@ -62,7 +62,7 @@ struct RustyStruct {
|
|||
# "",
|
||||
# "",
|
||||
# )?;
|
||||
#
|
||||
#
|
||||
# let class = module.getattr("Foo")?;
|
||||
# let instance = class.call0()?;
|
||||
# let rustystruct: RustyStruct = instance.extract()?;
|
||||
|
@ -77,7 +77,6 @@ By setting the `#[pyo3(item)]` attribute on the field, PyO3 will attempt to extr
|
|||
```rust
|
||||
use pyo3::prelude::*;
|
||||
|
||||
|
||||
#[derive(FromPyObject)]
|
||||
struct RustyStruct {
|
||||
#[pyo3(item)]
|
||||
|
@ -89,7 +88,7 @@ struct RustyStruct {
|
|||
# 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(())
|
||||
|
@ -109,7 +108,7 @@ struct RustyStruct {
|
|||
#[pyo3(attribute("name"))]
|
||||
string_attr: String,
|
||||
}
|
||||
#
|
||||
#
|
||||
# fn main() -> PyResult<()> {
|
||||
# Python::with_gil(|py| -> PyResult<()> {
|
||||
# let module = PyModule::from_code(
|
||||
|
@ -121,13 +120,13 @@ struct RustyStruct {
|
|||
# "",
|
||||
# "",
|
||||
# )?;
|
||||
#
|
||||
#
|
||||
# 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(())
|
||||
# })
|
||||
# }
|
||||
|
@ -154,11 +153,11 @@ struct RustyTuple(String, String);
|
|||
# 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(())
|
||||
# })
|
||||
# }
|
||||
|
@ -177,10 +176,10 @@ struct RustyTuple((String,));
|
|||
# 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(())
|
||||
# })
|
||||
# }
|
||||
|
@ -209,13 +208,13 @@ struct RustyTransparentStruct {
|
|||
# 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(())
|
||||
# })
|
||||
# }
|
||||
|
@ -256,14 +255,14 @@ 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 {
|
||||
|
@ -275,7 +274,7 @@ enum RustyEnum<'a> {
|
|||
# {
|
||||
# let thing = PyString::new(py, "text");
|
||||
# let rust_thing: RustyEnum<'_> = thing.extract()?;
|
||||
#
|
||||
#
|
||||
# assert_eq!(
|
||||
# "text",
|
||||
# match rust_thing {
|
||||
|
@ -287,7 +286,7 @@ enum RustyEnum<'a> {
|
|||
# {
|
||||
# let thing = (32_u8, 73_u8).to_object(py);
|
||||
# let rust_thing: RustyEnum<'_> = thing.extract(py)?;
|
||||
#
|
||||
#
|
||||
# assert_eq!(
|
||||
# (32, 73),
|
||||
# match rust_thing {
|
||||
|
@ -299,7 +298,7 @@ enum RustyEnum<'a> {
|
|||
# {
|
||||
# let thing = ("foo", 73_u8).to_object(py);
|
||||
# let rust_thing: RustyEnum<'_> = thing.extract(py)?;
|
||||
#
|
||||
#
|
||||
# assert_eq!(
|
||||
# (String::from("foo"), 73),
|
||||
# match rust_thing {
|
||||
|
@ -319,11 +318,11 @@ enum RustyEnum<'a> {
|
|||
# "",
|
||||
# "",
|
||||
# )?;
|
||||
#
|
||||
#
|
||||
# let class = module.getattr("Foo")?;
|
||||
# let instance = class.call0()?;
|
||||
# let rust_thing: RustyEnum<'_> = instance.extract()?;
|
||||
#
|
||||
#
|
||||
# assert_eq!(
|
||||
# (0, 1, 2),
|
||||
# match rust_thing {
|
||||
|
@ -332,7 +331,7 @@ enum RustyEnum<'a> {
|
|||
# }
|
||||
# );
|
||||
# }
|
||||
#
|
||||
#
|
||||
# {
|
||||
# let module = PyModule::from_code(
|
||||
# py,
|
||||
|
@ -343,11 +342,11 @@ enum RustyEnum<'a> {
|
|||
# "",
|
||||
# "",
|
||||
# )?;
|
||||
#
|
||||
#
|
||||
# let class = module.getattr("Foo")?;
|
||||
# let instance = class.call0()?;
|
||||
# let rust_thing: RustyEnum<'_> = instance.extract()?;
|
||||
#
|
||||
#
|
||||
# assert_eq!(
|
||||
# (3, 4),
|
||||
# match rust_thing {
|
||||
|
@ -356,11 +355,11 @@ enum RustyEnum<'a> {
|
|||
# }
|
||||
# );
|
||||
# }
|
||||
#
|
||||
#
|
||||
# {
|
||||
# let thing = PyBytes::new(py, b"text");
|
||||
# let rust_thing: RustyEnum<'_> = thing.extract()?;
|
||||
#
|
||||
#
|
||||
# assert_eq!(
|
||||
# b"text",
|
||||
# match rust_thing {
|
||||
|
@ -396,7 +395,7 @@ enum RustyEnum {
|
|||
# {
|
||||
# let thing = 42_u8.to_object(py);
|
||||
# let rust_thing: RustyEnum = thing.extract(py)?;
|
||||
#
|
||||
#
|
||||
# assert_eq!(
|
||||
# 42,
|
||||
# match rust_thing {
|
||||
|
@ -405,11 +404,11 @@ enum RustyEnum {
|
|||
# }
|
||||
# );
|
||||
# }
|
||||
#
|
||||
#
|
||||
# {
|
||||
# let thing = "foo".to_object(py);
|
||||
# let rust_thing: RustyEnum = thing.extract(py)?;
|
||||
#
|
||||
#
|
||||
# assert_eq!(
|
||||
# "foo",
|
||||
# match rust_thing {
|
||||
|
@ -418,13 +417,13 @@ enum RustyEnum {
|
|||
# }
|
||||
# );
|
||||
# }
|
||||
#
|
||||
#
|
||||
# {
|
||||
# let thing = b"foo".to_object(py);
|
||||
# let error = thing.extract::<RustyEnum>(py).unwrap_err();
|
||||
# assert!(error.is_instance_of::<pyo3::exceptions::PyTypeError>(py));
|
||||
# }
|
||||
#
|
||||
#
|
||||
# Ok(())
|
||||
# })
|
||||
# }
|
||||
|
|
|
@ -131,7 +131,6 @@ fn my_async_module(py: Python<'_>, m: &PyModule) -> PyResult<()> {
|
|||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
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| {
|
||||
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',)");
|
||||
});
|
||||
```
|
||||
|
@ -47,7 +51,6 @@ fn mymodule(py: Python<'_>, m: &PyModule) -> PyResult<()> {
|
|||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
## Raising an exception
|
||||
|
@ -115,7 +118,6 @@ fn tell(file: &PyAny) -> PyResult<u64> {
|
|||
Ok(x) => x.extract::<u64>(),
|
||||
}
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
[`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::*;
|
||||
#[pyclass]
|
||||
#[derive(Clone)]
|
||||
struct Inner { /* fields omitted */ }
|
||||
struct Inner {/* fields omitted */}
|
||||
|
||||
#[pyclass]
|
||||
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::*;
|
||||
#[pyclass]
|
||||
#[derive(Clone)]
|
||||
struct Inner { /* fields omitted */ }
|
||||
struct Inner {/* fields omitted */}
|
||||
|
||||
#[pyclass]
|
||||
struct Outer {
|
||||
|
|
|
@ -138,14 +138,14 @@ This allows to use [`#[derive(Serialize, Deserialize)`](https://serde.rs/derive.
|
|||
#[pyclass]
|
||||
#[derive(Serialize, Deserialize)]
|
||||
struct Permission {
|
||||
name: String
|
||||
name: String,
|
||||
}
|
||||
|
||||
#[pyclass]
|
||||
#[derive(Serialize, Deserialize)]
|
||||
struct User {
|
||||
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]
|
||||
#[pyo3(name = "no_args")]
|
||||
fn no_args_py() -> usize { 42 }
|
||||
fn no_args_py() -> usize {
|
||||
42
|
||||
}
|
||||
|
||||
#[pymodule]
|
||||
fn module_with_functions(py: Python<'_>, m: &PyModule) -> PyResult<()> {
|
||||
|
@ -185,8 +187,6 @@ fn add(a: u64, b: u64) -> u64 {
|
|||
|
||||
/// sub(a, b, /)
|
||||
/// --
|
||||
///
|
||||
///
|
||||
#[pyfunction]
|
||||
fn sub(a: u64, b: u64) -> u64 {
|
||||
a - b
|
||||
|
@ -255,7 +255,6 @@ use pyo3::prelude::*;
|
|||
|
||||
#[pymodule]
|
||||
fn my_extension(py: Python<'_>, m: &PyModule) -> PyResult<()> {
|
||||
|
||||
#[pyfn(m)]
|
||||
fn double(x: usize) -> usize {
|
||||
x * 2
|
||||
|
@ -273,7 +272,6 @@ use pyo3::prelude::*;
|
|||
|
||||
#[pymodule]
|
||||
fn my_extension(py: Python<'_>, m: &PyModule) -> PyResult<()> {
|
||||
|
||||
#[pyfunction]
|
||||
fn double(x: usize) -> usize {
|
||||
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> {
|
||||
if &addr == "0.0.0.0"{
|
||||
if &addr == "0.0.0.0" {
|
||||
Err(CustomIOError)
|
||||
} else {
|
||||
Ok(Connection{ /* ... */})
|
||||
|
|
|
@ -120,7 +120,7 @@ Below are the same examples as above which using the deprecated syntax:
|
|||
use pyo3::prelude::*;
|
||||
use pyo3::types::PyDict;
|
||||
|
||||
#[pyfunction(kwds="**")]
|
||||
#[pyfunction(kwds = "**")]
|
||||
fn num_kwds(kwds: Option<&PyDict>) -> usize {
|
||||
kwds.map_or(0, |dict| dict.len())
|
||||
}
|
||||
|
@ -166,12 +166,7 @@ impl MyClass {
|
|||
MyClass { num }
|
||||
}
|
||||
|
||||
#[args(
|
||||
num = "10",
|
||||
py_args = "*",
|
||||
name = "\"Hello\"",
|
||||
py_kwargs = "**"
|
||||
)]
|
||||
#[args(num = "10", py_args = "*", name = "\"Hello\"", py_kwargs = "**")]
|
||||
fn method(
|
||||
&mut self,
|
||||
num: i32,
|
||||
|
|
|
@ -44,7 +44,6 @@ impl Mapping {
|
|||
// ...
|
||||
// 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:
|
||||
|
@ -155,7 +154,7 @@ use pyo3::class::{PyBasicProtocol, PyIterProtocol};
|
|||
use pyo3::types::PyString;
|
||||
|
||||
#[pyclass]
|
||||
struct MyClass { }
|
||||
struct MyClass {}
|
||||
|
||||
#[pyproto]
|
||||
impl PyBasicProtocol for MyClass {
|
||||
|
@ -179,7 +178,7 @@ use pyo3::prelude::*;
|
|||
use pyo3::types::PyString;
|
||||
|
||||
#[pyclass]
|
||||
struct MyClass { }
|
||||
struct MyClass {}
|
||||
|
||||
#[pymethods]
|
||||
impl MyClass {
|
||||
|
@ -343,7 +342,7 @@ use pyo3::prelude::*;
|
|||
use pyo3::class::basic::PyBasicProtocol;
|
||||
|
||||
#[pyclass]
|
||||
struct MyClass { }
|
||||
struct MyClass {}
|
||||
|
||||
#[pyproto]
|
||||
impl PyBasicProtocol for MyClass {
|
||||
|
@ -359,7 +358,7 @@ After:
|
|||
use pyo3::prelude::*;
|
||||
|
||||
#[pyclass]
|
||||
struct MyClass { }
|
||||
struct MyClass {}
|
||||
|
||||
#[pymethods]
|
||||
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
|
||||
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(())
|
||||
# }).unwrap();
|
||||
```
|
||||
|
@ -568,7 +570,7 @@ There can be two fixes:
|
|||
#[pyclass]
|
||||
struct NotThreadSafe {
|
||||
shared_bools: Rc<RefCell<Vec<bool>>>,
|
||||
closure: Box<dyn Fn()>
|
||||
closure: Box<dyn Fn()>,
|
||||
}
|
||||
```
|
||||
|
||||
|
@ -581,7 +583,7 @@ There can be two fixes:
|
|||
#[pyclass]
|
||||
struct ThreadSafe {
|
||||
shared_bools: Arc<Mutex<Vec<bool>>>,
|
||||
closure: Box<dyn Fn() + Send>
|
||||
closure: Box<dyn Fn() + Send>,
|
||||
}
|
||||
```
|
||||
|
||||
|
@ -679,10 +681,10 @@ struct MyClass {}
|
|||
|
||||
#[pymethods]
|
||||
impl MyClass {
|
||||
#[new]
|
||||
fn new(obj: &PyRawObject) {
|
||||
obj.init(MyClass { })
|
||||
}
|
||||
#[new]
|
||||
fn new(obj: &PyRawObject) {
|
||||
obj.init(MyClass {})
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
|
@ -694,10 +696,10 @@ struct MyClass {}
|
|||
|
||||
#[pymethods]
|
||||
impl MyClass {
|
||||
#[new]
|
||||
fn new() -> Self {
|
||||
MyClass {}
|
||||
}
|
||||
#[new]
|
||||
fn new() -> Self {
|
||||
MyClass {}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
|
@ -720,7 +722,7 @@ Here is an example.
|
|||
|
||||
#[pyclass]
|
||||
struct Names {
|
||||
names: Vec<String>
|
||||
names: Vec<String>,
|
||||
}
|
||||
|
||||
#[pymethods]
|
||||
|
|
|
@ -43,7 +43,7 @@ But let's assume you have a long running Rust function which you would like to e
|
|||
# }
|
||||
# total
|
||||
# }
|
||||
#
|
||||
#
|
||||
fn search_sequential(contents: &str, needle: &str) -> usize {
|
||||
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
|
||||
# }
|
||||
#
|
||||
#
|
||||
# fn search_sequential(contents: &str, needle: &str) -> usize {
|
||||
# contents.lines().map(|line| count_line(line, needle)).sum()
|
||||
# }
|
||||
|
|
|
@ -43,7 +43,9 @@ fn main() -> PyResult<()> {
|
|||
print('called with no arguments')",
|
||||
"",
|
||||
"",
|
||||
)?.getattr("example")?.into();
|
||||
)?
|
||||
.getattr("example")?
|
||||
.into();
|
||||
|
||||
// call object without any arguments
|
||||
fun.call0(py)?;
|
||||
|
@ -87,8 +89,9 @@ fn main() -> PyResult<()> {
|
|||
print('called with no arguments')",
|
||||
"",
|
||||
"",
|
||||
)?.getattr("example")?.into();
|
||||
|
||||
)?
|
||||
.getattr("example")?
|
||||
.into();
|
||||
|
||||
// call object with PyDict
|
||||
let kwargs = [(key1, val1)].into_py_dict(py);
|
||||
|
@ -104,7 +107,7 @@ fn main() -> PyResult<()> {
|
|||
fun.call(py, (), Some(kwargs.into_py_dict(py)))?;
|
||||
|
||||
Ok(())
|
||||
})
|
||||
})
|
||||
}
|
||||
```
|
||||
|
||||
|
@ -124,7 +127,10 @@ use pyo3::prelude::*;
|
|||
fn main() -> PyResult<()> {
|
||||
Python::with_gil(|py| {
|
||||
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);
|
||||
Ok(())
|
||||
})
|
||||
|
@ -142,9 +148,11 @@ use pyo3::prelude::*;
|
|||
|
||||
# fn main() -> Result<(), ()> {
|
||||
Python::with_gil(|py| {
|
||||
let result = py.eval("[i * 10 for i in range(5)]", None, None).map_err(|e| {
|
||||
e.print_and_set_sys_last_vars(py);
|
||||
})?;
|
||||
let result = 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();
|
||||
assert_eq!(res, vec![0, 10, 20, 30, 40]);
|
||||
Ok(())
|
||||
|
@ -228,7 +236,8 @@ def leaky_relu(x, slope=0.01):
|
|||
|
||||
let kwargs = [("slope", 0.2)].into_py_dict(py);
|
||||
let lrelu_result: f64 = activators
|
||||
.getattr("leaky_relu")?.call((-1.0,), Some(kwargs))?
|
||||
.getattr("leaky_relu")?
|
||||
.call((-1.0,), Some(kwargs))?
|
||||
.extract()?;
|
||||
assert_eq!(lrelu_result, -0.2);
|
||||
# Ok(())
|
||||
|
|
|
@ -27,7 +27,7 @@ use pyo3::prelude::*;
|
|||
|
||||
#[pyclass]
|
||||
struct MyClass {
|
||||
num: u32,
|
||||
num: u32,
|
||||
}
|
||||
|
||||
#[pymethods]
|
||||
|
|
|
@ -25,13 +25,13 @@ 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);
|
||||
fn get_results(&self) -> Vec<f64>;
|
||||
fn set_variables(&mut self, inputs: &Vec<f64>);
|
||||
fn compute(&mut self);
|
||||
fn get_results(&self) -> Vec<f64>;
|
||||
}
|
||||
|
||||
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:
|
||||
|
@ -152,7 +152,7 @@ Now we add the PyO3 annotations to the trait implementation:
|
|||
```rust,ignore
|
||||
#[pymethods]
|
||||
impl Model for UserModel {
|
||||
// the previous trait implementation
|
||||
// the previous trait implementation
|
||||
}
|
||||
```
|
||||
|
||||
|
@ -411,7 +411,10 @@ impl Model for UserModel {
|
|||
.unwrap();
|
||||
|
||||
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()
|
||||
})
|
||||
|
@ -472,7 +475,7 @@ pub trait Model {
|
|||
}
|
||||
|
||||
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]
|
||||
|
@ -538,7 +541,10 @@ impl Model for UserModel {
|
|||
.unwrap();
|
||||
|
||||
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()
|
||||
})
|
||||
|
|
|
@ -89,7 +89,7 @@ For a `&PyAny` object reference `any` where the underlying object is a `#[pyclas
|
|||
# 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);
|
||||
let obj: &PyAny = Py::new(py, MyClass {})?.into_ref(py);
|
||||
|
||||
// To &PyCell<MyClass> with PyAny::downcast
|
||||
let _: &PyCell<MyClass> = obj.downcast()?;
|
||||
|
@ -238,7 +238,7 @@ so it also exposes all of the methods on `PyAny`.
|
|||
# use pyo3::prelude::*;
|
||||
# #[pyclass] struct MyClass { }
|
||||
# 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()
|
||||
let py_ref: PyRef<'_, MyClass> = cell.try_borrow()?;
|
||||
|
@ -258,7 +258,7 @@ let _: &mut MyClass = &mut *py_ref_mut;
|
|||
# use pyo3::prelude::*;
|
||||
# #[pyclass] struct MyClass { }
|
||||
# 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
|
||||
let _ = cell.repr()?;
|
||||
|
|
53
noxfile.py
53
noxfile.py
|
@ -2,6 +2,7 @@ import os
|
|||
import re
|
||||
import subprocess
|
||||
import sys
|
||||
import tempfile
|
||||
import time
|
||||
from glob import glob
|
||||
from pathlib import Path
|
||||
|
@ -231,6 +232,58 @@ def build_guide(session: nox.Session):
|
|||
_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")
|
||||
def address_sanitizer(session: nox.Session):
|
||||
_run(
|
||||
|
|
Loading…
Reference in New Issue