diff --git a/CHANGELOG.md b/CHANGELOG.md index 50ed3b3a..bd8c315b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,13 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. ## Unreleased +### Changed + +* The blanket implementations for `FromPyObject` for `&T` and `&mut T` are no longer specializable. Implement `PyTryFrom` for your type to control the behavior of `FromPyObject::extract()` for your types. +* The implementation for `IntoPy for T` where `U: FromPy` is no longer specializable. Control the behavior of this via the implementation of `FromPy`. + +## [0.8.5] + * Support for `#[name = "foo"]` attribute for `#[pyfunction]` and in `#[pymethods]`. [#692](https://github.com/PyO3/pyo3/pull/692) * Implemented `FromPyObject` for `HashMap` and `BTreeMap` diff --git a/Cargo.toml b/Cargo.toml index b23ab06e..dde8dbb9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "pyo3" -version = "0.8.4" +version = "0.8.5" description = "Bindings to Python interpreter" authors = ["PyO3 Project and Contributors "] readme = "README.md" @@ -22,7 +22,7 @@ appveyor = { repository = "fafhrd91/pyo3" } libc = "0.2.62" spin = "0.5.1" num-traits = "0.2.8" -pyo3cls = { path = "pyo3cls", version = "=0.8.4" } +pyo3cls = { path = "pyo3cls", version = "=0.8.5" } num-complex = { version = ">= 0.2", optional = true } num-bigint = { version = ">= 0.2", optional = true } inventory = "0.1.4" diff --git a/README.md b/README.md index 51899c69..bf9c9efc 100644 --- a/README.md +++ b/README.md @@ -50,7 +50,7 @@ name = "string_sum" crate-type = ["cdylib"] [dependencies.pyo3] -version = "0.8.4" +version = "0.8.5" features = ["extension-module"] ``` @@ -95,7 +95,7 @@ Add `pyo3` to your `Cargo.toml` like this: ```toml [dependencies] -pyo3 = "0.8.4" +pyo3 = "0.8.5" ``` Example program displaying the value of `sys.version` and the current user name: diff --git a/guide/src/class.md b/guide/src/class.md index 3f5c3374..6831c340 100644 --- a/guide/src/class.md +++ b/guide/src/class.md @@ -86,6 +86,23 @@ pyo3::inventory::collect!(MyClassGeneratedPyo3Inventory); # pyo3::py_run!(py, cls, "assert cls.__name__ == 'MyClass'") ``` +## Add class to module + +Custom Python classes can then be added to a module using `add_class`. + +```rust +# use pyo3::prelude::*; +# #[pyclass] +# struct MyClass { +# num: i32, +# debug: bool, +# } +#[pymodule] +fn mymodule(_py: Python, m: &PyModule) -> PyResult<()> { + m.add_class::()?; + Ok(()) +} +``` ## Get Python objects from `pyclass` You sometimes need to convert your `pyclass` into a Python object in Rust code (e.g., for testing it). @@ -568,13 +585,59 @@ use pyo3::types::{PyDict, PyTuple}; # #[pymethods] impl MyClass { - #[args(arg1=true, args="*", arg2=10, args3="\"Hello\"", kwargs="**")] - fn method(&self, arg1: bool, args: &PyTuple, arg2: i32, arg3: &str, kwargs: Option<&PyDict>) -> PyResult { - Ok(1) + #[new] + #[args(num = "-1", debug = "true")] + fn new(num: i32, debug: bool) -> Self { + MyClass { num, debug } + } + + #[args( + num = "10", + debug = "true", + py_args = "*", + name = "\"Hello\"", + py_kwargs = "**" + )] + fn method( + &mut self, + num: i32, + debug: bool, + name: &str, + py_args: &PyTuple, + py_kwargs: Option<&PyDict>, + ) -> PyResult { + self.debug = debug; + self.num = num; + Ok(format!( + "py_args={:?}, py_kwargs={:?}, name={}, num={}, debug={}", + py_args, py_kwargs, name, self.num, self.debug + )) + } + + fn make_change(&mut self, num: i32, debug: bool) -> PyResult { + self.num = num; + self.debug = debug; + Ok(format!("num={}, debug={}", self.num, self.debug)) } } ``` +N.B. the position of the `"*"` argument (if included) controls the system of handling positional and keyword arguments. In Python: +```python +import mymodule +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 +``` ## Class customizations diff --git a/guide/src/get_started.md b/guide/src/get_started.md index ab04185c..ae1e864c 100644 --- a/guide/src/get_started.md +++ b/guide/src/get_started.md @@ -44,7 +44,7 @@ name = "string_sum" crate-type = ["cdylib"] [dependencies.pyo3] -version = "0.8.4" +version = "0.8.5" features = ["extension-module"] ``` @@ -89,7 +89,7 @@ Add `pyo3` to your `Cargo.toml` like this: ```toml [dependencies] -pyo3 = "0.8.4" +pyo3 = "0.8.5" ``` Example program displaying the value of `sys.version` and the current user name: diff --git a/pyo3-derive-backend/Cargo.toml b/pyo3-derive-backend/Cargo.toml index 9b0563c9..a040ab89 100644 --- a/pyo3-derive-backend/Cargo.toml +++ b/pyo3-derive-backend/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "pyo3-derive-backend" -version = "0.8.4" +version = "0.8.5" description = "Code generation for PyO3 package" authors = ["PyO3 Project and Contributors "] keywords = ["pyo3", "python", "cpython", "ffi"] diff --git a/pyo3-derive-backend/src/defs.rs b/pyo3-derive-backend/src/defs.rs index e099f853..145b56f5 100644 --- a/pyo3-derive-backend/src/defs.rs +++ b/pyo3-derive-backend/src/defs.rs @@ -31,7 +31,7 @@ pub const OBJECT: Proto = Proto { MethodProto::Binary { name: "__delattr__", arg: "Name", - pyres: true, + pyres: false, proto: "pyo3::class::basic::PyObjectDelAttrProtocol", }, MethodProto::Unary { diff --git a/pyo3cls/Cargo.toml b/pyo3cls/Cargo.toml index 7ed2a69e..344a2da3 100644 --- a/pyo3cls/Cargo.toml +++ b/pyo3cls/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "pyo3cls" -version = "0.8.4" +version = "0.8.5" description = "Proc macros for PyO3 package" authors = ["PyO3 Project and Contributors "] keywords = ["pyo3", "python", "cpython", "ffi"] @@ -17,7 +17,7 @@ proc-macro = true quote = "1" proc-macro2 = "1" syn = { version = "1", features = ["full", "extra-traits"] } -pyo3-derive-backend = { path = "../pyo3-derive-backend", version = "=0.8.4" } +pyo3-derive-backend = { path = "../pyo3-derive-backend", version = "=0.8.5" } [features] unsound-subclass = ["pyo3-derive-backend/unsound-subclass"] diff --git a/src/conversion.rs b/src/conversion.rs index a6f65c53..d24e9f48 100644 --- a/src/conversion.rs +++ b/src/conversion.rs @@ -146,7 +146,7 @@ impl IntoPy for T where U: FromPy, { - default fn into_py(self, py: Python) -> U { + fn into_py(self, py: Python) -> U { U::from_py(self, py) } } @@ -250,7 +250,7 @@ where T: PyTryFrom<'a>, { #[inline] - default fn extract(ob: &'a PyAny) -> PyResult<&'a T> { + fn extract(ob: &'a PyAny) -> PyResult<&'a T> { Ok(T::try_from(ob)?) } } @@ -261,7 +261,7 @@ where T: PyTryFrom<'a>, { #[inline] - default fn extract(ob: &'a PyAny) -> PyResult<&'a mut T> { + fn extract(ob: &'a PyAny) -> PyResult<&'a mut T> { Ok(T::try_from_mut(ob)?) } } diff --git a/src/lib.rs b/src/lib.rs index 375e76cd..0367af54 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -48,7 +48,7 @@ //! crate-type = ["cdylib"] //! //! [dependencies.pyo3] -//! version = "0.8.4" +//! version = "0.8.5" //! features = ["extension-module"] //! ``` //! @@ -93,7 +93,7 @@ //! //! ```toml //! [dependencies] -//! pyo3 = "0.8.4" +//! pyo3 = "0.8.5" //! ``` //! //! Example program displaying the value of `sys.version`: