From 4144a098bc07f8d37eb6507d06dd1688b19b466e Mon Sep 17 00:00:00 2001 From: mejrs Date: Fri, 30 Apr 2021 00:13:19 +0200 Subject: [PATCH 1/6] proc_macro_docs --- pyo3-macros/src/lib.rs | 82 ++++++++++++++++++++++++++++++++++++++++-- src/lib.rs | 6 ++-- 2 files changed, 84 insertions(+), 4 deletions(-) diff --git a/pyo3-macros/src/lib.rs b/pyo3-macros/src/lib.rs index 756bb5d8243..4d3a6ed05d7 100644 --- a/pyo3-macros/src/lib.rs +++ b/pyo3-macros/src/lib.rs @@ -13,8 +13,10 @@ use pyo3_macros_backend::{ use quote::quote; use syn::parse_macro_input; -/// Internally, this proc macro create a new c function called `PyInit_{my_module}` -/// that then calls the init function you provided +/// A proc macro used to implement Python modules. +/// +/// For more on information on creating Python modules +/// see the [module section of the guide](https://pyo3.rs/main/module.html). #[proc_macro_attribute] pub fn pymodule(attr: TokenStream, input: TokenStream) -> TokenStream { let mut ast = parse_macro_input!(input as syn::ItemFn); @@ -43,6 +45,16 @@ pub fn pymodule(attr: TokenStream, input: TokenStream) -> TokenStream { .into() } +/// A proc macro used to implement Python's [dunder methods][1]. +/// +/// This atribute is required on blocks implementing [`PyObjectProtocol`][2], +/// [`PyNumberProtocol`][3], [`PyGCProtocol`][4] and [`PyIterProtocol`][5]. +/// +/// [1]: https://docs.python.org/3/reference/datamodel.html#special-method-names +/// [2]: ../class/basic/trait.PyObjectProtocol.html +/// [3]: ../class/number/trait.PyNumberProtocol.html +/// [4]: ../class/gc/trait.PyGCProtocol.html +/// [5]: ../class/iter/trait.PyIterProtocol.html #[proc_macro_attribute] pub fn pyproto(_: TokenStream, input: TokenStream) -> TokenStream { let mut ast = parse_macro_input!(input as syn::ItemImpl); @@ -55,6 +67,34 @@ pub fn pyproto(_: TokenStream, input: TokenStream) -> TokenStream { .into() } +/// A proc macro used to expose Rust structs as Python objects. +/// +/// `#[pyclass]` accepts the following [parameters][2]: +/// +/// | Parameter | Description | +/// | :- | :- | +/// | `name = "python_name"` | Sets the name that Python sees this class as. Defaults to the name of the Rust struct. | +/// | `freelist = N` | Implements a [free list][10] of size N. This can improve performance for types that are often created and deleted in a row. Profile your code to see whether `freelist` is right for you. | +/// | `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].| +/// | `weakref` | Allows this class to be [weakly referenceable][6]. | +/// | `extends = BaseType` | Use a custom baseclass. Defaults to [`PyAny`][4] | +/// | `subclass` | Allows Python classes to inherit from this class. | +/// | `unsendable`                                 | Required if your struct is not [`Send`][3]. Rather than using `unsendable`, prefer 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.| +/// | `module = "module_name"` | Python code will see the class as being defined in this module. Defaults to `builtins`. | +/// +/// For more on creating Python classes, +/// see the [class section of the guide][1]. +/// +/// [1]: https://pyo3.rs/main/class.html +/// [2]: https://pyo3.rs/main/class.html#customizing-the-class +/// [3]: std::marker::Send +/// [4]: ../prelude/struct.PyAny.html +/// [5]: https://pyo3.rs/main/class/protocols.html#garbage-collector-integration +/// [6]: https://docs.python.org/3/library/weakref.html +/// [7]: https://doc.rust-lang.org/nomicon/leaking.html +/// [8]: std::rc::Rc +/// [9]: std::sync::Arc +/// [10]: https://en.wikipedia.org/wiki/Free_list #[proc_macro_attribute] pub fn pyclass(attr: TokenStream, input: TokenStream) -> TokenStream { pyclass_impl(attr, input, PyClassMethodsType::Specialization) @@ -65,6 +105,38 @@ pub fn pyclass_with_inventory(attr: TokenStream, input: TokenStream) -> TokenStr pyclass_impl(attr, input, PyClassMethodsType::Inventory) } +/// A proc macro used to expose methods to Python. +/// +/// Methods within a `#[pymethods]` block can be annotated with the following: +/// +/// | Annotation | Description | +/// | :- | :- | +/// | [`#[new]`][4] | Defines the class constructor, like Python's `__new__` method. | +/// | [`#[getter]`][5] and [`#[setter]`][5] | These define getters and setters, similar to Python's `@property` decorator. This is useful for getters/setters that require computation or side effects; if that is not the case prefer using [`#[pyo3(get, set)]`][11] on the struct's field(s).| +/// | [`#[staticmethod]`][6]| Defines the method as a staticmethod, like Python's `@staticmethod` decorator.| +/// | [`#[classmethod]`][7] | Defines the method as a classmethod, like Python's `@classmethod` decorator.| +/// | [`#[call]`][8] | Allows Python code to call a class instance as a function, like Python's `__call__` method. | +/// | [`#[classattr]`][9] | Defines a class variable. | +/// | [`#[args]`][10] | Define a method's default arguments and allows the function to receive `*args` and `**kwargs`. | +/// +/// For more on creating class methods, +/// see the [class section of the guide][1]. +/// +/// If the [`multiple-pymethods`][2] feature is enabled, it is possible to implement +/// multiple `#[pymethods]` blocks for a single `#[pyclass]`. +/// This will add a transitive dependency on the [`inventory`][3] crate. +/// +/// [1]: https://pyo3.rs/main/class.html#instance-methods +/// [2]: https://pyo3.rs/main/features.html#multiple-pymethods +/// [3]: https://docs.rs/inventory/ +/// [4]: https://pyo3.rs/main/class.html#constructor +/// [5]: https://pyo3.rs/main/class.html#object-properties-using-getter-and-setter +/// [6]: https://pyo3.rs/main/class.html#static-methods +/// [7]: https://pyo3.rs/main/class.html#class-methods +/// [8]: https://pyo3.rs/main/class.html#callable-objects +/// [9]: https://pyo3.rs/main/class.html#class-attributes +/// [10]: https://pyo3.rs/main/class.html#method-arguments +/// [11]: https://pyo3.rs/main/class.html#object-properties-using-pyo3get-set #[proc_macro_attribute] pub fn pymethods(_: TokenStream, input: TokenStream) -> TokenStream { pymethods_impl(input, PyClassMethodsType::Specialization) @@ -75,6 +147,12 @@ pub fn pymethods_with_inventory(_: TokenStream, input: TokenStream) -> TokenStre pymethods_impl(input, PyClassMethodsType::Inventory) } +/// A proc macro used to expose Rust functions to Python. +/// +/// For more on exposing functions, +/// see the [function section of the guide][1]. +/// +/// [1]: https://pyo3.rs/main/function.html #[proc_macro_attribute] pub fn pyfunction(attr: TokenStream, input: TokenStream) -> TokenStream { let mut ast = parse_macro_input!(input as syn::ItemFn); diff --git a/src/lib.rs b/src/lib.rs index 69735f74c24..298b423b0c0 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -190,11 +190,13 @@ pub mod types; #[cfg(feature = "serde")] pub mod serde; -/// The proc macros, which are also part of the prelude. +/// The proc macros, all of which are part of the prelude. +/// +/// Import these with `use pyo3::prelude::*;` #[cfg(feature = "macros")] pub mod proc_macro { pub use pyo3_macros::pymodule; - /// The proc macro attributes + pub use pyo3_macros::{pyfunction, pyproto}; #[cfg(not(feature = "multiple-pymethods"))] From 90dfb0e5ae6ef98e177643c448643d713dc19a4a Mon Sep 17 00:00:00 2001 From: mejrs Date: Fri, 30 Apr 2021 00:31:09 +0200 Subject: [PATCH 2/6] relax wording a bit --- pyo3-macros/src/lib.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pyo3-macros/src/lib.rs b/pyo3-macros/src/lib.rs index 4d3a6ed05d7..24ed7fb6d8c 100644 --- a/pyo3-macros/src/lib.rs +++ b/pyo3-macros/src/lib.rs @@ -79,7 +79,7 @@ pub fn pyproto(_: TokenStream, input: TokenStream) -> TokenStream { /// | `weakref` | Allows this class to be [weakly referenceable][6]. | /// | `extends = BaseType` | Use a custom baseclass. Defaults to [`PyAny`][4] | /// | `subclass` | Allows Python classes to inherit from this class. | -/// | `unsendable`                                 | Required if your struct is not [`Send`][3]. Rather than using `unsendable`, prefer 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.| +/// | `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.| /// | `module = "module_name"` | Python code will see the class as being defined in this module. Defaults to `builtins`. | /// /// For more on creating Python classes, @@ -112,7 +112,7 @@ pub fn pyclass_with_inventory(attr: TokenStream, input: TokenStream) -> TokenStr /// | Annotation | Description | /// | :- | :- | /// | [`#[new]`][4] | Defines the class constructor, like Python's `__new__` method. | -/// | [`#[getter]`][5] and [`#[setter]`][5] | These define getters and setters, similar to Python's `@property` decorator. This is useful for getters/setters that require computation or side effects; if that is not the case prefer using [`#[pyo3(get, set)]`][11] on the struct's field(s).| +/// | [`#[getter]`][5] and [`#[setter]`][5] | These define getters and setters, similar to Python's `@property` decorator. This is useful for getters/setters that require computation or side effects; if that is not the case consider using [`#[pyo3(get, set)]`][11] on the struct's field(s).| /// | [`#[staticmethod]`][6]| Defines the method as a staticmethod, like Python's `@staticmethod` decorator.| /// | [`#[classmethod]`][7] | Defines the method as a classmethod, like Python's `@classmethod` decorator.| /// | [`#[call]`][8] | Allows Python code to call a class instance as a function, like Python's `__call__` method. | From 49ebc7b9cd838356b17e9f68e52a6db8b2209fa2 Mon Sep 17 00:00:00 2001 From: mejrs Date: Fri, 30 Apr 2021 00:43:07 +0200 Subject: [PATCH 3/6] fixed doc typo --- pyo3-macros/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyo3-macros/src/lib.rs b/pyo3-macros/src/lib.rs index 24ed7fb6d8c..ee5fa36738e 100644 --- a/pyo3-macros/src/lib.rs +++ b/pyo3-macros/src/lib.rs @@ -15,7 +15,7 @@ use syn::parse_macro_input; /// A proc macro used to implement Python modules. /// -/// For more on information on creating Python modules +/// For more on creating Python modules /// see the [module section of the guide](https://pyo3.rs/main/module.html). #[proc_macro_attribute] pub fn pymodule(attr: TokenStream, input: TokenStream) -> TokenStream { From 2c7670e12413f8683fad9f78400dc7f55032984c Mon Sep 17 00:00:00 2001 From: mejrs Date: Fri, 30 Apr 2021 01:23:20 +0200 Subject: [PATCH 4/6] fixed extra whitespace --- pyo3-macros/src/lib.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/pyo3-macros/src/lib.rs b/pyo3-macros/src/lib.rs index ee5fa36738e..a6650441c5c 100644 --- a/pyo3-macros/src/lib.rs +++ b/pyo3-macros/src/lib.rs @@ -15,7 +15,7 @@ use syn::parse_macro_input; /// A proc macro used to implement Python modules. /// -/// For more on creating Python modules +/// For more on creating Python modules /// see the [module section of the guide](https://pyo3.rs/main/module.html). #[proc_macro_attribute] pub fn pymodule(attr: TokenStream, input: TokenStream) -> TokenStream { @@ -47,7 +47,7 @@ pub fn pymodule(attr: TokenStream, input: TokenStream) -> TokenStream { /// A proc macro used to implement Python's [dunder methods][1]. /// -/// This atribute is required on blocks implementing [`PyObjectProtocol`][2], +/// This atribute is required on blocks implementing [`PyObjectProtocol`][2], /// [`PyNumberProtocol`][3], [`PyGCProtocol`][4] and [`PyIterProtocol`][5]. /// /// [1]: https://docs.python.org/3/reference/datamodel.html#special-method-names @@ -70,7 +70,7 @@ pub fn pyproto(_: TokenStream, input: TokenStream) -> TokenStream { /// A proc macro used to expose Rust structs as Python objects. /// /// `#[pyclass]` accepts the following [parameters][2]: -/// +/// /// | Parameter | Description | /// | :- | :- | /// | `name = "python_name"` | Sets the name that Python sees this class as. Defaults to the name of the Rust struct. | @@ -108,7 +108,7 @@ pub fn pyclass_with_inventory(attr: TokenStream, input: TokenStream) -> TokenStr /// A proc macro used to expose methods to Python. /// /// Methods within a `#[pymethods]` block can be annotated with the following: -/// +/// /// | Annotation | Description | /// | :- | :- | /// | [`#[new]`][4] | Defines the class constructor, like Python's `__new__` method. | @@ -123,8 +123,8 @@ pub fn pyclass_with_inventory(attr: TokenStream, input: TokenStream) -> TokenStr /// see the [class section of the guide][1]. /// /// If the [`multiple-pymethods`][2] feature is enabled, it is possible to implement -/// multiple `#[pymethods]` blocks for a single `#[pyclass]`. -/// This will add a transitive dependency on the [`inventory`][3] crate. +/// multiple `#[pymethods]` blocks for a single `#[pyclass]`. +/// This will add a transitive dependency on the [`inventory`][3] crate. /// /// [1]: https://pyo3.rs/main/class.html#instance-methods /// [2]: https://pyo3.rs/main/features.html#multiple-pymethods From dc997077562701de2763c33a25dd5850348ab120 Mon Sep 17 00:00:00 2001 From: mejrs Date: Fri, 30 Apr 2021 17:21:46 +0200 Subject: [PATCH 5/6] duplicated docs to *_with_inventory macros --- pyo3-macros/src/lib.rs | 60 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 60 insertions(+) diff --git a/pyo3-macros/src/lib.rs b/pyo3-macros/src/lib.rs index a6650441c5c..8c157e5e715 100644 --- a/pyo3-macros/src/lib.rs +++ b/pyo3-macros/src/lib.rs @@ -100,6 +100,34 @@ pub fn pyclass(attr: TokenStream, input: TokenStream) -> TokenStream { pyclass_impl(attr, input, PyClassMethodsType::Specialization) } +/// A proc macro used to expose Rust structs as Python objects. +/// +/// `#[pyclass]` accepts the following [parameters][2]: +/// +/// | Parameter | Description | +/// | :- | :- | +/// | `name = "python_name"` | Sets the name that Python sees this class as. Defaults to the name of the Rust struct. | +/// | `freelist = N` | Implements a [free list][10] of size N. This can improve performance for types that are often created and deleted in a row. Profile your code to see whether `freelist` is right for you. | +/// | `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].| +/// | `weakref` | Allows this class to be [weakly referenceable][6]. | +/// | `extends = BaseType` | Use a custom baseclass. Defaults to [`PyAny`][4] | +/// | `subclass` | Allows Python classes to inherit from this class. | +/// | `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.| +/// | `module = "module_name"` | Python code will see the class as being defined in this module. Defaults to `builtins`. | +/// +/// For more on creating Python classes, +/// see the [class section of the guide][1]. +/// +/// [1]: https://pyo3.rs/main/class.html +/// [2]: https://pyo3.rs/main/class.html#customizing-the-class +/// [3]: std::marker::Send +/// [4]: ../prelude/struct.PyAny.html +/// [5]: https://pyo3.rs/main/class/protocols.html#garbage-collector-integration +/// [6]: https://docs.python.org/3/library/weakref.html +/// [7]: https://doc.rust-lang.org/nomicon/leaking.html +/// [8]: std::rc::Rc +/// [9]: std::sync::Arc +/// [10]: https://en.wikipedia.org/wiki/Free_list #[proc_macro_attribute] pub fn pyclass_with_inventory(attr: TokenStream, input: TokenStream) -> TokenStream { pyclass_impl(attr, input, PyClassMethodsType::Inventory) @@ -142,6 +170,38 @@ pub fn pymethods(_: TokenStream, input: TokenStream) -> TokenStream { pymethods_impl(input, PyClassMethodsType::Specialization) } +/// A proc macro used to expose methods to Python. +/// +/// Methods within a `#[pymethods]` block can be annotated with the following: +/// +/// | Annotation | Description | +/// | :- | :- | +/// | [`#[new]`][4] | Defines the class constructor, like Python's `__new__` method. | +/// | [`#[getter]`][5] and [`#[setter]`][5] | These define getters and setters, similar to Python's `@property` decorator. This is useful for getters/setters that require computation or side effects; if that is not the case consider using [`#[pyo3(get, set)]`][11] on the struct's field(s).| +/// | [`#[staticmethod]`][6]| Defines the method as a staticmethod, like Python's `@staticmethod` decorator.| +/// | [`#[classmethod]`][7] | Defines the method as a classmethod, like Python's `@classmethod` decorator.| +/// | [`#[call]`][8] | Allows Python code to call a class instance as a function, like Python's `__call__` method. | +/// | [`#[classattr]`][9] | Defines a class variable. | +/// | [`#[args]`][10] | Define a method's default arguments and allows the function to receive `*args` and `**kwargs`. | +/// +/// For more on creating class methods, +/// see the [class section of the guide][1]. +/// +/// If the [`multiple-pymethods`][2] feature is enabled, it is possible to implement +/// multiple `#[pymethods]` blocks for a single `#[pyclass]`. +/// This will add a transitive dependency on the [`inventory`][3] crate. +/// +/// [1]: https://pyo3.rs/main/class.html#instance-methods +/// [2]: https://pyo3.rs/main/features.html#multiple-pymethods +/// [3]: https://docs.rs/inventory/ +/// [4]: https://pyo3.rs/main/class.html#constructor +/// [5]: https://pyo3.rs/main/class.html#object-properties-using-getter-and-setter +/// [6]: https://pyo3.rs/main/class.html#static-methods +/// [7]: https://pyo3.rs/main/class.html#class-methods +/// [8]: https://pyo3.rs/main/class.html#callable-objects +/// [9]: https://pyo3.rs/main/class.html#class-attributes +/// [10]: https://pyo3.rs/main/class.html#method-arguments +/// [11]: https://pyo3.rs/main/class.html#object-properties-using-pyo3get-set #[proc_macro_attribute] pub fn pymethods_with_inventory(_: TokenStream, input: TokenStream) -> TokenStream { pymethods_impl(input, PyClassMethodsType::Inventory) From aa6a2363623ce6160f2baec6a1416694bd081c8c Mon Sep 17 00:00:00 2001 From: mejrs Date: Mon, 3 May 2021 00:58:00 +0200 Subject: [PATCH 6/6] added suggested changes --- pyo3-macros/src/lib.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/pyo3-macros/src/lib.rs b/pyo3-macros/src/lib.rs index 8c157e5e715..7d970ee711f 100644 --- a/pyo3-macros/src/lib.rs +++ b/pyo3-macros/src/lib.rs @@ -74,11 +74,11 @@ pub fn pyproto(_: TokenStream, input: TokenStream) -> TokenStream { /// | Parameter | Description | /// | :- | :- | /// | `name = "python_name"` | Sets the name that Python sees this class as. Defaults to the name of the Rust struct. | -/// | `freelist = N` | Implements a [free list][10] of size N. This can improve performance for types that are often created and deleted in a row. Profile your code to see whether `freelist` is right for you. | +/// | `freelist = N` | Implements a [free list][10] 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. | /// | `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].| /// | `weakref` | Allows this class to be [weakly referenceable][6]. | /// | `extends = BaseType` | Use a custom baseclass. Defaults to [`PyAny`][4] | -/// | `subclass` | Allows Python classes to inherit from this class. | +/// | `subclass` | Allows other Python classes and `#[pyclass]` to inherit from this class. | /// | `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.| /// | `module = "module_name"` | Python code will see the class as being defined in this module. Defaults to `builtins`. | /// @@ -107,11 +107,11 @@ pub fn pyclass(attr: TokenStream, input: TokenStream) -> TokenStream { /// | Parameter | Description | /// | :- | :- | /// | `name = "python_name"` | Sets the name that Python sees this class as. Defaults to the name of the Rust struct. | -/// | `freelist = N` | Implements a [free list][10] of size N. This can improve performance for types that are often created and deleted in a row. Profile your code to see whether `freelist` is right for you. | +/// | `freelist = N` | Implements a [free list][10] 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. | /// | `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].| /// | `weakref` | Allows this class to be [weakly referenceable][6]. | /// | `extends = BaseType` | Use a custom baseclass. Defaults to [`PyAny`][4] | -/// | `subclass` | Allows Python classes to inherit from this class. | +/// | `subclass` | Allows other Python classes and `#[pyclass]` to inherit from this class. | /// | `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.| /// | `module = "module_name"` | Python code will see the class as being defined in this module. Defaults to `builtins`. | ///