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