2222_DEFAULT_TYPING_IMPORTS = (
2323 'Any' ,
2424 'Callable' ,
25+ 'ClassVar' ,
2526 'Dict' ,
2627 'Iterable' ,
2728 'Iterator' ,
@@ -243,7 +244,13 @@ def strip_or_import(typ: str, module: ModuleType, imports: List[str]) -> str:
243244 return stripped_type
244245
245246
246- def generate_c_property_stub (name : str , obj : object , output : List [str ], readonly : bool ,
247+ def is_static_property (obj : object ) -> bool :
248+ return type (obj ).__name__ == 'pybind11_static_property'
249+
250+
251+ def generate_c_property_stub (name : str , obj : object ,
252+ static_properties : List [str ],
253+ properties : List [str ], readonly : bool ,
247254 module : Optional [ModuleType ] = None ,
248255 imports : Optional [List [str ]] = None ) -> None :
249256 """Generate property stub using introspection of 'obj'.
@@ -273,11 +280,17 @@ def infer_prop_type(docstr: Optional[str]) -> Optional[str]:
273280 if module is not None and imports is not None :
274281 inferred = strip_or_import (inferred , module , imports )
275282
276- output .append ('@property' )
277- output .append ('def {}(self) -> {}: ...' .format (name , inferred ))
278- if not readonly :
279- output .append ('@{}.setter' .format (name ))
280- output .append ('def {}(self, val: {}) -> None: ...' .format (name , inferred ))
283+ if is_static_property (obj ):
284+ trailing_comment = " # read-only" if readonly else ""
285+ static_properties .append (
286+ '{}: ClassVar[{}] = ...{}' .format (name , inferred , trailing_comment )
287+ )
288+ else : # regular property
289+ properties .append ('@property' )
290+ properties .append ('def {}(self) -> {}: ...' .format (name , inferred ))
291+ if not readonly :
292+ properties .append ('@{}.setter' .format (name ))
293+ properties .append ('def {}(self, val: {}) -> None: ...' .format (name , inferred ))
281294
282295
283296def generate_c_type_stub (module : ModuleType ,
@@ -298,6 +311,7 @@ def generate_c_type_stub(module: ModuleType,
298311 items = sorted (obj_dict .items (), key = lambda x : method_name_sort_key (x [0 ]))
299312 methods = [] # type: List[str]
300313 types = [] # type: List[str]
314+ static_properties = [] # type: List[str]
301315 properties = [] # type: List[str]
302316 done = set () # type: Set[str]
303317 for attr , value in items :
@@ -322,19 +336,19 @@ def generate_c_type_stub(module: ModuleType,
322336 class_sigs = class_sigs )
323337 elif is_c_property (value ):
324338 done .add (attr )
325- generate_c_property_stub (attr , value , properties , is_c_property_readonly (value ),
339+ generate_c_property_stub (attr , value , static_properties , properties ,
340+ is_c_property_readonly (value ),
326341 module = module , imports = imports )
327342 elif is_c_type (value ):
328343 generate_c_type_stub (module , attr , value , types , imports = imports , sigs = sigs ,
329344 class_sigs = class_sigs )
330345 done .add (attr )
331346
332- variables = []
333347 for attr , value in items :
334348 if is_skipped_attribute (attr ):
335349 continue
336350 if attr not in done :
337- variables .append ('%s: %s = ...' % (
351+ static_properties .append ('%s: ClassVar[%s] = ...' % (
338352 attr , strip_or_import (get_type_fullname (type (value )), module , imports )))
339353 all_bases = obj .mro ()
340354 if all_bases [- 1 ] is object :
@@ -361,21 +375,21 @@ def generate_c_type_stub(module: ModuleType,
361375 )
362376 else :
363377 bases_str = ''
364- if not methods and not variables and not properties and not types :
365- output .append ('class %s%s: ...' % (class_name , bases_str ))
366- else :
378+ if types or static_properties or methods or properties :
367379 output .append ('class %s%s:' % (class_name , bases_str ))
368380 for line in types :
369381 if output and output [- 1 ] and \
370382 not output [- 1 ].startswith ('class' ) and line .startswith ('class' ):
371383 output .append ('' )
372384 output .append (' ' + line )
373- for variable in variables :
374- output .append (' %s' % variable )
375- for method in methods :
376- output .append (' %s' % method )
377- for prop in properties :
378- output .append (' %s' % prop )
385+ for line in static_properties :
386+ output .append (' %s' % line )
387+ for line in methods :
388+ output .append (' %s' % line )
389+ for line in properties :
390+ output .append (' %s' % line )
391+ else :
392+ output .append ('class %s%s: ...' % (class_name , bases_str ))
379393
380394
381395def get_type_fullname (typ : type ) -> str :
0 commit comments