diff --git a/guide/src/class.md b/guide/src/class.md index 48077d30..71afdcfe 100644 --- a/guide/src/class.md +++ b/guide/src/class.md @@ -4,7 +4,7 @@ Python class generation is powered by unstable [Procedural Macros](https://doc.r [Specialization](https://github.com/rust-lang/rfcs/blob/master/text/1210-impl-specialization.md) features, so you need to turn on `proc_macro` and `specialization` features: ```rust -#![feature(proc_macro, specialization, associated_consts)] +#![feature(proc_macro, specialization)] extern crate pyo3; ``` @@ -223,11 +223,7 @@ impl MyClass { } ``` -## Method arguments - -## Class customizations - -### Callable object +## Callable object To specify custom `__call__` method for custom class, call method needs to be annotated with `#[call]` attribute. Arguments of the method are speficied same as for instance method. @@ -243,3 +239,187 @@ impl MyClass { Ok(self.num) } } +``` + +## Method arguments + +By default pyo3 library uses function signature to determine which arguments are required. +Then it scans incoming `args` parameter and then incoming `kwargs` parameter. If it can not +find all required parameters, it raises `TypeError` exception. +It is possible to override default bahavior with `#[args(...)]` attribute. `args` attribute +accept comma separated list of parameters in form `attr_name="default value"`. Each parameter +has to match method parameter by name. + +Each parameter could one of following type: + + * "\*": var arguments separator, each parameter defined after "*" is keyword only paramters. + coresponds to python's `def meth(*, arg1.., arg2=..)` + * args="\*": "args" is var args, coresponds to python's `def meth(*args)`. Type of `args` + parameter has to be `&PyTuple`. + * kwargs="\*\*": "kwargs" is kwyword arguments, coresponds to python's `def meth(**kwargs)`. + Type of `kwargs` parameter has to be `Option<&PyDict>`. + * arg="Value": arguments with default value. coresponds to python's `def meth(arg=Value)`. + if `arg` argument is defined after var arguments it is treated as keyword argument. + Note that `Value` has to be valid rust code, pyo3 just inserts it into generated + code unmodified. + +Example: +```rust +#[py::methods] +impl MyClass { + + #[args(arg1=true, args="*", arg2=10, kwargs="**")] + fn method(&self, arg1: bool, args: &PyTuple, arg2: i32, kwargs: Option<&PyTuple>) -> PyResult { + Ok(1) + } +} +``` + + +## Class customizations + +Python object model defines several protocols for different object behavior, +like sequence, mapping or number protocols. pyo3 library defines separate trait for each +of them. To provide specific python object behavior you need to implement specific trait +for your struct. Important note, each protocol implementation block has to be annotated +with `#[py::proto]` attribute. + +### Basic object customization + +[`PyObjectProtocol`](https://pyo3.github.io/pyo3/pyo3/class/basic/trait.PyObjectProtocol.html) trait provide several basic customizations. + +#### Attribute access + +To customize object attribute access define following methods: + + * `fn __getattr__(&self, name: FromPyObject) -> PyResult` + * `fn __setattr__(&mut self, name: FromPyObject, value: FromPyObject) -> PyResult<()>` + * `fn __delattr__(&mut self, name: FromPyObject) -> PyResult<()>` + +Each methods coresponds to python's `self.attr`, `self.attr = value` and `del self.attr` code. + +#### String Conversions + + * `fn __repr__(&self) -> PyResult>` + * `fn __str__(&self) -> PyResult>` + + Possible return types for `__str__` and `__repr__` are `PyResult` or `PyResult`. + In Python 2.7, Unicode strings returned by `__str__` and `__repr__` will be converted to byte strings + by the Python runtime, which results in an exception if the string contains non-ASCII characters. + + * `fn __bytes__(&self) -> PyResult` + + On Python 3.x, provides the conversion to `bytes`. + On Python 2.7, `__bytes__` is allowed but has no effect. + + * `fn __unicode__(&self) -> PyResult` + + On Python 2.7, provides the conversion to `unicode`. + On Python 3.x, `__unicode__` is allowed but has no effect. + + * `fn __format__(&self, format_spec: &str) -> PyResult>` + + Special method that is used by the `format()` builtin and the `str.format()` method. + Possible return types are `PyResult` or `PyResult`. + +#### Comparison operators + + * `fn __richcmp__(&self, other: impl FromPyObject, op: CompareOp) -> PyResult` + + Overloads Python comparison operations (`==`, `!=`, `<`, `<=`, `>`, and `>=`). + The `op` argument indicates the comparison operation being performed. + The return type will normally be `PyResult`, but any Python object can be returned. + If `other` is not of the type specified in the signature, the generated code will + automatically `return NotImplemented`. + + * `fn __hash__(&self) -> PyResult` + + Objects that compare equal must have the same hash value. + The return type must be `PyResult` where `T` is one of Rust's primitive integer types. + +#### Other methods + + * `fn __bool__(&self) -> PyResult` + + Determines the "truthyness" of the object. + This method works for both python 3 and python 2, + even on Python 2.7 where the Python spelling was `__nonzero__`. + +### Garbage Collector Integration + +If your type owns references to other python objects, you will need to +integrate with Python's garbage collector so that the GC is aware of +those references. +To do this, implement [`PyGCProtocol`](https://pyo3.github.io/pyo3/pyo3/class/gc/trait.PyGCProtocol.html) trait for your struct. +It includes two methods `__traverse__` and `__clear__`. +These correspond to the slots `tp_traverse` and `tp_clear` in the Python C API. +`__traverse__` must call `visit.call()` for each reference to another python object. +`__clear__` must clear out any mutable references to other python objects +(thus breaking reference cycles). Immutable references do not have to be cleared, +as every cycle must contain at least one mutable reference. +Example: +```rust +#![feature(proc_macro, specialization)] +extern crate pyo3; + +use pyo3::{py, PyObject, PyGCProtocol, PyVisit, PyTraverseError}; + +#[py::class] +struct ClassWithGCSupport { + obj: Option, +} + +#[py::proto] +impl PyGCProtocol for ClassWithGCSupport { + fn __traverse__(&self, visit: PyVisit) -> Result<(), PyTraverseError> { + if let Some(ref obj) = self.obj { + visit.call(obj)? + } + Ok(()) + } + + fn __clear__(&mut self) { + if let Some(obj) = self.obj.take() { + // Release reference, this decrements ref counter. + self.py().release(obj); + } + } +} +``` + +Special protocol trait implementation has to be annotated with `#[py::proto]` attribute. + +### Iterator Types + +Iterators can be defined using the +[`PyIterProtocol`](https://pyo3.github.io/pyo3/pyo3/class/iter/trait.PyIterProtocol.html) trait. +It includes two methods `__iter__` and `__next__`: + * `fn __iter__(&mut self) -> PyResult` + * `fn __next__(&mut self) -> PyResult>` + + Returning `Ok(None)` from `__next__` indicates that that there are no further items. + +Example: +```rust +#![feature(proc_macro, specialization)] +extern crate pyo3; + +use pyo3::{py, PyObject, PyResult, PyIterProtocol}; + +#[py::class] +struct MyIterator { + iter: Box + Send> +} + +#[py::proto] +impl PyIterProtocol { + + fn __iter__(&mut self) -> PyResult { + Ok(self.into()) + } + fn __next__(&mut self) -> PyResult> { + Ok(self.iter.next()) + } +} +# fn main() {} +``` diff --git a/src/class/buffer.rs b/src/class/buffer.rs index 4dc78967..19c61c6d 100644 --- a/src/class/buffer.rs +++ b/src/class/buffer.rs @@ -15,6 +15,9 @@ use callback::UnitCallbackConverter; /// Buffer protocol interface +/// +/// more information on buffer protocol can be found +/// https://docs.python.org/3/c-api/buffer.html #[allow(unused_variables)] pub trait PyBufferProtocol<'p> : PyTypeInfo + PyDowncastFrom { diff --git a/src/class/iter.rs b/src/class/iter.rs index ad087a03..361aeed7 100644 --- a/src/class/iter.rs +++ b/src/class/iter.rs @@ -1,10 +1,6 @@ // Copyright (c) 2017-present PyO3 Project and Contributors - -//! Python Iterator Interface +//! Python Iterator Interface. //! Trait and support implementation for implementing iterators -//! -//! more information -//! https://docs.python.org/3/c-api/typeobj.html#c.PyTypeObject.tp_iter use std::ptr; @@ -16,7 +12,10 @@ use conversion::IntoPyObject; use callback::{CallbackConverter, PyObjectCallbackConverter}; -/// Iterator protocol +/// Python Iterator Interface. +/// +/// more information +/// https://docs.python.org/3/c-api/typeobj.html#c.PyTypeObject.tp_iter #[allow(unused_variables)] pub trait PyIterProtocol<'p> : PyTypeInfo + PyDowncastFrom { fn __iter__(&'p mut self)