Skip to content

Navigation Menu

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit d698b28

Browse filesBrowse files
authored
Ensure pymethod cannot be both magic and named simultaneously + macro documentation (#5538)
Signed-off-by: Ashwin Naren <arihant2math@gmail.com>
1 parent 23236aa commit d698b28
Copy full SHA for d698b28

File tree

2 files changed

+190
-0
lines changed
Filter options

2 files changed

+190
-0
lines changed

‎derive-impl/src/pyclass.rs

Copy file name to clipboardExpand all lines: derive-impl/src/pyclass.rs
+7Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1229,6 +1229,13 @@ impl MethodItemMeta {
12291229
let inner = self.inner();
12301230
let name = inner._optional_str("name")?;
12311231
let magic = inner._bool("magic")?;
1232+
if magic && name.is_some() {
1233+
bail_span!(
1234+
&inner.meta_ident,
1235+
"A #[{}] method cannot be magic and have a specified name, choose one.",
1236+
inner.meta_name()
1237+
);
1238+
}
12321239
Ok(if let Some(name) = name {
12331240
name
12341241
} else {

‎derive/src/lib.rs

Copy file name to clipboardExpand all lines: derive/src/lib.rs
+183Lines changed: 183 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,124 @@ pub fn derive_from_args(input: TokenStream) -> TokenStream {
1212
derive_impl::derive_from_args(input).into()
1313
}
1414

15+
/// The attribute can be applied either to a struct, trait, or impl.
16+
/// # Struct
17+
/// This implements `MaybeTraverse`, `PyClassDef`, and `StaticType` for the struct.
18+
/// Consider deriving `Traverse` to implement it.
19+
/// ## Arguments
20+
/// - `module`: the module which contains the class -- can be omitted if in a `#[pymodule]`.
21+
/// - `name`: the name of the Python class, by default it is the name of the struct.
22+
/// - `base`: the base class of the Python class.
23+
/// This does not cause inheritance of functions or attributes that must be done by a separate trait.
24+
/// # Impl
25+
/// This part implements `PyClassImpl` for the struct.
26+
/// This includes methods, getters/setters, etc.; only annotated methods will be included.
27+
/// Common functions and abilities like instantiation and `__call__` are often implemented by
28+
/// traits rather than in the `impl` itself; see `Constructor` and `Callable` respectively for those.
29+
/// ## Arguments
30+
/// - `name`: the name of the Python class, when no name is provided the struct name is used.
31+
/// - `flags`: the flags of the class, see `PyTypeFlags`.
32+
/// - `BASETYPE`: allows the class to be inheritable.
33+
/// - `IMMUTABLETYPE`: class attributes are immutable.
34+
/// - `with`: which trait implementations are to be included in the python class.
35+
/// ```rust, ignore
36+
/// #[pyclass(module = "mymodule", name = "MyClass", base = "BaseClass")]
37+
/// struct MyStruct {
38+
/// x: i32,
39+
/// }
40+
///
41+
/// impl Constructor for MyStruct {
42+
/// ...
43+
/// }
44+
///
45+
/// #[pyclass(with(Constructor))]
46+
/// impl MyStruct {
47+
/// ...
48+
/// }
49+
/// ```
50+
/// ## Inner markers
51+
/// ### pymethod/pyclassmethod/pystaticmethod
52+
/// `pymethod` is used to mark a method of the Python class.
53+
/// `pyclassmethod` is used to mark a class method.
54+
/// `pystaticmethod` is used to mark a static method.
55+
/// #### Method signature
56+
/// The first parameter can be either `&self` or `<var>: PyRef<Self>` for `pymethod`.
57+
/// The first parameter can be `cls: PyTypeRef` for `pyclassmethod`.
58+
/// There is no mandatory parameter for `pystaticmethod`.
59+
/// Both are valid and essentially the same, but the latter can yield more control.
60+
/// The last parameter can optionally be of the type `&VirtualMachine` to access the VM.
61+
/// All other values must implement `IntoPyResult`.
62+
/// Numeric types, `String`, `bool`, and `PyObjectRef` implement this trait,
63+
/// but so does any object that implements `PyValue`.
64+
/// Consider using `OptionalArg` for optional arguments.
65+
/// #### Arguments
66+
/// - `magic`: marks the method as a magic method: the method name is surrounded with double underscores.
67+
/// ```rust, ignore
68+
/// #[pyclass]
69+
/// impl MyStruct {
70+
/// // This will be called as the `__add__` method in Python.
71+
/// #[pymethod(magic)]
72+
/// fn add(&self, other: &Self) -> PyResult<i32> {
73+
/// ...
74+
/// }
75+
/// }
76+
/// ```
77+
/// - `name`: the name of the method in Python,
78+
/// by default it is the same as the Rust method, or surrounded by double underscores if magic is present.
79+
/// This overrides `magic` and the default name and cannot be used with `magic` to prevent ambiguity.
80+
/// ### pygetset
81+
/// This is used to mark a getter/setter pair.
82+
/// #### Arguments
83+
/// - `setter`: marks the method as a setter, it acts as a getter by default.
84+
/// Setter method names should be prefixed with `set_`.
85+
/// - `name`: the name of the attribute in Python, by default it is the same as the Rust method.
86+
/// - `magic`: marks the method as a magic method: the method name is surrounded with double underscores.
87+
/// This cannot be used with `name` to prevent ambiguity.
88+
///
89+
/// Ensure both the getter and setter are marked with `name` and `magic` in the same manner.
90+
/// #### Examples
91+
/// ```rust, ignore
92+
/// #[pyclass]
93+
/// impl MyStruct {
94+
/// #[pygetset]
95+
/// fn x(&self) -> PyResult<i32> {
96+
/// Ok(self.x.lock())
97+
/// }
98+
/// #[pygetset(setter)]
99+
/// fn set_x(&mut self, value: i32) -> PyResult<()> {
100+
/// self.x.set(value);
101+
/// Ok(())
102+
/// }
103+
/// }
104+
/// ```
105+
/// ### pyslot
106+
/// This is used to mark a slot method it should be marked by prefixing the method in rust with `slot_`.
107+
/// #### Arguments
108+
/// - name: the name of the slot method.
109+
/// ### pyattr
110+
/// ### extend_class
111+
/// This helps inherit attributes from a parent class.
112+
/// The method this is applied on should be called `extend_class_with_fields`.
113+
/// #### Examples
114+
/// ```rust, ignore
115+
/// #[extend_class]
116+
/// fn extend_class_with_fields(ctx: &Context, class: &'static Py<PyType>) {
117+
/// class.set_attr(
118+
/// identifier!(ctx, _fields),
119+
/// ctx.new_tuple(vec![
120+
/// ctx.new_str(ascii!("body")).into(),
121+
/// ctx.new_str(ascii!("type_ignores")).into(),
122+
/// ])
123+
/// .into(),
124+
/// );
125+
/// class.set_attr(identifier!(ctx, _attributes), ctx.new_list(vec![]).into());
126+
/// }
127+
/// ```
128+
/// ### pymember
129+
/// # Trait
130+
/// `#[pyclass]` on traits functions a lot like `#[pyclass]` on `impl` blocks.
131+
/// Note that associated functions that are annotated with `#[pymethod]` or similar **must**
132+
/// have a body, abstract functions should be wrapped before applying an annotation.
15133
#[proc_macro_attribute]
16134
pub fn pyclass(attr: TokenStream, item: TokenStream) -> TokenStream {
17135
let attr = parse_macro_input!(attr);
@@ -34,6 +152,71 @@ pub fn pyexception(attr: TokenStream, item: TokenStream) -> TokenStream {
34152
derive_impl::pyexception(attr, item).into()
35153
}
36154

155+
/// This attribute must be applied to an inline module.
156+
/// It defines a Python module in the form a `make_module` function in the module;
157+
/// this has to be used in a `get_module_inits` to properly register the module.
158+
/// Additionally, this macro defines 'MODULE_NAME' and 'DOC' in the module.
159+
/// # Arguments
160+
/// - `name`: the name of the python module,
161+
/// by default, it is the name of the module, but this can be configured.
162+
/// ```rust, ignore
163+
/// // This will create a module named `mymodule`
164+
/// #[pymodule(name = "mymodule")]
165+
/// mod module {
166+
/// }
167+
/// ```
168+
/// - `sub`: declare the module as a submodule of another module.
169+
/// ```rust, ignore
170+
/// #[pymodule(sub)]
171+
/// mod submodule {
172+
/// }
173+
///
174+
/// #[pymodule(with(submodule))]
175+
/// mod mymodule {
176+
/// }
177+
/// ```
178+
/// - `with`: declare the list of submodules that this module contains (see `sub` for example).
179+
/// ## Inner markers
180+
/// ### pyattr
181+
/// `pyattr` is a multipurpose marker that can be used in a pymodule.
182+
/// The most common use is to mark a function or class as a part of the module.
183+
/// This can be done by applying it to a function or struct prior to the `#[pyfunction]` or `#[pyclass]` macro.
184+
/// If applied to a constant, it will be added to the module as an attribute.
185+
/// If applied to a function not marked with `pyfunction`,
186+
/// it will also be added to the module as an attribute but the value is the result of the function.
187+
/// If `#[pyattr(once)]` is used in this case, the function will be called once
188+
/// and the result will be stored using a `static_cell`.
189+
/// #### Examples
190+
/// ```rust, ignore
191+
/// #[pymodule]
192+
/// mod mymodule {
193+
/// #[pyattr]
194+
/// const MY_CONSTANT: i32 = 42;
195+
/// #[pyattr]
196+
/// fn another_constant() -> PyResult<i32> {
197+
/// Ok(42)
198+
/// }
199+
/// #[pyattr(once)]
200+
/// fn once() -> PyResult<i32> {
201+
/// // This will only be called once and the result will be stored.
202+
/// Ok(2 ** 24)
203+
/// }
204+
///
205+
/// #[pyattr]
206+
/// #[pyfunction]
207+
/// fn my_function(vm: &VirtualMachine) -> PyResult<()> {
208+
/// ...
209+
/// }
210+
/// }
211+
/// ```
212+
/// ### pyfunction
213+
/// This is used to create a python function.
214+
/// #### Function signature
215+
/// The last argument can optionally be of the type `&VirtualMachine` to access the VM.
216+
/// Refer to the `pymethod` documentation (located in the `pyclass` macro documentation)
217+
/// for more information on what regular argument types are permitted.
218+
/// #### Arguments
219+
/// - `name`: the name of the function in Python, by default it is the same as the associated Rust function.
37220
#[proc_macro_attribute]
38221
pub fn pymodule(attr: TokenStream, item: TokenStream) -> TokenStream {
39222
let attr = parse_macro_input!(attr);

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.