diff --git a/guide/src/class.md b/guide/src/class.md index 353cb5b0..90c25444 100644 --- a/guide/src/class.md +++ b/guide/src/class.md @@ -18,12 +18,13 @@ struct MyClass { The above example generates implementations for `PyTypeInfo`, `PyTypeObject` and `PyClass` for `MyClass`. -Specifically, the following implementation is generated. +Specifically, the following implementation is generated: ```rust use pyo3::prelude::*; use pyo3::{PyClassShell, PyTypeInfo}; +/// Class for demonstration struct MyClass { num: i32, debug: bool, @@ -38,7 +39,7 @@ impl PyTypeInfo for MyClass { const NAME: &'static str = "MyClass"; const MODULE: Option<&'static str> = None; - const DESCRIPTION: &'static str = "This is a demo class"; + const DESCRIPTION: &'static str = "Class for demonstration"; const FLAGS: usize = 0; #[inline] @@ -89,14 +90,14 @@ pyo3::inventory::collect!(MyClassGeneratedPyo3Inventory); ## Get Python objects from `pyclass` You sometimes need to convert your `pyclass` into a Python object in Rust code (e.g., for testing it). -For getting *GIL-bounded*(i.e., with `'py` lifetime) references of `pyclass`, +For getting *GIL-bounded* (i.e., with `'py` lifetime) references of `pyclass`, you can use `PyClassShell`. Or you can use `Py` directly, for *not-GIL-bounded* references. ### `PyClassShell` `PyClassShell` represents the actual layout of `pyclass` on the Python heap. -If you want to instantiate `pyclass` in Python and get the the reference, +If you want to instantiate `pyclass` in Python and get the reference, you can use `PyClassShell::new_ref` or `PyClassShell::new_mut`. ```rust @@ -182,21 +183,24 @@ impl MyClass { } ``` -Rules for the `new` method: +If no method marked with `#[new]` is declared, object instances can only be +created from Rust, but not from Python. -* If no method marked with `#[new]` is declared, object instances can only be created - from Rust, but not from Python. -* All parameters are from Python. -* It can return one of these types: - - `T` - - `PyResult` - - `PyClassInitializer` - - `PyResult>` -* If you pyclass declared with `#[pyclass(extends=BaseType)]` and `BaseType` -is also `#[pyclass]`, you have to return `PyClassInitializer` or -`PyResult>` with the baseclass initialized. See the -below Inheritance section for detail. -* For details on the parameter list, see the `Method arguments` section below. +For arguments, see the `Method arguments` section below. + +### Return type + +If your pyclass is declared with baseclass(i.e., you use `#[pyclass(extends=...)])`), +you must return a `PyClassInitializer` with the base class initialized. + +For constructors that may fail, you should wrap the return type in a PyResult as well. +Consult the table below to determine which type your constructor should return: + + +| | **Cannot fail** | **May fail** | +|--------------------|-------------------------|-----------------------------------| +| **No inheritance** | `T` | `PyResult` | +| **Inheritance** | `PyClassInitializer` | `PyResult>` | ## Inheritance diff --git a/src/pyclass.rs b/src/pyclass.rs index 8ec9897f..258090d6 100644 --- a/src/pyclass.rs +++ b/src/pyclass.rs @@ -26,7 +26,7 @@ pub(crate) unsafe fn default_alloc() -> *mut ffi::PyObject { alloc(tp_ptr, 0) } -/// A trait that enables custome alloc/dealloc implementations for pyclasses. +/// A trait that enables custom alloc/dealloc implementations for pyclasses. pub trait PyClassAlloc: PyTypeInfo + Sized { unsafe fn alloc(_py: Python) -> *mut Self::ConcreteLayout { default_alloc::() as _ @@ -65,7 +65,7 @@ pub unsafe fn tp_free_fallback(obj: *mut ffi::PyObject) { /// If `PyClass` is implemented for `T`, then we can use `T` in the Python world, /// via `PyClassShell`. /// -/// `#[pyclass]` attribute automatically implement this trait for your Rust struct, +/// The `#[pyclass]` attribute automatically implements this trait for your Rust struct, /// so you don't have to use this trait directly. pub trait PyClass: PyTypeInfo> + Sized + PyClassAlloc + PyMethodsProtocol @@ -96,9 +96,10 @@ where } } -/// `PyClassShell` represents the concrete layout of `PyClass` in the Python heap. +/// `PyClassShell` represents the concrete layout of `T: PyClass` when it is converted +/// to a Python class. /// -/// You can use it for testing your `#[pyclass]` correctly works. +/// You can use it to test your `#[pyclass]` correctly works. /// /// ``` /// # use pyo3::prelude::*; @@ -268,7 +269,7 @@ where } } -/// A speciall initializer for `PyClassShell`, which enables `super().__init__` +/// A special initializer for `PyClassShell`, which enables `super().__init__` /// in Rust code. /// /// You have to use it only when your `#[pyclass]` extends another `#[pyclass]`. @@ -387,9 +388,9 @@ impl PyClassInitializer { } } -/// Represets that we can convert the type to `PyClassInitializer`. +/// Represents that we can convert the type to `PyClassInitializer`. /// -/// It is mainly used in our proc-macro code. +/// This is mainly used in our proc-macro code. pub trait IntoInitializer { fn into_initializer(self) -> PyResult>; } @@ -418,7 +419,7 @@ impl IntoInitializer for PyResult> { } } -/// Register new type in python object system. +/// Register new type in the python object system. #[cfg(not(Py_LIMITED_API))] pub fn initialize_type(py: Python, module_name: Option<&str>) -> PyResult<*mut ffi::PyTypeObject> where