pyo3_pytests/
pyclasses.rs

1use std::{thread, time};
2
3use pyo3::exceptions::{PyStopIteration, PyValueError};
4use pyo3::prelude::*;
5use pyo3::types::PyType;
6
7#[pyclass]
8struct EmptyClass {}
9
10#[pymethods]
11impl EmptyClass {
12    #[new]
13    fn new() -> Self {
14        EmptyClass {}
15    }
16
17    fn method(&self) {}
18
19    fn __len__(&self) -> usize {
20        0
21    }
22}
23
24/// This is for demonstrating how to return a value from __next__
25#[pyclass]
26#[derive(Default)]
27struct PyClassIter {
28    count: usize,
29}
30
31#[pymethods]
32impl PyClassIter {
33    #[new]
34    pub fn new() -> Self {
35        Default::default()
36    }
37
38    fn __next__(&mut self) -> PyResult<usize> {
39        if self.count < 5 {
40            self.count += 1;
41            Ok(self.count)
42        } else {
43            Err(PyStopIteration::new_err("Ended"))
44        }
45    }
46}
47
48#[pyclass]
49#[derive(Default)]
50struct PyClassThreadIter {
51    count: usize,
52}
53
54#[pymethods]
55impl PyClassThreadIter {
56    #[new]
57    pub fn new() -> Self {
58        Default::default()
59    }
60
61    fn __next__(&mut self, py: Python<'_>) -> usize {
62        let current_count = self.count;
63        self.count += 1;
64        if current_count == 0 {
65            py.allow_threads(|| thread::sleep(time::Duration::from_millis(100)));
66        }
67        self.count
68    }
69}
70
71/// Demonstrates a base class which can operate on the relevant subclass in its constructor.
72#[pyclass(subclass)]
73#[derive(Clone, Debug)]
74struct AssertingBaseClass;
75
76#[pymethods]
77impl AssertingBaseClass {
78    #[new]
79    #[classmethod]
80    fn new(cls: &Bound<'_, PyType>, expected_type: Bound<'_, PyType>) -> PyResult<Self> {
81        if !cls.is(&expected_type) {
82            return Err(PyValueError::new_err(format!(
83                "{:?} != {:?}",
84                cls, expected_type
85            )));
86        }
87        Ok(Self)
88    }
89}
90
91#[pyclass]
92struct ClassWithoutConstructor;
93
94#[cfg(any(Py_3_10, not(Py_LIMITED_API)))]
95#[pyclass(dict)]
96struct ClassWithDict;
97
98#[cfg(any(Py_3_10, not(Py_LIMITED_API)))]
99#[pymethods]
100impl ClassWithDict {
101    #[new]
102    fn new() -> Self {
103        ClassWithDict
104    }
105}
106
107#[pymodule(gil_used = false)]
108pub fn pyclasses(m: &Bound<'_, PyModule>) -> PyResult<()> {
109    m.add_class::<EmptyClass>()?;
110    m.add_class::<PyClassIter>()?;
111    m.add_class::<PyClassThreadIter>()?;
112    m.add_class::<AssertingBaseClass>()?;
113    m.add_class::<ClassWithoutConstructor>()?;
114    #[cfg(any(Py_3_10, not(Py_LIMITED_API)))]
115    m.add_class::<ClassWithDict>()?;
116
117    Ok(())
118}
⚠️ Internal Docs ⚠️ Not Public API 👉 Official Docs Here