9
9
10
10
import collections
11
11
import collections .abc
12
- from collections .abc import Iterator , Sequence
12
+ from collections .abc import Iterable , Iterator
13
13
from typing import TYPE_CHECKING , Any , ClassVar , Literal
14
14
15
15
from astroid import nodes
66
66
}
67
67
68
68
69
- def _is_property (meth , context : InferenceContext | None = None ) -> bool :
69
+ def _is_property (
70
+ meth : nodes .FunctionDef | UnboundMethod , context : InferenceContext | None = None
71
+ ) -> bool :
70
72
from astroid import helpers # pylint: disable=import-outside-toplevel
71
73
72
74
decoratornames = meth .decoratornames (context = context )
@@ -92,7 +94,11 @@ def _is_property(meth, context: InferenceContext | None = None) -> bool:
92
94
if not isinstance (base_class , nodes .Name ):
93
95
continue
94
96
module , _ = base_class .lookup (base_class .name )
95
- if module .name == "builtins" and base_class .name == "property" :
97
+ if (
98
+ isinstance (module , nodes .Module )
99
+ and module .name == "builtins"
100
+ and base_class .name == "property"
101
+ ):
96
102
return True
97
103
98
104
return False
@@ -107,10 +113,15 @@ class Proxy:
107
113
if new instance attributes are created. See the Const class
108
114
"""
109
115
110
- _proxied : nodes .ClassDef | nodes .FunctionDef
116
+ _proxied : nodes .ClassDef | nodes .FunctionDef | nodes . Lambda | UnboundMethod
111
117
112
118
def __init__ (
113
- self , proxied : nodes .ClassDef | nodes .FunctionDef | None = None
119
+ self ,
120
+ proxied : nodes .ClassDef
121
+ | nodes .FunctionDef
122
+ | nodes .Lambda
123
+ | UnboundMethod
124
+ | None = None ,
114
125
) -> None :
115
126
if proxied is None :
116
127
# This is a hack to allow calling this __init__ during bootstrapping of
@@ -138,7 +149,7 @@ def infer( # type: ignore[return]
138
149
139
150
140
151
def _infer_stmts (
141
- stmts : Sequence [InferenceResult ],
152
+ stmts : Iterator [InferenceResult ],
142
153
context : InferenceContext | None ,
143
154
frame : nodes .NodeNG | BaseInstance | None = None ,
144
155
) -> collections .abc .Generator [InferenceResult , None , None ]:
@@ -148,7 +159,10 @@ def _infer_stmts(
148
159
if context is not None :
149
160
name = context .lookupname
150
161
context = context .clone ()
151
- constraints = context .constraints .get (name , {})
162
+ if name is not None :
163
+ constraints = context .constraints .get (name , {})
164
+ else :
165
+ constraints = {}
152
166
else :
153
167
name = None
154
168
constraints = {}
@@ -159,8 +173,7 @@ def _infer_stmts(
159
173
yield stmt
160
174
inferred = True
161
175
continue
162
- # 'context' is always InferenceContext and Instances get '_infer_name' from ClassDef
163
- context .lookupname = stmt ._infer_name (frame , name ) # type: ignore[union-attr]
176
+ context .lookupname = stmt ._infer_name (frame , name )
164
177
try :
165
178
stmt_constraints : set [Constraint ] = set ()
166
179
for constraint_stmt , potential_constraints in constraints .items ():
@@ -289,15 +302,17 @@ def igetattr(
289
302
except AttributeInferenceError as error :
290
303
raise InferenceError (** vars (error )) from error
291
304
292
- def _wrap_attr (self , attrs , context : InferenceContext | None = None ):
305
+ def _wrap_attr (
306
+ self , attrs : Iterable [InferenceResult ], context : InferenceContext | None = None
307
+ ) -> Iterator [InferenceResult ]:
293
308
"""Wrap bound methods of attrs in a InstanceMethod proxies."""
294
309
for attr in attrs :
295
310
if isinstance (attr , UnboundMethod ):
296
311
if _is_property (attr ):
297
312
yield from attr .infer_call_result (self , context )
298
313
else :
299
314
yield BoundMethod (attr , self )
300
- elif hasattr (attr , "name" ) and attr . name == "<lambda>" :
315
+ elif isinstance (attr , nodes . Lambda ) :
301
316
if attr .args .arguments and attr .args .arguments [0 ].name == "self" :
302
317
yield BoundMethod (attr , self )
303
318
continue
@@ -390,7 +405,9 @@ def bool_value(
390
405
return True
391
406
return result
392
407
393
- def getitem (self , index , context : InferenceContext | None = None ):
408
+ def getitem (
409
+ self , index : nodes .Const , context : InferenceContext | None = None
410
+ ) -> InferenceResult | None :
394
411
new_context = bind_context_to_node (context , self )
395
412
if not context :
396
413
context = new_context
@@ -413,13 +430,14 @@ def getitem(self, index, context: InferenceContext | None = None):
413
430
class UnboundMethod (Proxy ):
414
431
"""A special node representing a method not bound to an instance."""
415
432
416
- _proxied : nodes .FunctionDef
433
+ _proxied : nodes .FunctionDef | UnboundMethod
417
434
418
435
special_attributes : objectmodel .BoundMethodModel | objectmodel .UnboundMethodModel = (
419
436
objectmodel .UnboundMethodModel ()
420
437
)
421
438
422
439
def __repr__ (self ) -> str :
440
+ assert self ._proxied .parent , "Expected a parent node"
423
441
frame = self ._proxied .parent .frame (future = True )
424
442
return "<{} {} of {} at 0x{}" .format (
425
443
self .__class__ .__name__ , self ._proxied .name , frame .qname (), id (self )
@@ -431,7 +449,7 @@ def implicit_parameters(self) -> Literal[0, 1]:
431
449
def is_bound (self ) -> bool :
432
450
return False
433
451
434
- def getattr (self , name , context : InferenceContext | None = None ):
452
+ def getattr (self , name : str , context : InferenceContext | None = None ):
435
453
if name in self .special_attributes :
436
454
return [self .special_attributes .lookup (name )]
437
455
return self ._proxied .getattr (name , context )
@@ -461,19 +479,22 @@ def infer_call_result(
461
479
# If we're unbound method __new__ of a builtin, the result is an
462
480
# instance of the class given as first argument.
463
481
if self ._proxied .name == "__new__" :
482
+ assert self ._proxied .parent , "Expected a parent node"
464
483
qname = self ._proxied .parent .frame (future = True ).qname ()
465
484
# Avoid checking builtins.type: _infer_type_new_call() does more validation
466
485
if qname .startswith ("builtins." ) and qname != "builtins.type" :
467
- return self ._infer_builtin_new (caller , context )
486
+ return self ._infer_builtin_new (caller , context or InferenceContext () )
468
487
return self ._proxied .infer_call_result (caller , context )
469
488
470
489
def _infer_builtin_new (
471
490
self ,
472
- caller : nodes . Call ,
491
+ caller : SuccessfulInferenceResult | None ,
473
492
context : InferenceContext ,
474
493
) -> collections .abc .Generator [
475
494
nodes .Const | Instance | UninferableBase , None , None
476
495
]:
496
+ if not isinstance (caller , nodes .Call ):
497
+ return
477
498
if not caller .args :
478
499
return
479
500
# Attempt to create a constant
@@ -508,7 +529,11 @@ class BoundMethod(UnboundMethod):
508
529
509
530
special_attributes = objectmodel .BoundMethodModel ()
510
531
511
- def __init__ (self , proxy , bound ):
532
+ def __init__ (
533
+ self ,
534
+ proxy : nodes .FunctionDef | nodes .Lambda | UnboundMethod ,
535
+ bound : SuccessfulInferenceResult ,
536
+ ) -> None :
512
537
super ().__init__ (proxy )
513
538
self .bound = bound
514
539
@@ -521,7 +546,9 @@ def implicit_parameters(self) -> Literal[0, 1]:
521
546
def is_bound (self ) -> Literal [True ]:
522
547
return True
523
548
524
- def _infer_type_new_call (self , caller , context ): # noqa: C901
549
+ def _infer_type_new_call (
550
+ self , caller : nodes .Call , context : InferenceContext
551
+ ) -> nodes .ClassDef | None : # noqa: C901
525
552
"""Try to infer what type.__new__(mcs, name, bases, attrs) returns.
526
553
527
554
In order for such call to be valid, the metaclass needs to be
@@ -536,7 +563,7 @@ def _infer_type_new_call(self, caller, context): # noqa: C901
536
563
mcs = next (caller .args [0 ].infer (context = context ))
537
564
except StopIteration as e :
538
565
raise InferenceError (context = context ) from e
539
- if mcs . __class__ . __name__ != " ClassDef" :
566
+ if not isinstance ( mcs , nodes . ClassDef ) :
540
567
# Not a valid first argument.
541
568
return None
542
569
if not mcs .is_subtype_of ("builtins.type" ):
@@ -548,7 +575,7 @@ def _infer_type_new_call(self, caller, context): # noqa: C901
548
575
name = next (caller .args [1 ].infer (context = context ))
549
576
except StopIteration as e :
550
577
raise InferenceError (context = context ) from e
551
- if name . __class__ . __name__ != " Const" :
578
+ if not isinstance ( name , nodes . Const ) :
552
579
# Not a valid name, needs to be a const.
553
580
return None
554
581
if not isinstance (name .value , str ):
@@ -560,14 +587,14 @@ def _infer_type_new_call(self, caller, context): # noqa: C901
560
587
bases = next (caller .args [2 ].infer (context = context ))
561
588
except StopIteration as e :
562
589
raise InferenceError (context = context ) from e
563
- if bases . __class__ . __name__ != " Tuple" :
590
+ if not isinstance ( bases , nodes . Tuple ) :
564
591
# Needs to be a tuple.
565
592
return None
566
593
try :
567
594
inferred_bases = [next (elt .infer (context = context )) for elt in bases .elts ]
568
595
except StopIteration as e :
569
596
raise InferenceError (context = context ) from e
570
- if any (base . __class__ . __name__ != " ClassDef" for base in inferred_bases ):
597
+ if any (not isinstance ( base , nodes . ClassDef ) for base in inferred_bases ):
571
598
# All the bases needs to be Classes
572
599
return None
573
600
@@ -576,10 +603,10 @@ def _infer_type_new_call(self, caller, context): # noqa: C901
576
603
attrs = next (caller .args [3 ].infer (context = context ))
577
604
except StopIteration as e :
578
605
raise InferenceError (context = context ) from e
579
- if attrs . __class__ . __name__ != " Dict" :
606
+ if not isinstance ( attrs , nodes . Dict ) :
580
607
# Needs to be a dictionary.
581
608
return None
582
- cls_locals = collections .defaultdict (list )
609
+ cls_locals : dict [ str , list [ InferenceResult ]] = collections .defaultdict (list )
583
610
for key , value in attrs .items :
584
611
try :
585
612
key = next (key .infer (context = context ))
@@ -590,14 +617,14 @@ def _infer_type_new_call(self, caller, context): # noqa: C901
590
617
except StopIteration as e :
591
618
raise InferenceError (context = context ) from e
592
619
# Ignore non string keys
593
- if key . __class__ . __name__ == " Const" and isinstance (key .value , str ):
620
+ if isinstance ( key , nodes . Const ) and isinstance (key .value , str ):
594
621
cls_locals [key .value ].append (value )
595
622
596
623
# Build the class from now.
597
624
cls = mcs .__class__ (
598
625
name = name .value ,
599
- lineno = caller .lineno ,
600
- col_offset = caller .col_offset ,
626
+ lineno = caller .lineno or 0 ,
627
+ col_offset = caller .col_offset or 0 ,
601
628
parent = caller ,
602
629
end_lineno = caller .end_lineno ,
603
630
end_col_offset = caller .end_col_offset ,
@@ -612,7 +639,7 @@ def _infer_type_new_call(self, caller, context): # noqa: C901
612
639
cls .postinit (
613
640
bases = bases .elts ,
614
641
body = [empty ],
615
- decorators = [] ,
642
+ decorators = None ,
616
643
newstyle = True ,
617
644
metaclass = mcs ,
618
645
keywords = [],
@@ -627,9 +654,10 @@ def infer_call_result(
627
654
) -> Iterator [InferenceResult ]:
628
655
context = bind_context_to_node (context , self .bound )
629
656
if (
630
- self .bound . __class__ . __name__ == " ClassDef"
657
+ isinstance ( self .bound , nodes . ClassDef )
631
658
and self .bound .name == "type"
632
659
and self .name == "__new__"
660
+ and isinstance (caller , nodes .Call )
633
661
and len (caller .args ) == 4
634
662
):
635
663
# Check if we have a ``type.__new__(mcs, name, bases, attrs)`` call.
@@ -655,16 +683,18 @@ class Generator(BaseInstance):
655
683
special_attributes : objectmodel .GeneratorModel
656
684
657
685
def __init__ (
658
- self , parent = None , generator_initial_context : InferenceContext | None = None
659
- ):
686
+ self ,
687
+ parent : nodes .FunctionDef ,
688
+ generator_initial_context : InferenceContext | None = None ,
689
+ ) -> None :
660
690
super ().__init__ ()
661
691
self .parent = parent
662
692
self ._call_context = copy_context (generator_initial_context )
663
693
664
694
# See comment above: this is a deferred initialization.
665
695
Generator .special_attributes = objectmodel .GeneratorModel ()
666
696
667
- def infer_yield_types (self ):
697
+ def infer_yield_types (self ) -> Iterator [ InferenceResult ] :
668
698
yield from self .parent .infer_yield_result (self ._call_context )
669
699
670
700
def callable (self ) -> Literal [False ]:
0 commit comments