You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: CHANGELOG.md
+1
Original file line number
Diff line number
Diff line change
@@ -23,6 +23,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
23
23
- Add `PyCapsule`, exposing the [Capsule API](https://docs.python.org/3/c-api/capsule.html#capsules). [#1980](https://github.com/PyO3/pyo3/pull/1980)
24
24
- All PyO3 proc-macros except the deprecated `#[pyproto]` now accept a supplemental attribute `#[pyo3(crate = "some::path")]` that specifies
25
25
where to find the `pyo3` crate, in case it has been renamed or is re-exported and not found at the crate root. [#2022](https://github.com/PyO3/pyo3/pull/2022)
26
+
- Enable `#[pyclass]` for fieldless (aka C-like) enums. [#2034](https://github.com/PyO3/pyo3/pull/2034)
Copy file name to clipboardExpand all lines: guide/src/class.md
+125-9
Original file line number
Diff line number
Diff line change
@@ -2,7 +2,7 @@
2
2
3
3
PyO3 exposes a group of attributes powered by Rust's proc macro system for defining Python classes as Rust structs.
4
4
5
-
The main attribute is `#[pyclass]`, which is placed upon a Rust `struct` to generate a Python type for it. A struct will usually also have *one*`#[pymethods]`-annotated `impl` block for the struct, which is used to define Python methods and constants for the generated Python type. (If the [`multiple-pymethods`] feature is enabled each `#[pyclass]` is allowed to have multiple `#[pymethods]` blocks.) Finally, there may be multiple `#[pyproto]` trait implementations for the struct, which are used to define certain python magic methods such as `__str__`.
5
+
The main attribute is `#[pyclass]`, which is placed upon a Rust `struct`or a fieldless `enum` (a.k.a. C-like enum) to generate a Python type for it. They will usually also have *one*`#[pymethods]`-annotated `impl` block for the struct, which is used to define Python methods and constants for the generated Python type. (If the [`multiple-pymethods`] feature is enabled each `#[pyclass]` is allowed to have multiple `#[pymethods]` blocks.) Finally, there may be multiple `#[pyproto]` trait implementations for the struct, which are used to define certain python magic methods such as `__str__`.
6
6
7
7
This chapter will discuss the functionality and configuration these attributes offer. Below is a list of links to the relevant section of this chapter for each:
8
8
@@ -20,9 +20,7 @@ This chapter will discuss the functionality and configuration these attributes o
20
20
21
21
## Defining a new class
22
22
23
-
To define a custom Python class, a Rust struct needs to be annotated with the
24
-
`#[pyclass]` attribute.
25
-
23
+
To define a custom Python class, add the `#[pyclass]` attribute to a Rust struct or a fieldless enum.
Because Python objects are freely shared between threads by the Python interpreter, all structs annotated with `#[pyclass]` must implement `Send` (unless annotated with [`#[pyclass(unsendable)]`](#customizing-the-class)).
40
+
Because Python objects are freely shared between threads by the Python interpreter, all types annotated with `#[pyclass]` must implement `Send` (unless annotated with [`#[pyclass(unsendable)]`](#customizing-the-class)).
37
41
38
-
The above example generates implementations for [`PyTypeInfo`], [`PyTypeObject`], and [`PyClass`] for `MyClass`. To see these generated implementations, refer to the [implementation details](#implementation-details) at the end of this chapter.
42
+
The above example generates implementations for [`PyTypeInfo`], [`PyTypeObject`], and [`PyClass`] for `MyClass` and `MyEnum`. To see these generated implementations, refer to the [implementation details](#implementation-details) at the end of this chapter.
39
43
40
44
## Adding the class to a module
41
45
@@ -140,8 +144,8 @@ so that they can benefit from a freelist. `XXX` is a number of items for the fre
140
144
*`gc` - Classes with the `gc` parameter participate in Python garbage collection.
141
145
If a custom class contains references to other Python objects that can be collected, the [`PyGCProtocol`]({{#PYO3_DOCS_URL}}/pyo3/class/gc/trait.PyGCProtocol.html) trait has to be implemented.
142
146
*`weakref` - Adds support for Python weak references.
143
-
*`extends=BaseType` - Use a custom base class. The base `BaseType` must implement `PyTypeInfo`.
144
-
*`subclass` - Allows Python classes to inherit from this class.
147
+
*`extends=BaseType` - Use a custom base class. The base `BaseType` must implement `PyTypeInfo`.`enum` pyclasses can't use a custom base class.
148
+
*`subclass` - Allows Python classes to inherit from this class.`enum` pyclasses can't be inherited from.
145
149
*`dict` - Adds `__dict__` support, so that the instances of this type have a dictionary containing arbitrary instance variables.
146
150
*`unsendable` - Making it safe to expose `!Send` structs to Python, where all object can be accessed
147
151
by multiple threads. A class marked with `unsendable` panics when accessed by another thread.
@@ -351,7 +355,7 @@ impl SubClass {
351
355
## Object properties
352
356
353
357
PyO3 supports two ways to add properties to your `#[pyclass]`:
354
-
- For simple fields with no side effects, a `#[pyo3(get, set)]` attribute can be added directly to the field definition in the `#[pyclass]`.
358
+
- For simple struct fields with no side effects, a `#[pyo3(get, set)]` attribute can be added directly to the field definition in the `#[pyclass]`.
355
359
- For properties which require computation you can define `#[getter]` and `#[setter]` functions in the [`#[pymethods]`](#instance-methods) block.
356
360
357
361
We'll cover each of these in the following sections.
@@ -802,6 +806,118 @@ impl MyClass {
802
806
Note that `text_signature` on classes is not compatible with compilation in
803
807
`abi3` mode until Python 3.10 or greater.
804
808
809
+
## #[pyclass] enums
810
+
811
+
Currently PyO3 only supports fieldless enums. PyO3 adds a class attribute for each variant, so you can access them in Python without defining `#[new]`. PyO3 also provides default implementations of `__richcmp__` and `__int__`, so they can be compared using `==`:
812
+
813
+
```rust
814
+
# usepyo3::prelude::*;
815
+
#[pyclass]
816
+
enumMyEnum {
817
+
Variant,
818
+
OtherVariant,
819
+
}
820
+
821
+
Python::with_gil(|py| {
822
+
letx=Py::new(py, MyEnum::Variant).unwrap();
823
+
lety=Py::new(py, MyEnum::OtherVariant).unwrap();
824
+
letcls=py.get_type::<MyEnum>();
825
+
pyo3::py_run!(py, xycls, r#"
826
+
assert x == cls.Variant
827
+
assert y == cls.OtherVariant
828
+
assert x != y
829
+
"#)
830
+
})
831
+
```
832
+
833
+
You can also convert your enums into `int`:
834
+
835
+
```rust
836
+
# usepyo3::prelude::*;
837
+
#[pyclass]
838
+
enumMyEnum {
839
+
Variant,
840
+
OtherVariant=10,
841
+
}
842
+
843
+
Python::with_gil(|py| {
844
+
letcls=py.get_type::<MyEnum>();
845
+
letx=MyEnum::Variantasi32; // The exact value is assigned by the compiler.
846
+
pyo3::py_run!(py, clsx, r#"
847
+
assert int(cls.Variant) == x
848
+
assert int(cls.OtherVariant) == 10
849
+
assert cls.OtherVariant == 10 # You can also compare against int.
You may not use enums as a base class or let enums inherit from other classes.
898
+
899
+
```rust,compile_fail
900
+
# use pyo3::prelude::*;
901
+
#[pyclass(subclass)]
902
+
enum BadBase{
903
+
Var1,
904
+
}
905
+
```
906
+
907
+
```rust,compile_fail
908
+
# use pyo3::prelude::*;
909
+
910
+
#[pyclass(subclass)]
911
+
struct Base;
912
+
913
+
#[pyclass(extends=Base)]
914
+
enum BadSubclass{
915
+
Var1,
916
+
}
917
+
```
918
+
919
+
`#[pyclass]` enums are currently not interoperable with `IntEnum` in Python.
920
+
805
921
## Implementation details
806
922
807
923
The `#[pyclass]` macros rely on a lot of conditional code generation: each `#[pyclass]` can optionally have a `#[pymethods]` block as well as several different possible `#[pyproto]` trait implementations.
/// | `gc` | Participate in Python's [garbage collection][5]. Required if your type contains references to other Python objects. If you don't (or incorrectly) implement this, contained Python objects may be hidden from Python's garbage collector and you may leak memory. Note that leaking memory, while undesirable, [is safe behavior][7].|
89
89
/// | `weakref` | Allows this class to be [weakly referenceable][6]. |
90
90
/// | <span style="white-space: pre">`extends = BaseType`</span> | Use a custom baseclass. Defaults to [`PyAny`][4] |
91
-
/// | `subclass` | Allows other Python classes and `#[pyclass]` to inherit from this class. |
91
+
/// | `subclass` | Allows other Python classes and `#[pyclass]` to inherit from this class. Enums cannot be subclassed. |
92
92
/// | `unsendable` | Required if your struct is not [`Send`][3]. Rather than using `unsendable`, consider implementing your struct in a threadsafe way by e.g. substituting [`Rc`][8] with [`Arc`][9]. By using `unsendable`, your class will panic when accessed by another thread.|
93
93
/// | <span style="white-space: pre">`module = "module_name"`</span> | Python code will see the class as being defined in this module. Defaults to `builtins`. |
0 commit comments