diff --git a/CHANGELOG.md b/CHANGELOG.md index 2bded739..37c09d50 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +### Changed + +- Allow `#[pyo3(crate = "...", text_signature = "...")]` options to be used directly in `#[pyclass(crate = "...", text_signature = "...")]`. [#2234](https://github.com/PyO3/pyo3/pull/2234) + ### Fixed - Considered `PYTHONFRAMEWORK` when cross compiling in order that on macos cross compiling against a [Framework bundle](https://developer.apple.com/library/archive/documentation/MacOSX/Conceptual/BPFrameworks/Concepts/FrameworkAnatomy.html) is considered shared. [#2233](https://github.com/PyO3/pyo3/pull/2233) diff --git a/guide/src/class.md b/guide/src/class.md index e40e4a5f..3b6ad618 100644 --- a/guide/src/class.md +++ b/guide/src/class.md @@ -195,22 +195,16 @@ Python::with_gil(|py|{ ## Customizing the class -The `#[pyclass]` macro accepts the following parameters: +{{#include ../../pyo3-macros/docs/pyclass_parameters.md}} -* `name="XXX"` - Set the class name shown in Python code. By default, the struct name is used as the class name. -* `freelist=XXX` - The `freelist` parameter adds support of free allocation list to custom class. -The performance improvement applies to types that are often created and deleted in a row, -so that they can benefit from a freelist. `XXX` is a number of items for the free list. -* `gc` - Classes with the `gc` parameter participate in Python garbage collection. -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. -* `weakref` - Adds support for Python weak references. -* `extends=BaseType` - Use a custom base class. The base `BaseType` must implement `PyTypeInfo`. `enum` pyclasses can't use a custom base class. -* `subclass` - Allows Python classes to inherit from this class. `enum` pyclasses can't be inherited from. -* `dict` - Adds `__dict__` support, so that the instances of this type have a dictionary containing arbitrary instance variables. -* `unsendable` - Making it safe to expose `!Send` structs to Python, where all object can be accessed - by multiple threads. A class marked with `unsendable` panics when accessed by another thread. -* `module="XXX"` - Set the name of the module the class will be shown as defined in. If not given, the class - will be a virtual member of the `builtins` module. +[params-1]: {{#PYO3_DOCS_URL}}/pyo3/prelude/struct.PyAny.html +[params-2]: https://en.wikipedia.org/wiki/Free_list +[params-3]: https://doc.rust-lang.org/stable/std/marker/trait.Send.html +[params-4]: https://doc.rust-lang.org/stable/std/rc/struct.Rc.html +[params-5]: https://doc.rust-lang.org/stable/std/sync/struct.Rc.html +[params-6]: https://docs.python.org/3/library/weakref.html + +These parameters are covered in various sections of this guide. ### Return type @@ -716,7 +710,7 @@ num=-1 ## Making class method signatures available to Python -The [`#[pyo3(text_signature = "...")]`](./function.md#text_signature) option for `#[pyfunction]` also works for classes and methods: +The [`text_signature = "..."`](./function.md#text_signature) option for `#[pyfunction]` also works for classes and methods: ```rust # #![allow(dead_code)] @@ -724,8 +718,7 @@ use pyo3::prelude::*; use pyo3::types::PyType; // it works even if the item is not documented: -#[pyclass] -#[pyo3(text_signature = "(c, d, /)")] +#[pyclass(text_signature = "(c, d, /)")] struct MyClass {} #[pymethods] diff --git a/pyo3-macros/docs/pyclass_parameters.md b/pyo3-macros/docs/pyclass_parameters.md new file mode 100644 index 00000000..ae5ef9dd --- /dev/null +++ b/pyo3-macros/docs/pyclass_parameters.md @@ -0,0 +1,28 @@ +`#[pyclass]` can be used with the following parameters: + +| Parameter | Description | +| :- | :- | +| `crate = "some::path"` | Path to import the `pyo3` crate, if it's not accessible at `::pyo3`. | +| `dict` | Gives instances of this class an empty `__dict__` to store custom attributes. | +| `extends = BaseType` | Use a custom baseclass. Defaults to [`PyAny`][params-1] | +| `freelist = N` | Implements a [free list][params-2] of size N. This can improve performance for types that are often created and deleted in quick succession. Profile your code to see whether `freelist` is right for you. | +| `module = "module_name"` | Python code will see the class as being defined in this module. Defaults to `builtins`. | +| `name = "python_name"` | Sets the name that Python sees this class as. Defaults to the name of the Rust struct. | +| `text_signature = "(arg1, arg2, ...)"` | Sets the text signature for the Python class' `__new__` method. | +| `subclass` | Allows other Python classes and `#[pyclass]` to inherit from this class. Enums cannot be subclassed. | +| `unsendable` | Required if your struct is not [`Send`][params-3]. Rather than using `unsendable`, consider implementing your struct in a threadsafe way by e.g. substituting [`Rc`][params-4] with [`Arc`][params-5]. By using `unsendable`, your class will panic when accessed by another thread.| +| `weakref` | Allows this class to be [weakly referenceable][params-6]. | + +All of these parameters can either be passed directly on the `#[pyclass(...)]` annotation, or as one or +more accompanying `#[pyo3(...)]` annotations, e.g.: + +```rust,ignore +// Argument supplied directly to the `#[pyclass]` annotation. +#[pyclass(name = "SomeName", subclass)] +struct MyClass { } + +// Argument supplied as a separate annotation. +#[pyclass] +#[pyo3(name = "SomeName", subclass)] +struct MyClass { } +``` diff --git a/pyo3-macros/src/lib.rs b/pyo3-macros/src/lib.rs index 367b37fa..a5f7faa7 100644 --- a/pyo3-macros/src/lib.rs +++ b/pyo3-macros/src/lib.rs @@ -81,47 +81,18 @@ pub fn pyproto(_: TokenStream, input: TokenStream) -> TokenStream { /// A proc macro used to expose Rust structs and fieldless enums as Python objects. /// -/// `#[pyclass]` can be used the following [parameters][2]: -/// -/// | Parameter | Description | -/// | :- | :- | -/// | `crate = "some::path"` | Path to import the `pyo3` crate, if it's not accessible at `::pyo3`. | -/// | `dict` | Gives instances of this class an empty `__dict__` to store custom attributes. | -/// | `extends = BaseType` | Use a custom baseclass. Defaults to [`PyAny`][4] | -/// | `freelist = N` | Implements a [free list][9] of size N. This can improve performance for types that are often created and deleted in quick succession. Profile your code to see whether `freelist` is right for you. | -/// | `module = "module_name"` | Python code will see the class as being defined in this module. Defaults to `builtins`. | -/// | `name = "python_name"` | Sets the name that Python sees this class as. Defaults to the name of the Rust struct. | -/// | `text_signature = "(arg1, arg2, ...)"` | Sets the text signature for the Python class' `__new__` method. | -/// | `subclass` | Allows other Python classes and `#[pyclass]` to inherit from this class. Enums cannot be subclassed. | -/// | `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`][7] with [`Arc`][8]. By using `unsendable`, your class will panic when accessed by another thread.| -/// | `weakref` | Allows this class to be [weakly referenceable][6]. | -/// -/// All of these parameters can either be passed directly on the `#[pyclass(...)]` annotation, or as one or -/// more accompanying `#[pyo3(...)]` annotations, e.g.: -/// -/// ```rust,ignore -/// // Argument supplied directly to the `#[pyclass]` annotation. -/// #[pyclass(name = "SomeName", subclass)] -/// struct MyClass { } -/// -/// // Argument supplied as a separate annotation. -/// #[pyclass] -/// #[pyo3(name = "SomeName", subclass)] -/// struct MyClass { } -/// ``` +#[cfg_attr(docsrs, cfg_attr(docsrs, doc = include_str!("../docs/pyclass_parameters.md")))] /// /// For more on creating Python classes, /// see the [class section of the guide][1]. /// /// [1]: https://pyo3.rs/latest/class.html -/// [2]: https://pyo3.rs/latest/class.html#customizing-the-class -/// [3]: std::marker::Send -/// [4]: ../prelude/struct.PyAny.html -/// [5]: https://pyo3.rs/latest/class/protocols.html#garbage-collector-integration -/// [6]: https://docs.python.org/3/library/weakref.html -/// [7]: std::rc::Rc -/// [8]: std::sync::Arc -/// [9]: https://en.wikipedia.org/wiki/Free_list +/// [params-1]: ../prelude/struct.PyAny.html +/// [params-2]: https://en.wikipedia.org/wiki/Free_list +/// [params-3]: std::marker::Send +/// [params-4]: std::rc::Rc +/// [params-5]: std::sync::Arc +/// [params-6]: https://docs.python.org/3/library/weakref.html #[proc_macro_attribute] pub fn pyclass(attr: TokenStream, input: TokenStream) -> TokenStream { use syn::Item;