@@ -263,15 +263,13 @@ def get_members(obj: object) -> list[tuple[str, Any]]:
263263 for name in obj_dict :
264264 if is_skipped_attribute (name ):
265265 continue
266- # First try to get the value via getattr. Some descriptors don't
267- # like calling their __get__ (see bug #1785), so fall back to
268- # looking in the __dict__.
266+ # Try to get the value via getattr
269267 try :
270- results . append (( name , getattr (obj , name )) )
268+ value = getattr (obj , name )
271269 except AttributeError :
272- # could be a (currently) missing slot member, or a buggy
273- # __dir__; discard and move on
274270 continue
271+ else :
272+ results .append ((name , value ))
275273 return results
276274
277275
@@ -314,6 +312,7 @@ def generate_c_function_stub(
314312 module : ModuleType ,
315313 name : str ,
316314 obj : object ,
315+ * ,
317316 known_modules : list [str ],
318317 sig_generators : Iterable [SignatureGenerator ],
319318 output : list [str ],
@@ -341,7 +340,7 @@ def generate_c_function_stub(
341340 if inferred :
342341 # add self/cls var, if not present
343342 for sig in inferred :
344- if not sig .args or sig .args [0 ].name != self_var :
343+ if not sig .args or sig .args [0 ].name not in ( "self" , "cls" ) :
345344 sig .args .insert (0 , ArgSig (name = self_var ))
346345 break
347346 else :
@@ -357,7 +356,6 @@ def generate_c_function_stub(
357356 "if FallbackSignatureGenerator is provided"
358357 )
359358
360- is_classmethod = self_var == "cls"
361359 is_overloaded = len (inferred ) > 1 if inferred else False
362360 if is_overloaded :
363361 imports .append ("from typing import overload" )
@@ -379,7 +377,8 @@ def generate_c_function_stub(
379377
380378 if is_overloaded :
381379 output .append ("@overload" )
382- if is_classmethod :
380+ # a sig generator indicates @classmethod by specifying the cls arg
381+ if class_name and signature .args and signature .args [0 ].name == "cls" :
383382 output .append ("@classmethod" )
384383 output .append (
385384 "def {function}({args}) -> {ret}: ..." .format (
@@ -501,6 +500,7 @@ def generate_c_type_stub(
501500 The result lines will be appended to 'output'. If necessary, any
502501 required names will be added to 'imports'.
503502 """
503+ raw_lookup = getattr (obj , "__dict__" ) # noqa: B009
504504 items = sorted (get_members (obj ), key = lambda x : method_name_sort_key (x [0 ]))
505505 names = set (x [0 ] for x in items )
506506 methods : list [str ] = []
@@ -510,6 +510,8 @@ def generate_c_type_stub(
510510 ro_properties : list [str ] = []
511511 attrs : list [tuple [str , Any ]] = []
512512 for attr , value in items :
513+ # use unevaluated descriptors when dealing with property inspection
514+ raw_value = raw_lookup .get (attr , value )
513515 if is_c_method (value ) or is_c_classmethod (value ):
514516 if attr == "__new__" :
515517 # TODO: We should support __new__.
@@ -535,14 +537,14 @@ def generate_c_type_stub(
535537 class_name = class_name ,
536538 sig_generators = sig_generators ,
537539 )
538- elif is_c_property (value ):
540+ elif is_c_property (raw_value ):
539541 generate_c_property_stub (
540542 attr ,
541- value ,
543+ raw_value ,
542544 static_properties ,
543545 rw_properties ,
544546 ro_properties ,
545- is_c_property_readonly (value ),
547+ is_c_property_readonly (raw_value ),
546548 module = module ,
547549 known_modules = known_modules ,
548550 imports = imports ,
@@ -756,6 +758,7 @@ def infer_method_ret_type(name: str) -> str:
756758 name = name [2 :- 2 ]
757759 if name in ("float" , "bool" , "bytes" , "int" ):
758760 return name
761+ # Note: __eq__ and co may return arbitrary types, but bool is good enough for stubgen.
759762 elif name in ("eq" , "ne" , "lt" , "le" , "gt" , "ge" , "contains" ):
760763 return "bool"
761764 elif name in ("len" , "hash" , "sizeof" , "trunc" , "floor" , "ceil" ):
0 commit comments