@@ -2458,14 +2458,11 @@ def igetattr(
2458
2458
2459
2459
:returns: The inferred possible values.
2460
2460
"""
2461
- from astroid import objects # pylint: disable=import-outside-toplevel
2462
-
2463
2461
# set lookup name since this is necessary to infer on import nodes for
2464
2462
# instance
2465
2463
context = copy_context (context )
2466
2464
context .lookupname = name
2467
2465
2468
- metaclass = self .metaclass (context = context )
2469
2466
try :
2470
2467
attributes = self .getattr (name , context , class_context = class_context )
2471
2468
# If we have more than one attribute, make sure that those starting from
@@ -2488,44 +2485,7 @@ def igetattr(
2488
2485
for a in attributes
2489
2486
if a not in functions or a is last_function or bases ._is_property (a )
2490
2487
]
2491
-
2492
- for inferred in bases ._infer_stmts (attributes , context , frame = self ):
2493
- # yield Uninferable object instead of descriptors when necessary
2494
- if not isinstance (inferred , node_classes .Const ) and isinstance (
2495
- inferred , bases .Instance
2496
- ):
2497
- try :
2498
- inferred ._proxied .getattr ("__get__" , context )
2499
- except AttributeInferenceError :
2500
- yield inferred
2501
- else :
2502
- yield util .Uninferable
2503
- elif isinstance (inferred , objects .Property ):
2504
- function = inferred .function
2505
- if not class_context :
2506
- if not context .callcontext :
2507
- context .callcontext = CallContext (
2508
- args = function .args .arguments , callee = function
2509
- )
2510
- # Through an instance so we can solve the property
2511
- yield from function .infer_call_result (
2512
- caller = self , context = context
2513
- )
2514
- # If we're in a class context, we need to determine if the property
2515
- # was defined in the metaclass (a derived class must be a subclass of
2516
- # the metaclass of all its bases), in which case we can resolve the
2517
- # property. If not, i.e. the property is defined in some base class
2518
- # instead, then we return the property object
2519
- elif metaclass and function .parent .scope () is metaclass :
2520
- # Resolve a property as long as it is not accessed through
2521
- # the class itself.
2522
- yield from function .infer_call_result (
2523
- caller = self , context = context
2524
- )
2525
- else :
2526
- yield inferred
2527
- else :
2528
- yield function_to_method (inferred , self )
2488
+ yield from self ._infer_attrs (attributes , context , class_context )
2529
2489
except AttributeInferenceError as error :
2530
2490
if not name .startswith ("__" ) and self .has_dynamic_getattr (context ):
2531
2491
# class handle some dynamic attributes, return a Uninferable object
@@ -2535,6 +2495,49 @@ def igetattr(
2535
2495
str (error ), target = self , attribute = name , context = context
2536
2496
) from error
2537
2497
2498
+ def _infer_attrs (
2499
+ self ,
2500
+ attributes : list [InferenceResult ],
2501
+ context : InferenceContext ,
2502
+ class_context : bool = True ,
2503
+ ) -> Iterator [InferenceResult ]:
2504
+ from astroid import objects # pylint: disable=import-outside-toplevel
2505
+
2506
+ metaclass = self .metaclass (context = context )
2507
+ for inferred in bases ._infer_stmts (attributes , context , frame = self ):
2508
+ # yield Uninferable object instead of descriptors when necessary
2509
+ if not isinstance (inferred , node_classes .Const ) and isinstance (
2510
+ inferred , bases .Instance
2511
+ ):
2512
+ try :
2513
+ inferred ._proxied .getattr ("__get__" , context )
2514
+ except AttributeInferenceError :
2515
+ yield inferred
2516
+ else :
2517
+ yield util .Uninferable
2518
+ elif isinstance (inferred , objects .Property ):
2519
+ function = inferred .function
2520
+ if not class_context :
2521
+ if not context .callcontext :
2522
+ context .callcontext = CallContext (
2523
+ args = function .args .arguments , callee = function
2524
+ )
2525
+ # Through an instance so we can solve the property
2526
+ yield from function .infer_call_result (caller = self , context = context )
2527
+ # If we're in a class context, we need to determine if the property
2528
+ # was defined in the metaclass (a derived class must be a subclass of
2529
+ # the metaclass of all its bases), in which case we can resolve the
2530
+ # property. If not, i.e. the property is defined in some base class
2531
+ # instead, then we return the property object
2532
+ elif metaclass and function .parent .scope () is metaclass :
2533
+ # Resolve a property as long as it is not accessed through
2534
+ # the class itself.
2535
+ yield from function .infer_call_result (caller = self , context = context )
2536
+ else :
2537
+ yield inferred
2538
+ else :
2539
+ yield function_to_method (inferred , self )
2540
+
2538
2541
def has_dynamic_getattr (self , context : InferenceContext | None = None ) -> bool :
2539
2542
"""Check if the class has a custom __getattr__ or __getattribute__.
2540
2543
0 commit comments