@@ -11,6 +11,10 @@ enum ClassItem {
1111 item_ident : Ident ,
1212 py_name : String ,
1313 } ,
14+ ClassMethod {
15+ item_ident : Ident ,
16+ py_name : String ,
17+ } ,
1418 Property {
1519 item_ident : Ident ,
1620 py_name : String ,
@@ -49,8 +53,8 @@ impl ClassItem {
4953 let nesteds = meta_to_vec ( meta) . map_err ( |meta| {
5054 err_span ! (
5155 meta,
52- "#[pyproperty = \" ...\" ] cannot be a name/value, you probably meant \
53- #[pyproperty (name = \" ...\" )]",
56+ "#[pymethod = \" ...\" ] cannot be a name/value, you probably meant \
57+ #[pymethod (name = \" ...\" )]",
5458 )
5559 } ) ?;
5660 let mut py_name = None ;
@@ -80,6 +84,47 @@ impl ClassItem {
8084 py_name : py_name. unwrap_or_else ( || sig. ident . to_string ( ) ) ,
8185 } ) ;
8286 attr_idx = Some ( i) ;
87+ } else if name == "pyclassmethod" {
88+ if item. is_some ( ) {
89+ bail_span ! (
90+ sig. ident,
91+ "You can only have one #[py*] attribute on an impl item"
92+ )
93+ }
94+ let nesteds = meta_to_vec ( meta) . map_err ( |meta| {
95+ err_span ! (
96+ meta,
97+ "#[pyclassmethod = \" ...\" ] cannot be a name/value, you probably meant \
98+ #[pyclassmethod(name = \" ...\" )]",
99+ )
100+ } ) ?;
101+ let mut py_name = None ;
102+ for meta in nesteds {
103+ let meta = match meta {
104+ NestedMeta :: Meta ( meta) => meta,
105+ NestedMeta :: Literal ( _) => continue ,
106+ } ;
107+ match meta {
108+ Meta :: NameValue ( name_value) => {
109+ if name_value. ident == "name" {
110+ if let Lit :: Str ( s) = & name_value. lit {
111+ py_name = Some ( s. value ( ) ) ;
112+ } else {
113+ bail_span ! (
114+ & sig. ident,
115+ "#[pyclassmethod(name = ...)] must be a string"
116+ ) ;
117+ }
118+ }
119+ }
120+ _ => { }
121+ }
122+ }
123+ item = Some ( ClassItem :: ClassMethod {
124+ item_ident : sig. ident . clone ( ) ,
125+ py_name : py_name. unwrap_or_else ( || sig. ident . to_string ( ) ) ,
126+ } ) ;
127+ attr_idx = Some ( i) ;
83128 } else if name == "pyproperty" {
84129 if item. is_some ( ) {
85130 bail_span ! (
@@ -210,18 +255,20 @@ pub fn impl_pyimpl(_attr: AttributeArgs, item: Item) -> Result<TokenStream2, Dia
210255 _ => { }
211256 }
212257 }
213- let methods = items. iter ( ) . filter_map ( |item| {
214- if let ClassItem :: Method {
258+ let methods = items. iter ( ) . filter_map ( |item| match item {
259+ ClassItem :: Method {
215260 item_ident,
216261 py_name,
217- } = item
218- {
219- Some ( quote ! {
220- class. set_str_attr( #py_name, ctx. new_rustfunc( Self :: #item_ident) ) ;
221- } )
222- } else {
223- None
224- }
262+ } => Some ( quote ! {
263+ class. set_str_attr( #py_name, ctx. new_rustfunc( Self :: #item_ident) ) ;
264+ } ) ,
265+ ClassItem :: ClassMethod {
266+ item_ident,
267+ py_name,
268+ } => Some ( quote ! {
269+ class. set_str_attr( #py_name, ctx. new_classmethod( Self :: #item_ident) ) ;
270+ } ) ,
271+ _ => None ,
225272 } ) ;
226273 let properties = properties
227274 . iter ( )
0 commit comments