Expand description
This library provides derive macros of Python spacial methods and a class attributes for PyO3.
The field attribute #[pyderive(..)] helps to customize implementations,
like dataclasses.field() of Python.
It requires to enable multiple-pymethods feature of PyO3
because the derive macros that this library provides may implement multiple #[pymethods].
§Example
// Enable `multiple-pymethods` feature of PyO3
use pyo3::prelude::*;
use pyderive::*;
// Place #[derive(PyNew, ...)] before #[pyclass]
#[derive(PyNew, PyMatchArgs, PyRepr, PyEq)]
#[pyclass(get_all)]
#[derive(PartialEq, Hash)]
struct MyClass {
string: String,
integer: i64,
option: Option<i64>
}# Python script
from rust_module import MyClass
# Derives __new__()
m = MyClass("a", 1, None)
# Derives __match_args__ (supports Pattern Matching by positional arguments)
match m:
case MyClass(a, b, c):
assert a == "a"
assert b == 1
assert c is None
case _:
raise AssertionError
# Derives __repr__(), calls Python repr() recursively
assert str(m) == "MyClass(string='a', integer=1, option=None)"
assert repr(m) == "MyClass(string='a', integer=1, option=None)"
# Derives __eq__() that depends on PartialEq trait
assert m == MyClass("a", 1, None)§Detail
Some macros change implementations depend on #[pyclass(..)] and #[pyo3(..)] arguments,
hence it should place #[derive(PyNew)] etc. before #[pyclass(..)] and #[pyo3(..)].
We list the default implementations that the macros generate.
| Derive Macro | Derives |
|---|---|
PyNew | __new__() with all fields |
PyMatchArgs | __match_args__ class attr. with get fields |
PyRepr | __repr__() returns get and set fields |
PyStr | __str__() returns get and set fields |
PyIter | __iter__() returns an iterator of get fields |
PyReversed | __reversed__() returns an iterator of get fields |
PyLen | __len__() returns number of get fields |
PyDataclassFields | __dataclass_fields__ class attr. with all fields |
Notes, methods implemented by PyRepr and PyStr are recursively calls repr() or str() like a Python dataclass.
We call the field is get (or set) field
if the field has a #[pyclass/pyo3(get)] (or #[pyclass/pyo3(set)]) attribute or
its struct has a #[pyclass/pyo3(get_all)] (or #[pyclass/pyo3(set_all)]) attribute.
The following derive macros depend on traits.
| Derive Macro | Derives |
|---|---|
PyEq | __eq__() and __ne__(), depends on PartialEq |
PyOrd | __lt__(), __le__(), __gt__() and __ge__(), depend on PartialOrd |
PyRichCmp | ==, !=, >, >=, < and <= by __richcmp__(), depend on PartialEq and PartialOrd |
PyNumeric | Numeric op traits (__add__() etc.) |
PyBitwise | Bitwise op traits (__and__() etc.) |
Notes, implementation of PyEq and PyOrd does not use __richcmp__().
Module pyderive::ops and pyderive::convert provides
derive macros that implement individual method that enumerating numeric type (__add__() etc.) and
called by builtin functions (__int__() etc.).
§Customize Implementation
The field attributes #[pyderive(..)] is used to customize implementations
produced by pyderive’s derive.
use pyderive::*;
#[derive(PyNew, PyRepr)]
#[pyclass]
struct MyClass {
string: String,
#[pyderive(repr=false)]
#[pyo3(get)]
integer: i64,
#[pyderive(default=10)]
option: Option<i64>
}It allows to omit the right-hand side,
and it evaluates to the right-hand as true
except default , for example,
#[pyderive(repr)] is equivalent to #[pyderive(repr=true)].
-
#[pyderive(repr=<bool>)]If
repr=true, the field is included in the string that the__repr__()method returns; ifrepr=false, it isn’t.The derive macro
PyDataclassFieldsreads this attribute also, seePyDataclassFieldsfor detail. -
#[pyderive(str=<bool>)]If
str=true, the field is included in the string that the__str__()method returns; ifstr=false, it isn’t. -
#[pyderive(new=<bool>)]If
new=false, the field is excluded from the arguments of the__new__()method. Notes,new=truehas no effect.The derive macro
PyDataclassFieldsreads this attribute also, seePyDataclassFieldsfor detail. -
#[pyderive(default=<expr>)]This is used to customize default value for the
__new__()method. It supports any rust expression which PyO3 supports, e.g.,#[derive(PyNew)] #[pyclass] struct PyClass { #[pyderive(default = Some("str".to_string()))] field: Option<String>, }We note that this internally produces
#[pyo3(signature = ..)]attribute.-
No
#[pyderive(..)](for example, justfield: i64)Pseudocode:
def __new__(cls, field): self = super().__new__(cls) self.field = field return self -
#[pyderive(new=false)]The field is excluded from the arguments, and initialized by
Default::default()in the__new__()method. We note that it is evaluated on every__new__()call.Pseudocode:
def __new__(cls): self = super().__new__(cls) self.field = field::default() # call rust fn return self -
#[pyderive(default=<expr>)]The field is included to the arguments with default value
<expr>. We note that<expr>(rust code) is evaluated on every__new__()call (PyO3 feature).Pseudocode:
def __new__(cls, field=<expr>): self = super().__new__(cls) self.field = field return self -
#[pyderive(new=false, default=<expr>)]The field is excluded from the arguments, and initialized with
<expr>in the__new__()method. We note that<expr>(rust code) is evaluated on every__new__()call.Pseudocode:
def __new__(cls): self = super().__new__(cls) self.field = <expr> return self
-
-
#[pyderive(default_factory=true)]If
default_factory=true, let thedefault_factoryattribute ofFieldobj belambda: <expr>, and let thedefaultattribute bedataclasses.MISSING, where<expr>is given by#[pyderive(default=<expr>)]. Notes,default_factory=falsehas no effect, If the field is not marked by#[pyderive(default=<expr>)], this ignores.See
PyDataclassFieldsfor detail. -
#[pyderive(kw_only=true)]If
kw_only=true, the following fields are keyword only arguments in the__new__()method, like*anddataclasses.KW_ONLY. Note,kw_only=falsehas no effect.The derive macro
PyDataclassFieldsreads this attribute also, seePyDataclassFieldsfor detail. -
#[pyderive(match_args=<bool>)]If
match_args=true, the field is included in the__match_args__class attribute; ifmatch_args=false, it isn’t.We note that, as far as I know, the field must be accessible on the pattern matching. For example, pattern matching does not work with not
getfield without a getter (even ifmatch_args=true), but it does work if the field has a getter. -
#[pyderive(iter=<bool>)]If
iter=true, the field is included in the iterator that__iter__()and__reversed__()return; ifiter=false, it isn’t. -
#[pyderive(len=<bool>)]If
len=true, the field is counted by the__len__(); iflen=false, it isn’t. -
#[pyderive(dataclass_field=false)]If
dataclass_field=false, the field is excluded from the__dataclass_fields__dict. Notes,dataclass_field=truehas no effect.See
PyDataclassFieldsfor detail. -
#[pyderive(annotation=<str>)]The derive macro
PyDataclassFieldsreads this attribute, seePyDataclassFieldsfor detail.
Modules§
- convert
- Provides derive macros that implements conversion by built-in functions.
- ops
- Provides derive macros that implements enumeration of numeric type.
Derive Macros§
- PyBitwise
- Derive macro generating an impl of bitwise op methods/fns base on std::ops traits.
- PyDataclass
Fields - Derive macro generating a
__dataclass_fields__fn/Python class attribute. - PyEq
- Derive macro generating a
__eq__()and__ne__()fn/Python methods. - PyHash
- Derive macro generating a
__hash__()fn/Python method. - PyIter
- Derive macro generating a
__iter__()fn/Python method. - PyLen
- Derive macro generating a
__len__()fn/Python method. - PyMatch
Args - Derive macro generating a
__match_args__const/Python class attribute. - PyNew
- Derive macro generating a
__new__()Python method. - PyNumeric
- Derive macro generating an impl of numeric op methods/fns base on std::ops traits.
- PyOrd
- Derive macro generating
__lt__(),__le__(),__gt__()and__ge__()fn/Python methods. - PyRepr
- Derive macro generating a
__repr__()fn/Python method. - PyReversed
- Derive macro generating a
__reversed__()fn/Python method. - PyRich
Cmp - Derive macro generating
__richcmp__fn that provides Python comparison operations (==,!=,<,<=,>, and>=). - PyStr
- Derive macro generating a
__str__()fn/Python method. - ToPy
Object - Derive macro generating an impl of the trait
ToPyObjectby traitIntoPy<PyObject>.