| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573357435753576357735783579358035813582358335843585358635873588358935903591359235933594359535963597359835993600360136023603360436053606360736083609361036113612361336143615361636173618361936203621362236233624362536263627362836293630363136323633363436353636363736383639364036413642364336443645364636473648364936503651365236533654365536563657365836593660366136623663366436653666366736683669367036713672367336743675367636773678367936803681368236833684368536863687368836893690369136923693369436953696369736983699370037013702370337043705370637073708370937103711371237133714371537163717371837193720372137223723372437253726372737283729373037313732373337343735373637373738373937403741374237433744374537463747374837493750375137523753375437553756375737583759376037613762376337643765376637673768376937703771377237733774377537763777377837793780378137823783378437853786378737883789379037913792379337943795379637973798379938003801380238033804380538063807380838093810381138123813381438153816381738183819382038213822382338243825382638273828382938303831383238333834383538363837383838393840384138423843384438453846384738483849385038513852385338543855385638573858385938603861386238633864386538663867386838693870387138723873387438753876387738783879388038813882388338843885388638873888388938903891389238933894389538963897389838993900390139023903390439053906390739083909391039113912391339143915391639173918391939203921392239233924392539263927392839293930393139323933393439353936393739383939394039413942394339443945394639473948394939503951395239533954395539563957395839593960396139623963396439653966396739683969397039713972397339743975397639773978397939803981398239833984398539863987398839893990399139923993399439953996399739983999400040014002400340044005400640074008400940104011401240134014401540164017401840194020402140224023402440254026402740284029403040314032403340344035403640374038403940404041404240434044404540464047404840494050405140524053405440554056405740584059406040614062406340644065406640674068406940704071407240734074407540764077407840794080408140824083408440854086408740884089409040914092409340944095409640974098409941004101410241034104 |
- """Abstract syntax tree node classes (i.e. parse tree)."""
- from __future__ import annotations
- import os
- from abc import abstractmethod
- from collections import defaultdict
- from enum import Enum, unique
- from typing import (
- TYPE_CHECKING,
- Any,
- Callable,
- Dict,
- Final,
- Iterator,
- List,
- Optional,
- Sequence,
- Tuple,
- TypeVar,
- Union,
- cast,
- )
- from typing_extensions import TypeAlias as _TypeAlias, TypeGuard
- from mypy_extensions import trait
- import mypy.strconv
- from mypy.options import Options
- from mypy.util import short_type
- from mypy.visitor import ExpressionVisitor, NodeVisitor, StatementVisitor
- if TYPE_CHECKING:
- from mypy.patterns import Pattern
- class Context:
- """Base type for objects that are valid as error message locations."""
- __slots__ = ("line", "column", "end_line", "end_column")
- def __init__(self, line: int = -1, column: int = -1) -> None:
- self.line = line
- self.column = column
- self.end_line: int | None = None
- self.end_column: int | None = None
- def set_line(
- self,
- target: Context | int,
- column: int | None = None,
- end_line: int | None = None,
- end_column: int | None = None,
- ) -> None:
- """If target is a node, pull line (and column) information
- into this node. If column is specified, this will override any column
- information coming from a node.
- """
- if isinstance(target, int):
- self.line = target
- else:
- self.line = target.line
- self.column = target.column
- self.end_line = target.end_line
- self.end_column = target.end_column
- if column is not None:
- self.column = column
- if end_line is not None:
- self.end_line = end_line
- if end_column is not None:
- self.end_column = end_column
- if TYPE_CHECKING:
- # break import cycle only needed for mypy
- import mypy.types
- T = TypeVar("T")
- JsonDict: _TypeAlias = Dict[str, Any]
- # Symbol table node kinds
- #
- # TODO rename to use more descriptive names
- LDEF: Final = 0
- GDEF: Final = 1
- MDEF: Final = 2
- # Placeholder for a name imported via 'from ... import'. Second phase of
- # semantic will replace this the actual imported reference. This is
- # needed so that we can detect whether a name has been imported during
- # XXX what?
- UNBOUND_IMPORTED: Final = 3
- # RevealExpr node kinds
- REVEAL_TYPE: Final = 0
- REVEAL_LOCALS: Final = 1
- LITERAL_YES: Final = 2
- LITERAL_TYPE: Final = 1
- LITERAL_NO: Final = 0
- node_kinds: Final = {LDEF: "Ldef", GDEF: "Gdef", MDEF: "Mdef", UNBOUND_IMPORTED: "UnboundImported"}
- inverse_node_kinds: Final = {_kind: _name for _name, _kind in node_kinds.items()}
- implicit_module_attrs: Final = {
- "__name__": "__builtins__.str",
- "__doc__": None, # depends on Python version, see semanal.py
- "__path__": None, # depends on if the module is a package
- "__file__": "__builtins__.str",
- "__package__": "__builtins__.str",
- "__annotations__": None, # dict[str, Any] bounded in add_implicit_module_attrs()
- }
- # These aliases exist because built-in class objects are not subscriptable.
- # For example `list[int]` fails at runtime. Instead List[int] should be used.
- type_aliases: Final = {
- "typing.List": "builtins.list",
- "typing.Dict": "builtins.dict",
- "typing.Set": "builtins.set",
- "typing.FrozenSet": "builtins.frozenset",
- "typing.ChainMap": "collections.ChainMap",
- "typing.Counter": "collections.Counter",
- "typing.DefaultDict": "collections.defaultdict",
- "typing.Deque": "collections.deque",
- "typing.OrderedDict": "collections.OrderedDict",
- # HACK: a lie in lieu of actual support for PEP 675
- "typing.LiteralString": "builtins.str",
- }
- # This keeps track of the oldest supported Python version where the corresponding
- # alias source is available.
- type_aliases_source_versions: Final = {
- "typing.List": (2, 7),
- "typing.Dict": (2, 7),
- "typing.Set": (2, 7),
- "typing.FrozenSet": (2, 7),
- "typing.ChainMap": (3, 3),
- "typing.Counter": (2, 7),
- "typing.DefaultDict": (2, 7),
- "typing.Deque": (2, 7),
- "typing.OrderedDict": (3, 7),
- "typing.LiteralString": (3, 11),
- }
- # This keeps track of aliases in `typing_extensions`, which we treat specially.
- typing_extensions_aliases: Final = {
- # See: https://github.com/python/mypy/issues/11528
- "typing_extensions.OrderedDict": "collections.OrderedDict",
- # HACK: a lie in lieu of actual support for PEP 675
- "typing_extensions.LiteralString": "builtins.str",
- }
- reverse_builtin_aliases: Final = {
- "builtins.list": "typing.List",
- "builtins.dict": "typing.Dict",
- "builtins.set": "typing.Set",
- "builtins.frozenset": "typing.FrozenSet",
- }
- _nongen_builtins: Final = {"builtins.tuple": "typing.Tuple", "builtins.enumerate": ""}
- _nongen_builtins.update((name, alias) for alias, name in type_aliases.items())
- # Drop OrderedDict from this for backward compatibility
- del _nongen_builtins["collections.OrderedDict"]
- # HACK: consequence of hackily treating LiteralString as an alias for str
- del _nongen_builtins["builtins.str"]
- def get_nongen_builtins(python_version: tuple[int, int]) -> dict[str, str]:
- # After 3.9 with pep585 generic builtins are allowed
- return _nongen_builtins if python_version < (3, 9) else {}
- RUNTIME_PROTOCOL_DECOS: Final = (
- "typing.runtime_checkable",
- "typing_extensions.runtime",
- "typing_extensions.runtime_checkable",
- )
- class Node(Context):
- """Common base class for all non-type parse tree nodes."""
- __slots__ = ()
- def __str__(self) -> str:
- ans = self.accept(mypy.strconv.StrConv(options=Options()))
- if ans is None:
- return repr(self)
- return ans
- def str_with_options(self, options: Options) -> str:
- ans = self.accept(mypy.strconv.StrConv(options=options))
- assert ans
- return ans
- def accept(self, visitor: NodeVisitor[T]) -> T:
- raise RuntimeError("Not implemented")
- @trait
- class Statement(Node):
- """A statement node."""
- __slots__ = ()
- def accept(self, visitor: StatementVisitor[T]) -> T:
- raise RuntimeError("Not implemented")
- @trait
- class Expression(Node):
- """An expression node."""
- __slots__ = ()
- def accept(self, visitor: ExpressionVisitor[T]) -> T:
- raise RuntimeError("Not implemented")
- class FakeExpression(Expression):
- """A dummy expression.
- We need a dummy expression in one place, and can't instantiate Expression
- because it is a trait and mypyc barfs.
- """
- __slots__ = ()
- # TODO:
- # Lvalue = Union['NameExpr', 'MemberExpr', 'IndexExpr', 'SuperExpr', 'StarExpr'
- # 'TupleExpr']; see #1783.
- Lvalue: _TypeAlias = Expression
- @trait
- class SymbolNode(Node):
- """Nodes that can be stored in a symbol table."""
- __slots__ = ()
- @property
- @abstractmethod
- def name(self) -> str:
- pass
- # Fully qualified name
- @property
- @abstractmethod
- def fullname(self) -> str:
- pass
- @abstractmethod
- def serialize(self) -> JsonDict:
- pass
- @classmethod
- def deserialize(cls, data: JsonDict) -> SymbolNode:
- classname = data[".class"]
- method = deserialize_map.get(classname)
- if method is not None:
- return method(data)
- raise NotImplementedError(f"unexpected .class {classname}")
- # Items: fullname, related symbol table node, surrounding type (if any)
- Definition: _TypeAlias = Tuple[str, "SymbolTableNode", Optional["TypeInfo"]]
- class MypyFile(SymbolNode):
- """The abstract syntax tree of a single source file."""
- __slots__ = (
- "_fullname",
- "path",
- "defs",
- "alias_deps",
- "is_bom",
- "names",
- "imports",
- "ignored_lines",
- "skipped_lines",
- "is_stub",
- "is_cache_skeleton",
- "is_partial_stub_package",
- "plugin_deps",
- "future_import_flags",
- )
- __match_args__ = ("name", "path", "defs")
- # Fully qualified module name
- _fullname: str
- # Path to the file (empty string if not known)
- path: str
- # Top-level definitions and statements
- defs: list[Statement]
- # Type alias dependencies as mapping from target to set of alias full names
- alias_deps: defaultdict[str, set[str]]
- # Is there a UTF-8 BOM at the start?
- is_bom: bool
- names: SymbolTable
- # All import nodes within the file (also ones within functions etc.)
- imports: list[ImportBase]
- # Lines on which to ignore certain errors when checking.
- # If the value is empty, ignore all errors; otherwise, the list contains all
- # error codes to ignore.
- ignored_lines: dict[int, list[str]]
- # Lines that were skipped during semantic analysis e.g. due to ALWAYS_FALSE, MYPY_FALSE,
- # or platform/version checks. Those lines would not be type-checked.
- skipped_lines: set[int]
- # Is this file represented by a stub file (.pyi)?
- is_stub: bool
- # Is this loaded from the cache and thus missing the actual body of the file?
- is_cache_skeleton: bool
- # Does this represent an __init__.pyi stub with a module __getattr__
- # (i.e. a partial stub package), for such packages we suppress any missing
- # module errors in addition to missing attribute errors.
- is_partial_stub_package: bool
- # Plugin-created dependencies
- plugin_deps: dict[str, set[str]]
- # Future imports defined in this file. Populated during semantic analysis.
- future_import_flags: set[str]
- def __init__(
- self,
- defs: list[Statement],
- imports: list[ImportBase],
- is_bom: bool = False,
- ignored_lines: dict[int, list[str]] | None = None,
- ) -> None:
- super().__init__()
- self.defs = defs
- self.line = 1 # Dummy line number
- self.column = 0 # Dummy column
- self.imports = imports
- self.is_bom = is_bom
- self.alias_deps = defaultdict(set)
- self.plugin_deps = {}
- if ignored_lines:
- self.ignored_lines = ignored_lines
- else:
- self.ignored_lines = {}
- self.skipped_lines = set()
- self.path = ""
- self.is_stub = False
- self.is_cache_skeleton = False
- self.is_partial_stub_package = False
- self.future_import_flags = set()
- def local_definitions(self) -> Iterator[Definition]:
- """Return all definitions within the module (including nested).
- This doesn't include imported definitions.
- """
- return local_definitions(self.names, self.fullname)
- @property
- def name(self) -> str:
- return "" if not self._fullname else self._fullname.split(".")[-1]
- @property
- def fullname(self) -> str:
- return self._fullname
- def accept(self, visitor: NodeVisitor[T]) -> T:
- return visitor.visit_mypy_file(self)
- def is_package_init_file(self) -> bool:
- return len(self.path) != 0 and os.path.basename(self.path).startswith("__init__.")
- def is_future_flag_set(self, flag: str) -> bool:
- return flag in self.future_import_flags
- def serialize(self) -> JsonDict:
- return {
- ".class": "MypyFile",
- "_fullname": self._fullname,
- "names": self.names.serialize(self._fullname),
- "is_stub": self.is_stub,
- "path": self.path,
- "is_partial_stub_package": self.is_partial_stub_package,
- "future_import_flags": list(self.future_import_flags),
- }
- @classmethod
- def deserialize(cls, data: JsonDict) -> MypyFile:
- assert data[".class"] == "MypyFile", data
- tree = MypyFile([], [])
- tree._fullname = data["_fullname"]
- tree.names = SymbolTable.deserialize(data["names"])
- tree.is_stub = data["is_stub"]
- tree.path = data["path"]
- tree.is_partial_stub_package = data["is_partial_stub_package"]
- tree.is_cache_skeleton = True
- tree.future_import_flags = set(data["future_import_flags"])
- return tree
- class ImportBase(Statement):
- """Base class for all import statements."""
- __slots__ = ("is_unreachable", "is_top_level", "is_mypy_only", "assignments")
- is_unreachable: bool # Set by semanal.SemanticAnalyzerPass1 if inside `if False` etc.
- is_top_level: bool # Ditto if outside any class or def
- is_mypy_only: bool # Ditto if inside `if TYPE_CHECKING` or `if MYPY`
- # If an import replaces existing definitions, we construct dummy assignment
- # statements that assign the imported names to the names in the current scope,
- # for type checking purposes. Example:
- #
- # x = 1
- # from m import x <-- add assignment representing "x = m.x"
- assignments: list[AssignmentStmt]
- def __init__(self) -> None:
- super().__init__()
- self.assignments = []
- self.is_unreachable = False
- self.is_top_level = False
- self.is_mypy_only = False
- class Import(ImportBase):
- """import m [as n]"""
- __slots__ = ("ids",)
- __match_args__ = ("ids",)
- ids: list[tuple[str, str | None]] # (module id, as id)
- def __init__(self, ids: list[tuple[str, str | None]]) -> None:
- super().__init__()
- self.ids = ids
- def accept(self, visitor: StatementVisitor[T]) -> T:
- return visitor.visit_import(self)
- class ImportFrom(ImportBase):
- """from m import x [as y], ..."""
- __slots__ = ("id", "names", "relative")
- __match_args__ = ("id", "names", "relative")
- id: str
- relative: int
- names: list[tuple[str, str | None]] # Tuples (name, as name)
- def __init__(self, id: str, relative: int, names: list[tuple[str, str | None]]) -> None:
- super().__init__()
- self.id = id
- self.names = names
- self.relative = relative
- def accept(self, visitor: StatementVisitor[T]) -> T:
- return visitor.visit_import_from(self)
- class ImportAll(ImportBase):
- """from m import *"""
- __slots__ = ("id", "relative")
- __match_args__ = ("id", "relative")
- id: str
- relative: int
- def __init__(self, id: str, relative: int) -> None:
- super().__init__()
- self.id = id
- self.relative = relative
- def accept(self, visitor: StatementVisitor[T]) -> T:
- return visitor.visit_import_all(self)
- FUNCBASE_FLAGS: Final = ["is_property", "is_class", "is_static", "is_final"]
- class FuncBase(Node):
- """Abstract base class for function-like nodes.
- N.B: Although this has SymbolNode subclasses (FuncDef,
- OverloadedFuncDef), avoid calling isinstance(..., FuncBase) on
- something that is typed as SymbolNode. This is to work around
- mypy bug #3603, in which mypy doesn't understand multiple
- inheritance very well, and will assume that a SymbolNode
- cannot be a FuncBase.
- Instead, test against SYMBOL_FUNCBASE_TYPES, which enumerates
- SymbolNode subclasses that are also FuncBase subclasses.
- """
- __slots__ = (
- "type",
- "unanalyzed_type",
- "info",
- "is_property",
- "is_class", # Uses "@classmethod" (explicit or implicit)
- "is_static", # Uses "@staticmethod" (explicit or implicit)
- "is_final", # Uses "@final"
- "is_explicit_override", # Uses "@override"
- "_fullname",
- )
- def __init__(self) -> None:
- super().__init__()
- # Type signature. This is usually CallableType or Overloaded, but it can be
- # something else for decorated functions.
- self.type: mypy.types.ProperType | None = None
- # Original, not semantically analyzed type (used for reprocessing)
- self.unanalyzed_type: mypy.types.ProperType | None = None
- # If method, reference to TypeInfo
- # TODO: Type should be Optional[TypeInfo]
- self.info = FUNC_NO_INFO
- self.is_property = False
- self.is_class = False
- self.is_static = False
- self.is_final = False
- self.is_explicit_override = False
- # Name with module prefix
- self._fullname = ""
- @property
- @abstractmethod
- def name(self) -> str:
- pass
- @property
- def fullname(self) -> str:
- return self._fullname
- OverloadPart: _TypeAlias = Union["FuncDef", "Decorator"]
- class OverloadedFuncDef(FuncBase, SymbolNode, Statement):
- """A logical node representing all the variants of a multi-declaration function.
- A multi-declaration function is often an @overload, but can also be a
- @property with a setter and a/or a deleter.
- This node has no explicit representation in the source program.
- Overloaded variants must be consecutive in the source file.
- """
- __slots__ = ("items", "unanalyzed_items", "impl")
- items: list[OverloadPart]
- unanalyzed_items: list[OverloadPart]
- impl: OverloadPart | None
- def __init__(self, items: list[OverloadPart]) -> None:
- super().__init__()
- self.items = items
- self.unanalyzed_items = items.copy()
- self.impl = None
- if items:
- # TODO: figure out how to reliably set end position (we don't know the impl here).
- self.set_line(items[0].line, items[0].column)
- self.is_final = False
- @property
- def name(self) -> str:
- if self.items:
- return self.items[0].name
- else:
- # This may happen for malformed overload
- assert self.impl is not None
- return self.impl.name
- def accept(self, visitor: StatementVisitor[T]) -> T:
- return visitor.visit_overloaded_func_def(self)
- def serialize(self) -> JsonDict:
- return {
- ".class": "OverloadedFuncDef",
- "items": [i.serialize() for i in self.items],
- "type": None if self.type is None else self.type.serialize(),
- "fullname": self._fullname,
- "impl": None if self.impl is None else self.impl.serialize(),
- "flags": get_flags(self, FUNCBASE_FLAGS),
- }
- @classmethod
- def deserialize(cls, data: JsonDict) -> OverloadedFuncDef:
- assert data[".class"] == "OverloadedFuncDef"
- res = OverloadedFuncDef(
- [cast(OverloadPart, SymbolNode.deserialize(d)) for d in data["items"]]
- )
- if data.get("impl") is not None:
- res.impl = cast(OverloadPart, SymbolNode.deserialize(data["impl"]))
- # set line for empty overload items, as not set in __init__
- if len(res.items) > 0:
- res.set_line(res.impl.line)
- if data.get("type") is not None:
- typ = mypy.types.deserialize_type(data["type"])
- assert isinstance(typ, mypy.types.ProperType)
- res.type = typ
- res._fullname = data["fullname"]
- set_flags(res, data["flags"])
- # NOTE: res.info will be set in the fixup phase.
- return res
- class Argument(Node):
- """A single argument in a FuncItem."""
- __slots__ = ("variable", "type_annotation", "initializer", "kind", "pos_only")
- __match_args__ = ("variable", "type_annotation", "initializer", "kind", "pos_only")
- def __init__(
- self,
- variable: Var,
- type_annotation: mypy.types.Type | None,
- initializer: Expression | None,
- kind: ArgKind,
- pos_only: bool = False,
- ) -> None:
- super().__init__()
- self.variable = variable
- self.type_annotation = type_annotation
- self.initializer = initializer
- self.kind = kind # must be an ARG_* constant
- self.pos_only = pos_only
- def set_line(
- self,
- target: Context | int,
- column: int | None = None,
- end_line: int | None = None,
- end_column: int | None = None,
- ) -> None:
- super().set_line(target, column, end_line, end_column)
- if self.initializer and self.initializer.line < 0:
- self.initializer.set_line(self.line, self.column, self.end_line, self.end_column)
- self.variable.set_line(self.line, self.column, self.end_line, self.end_column)
- FUNCITEM_FLAGS: Final = FUNCBASE_FLAGS + [
- "is_overload",
- "is_generator",
- "is_coroutine",
- "is_async_generator",
- "is_awaitable_coroutine",
- ]
- class FuncItem(FuncBase):
- """Base class for nodes usable as overloaded function items."""
- __slots__ = (
- "arguments", # Note that can be unset if deserialized (type is a lie!)
- "arg_names", # Names of arguments
- "arg_kinds", # Kinds of arguments
- "min_args", # Minimum number of arguments
- "max_pos", # Maximum number of positional arguments, -1 if no explicit
- # limit (*args not included)
- "body", # Body of the function
- "is_overload", # Is this an overload variant of function with more than
- # one overload variant?
- "is_generator", # Contains a yield statement?
- "is_coroutine", # Defined using 'async def' syntax?
- "is_async_generator", # Is an async def generator?
- "is_awaitable_coroutine", # Decorated with '@{typing,asyncio}.coroutine'?
- "expanded", # Variants of function with type variables with values expanded
- )
- __deletable__ = ("arguments", "max_pos", "min_args")
- def __init__(
- self,
- arguments: list[Argument] | None = None,
- body: Block | None = None,
- typ: mypy.types.FunctionLike | None = None,
- ) -> None:
- super().__init__()
- self.arguments = arguments or []
- self.arg_names = [None if arg.pos_only else arg.variable.name for arg in self.arguments]
- self.arg_kinds: list[ArgKind] = [arg.kind for arg in self.arguments]
- self.max_pos: int = self.arg_kinds.count(ARG_POS) + self.arg_kinds.count(ARG_OPT)
- self.body: Block = body or Block([])
- self.type = typ
- self.unanalyzed_type = typ
- self.is_overload: bool = False
- self.is_generator: bool = False
- self.is_coroutine: bool = False
- self.is_async_generator: bool = False
- self.is_awaitable_coroutine: bool = False
- self.expanded: list[FuncItem] = []
- self.min_args = 0
- for i in range(len(self.arguments)):
- if self.arguments[i] is None and i < self.max_fixed_argc():
- self.min_args = i + 1
- def max_fixed_argc(self) -> int:
- return self.max_pos
- def is_dynamic(self) -> bool:
- return self.type is None
- FUNCDEF_FLAGS: Final = FUNCITEM_FLAGS + [
- "is_decorated",
- "is_conditional",
- "is_trivial_body",
- "is_mypy_only",
- ]
- # Abstract status of a function
- NOT_ABSTRACT: Final = 0
- # Explicitly abstract (with @abstractmethod or overload without implementation)
- IS_ABSTRACT: Final = 1
- # Implicitly abstract: used for functions with trivial bodies defined in Protocols
- IMPLICITLY_ABSTRACT: Final = 2
- class FuncDef(FuncItem, SymbolNode, Statement):
- """Function definition.
- This is a non-lambda function defined using 'def'.
- """
- __slots__ = (
- "_name",
- "is_decorated",
- "is_conditional",
- "abstract_status",
- "original_def",
- "deco_line",
- "is_trivial_body",
- "is_mypy_only",
- # Present only when a function is decorated with @typing.datasclass_transform or similar
- "dataclass_transform_spec",
- )
- __match_args__ = ("name", "arguments", "type", "body")
- # Note that all __init__ args must have default values
- def __init__(
- self,
- name: str = "", # Function name
- arguments: list[Argument] | None = None,
- body: Block | None = None,
- typ: mypy.types.FunctionLike | None = None,
- ) -> None:
- super().__init__(arguments, body, typ)
- self._name = name
- self.is_decorated = False
- self.is_conditional = False # Defined conditionally (within block)?
- self.abstract_status = NOT_ABSTRACT
- # Is this an abstract method with trivial body?
- # Such methods can't be called via super().
- self.is_trivial_body = False
- self.is_final = False
- # Original conditional definition
- self.original_def: None | FuncDef | Var | Decorator = None
- # Used for error reporting (to keep backward compatibility with pre-3.8)
- self.deco_line: int | None = None
- # Definitions that appear in if TYPE_CHECKING are marked with this flag.
- self.is_mypy_only = False
- self.dataclass_transform_spec: DataclassTransformSpec | None = None
- @property
- def name(self) -> str:
- return self._name
- def accept(self, visitor: StatementVisitor[T]) -> T:
- return visitor.visit_func_def(self)
- def serialize(self) -> JsonDict:
- # We're deliberating omitting arguments and storing only arg_names and
- # arg_kinds for space-saving reasons (arguments is not used in later
- # stages of mypy).
- # TODO: After a FuncDef is deserialized, the only time we use `arg_names`
- # and `arg_kinds` is when `type` is None and we need to infer a type. Can
- # we store the inferred type ahead of time?
- return {
- ".class": "FuncDef",
- "name": self._name,
- "fullname": self._fullname,
- "arg_names": self.arg_names,
- "arg_kinds": [int(x.value) for x in self.arg_kinds],
- "type": None if self.type is None else self.type.serialize(),
- "flags": get_flags(self, FUNCDEF_FLAGS),
- "abstract_status": self.abstract_status,
- # TODO: Do we need expanded, original_def?
- "dataclass_transform_spec": (
- None
- if self.dataclass_transform_spec is None
- else self.dataclass_transform_spec.serialize()
- ),
- }
- @classmethod
- def deserialize(cls, data: JsonDict) -> FuncDef:
- assert data[".class"] == "FuncDef"
- body = Block([])
- ret = FuncDef(
- data["name"],
- [],
- body,
- (
- None
- if data["type"] is None
- else cast(mypy.types.FunctionLike, mypy.types.deserialize_type(data["type"]))
- ),
- )
- ret._fullname = data["fullname"]
- set_flags(ret, data["flags"])
- # NOTE: ret.info is set in the fixup phase.
- ret.arg_names = data["arg_names"]
- ret.arg_kinds = [ArgKind(x) for x in data["arg_kinds"]]
- ret.abstract_status = data["abstract_status"]
- ret.dataclass_transform_spec = (
- DataclassTransformSpec.deserialize(data["dataclass_transform_spec"])
- if data["dataclass_transform_spec"] is not None
- else None
- )
- # Leave these uninitialized so that future uses will trigger an error
- del ret.arguments
- del ret.max_pos
- del ret.min_args
- return ret
- # All types that are both SymbolNodes and FuncBases. See the FuncBase
- # docstring for the rationale.
- SYMBOL_FUNCBASE_TYPES = (OverloadedFuncDef, FuncDef)
- class Decorator(SymbolNode, Statement):
- """A decorated function.
- A single Decorator object can include any number of function decorators.
- """
- __slots__ = ("func", "decorators", "original_decorators", "var", "is_overload")
- __match_args__ = ("decorators", "var", "func")
- func: FuncDef # Decorated function
- decorators: list[Expression] # Decorators (may be empty)
- # Some decorators are removed by semanal, keep the original here.
- original_decorators: list[Expression]
- # TODO: This is mostly used for the type; consider replacing with a 'type' attribute
- var: Var # Represents the decorated function obj
- is_overload: bool
- def __init__(self, func: FuncDef, decorators: list[Expression], var: Var) -> None:
- super().__init__()
- self.func = func
- self.decorators = decorators
- self.original_decorators = decorators.copy()
- self.var = var
- self.is_overload = False
- @property
- def name(self) -> str:
- return self.func.name
- @property
- def fullname(self) -> str:
- return self.func.fullname
- @property
- def is_final(self) -> bool:
- return self.func.is_final
- @property
- def info(self) -> TypeInfo:
- return self.func.info
- @property
- def type(self) -> mypy.types.Type | None:
- return self.var.type
- def accept(self, visitor: StatementVisitor[T]) -> T:
- return visitor.visit_decorator(self)
- def serialize(self) -> JsonDict:
- return {
- ".class": "Decorator",
- "func": self.func.serialize(),
- "var": self.var.serialize(),
- "is_overload": self.is_overload,
- }
- @classmethod
- def deserialize(cls, data: JsonDict) -> Decorator:
- assert data[".class"] == "Decorator"
- dec = Decorator(FuncDef.deserialize(data["func"]), [], Var.deserialize(data["var"]))
- dec.is_overload = data["is_overload"]
- return dec
- VAR_FLAGS: Final = [
- "is_self",
- "is_cls",
- "is_initialized_in_class",
- "is_staticmethod",
- "is_classmethod",
- "is_property",
- "is_settable_property",
- "is_suppressed_import",
- "is_classvar",
- "is_abstract_var",
- "is_final",
- "final_unset_in_class",
- "final_set_in_init",
- "explicit_self_type",
- "is_ready",
- "is_inferred",
- "invalid_partial_type",
- "from_module_getattr",
- "has_explicit_value",
- "allow_incompatible_override",
- ]
- class Var(SymbolNode):
- """A variable.
- It can refer to global/local variable or a data attribute.
- """
- __slots__ = (
- "_name",
- "_fullname",
- "info",
- "type",
- "final_value",
- "is_self",
- "is_cls",
- "is_ready",
- "is_inferred",
- "is_initialized_in_class",
- "is_staticmethod",
- "is_classmethod",
- "is_property",
- "is_settable_property",
- "is_classvar",
- "is_abstract_var",
- "is_final",
- "final_unset_in_class",
- "final_set_in_init",
- "is_suppressed_import",
- "explicit_self_type",
- "from_module_getattr",
- "has_explicit_value",
- "allow_incompatible_override",
- "invalid_partial_type",
- )
- __match_args__ = ("name", "type", "final_value")
- def __init__(self, name: str, type: mypy.types.Type | None = None) -> None:
- super().__init__()
- self._name = name # Name without module prefix
- # TODO: Should be Optional[str]
- self._fullname = "" # Name with module prefix
- # TODO: Should be Optional[TypeInfo]
- self.info = VAR_NO_INFO
- self.type: mypy.types.Type | None = type # Declared or inferred type, or None
- # Is this the first argument to an ordinary method (usually "self")?
- self.is_self = False
- # Is this the first argument to a classmethod (typically "cls")?
- self.is_cls = False
- self.is_ready = True # If inferred, is the inferred type available?
- self.is_inferred = self.type is None
- # Is this initialized explicitly to a non-None value in class body?
- self.is_initialized_in_class = False
- self.is_staticmethod = False
- self.is_classmethod = False
- self.is_property = False
- self.is_settable_property = False
- self.is_classvar = False
- self.is_abstract_var = False
- # Set to true when this variable refers to a module we were unable to
- # parse for some reason (eg a silenced module)
- self.is_suppressed_import = False
- # Was this "variable" (rather a constant) defined as Final[...]?
- self.is_final = False
- # If constant value is a simple literal,
- # store the literal value (unboxed) for the benefit of
- # tools like mypyc.
- self.final_value: int | float | complex | bool | str | None = None
- # Where the value was set (only for class attributes)
- self.final_unset_in_class = False
- self.final_set_in_init = False
- # This is True for a variable that was declared on self with an explicit type:
- # class C:
- # def __init__(self) -> None:
- # self.x: int
- # This case is important because this defines a new Var, even if there is one
- # present in a superclass (without explicit type this doesn't create a new Var).
- # See SemanticAnalyzer.analyze_member_lvalue() for details.
- self.explicit_self_type = False
- # If True, this is an implicit Var created due to module-level __getattr__.
- self.from_module_getattr = False
- # Var can be created with an explicit value `a = 1` or without one `a: int`,
- # we need a way to tell which one is which.
- self.has_explicit_value = False
- # If True, subclasses can override this with an incompatible type.
- self.allow_incompatible_override = False
- # If True, this means we didn't manage to infer full type and fall back to
- # something like list[Any]. We may decide to not use such types as context.
- self.invalid_partial_type = False
- @property
- def name(self) -> str:
- return self._name
- @property
- def fullname(self) -> str:
- return self._fullname
- def accept(self, visitor: NodeVisitor[T]) -> T:
- return visitor.visit_var(self)
- def serialize(self) -> JsonDict:
- # TODO: Leave default values out?
- # NOTE: Sometimes self.is_ready is False here, but we don't care.
- data: JsonDict = {
- ".class": "Var",
- "name": self._name,
- "fullname": self._fullname,
- "type": None if self.type is None else self.type.serialize(),
- "flags": get_flags(self, VAR_FLAGS),
- }
- if self.final_value is not None:
- data["final_value"] = self.final_value
- return data
- @classmethod
- def deserialize(cls, data: JsonDict) -> Var:
- assert data[".class"] == "Var"
- name = data["name"]
- type = None if data["type"] is None else mypy.types.deserialize_type(data["type"])
- v = Var(name, type)
- v.is_ready = False # Override True default set in __init__
- v._fullname = data["fullname"]
- set_flags(v, data["flags"])
- v.final_value = data.get("final_value")
- return v
- class ClassDef(Statement):
- """Class definition"""
- __slots__ = (
- "name",
- "_fullname",
- "defs",
- "type_vars",
- "base_type_exprs",
- "removed_base_type_exprs",
- "info",
- "metaclass",
- "decorators",
- "keywords",
- "analyzed",
- "has_incompatible_baseclass",
- "deco_line",
- "removed_statements",
- )
- __match_args__ = ("name", "defs")
- name: str # Name of the class without module prefix
- _fullname: str # Fully qualified name of the class
- defs: Block
- type_vars: list[mypy.types.TypeVarLikeType]
- # Base class expressions (not semantically analyzed -- can be arbitrary expressions)
- base_type_exprs: list[Expression]
- # Special base classes like Generic[...] get moved here during semantic analysis
- removed_base_type_exprs: list[Expression]
- info: TypeInfo # Related TypeInfo
- metaclass: Expression | None
- decorators: list[Expression]
- keywords: dict[str, Expression]
- analyzed: Expression | None
- has_incompatible_baseclass: bool
- # Used by special forms like NamedTuple and TypedDict to store invalid statements
- removed_statements: list[Statement]
- def __init__(
- self,
- name: str,
- defs: Block,
- type_vars: list[mypy.types.TypeVarLikeType] | None = None,
- base_type_exprs: list[Expression] | None = None,
- metaclass: Expression | None = None,
- keywords: list[tuple[str, Expression]] | None = None,
- ) -> None:
- super().__init__()
- self.name = name
- self._fullname = ""
- self.defs = defs
- self.type_vars = type_vars or []
- self.base_type_exprs = base_type_exprs or []
- self.removed_base_type_exprs = []
- self.info = CLASSDEF_NO_INFO
- self.metaclass = metaclass
- self.decorators = []
- self.keywords = dict(keywords) if keywords else {}
- self.analyzed = None
- self.has_incompatible_baseclass = False
- # Used for error reporting (to keep backwad compatibility with pre-3.8)
- self.deco_line: int | None = None
- self.removed_statements = []
- @property
- def fullname(self) -> str:
- return self._fullname
- @fullname.setter
- def fullname(self, v: str) -> None:
- self._fullname = v
- def accept(self, visitor: StatementVisitor[T]) -> T:
- return visitor.visit_class_def(self)
- def is_generic(self) -> bool:
- return self.info.is_generic()
- def serialize(self) -> JsonDict:
- # Not serialized: defs, base_type_exprs, metaclass, decorators,
- # analyzed (for named tuples etc.)
- return {
- ".class": "ClassDef",
- "name": self.name,
- "fullname": self.fullname,
- "type_vars": [v.serialize() for v in self.type_vars],
- }
- @classmethod
- def deserialize(self, data: JsonDict) -> ClassDef:
- assert data[".class"] == "ClassDef"
- res = ClassDef(
- data["name"],
- Block([]),
- # https://github.com/python/mypy/issues/12257
- [
- cast(mypy.types.TypeVarLikeType, mypy.types.deserialize_type(v))
- for v in data["type_vars"]
- ],
- )
- res.fullname = data["fullname"]
- return res
- class GlobalDecl(Statement):
- """Declaration global x, y, ..."""
- __slots__ = ("names",)
- __match_args__ = ("names",)
- names: list[str]
- def __init__(self, names: list[str]) -> None:
- super().__init__()
- self.names = names
- def accept(self, visitor: StatementVisitor[T]) -> T:
- return visitor.visit_global_decl(self)
- class NonlocalDecl(Statement):
- """Declaration nonlocal x, y, ..."""
- __slots__ = ("names",)
- __match_args__ = ("names",)
- names: list[str]
- def __init__(self, names: list[str]) -> None:
- super().__init__()
- self.names = names
- def accept(self, visitor: StatementVisitor[T]) -> T:
- return visitor.visit_nonlocal_decl(self)
- class Block(Statement):
- __slots__ = ("body", "is_unreachable")
- __match_args__ = ("body", "is_unreachable")
- def __init__(self, body: list[Statement]) -> None:
- super().__init__()
- self.body = body
- # True if we can determine that this block is not executed during semantic
- # analysis. For example, this applies to blocks that are protected by
- # something like "if PY3:" when using Python 2. However, some code is
- # only considered unreachable during type checking and this is not true
- # in those cases.
- self.is_unreachable = False
- def accept(self, visitor: StatementVisitor[T]) -> T:
- return visitor.visit_block(self)
- # Statements
- class ExpressionStmt(Statement):
- """An expression as a statement, such as print(s)."""
- __slots__ = ("expr",)
- __match_args__ = ("expr",)
- expr: Expression
- def __init__(self, expr: Expression) -> None:
- super().__init__()
- self.expr = expr
- def accept(self, visitor: StatementVisitor[T]) -> T:
- return visitor.visit_expression_stmt(self)
- class AssignmentStmt(Statement):
- """Assignment statement.
- The same node class is used for single assignment, multiple assignment
- (e.g. x, y = z) and chained assignment (e.g. x = y = z), assignments
- that define new names, and assignments with explicit types ("# type: t"
- or "x: t [= ...]").
- An lvalue can be NameExpr, TupleExpr, ListExpr, MemberExpr, or IndexExpr.
- """
- __slots__ = (
- "lvalues",
- "rvalue",
- "type",
- "unanalyzed_type",
- "new_syntax",
- "is_alias_def",
- "is_final_def",
- "invalid_recursive_alias",
- )
- __match_args__ = ("lvalues", "rvalues", "type")
- lvalues: list[Lvalue]
- # This is a TempNode if and only if no rvalue (x: t).
- rvalue: Expression
- # Declared type in a comment, may be None.
- type: mypy.types.Type | None
- # Original, not semantically analyzed type in annotation (used for reprocessing)
- unanalyzed_type: mypy.types.Type | None
- # This indicates usage of PEP 526 type annotation syntax in assignment.
- new_syntax: bool
- # Does this assignment define a type alias?
- is_alias_def: bool
- # Is this a final definition?
- # Final attributes can't be re-assigned once set, and can't be overridden
- # in a subclass. This flag is not set if an attempted declaration was found to
- # be invalid during semantic analysis. It is still set to `True` if
- # a final declaration overrides another final declaration (this is checked
- # during type checking when MROs are known).
- is_final_def: bool
- # Stop further processing of this assignment, to prevent flipping back and forth
- # during semantic analysis passes.
- invalid_recursive_alias: bool
- def __init__(
- self,
- lvalues: list[Lvalue],
- rvalue: Expression,
- type: mypy.types.Type | None = None,
- new_syntax: bool = False,
- ) -> None:
- super().__init__()
- self.lvalues = lvalues
- self.rvalue = rvalue
- self.type = type
- self.unanalyzed_type = type
- self.new_syntax = new_syntax
- self.is_alias_def = False
- self.is_final_def = False
- self.invalid_recursive_alias = False
- def accept(self, visitor: StatementVisitor[T]) -> T:
- return visitor.visit_assignment_stmt(self)
- class OperatorAssignmentStmt(Statement):
- """Operator assignment statement such as x += 1"""
- __slots__ = ("op", "lvalue", "rvalue")
- __match_args__ = ("lvalue", "op", "rvalue")
- op: str # TODO: Enum?
- lvalue: Lvalue
- rvalue: Expression
- def __init__(self, op: str, lvalue: Lvalue, rvalue: Expression) -> None:
- super().__init__()
- self.op = op
- self.lvalue = lvalue
- self.rvalue = rvalue
- def accept(self, visitor: StatementVisitor[T]) -> T:
- return visitor.visit_operator_assignment_stmt(self)
- class WhileStmt(Statement):
- __slots__ = ("expr", "body", "else_body")
- __match_args__ = ("expr", "body", "else_body")
- expr: Expression
- body: Block
- else_body: Block | None
- def __init__(self, expr: Expression, body: Block, else_body: Block | None) -> None:
- super().__init__()
- self.expr = expr
- self.body = body
- self.else_body = else_body
- def accept(self, visitor: StatementVisitor[T]) -> T:
- return visitor.visit_while_stmt(self)
- class ForStmt(Statement):
- __slots__ = (
- "index",
- "index_type",
- "unanalyzed_index_type",
- "inferred_item_type",
- "inferred_iterator_type",
- "expr",
- "body",
- "else_body",
- "is_async",
- )
- __match_args__ = ("index", "index_type", "expr", "body", "else_body")
- # Index variables
- index: Lvalue
- # Type given by type comments for index, can be None
- index_type: mypy.types.Type | None
- # Original, not semantically analyzed type in annotation (used for reprocessing)
- unanalyzed_index_type: mypy.types.Type | None
- # Inferred iterable item type
- inferred_item_type: mypy.types.Type | None
- # Inferred iterator type
- inferred_iterator_type: mypy.types.Type | None
- # Expression to iterate
- expr: Expression
- body: Block
- else_body: Block | None
- is_async: bool # True if `async for ...` (PEP 492, Python 3.5)
- def __init__(
- self,
- index: Lvalue,
- expr: Expression,
- body: Block,
- else_body: Block | None,
- index_type: mypy.types.Type | None = None,
- ) -> None:
- super().__init__()
- self.index = index
- self.index_type = index_type
- self.unanalyzed_index_type = index_type
- self.inferred_item_type = None
- self.inferred_iterator_type = None
- self.expr = expr
- self.body = body
- self.else_body = else_body
- self.is_async = False
- def accept(self, visitor: StatementVisitor[T]) -> T:
- return visitor.visit_for_stmt(self)
- class ReturnStmt(Statement):
- __slots__ = ("expr",)
- __match_args__ = ("expr",)
- expr: Expression | None
- def __init__(self, expr: Expression | None) -> None:
- super().__init__()
- self.expr = expr
- def accept(self, visitor: StatementVisitor[T]) -> T:
- return visitor.visit_return_stmt(self)
- class AssertStmt(Statement):
- __slots__ = ("expr", "msg")
- __match_args__ = ("expr", "msg")
- expr: Expression
- msg: Expression | None
- def __init__(self, expr: Expression, msg: Expression | None = None) -> None:
- super().__init__()
- self.expr = expr
- self.msg = msg
- def accept(self, visitor: StatementVisitor[T]) -> T:
- return visitor.visit_assert_stmt(self)
- class DelStmt(Statement):
- __slots__ = ("expr",)
- __match_args__ = ("expr",)
- expr: Lvalue
- def __init__(self, expr: Lvalue) -> None:
- super().__init__()
- self.expr = expr
- def accept(self, visitor: StatementVisitor[T]) -> T:
- return visitor.visit_del_stmt(self)
- class BreakStmt(Statement):
- __slots__ = ()
- def accept(self, visitor: StatementVisitor[T]) -> T:
- return visitor.visit_break_stmt(self)
- class ContinueStmt(Statement):
- __slots__ = ()
- def accept(self, visitor: StatementVisitor[T]) -> T:
- return visitor.visit_continue_stmt(self)
- class PassStmt(Statement):
- __slots__ = ()
- def accept(self, visitor: StatementVisitor[T]) -> T:
- return visitor.visit_pass_stmt(self)
- class IfStmt(Statement):
- __slots__ = ("expr", "body", "else_body")
- __match_args__ = ("expr", "body", "else_body")
- expr: list[Expression]
- body: list[Block]
- else_body: Block | None
- def __init__(self, expr: list[Expression], body: list[Block], else_body: Block | None) -> None:
- super().__init__()
- self.expr = expr
- self.body = body
- self.else_body = else_body
- def accept(self, visitor: StatementVisitor[T]) -> T:
- return visitor.visit_if_stmt(self)
- class RaiseStmt(Statement):
- __slots__ = ("expr", "from_expr")
- __match_args__ = ("expr", "from_expr")
- # Plain 'raise' is a valid statement.
- expr: Expression | None
- from_expr: Expression | None
- def __init__(self, expr: Expression | None, from_expr: Expression | None) -> None:
- super().__init__()
- self.expr = expr
- self.from_expr = from_expr
- def accept(self, visitor: StatementVisitor[T]) -> T:
- return visitor.visit_raise_stmt(self)
- class TryStmt(Statement):
- __slots__ = ("body", "types", "vars", "handlers", "else_body", "finally_body", "is_star")
- __match_args__ = ("body", "types", "vars", "handlers", "else_body", "finally_body", "is_star")
- body: Block # Try body
- # Plain 'except:' also possible
- types: list[Expression | None] # Except type expressions
- vars: list[NameExpr | None] # Except variable names
- handlers: list[Block] # Except bodies
- else_body: Block | None
- finally_body: Block | None
- # Whether this is try ... except* (added in Python 3.11)
- is_star: bool
- def __init__(
- self,
- body: Block,
- vars: list[NameExpr | None],
- types: list[Expression | None],
- handlers: list[Block],
- else_body: Block | None,
- finally_body: Block | None,
- ) -> None:
- super().__init__()
- self.body = body
- self.vars = vars
- self.types = types
- self.handlers = handlers
- self.else_body = else_body
- self.finally_body = finally_body
- self.is_star = False
- def accept(self, visitor: StatementVisitor[T]) -> T:
- return visitor.visit_try_stmt(self)
- class WithStmt(Statement):
- __slots__ = ("expr", "target", "unanalyzed_type", "analyzed_types", "body", "is_async")
- __match_args__ = ("expr", "target", "body")
- expr: list[Expression]
- target: list[Lvalue | None]
- # Type given by type comments for target, can be None
- unanalyzed_type: mypy.types.Type | None
- # Semantically analyzed types from type comment (TypeList type expanded)
- analyzed_types: list[mypy.types.Type]
- body: Block
- is_async: bool # True if `async with ...` (PEP 492, Python 3.5)
- def __init__(
- self,
- expr: list[Expression],
- target: list[Lvalue | None],
- body: Block,
- target_type: mypy.types.Type | None = None,
- ) -> None:
- super().__init__()
- self.expr = expr
- self.target = target
- self.unanalyzed_type = target_type
- self.analyzed_types = []
- self.body = body
- self.is_async = False
- def accept(self, visitor: StatementVisitor[T]) -> T:
- return visitor.visit_with_stmt(self)
- class MatchStmt(Statement):
- __slots__ = ("subject", "patterns", "guards", "bodies")
- __match_args__ = ("subject", "patterns", "guards", "bodies")
- subject: Expression
- patterns: list[Pattern]
- guards: list[Expression | None]
- bodies: list[Block]
- def __init__(
- self,
- subject: Expression,
- patterns: list[Pattern],
- guards: list[Expression | None],
- bodies: list[Block],
- ) -> None:
- super().__init__()
- assert len(patterns) == len(guards) == len(bodies)
- self.subject = subject
- self.patterns = patterns
- self.guards = guards
- self.bodies = bodies
- def accept(self, visitor: StatementVisitor[T]) -> T:
- return visitor.visit_match_stmt(self)
- # Expressions
- class IntExpr(Expression):
- """Integer literal"""
- __slots__ = ("value",)
- __match_args__ = ("value",)
- value: int # 0 by default
- def __init__(self, value: int) -> None:
- super().__init__()
- self.value = value
- def accept(self, visitor: ExpressionVisitor[T]) -> T:
- return visitor.visit_int_expr(self)
- # How mypy uses StrExpr and BytesExpr:
- #
- # b'x' -> BytesExpr
- # 'x', u'x' -> StrExpr
- class StrExpr(Expression):
- """String literal"""
- __slots__ = ("value",)
- __match_args__ = ("value",)
- value: str # '' by default
- def __init__(self, value: str) -> None:
- super().__init__()
- self.value = value
- def accept(self, visitor: ExpressionVisitor[T]) -> T:
- return visitor.visit_str_expr(self)
- def is_StrExpr_list(seq: list[Expression]) -> TypeGuard[list[StrExpr]]:
- return all(isinstance(item, StrExpr) for item in seq)
- class BytesExpr(Expression):
- """Bytes literal"""
- __slots__ = ("value",)
- __match_args__ = ("value",)
- # Note: we deliberately do NOT use bytes here because it ends up
- # unnecessarily complicating a lot of the result logic. For example,
- # we'd have to worry about converting the bytes into a format we can
- # easily serialize/deserialize to and from JSON, would have to worry
- # about turning the bytes into a human-readable representation in
- # error messages...
- #
- # It's more convenient to just store the human-readable representation
- # from the very start.
- value: str
- def __init__(self, value: str) -> None:
- super().__init__()
- self.value = value
- def accept(self, visitor: ExpressionVisitor[T]) -> T:
- return visitor.visit_bytes_expr(self)
- class FloatExpr(Expression):
- """Float literal"""
- __slots__ = ("value",)
- __match_args__ = ("value",)
- value: float # 0.0 by default
- def __init__(self, value: float) -> None:
- super().__init__()
- self.value = value
- def accept(self, visitor: ExpressionVisitor[T]) -> T:
- return visitor.visit_float_expr(self)
- class ComplexExpr(Expression):
- """Complex literal"""
- __slots__ = ("value",)
- __match_args__ = ("value",)
- value: complex
- def __init__(self, value: complex) -> None:
- super().__init__()
- self.value = value
- def accept(self, visitor: ExpressionVisitor[T]) -> T:
- return visitor.visit_complex_expr(self)
- class EllipsisExpr(Expression):
- """Ellipsis (...)"""
- __slots__ = ()
- def accept(self, visitor: ExpressionVisitor[T]) -> T:
- return visitor.visit_ellipsis(self)
- class StarExpr(Expression):
- """Star expression"""
- __slots__ = ("expr", "valid")
- __match_args__ = ("expr", "valid")
- expr: Expression
- valid: bool
- def __init__(self, expr: Expression) -> None:
- super().__init__()
- self.expr = expr
- # Whether this starred expression is used in a tuple/list and as lvalue
- self.valid = False
- def accept(self, visitor: ExpressionVisitor[T]) -> T:
- return visitor.visit_star_expr(self)
- class RefExpr(Expression):
- """Abstract base class for name-like constructs"""
- __slots__ = (
- "kind",
- "node",
- "_fullname",
- "is_new_def",
- "is_inferred_def",
- "is_alias_rvalue",
- "type_guard",
- )
- def __init__(self) -> None:
- super().__init__()
- # LDEF/GDEF/MDEF/... (None if not available)
- self.kind: int | None = None
- # Var, FuncDef or TypeInfo that describes this
- self.node: SymbolNode | None = None
- # Fully qualified name (or name if not global)
- self._fullname = ""
- # Does this define a new name?
- self.is_new_def = False
- # Does this define a new name with inferred type?
- #
- # For members, after semantic analysis, this does not take base
- # classes into consideration at all; the type checker deals with these.
- self.is_inferred_def = False
- # Is this expression appears as an rvalue of a valid type alias definition?
- self.is_alias_rvalue = False
- # Cache type guard from callable_type.type_guard
- self.type_guard: mypy.types.Type | None = None
- @property
- def fullname(self) -> str:
- return self._fullname
- @fullname.setter
- def fullname(self, v: str) -> None:
- self._fullname = v
- class NameExpr(RefExpr):
- """Name expression
- This refers to a local name, global name or a module.
- """
- __slots__ = ("name", "is_special_form")
- __match_args__ = ("name", "node")
- def __init__(self, name: str) -> None:
- super().__init__()
- self.name = name # Name referred to
- # Is this a l.h.s. of a special form assignment like typed dict or type variable?
- self.is_special_form = False
- def accept(self, visitor: ExpressionVisitor[T]) -> T:
- return visitor.visit_name_expr(self)
- def serialize(self) -> JsonDict:
- assert False, f"Serializing NameExpr: {self}"
- class MemberExpr(RefExpr):
- """Member access expression x.y"""
- __slots__ = ("expr", "name", "def_var")
- __match_args__ = ("expr", "name", "node")
- def __init__(self, expr: Expression, name: str) -> None:
- super().__init__()
- self.expr = expr
- self.name = name
- # The variable node related to a definition through 'self.x = <initializer>'.
- # The nodes of other kinds of member expressions are resolved during type checking.
- self.def_var: Var | None = None
- def accept(self, visitor: ExpressionVisitor[T]) -> T:
- return visitor.visit_member_expr(self)
- # Kinds of arguments
- @unique
- class ArgKind(Enum):
- # Positional argument
- ARG_POS = 0
- # Positional, optional argument (functions only, not calls)
- ARG_OPT = 1
- # *arg argument
- ARG_STAR = 2
- # Keyword argument x=y in call, or keyword-only function arg
- ARG_NAMED = 3
- # **arg argument
- ARG_STAR2 = 4
- # In an argument list, keyword-only and also optional
- ARG_NAMED_OPT = 5
- def is_positional(self, star: bool = False) -> bool:
- return self == ARG_POS or self == ARG_OPT or (star and self == ARG_STAR)
- def is_named(self, star: bool = False) -> bool:
- return self == ARG_NAMED or self == ARG_NAMED_OPT or (star and self == ARG_STAR2)
- def is_required(self) -> bool:
- return self == ARG_POS or self == ARG_NAMED
- def is_optional(self) -> bool:
- return self == ARG_OPT or self == ARG_NAMED_OPT
- def is_star(self) -> bool:
- return self == ARG_STAR or self == ARG_STAR2
- ARG_POS: Final = ArgKind.ARG_POS
- ARG_OPT: Final = ArgKind.ARG_OPT
- ARG_STAR: Final = ArgKind.ARG_STAR
- ARG_NAMED: Final = ArgKind.ARG_NAMED
- ARG_STAR2: Final = ArgKind.ARG_STAR2
- ARG_NAMED_OPT: Final = ArgKind.ARG_NAMED_OPT
- class CallExpr(Expression):
- """Call expression.
- This can also represent several special forms that are syntactically calls
- such as cast(...) and None # type: ....
- """
- __slots__ = ("callee", "args", "arg_kinds", "arg_names", "analyzed")
- __match_args__ = ("callee", "args", "arg_kinds", "arg_names")
- def __init__(
- self,
- callee: Expression,
- args: list[Expression],
- arg_kinds: list[ArgKind],
- arg_names: list[str | None],
- analyzed: Expression | None = None,
- ) -> None:
- super().__init__()
- if not arg_names:
- arg_names = [None] * len(args)
- self.callee = callee
- self.args = args
- self.arg_kinds = arg_kinds # ARG_ constants
- # Each name can be None if not a keyword argument.
- self.arg_names: list[str | None] = arg_names
- # If not None, the node that represents the meaning of the CallExpr. For
- # cast(...) this is a CastExpr.
- self.analyzed = analyzed
- def accept(self, visitor: ExpressionVisitor[T]) -> T:
- return visitor.visit_call_expr(self)
- class YieldFromExpr(Expression):
- __slots__ = ("expr",)
- __match_args__ = ("expr",)
- expr: Expression
- def __init__(self, expr: Expression) -> None:
- super().__init__()
- self.expr = expr
- def accept(self, visitor: ExpressionVisitor[T]) -> T:
- return visitor.visit_yield_from_expr(self)
- class YieldExpr(Expression):
- __slots__ = ("expr",)
- __match_args__ = ("expr",)
- expr: Expression | None
- def __init__(self, expr: Expression | None) -> None:
- super().__init__()
- self.expr = expr
- def accept(self, visitor: ExpressionVisitor[T]) -> T:
- return visitor.visit_yield_expr(self)
- class IndexExpr(Expression):
- """Index expression x[y].
- Also wraps type application such as List[int] as a special form.
- """
- __slots__ = ("base", "index", "method_type", "analyzed")
- __match_args__ = ("base", "index")
- base: Expression
- index: Expression
- # Inferred __getitem__ method type
- method_type: mypy.types.Type | None
- # If not None, this is actually semantically a type application
- # Class[type, ...] or a type alias initializer.
- analyzed: TypeApplication | TypeAliasExpr | None
- def __init__(self, base: Expression, index: Expression) -> None:
- super().__init__()
- self.base = base
- self.index = index
- self.method_type = None
- self.analyzed = None
- def accept(self, visitor: ExpressionVisitor[T]) -> T:
- return visitor.visit_index_expr(self)
- class UnaryExpr(Expression):
- """Unary operation"""
- __slots__ = ("op", "expr", "method_type")
- __match_args__ = ("op", "expr")
- op: str # TODO: Enum?
- expr: Expression
- # Inferred operator method type
- method_type: mypy.types.Type | None
- def __init__(self, op: str, expr: Expression) -> None:
- super().__init__()
- self.op = op
- self.expr = expr
- self.method_type = None
- def accept(self, visitor: ExpressionVisitor[T]) -> T:
- return visitor.visit_unary_expr(self)
- class AssignmentExpr(Expression):
- """Assignment expressions in Python 3.8+, like "a := 2"."""
- __slots__ = ("target", "value")
- __match_args__ = ("target", "value")
- def __init__(self, target: Expression, value: Expression) -> None:
- super().__init__()
- self.target = target
- self.value = value
- def accept(self, visitor: ExpressionVisitor[T]) -> T:
- return visitor.visit_assignment_expr(self)
- class OpExpr(Expression):
- """Binary operation.
- The dot (.), [] and comparison operators have more specific nodes.
- """
- __slots__ = (
- "op",
- "left",
- "right",
- "method_type",
- "right_always",
- "right_unreachable",
- "analyzed",
- )
- __match_args__ = ("left", "op", "right")
- op: str # TODO: Enum?
- left: Expression
- right: Expression
- # Inferred type for the operator method type (when relevant).
- method_type: mypy.types.Type | None
- # Per static analysis only: Is the right side going to be evaluated every time?
- right_always: bool
- # Per static analysis only: Is the right side unreachable?
- right_unreachable: bool
- # Used for expressions that represent a type "X | Y" in some contexts
- analyzed: TypeAliasExpr | None
- def __init__(
- self, op: str, left: Expression, right: Expression, analyzed: TypeAliasExpr | None = None
- ) -> None:
- super().__init__()
- self.op = op
- self.left = left
- self.right = right
- self.method_type = None
- self.right_always = False
- self.right_unreachable = False
- self.analyzed = analyzed
- def accept(self, visitor: ExpressionVisitor[T]) -> T:
- return visitor.visit_op_expr(self)
- class ComparisonExpr(Expression):
- """Comparison expression (e.g. a < b > c < d)."""
- __slots__ = ("operators", "operands", "method_types")
- __match_args__ = ("operands", "operators")
- operators: list[str]
- operands: list[Expression]
- # Inferred type for the operator methods (when relevant; None for 'is').
- method_types: list[mypy.types.Type | None]
- def __init__(self, operators: list[str], operands: list[Expression]) -> None:
- super().__init__()
- self.operators = operators
- self.operands = operands
- self.method_types = []
- def pairwise(self) -> Iterator[tuple[str, Expression, Expression]]:
- """If this comparison expr is "a < b is c == d", yields the sequence
- ("<", a, b), ("is", b, c), ("==", c, d)
- """
- for i, operator in enumerate(self.operators):
- yield operator, self.operands[i], self.operands[i + 1]
- def accept(self, visitor: ExpressionVisitor[T]) -> T:
- return visitor.visit_comparison_expr(self)
- class SliceExpr(Expression):
- """Slice expression (e.g. 'x:y', 'x:', '::2' or ':').
- This is only valid as index in index expressions.
- """
- __slots__ = ("begin_index", "end_index", "stride")
- __match_args__ = ("begin_index", "end_index", "stride")
- begin_index: Expression | None
- end_index: Expression | None
- stride: Expression | None
- def __init__(
- self,
- begin_index: Expression | None,
- end_index: Expression | None,
- stride: Expression | None,
- ) -> None:
- super().__init__()
- self.begin_index = begin_index
- self.end_index = end_index
- self.stride = stride
- def accept(self, visitor: ExpressionVisitor[T]) -> T:
- return visitor.visit_slice_expr(self)
- class CastExpr(Expression):
- """Cast expression cast(type, expr)."""
- __slots__ = ("expr", "type")
- __match_args__ = ("expr", "type")
- expr: Expression
- type: mypy.types.Type
- def __init__(self, expr: Expression, typ: mypy.types.Type) -> None:
- super().__init__()
- self.expr = expr
- self.type = typ
- def accept(self, visitor: ExpressionVisitor[T]) -> T:
- return visitor.visit_cast_expr(self)
- class AssertTypeExpr(Expression):
- """Represents a typing.assert_type(expr, type) call."""
- __slots__ = ("expr", "type")
- __match_args__ = ("expr", "type")
- expr: Expression
- type: mypy.types.Type
- def __init__(self, expr: Expression, typ: mypy.types.Type) -> None:
- super().__init__()
- self.expr = expr
- self.type = typ
- def accept(self, visitor: ExpressionVisitor[T]) -> T:
- return visitor.visit_assert_type_expr(self)
- class RevealExpr(Expression):
- """Reveal type expression reveal_type(expr) or reveal_locals() expression."""
- __slots__ = ("expr", "kind", "local_nodes")
- __match_args__ = ("expr", "kind", "local_nodes")
- expr: Expression | None
- kind: int
- local_nodes: list[Var] | None
- def __init__(
- self, kind: int, expr: Expression | None = None, local_nodes: list[Var] | None = None
- ) -> None:
- super().__init__()
- self.expr = expr
- self.kind = kind
- self.local_nodes = local_nodes
- def accept(self, visitor: ExpressionVisitor[T]) -> T:
- return visitor.visit_reveal_expr(self)
- class SuperExpr(Expression):
- """Expression super().name"""
- __slots__ = ("name", "info", "call")
- __match_args__ = ("name", "call", "info")
- name: str
- info: TypeInfo | None # Type that contains this super expression
- call: CallExpr # The expression super(...)
- def __init__(self, name: str, call: CallExpr) -> None:
- super().__init__()
- self.name = name
- self.call = call
- self.info = None
- def accept(self, visitor: ExpressionVisitor[T]) -> T:
- return visitor.visit_super_expr(self)
- class LambdaExpr(FuncItem, Expression):
- """Lambda expression"""
- __match_args__ = ("arguments", "arg_names", "arg_kinds", "body")
- @property
- def name(self) -> str:
- return "<lambda>"
- def expr(self) -> Expression:
- """Return the expression (the body) of the lambda."""
- ret = self.body.body[-1]
- assert isinstance(ret, ReturnStmt)
- expr = ret.expr
- assert expr is not None # lambda can't have empty body
- return expr
- def accept(self, visitor: ExpressionVisitor[T]) -> T:
- return visitor.visit_lambda_expr(self)
- def is_dynamic(self) -> bool:
- return False
- class ListExpr(Expression):
- """List literal expression [...]."""
- __slots__ = ("items",)
- __match_args__ = ("items",)
- items: list[Expression]
- def __init__(self, items: list[Expression]) -> None:
- super().__init__()
- self.items = items
- def accept(self, visitor: ExpressionVisitor[T]) -> T:
- return visitor.visit_list_expr(self)
- class DictExpr(Expression):
- """Dictionary literal expression {key: value, ...}."""
- __slots__ = ("items",)
- __match_args__ = ("items",)
- items: list[tuple[Expression | None, Expression]]
- def __init__(self, items: list[tuple[Expression | None, Expression]]) -> None:
- super().__init__()
- self.items = items
- def accept(self, visitor: ExpressionVisitor[T]) -> T:
- return visitor.visit_dict_expr(self)
- class TupleExpr(Expression):
- """Tuple literal expression (..., ...)
- Also lvalue sequences (..., ...) and [..., ...]"""
- __slots__ = ("items",)
- __match_args__ = ("items",)
- items: list[Expression]
- def __init__(self, items: list[Expression]) -> None:
- super().__init__()
- self.items = items
- def accept(self, visitor: ExpressionVisitor[T]) -> T:
- return visitor.visit_tuple_expr(self)
- class SetExpr(Expression):
- """Set literal expression {value, ...}."""
- __slots__ = ("items",)
- __match_args__ = ("items",)
- items: list[Expression]
- def __init__(self, items: list[Expression]) -> None:
- super().__init__()
- self.items = items
- def accept(self, visitor: ExpressionVisitor[T]) -> T:
- return visitor.visit_set_expr(self)
- class GeneratorExpr(Expression):
- """Generator expression ... for ... in ... [ for ... in ... ] [ if ... ]."""
- __slots__ = ("left_expr", "sequences", "condlists", "is_async", "indices")
- __match_args__ = ("left_expr", "indices", "sequences", "condlists")
- left_expr: Expression
- sequences: list[Expression]
- condlists: list[list[Expression]]
- is_async: list[bool]
- indices: list[Lvalue]
- def __init__(
- self,
- left_expr: Expression,
- indices: list[Lvalue],
- sequences: list[Expression],
- condlists: list[list[Expression]],
- is_async: list[bool],
- ) -> None:
- super().__init__()
- self.left_expr = left_expr
- self.sequences = sequences
- self.condlists = condlists
- self.indices = indices
- self.is_async = is_async
- def accept(self, visitor: ExpressionVisitor[T]) -> T:
- return visitor.visit_generator_expr(self)
- class ListComprehension(Expression):
- """List comprehension (e.g. [x + 1 for x in a])"""
- __slots__ = ("generator",)
- __match_args__ = ("generator",)
- generator: GeneratorExpr
- def __init__(self, generator: GeneratorExpr) -> None:
- super().__init__()
- self.generator = generator
- def accept(self, visitor: ExpressionVisitor[T]) -> T:
- return visitor.visit_list_comprehension(self)
- class SetComprehension(Expression):
- """Set comprehension (e.g. {x + 1 for x in a})"""
- __slots__ = ("generator",)
- __match_args__ = ("generator",)
- generator: GeneratorExpr
- def __init__(self, generator: GeneratorExpr) -> None:
- super().__init__()
- self.generator = generator
- def accept(self, visitor: ExpressionVisitor[T]) -> T:
- return visitor.visit_set_comprehension(self)
- class DictionaryComprehension(Expression):
- """Dictionary comprehension (e.g. {k: v for k, v in a}"""
- __slots__ = ("key", "value", "sequences", "condlists", "is_async", "indices")
- __match_args__ = ("key", "value", "indices", "sequences", "condlists")
- key: Expression
- value: Expression
- sequences: list[Expression]
- condlists: list[list[Expression]]
- is_async: list[bool]
- indices: list[Lvalue]
- def __init__(
- self,
- key: Expression,
- value: Expression,
- indices: list[Lvalue],
- sequences: list[Expression],
- condlists: list[list[Expression]],
- is_async: list[bool],
- ) -> None:
- super().__init__()
- self.key = key
- self.value = value
- self.sequences = sequences
- self.condlists = condlists
- self.indices = indices
- self.is_async = is_async
- def accept(self, visitor: ExpressionVisitor[T]) -> T:
- return visitor.visit_dictionary_comprehension(self)
- class ConditionalExpr(Expression):
- """Conditional expression (e.g. x if y else z)"""
- __slots__ = ("cond", "if_expr", "else_expr")
- __match_args__ = ("if_expr", "cond", "else_expr")
- cond: Expression
- if_expr: Expression
- else_expr: Expression
- def __init__(self, cond: Expression, if_expr: Expression, else_expr: Expression) -> None:
- super().__init__()
- self.cond = cond
- self.if_expr = if_expr
- self.else_expr = else_expr
- def accept(self, visitor: ExpressionVisitor[T]) -> T:
- return visitor.visit_conditional_expr(self)
- class TypeApplication(Expression):
- """Type application expr[type, ...]"""
- __slots__ = ("expr", "types")
- __match_args__ = ("expr", "types")
- expr: Expression
- types: list[mypy.types.Type]
- def __init__(self, expr: Expression, types: list[mypy.types.Type]) -> None:
- super().__init__()
- self.expr = expr
- self.types = types
- def accept(self, visitor: ExpressionVisitor[T]) -> T:
- return visitor.visit_type_application(self)
- # Variance of a type variable. For example, T in the definition of
- # List[T] is invariant, so List[int] is not a subtype of List[object],
- # and also List[object] is not a subtype of List[int].
- #
- # The T in Iterable[T] is covariant, so Iterable[int] is a subtype of
- # Iterable[object], but not vice versa.
- #
- # If T is contravariant in Foo[T], Foo[object] is a subtype of
- # Foo[int], but not vice versa.
- INVARIANT: Final = 0
- COVARIANT: Final = 1
- CONTRAVARIANT: Final = 2
- class TypeVarLikeExpr(SymbolNode, Expression):
- """Base class for TypeVarExpr, ParamSpecExpr and TypeVarTupleExpr.
- Note that they are constructed by the semantic analyzer.
- """
- __slots__ = ("_name", "_fullname", "upper_bound", "default", "variance")
- _name: str
- _fullname: str
- # Upper bound: only subtypes of upper_bound are valid as values. By default
- # this is 'object', meaning no restriction.
- upper_bound: mypy.types.Type
- # Default: used to resolve the TypeVar if the default is not explicitly given.
- # By default this is 'AnyType(TypeOfAny.from_omitted_generics)'. See PEP 696.
- default: mypy.types.Type
- # Variance of the type variable. Invariant is the default.
- # TypeVar(..., covariant=True) defines a covariant type variable.
- # TypeVar(..., contravariant=True) defines a contravariant type
- # variable.
- variance: int
- def __init__(
- self,
- name: str,
- fullname: str,
- upper_bound: mypy.types.Type,
- default: mypy.types.Type,
- variance: int = INVARIANT,
- ) -> None:
- super().__init__()
- self._name = name
- self._fullname = fullname
- self.upper_bound = upper_bound
- self.default = default
- self.variance = variance
- @property
- def name(self) -> str:
- return self._name
- @property
- def fullname(self) -> str:
- return self._fullname
- class TypeVarExpr(TypeVarLikeExpr):
- """Type variable expression TypeVar(...).
- This is also used to represent type variables in symbol tables.
- A type variable is not valid as a type unless bound in a TypeVarLikeScope.
- That happens within:
- 1. a generic class that uses the type variable as a type argument or
- 2. a generic function that refers to the type variable in its signature.
- """
- __slots__ = ("values",)
- __match_args__ = ("name", "values", "upper_bound", "default")
- # Value restriction: only types in the list are valid as values. If the
- # list is empty, there is no restriction.
- values: list[mypy.types.Type]
- def __init__(
- self,
- name: str,
- fullname: str,
- values: list[mypy.types.Type],
- upper_bound: mypy.types.Type,
- default: mypy.types.Type,
- variance: int = INVARIANT,
- ) -> None:
- super().__init__(name, fullname, upper_bound, default, variance)
- self.values = values
- def accept(self, visitor: ExpressionVisitor[T]) -> T:
- return visitor.visit_type_var_expr(self)
- def serialize(self) -> JsonDict:
- return {
- ".class": "TypeVarExpr",
- "name": self._name,
- "fullname": self._fullname,
- "values": [t.serialize() for t in self.values],
- "upper_bound": self.upper_bound.serialize(),
- "default": self.default.serialize(),
- "variance": self.variance,
- }
- @classmethod
- def deserialize(cls, data: JsonDict) -> TypeVarExpr:
- assert data[".class"] == "TypeVarExpr"
- return TypeVarExpr(
- data["name"],
- data["fullname"],
- [mypy.types.deserialize_type(v) for v in data["values"]],
- mypy.types.deserialize_type(data["upper_bound"]),
- mypy.types.deserialize_type(data["default"]),
- data["variance"],
- )
- class ParamSpecExpr(TypeVarLikeExpr):
- __slots__ = ()
- __match_args__ = ("name", "upper_bound", "default")
- def accept(self, visitor: ExpressionVisitor[T]) -> T:
- return visitor.visit_paramspec_expr(self)
- def serialize(self) -> JsonDict:
- return {
- ".class": "ParamSpecExpr",
- "name": self._name,
- "fullname": self._fullname,
- "upper_bound": self.upper_bound.serialize(),
- "default": self.default.serialize(),
- "variance": self.variance,
- }
- @classmethod
- def deserialize(cls, data: JsonDict) -> ParamSpecExpr:
- assert data[".class"] == "ParamSpecExpr"
- return ParamSpecExpr(
- data["name"],
- data["fullname"],
- mypy.types.deserialize_type(data["upper_bound"]),
- mypy.types.deserialize_type(data["default"]),
- data["variance"],
- )
- class TypeVarTupleExpr(TypeVarLikeExpr):
- """Type variable tuple expression TypeVarTuple(...)."""
- __slots__ = "tuple_fallback"
- tuple_fallback: mypy.types.Instance
- __match_args__ = ("name", "upper_bound", "default")
- def __init__(
- self,
- name: str,
- fullname: str,
- upper_bound: mypy.types.Type,
- tuple_fallback: mypy.types.Instance,
- default: mypy.types.Type,
- variance: int = INVARIANT,
- ) -> None:
- super().__init__(name, fullname, upper_bound, default, variance)
- self.tuple_fallback = tuple_fallback
- def accept(self, visitor: ExpressionVisitor[T]) -> T:
- return visitor.visit_type_var_tuple_expr(self)
- def serialize(self) -> JsonDict:
- return {
- ".class": "TypeVarTupleExpr",
- "name": self._name,
- "fullname": self._fullname,
- "upper_bound": self.upper_bound.serialize(),
- "tuple_fallback": self.tuple_fallback.serialize(),
- "default": self.default.serialize(),
- "variance": self.variance,
- }
- @classmethod
- def deserialize(cls, data: JsonDict) -> TypeVarTupleExpr:
- assert data[".class"] == "TypeVarTupleExpr"
- return TypeVarTupleExpr(
- data["name"],
- data["fullname"],
- mypy.types.deserialize_type(data["upper_bound"]),
- mypy.types.Instance.deserialize(data["tuple_fallback"]),
- mypy.types.deserialize_type(data["default"]),
- data["variance"],
- )
- class TypeAliasExpr(Expression):
- """Type alias expression (rvalue)."""
- __slots__ = ("type", "tvars", "no_args", "node")
- __match_args__ = ("type", "tvars", "no_args", "node")
- # The target type.
- type: mypy.types.Type
- # Names of type variables used to define the alias
- tvars: list[str]
- # Whether this alias was defined in bare form. Used to distinguish
- # between
- # A = List
- # and
- # A = List[Any]
- no_args: bool
- node: TypeAlias
- def __init__(self, node: TypeAlias) -> None:
- super().__init__()
- self.type = node.target
- self.tvars = [v.name for v in node.alias_tvars]
- self.no_args = node.no_args
- self.node = node
- def accept(self, visitor: ExpressionVisitor[T]) -> T:
- return visitor.visit_type_alias_expr(self)
- class NamedTupleExpr(Expression):
- """Named tuple expression namedtuple(...) or NamedTuple(...)."""
- __slots__ = ("info", "is_typed")
- __match_args__ = ("info",)
- # The class representation of this named tuple (its tuple_type attribute contains
- # the tuple item types)
- info: TypeInfo
- is_typed: bool # whether this class was created with typing(_extensions).NamedTuple
- def __init__(self, info: TypeInfo, is_typed: bool = False) -> None:
- super().__init__()
- self.info = info
- self.is_typed = is_typed
- def accept(self, visitor: ExpressionVisitor[T]) -> T:
- return visitor.visit_namedtuple_expr(self)
- class TypedDictExpr(Expression):
- """Typed dict expression TypedDict(...)."""
- __slots__ = ("info",)
- __match_args__ = ("info",)
- # The class representation of this typed dict
- info: TypeInfo
- def __init__(self, info: TypeInfo) -> None:
- super().__init__()
- self.info = info
- def accept(self, visitor: ExpressionVisitor[T]) -> T:
- return visitor.visit_typeddict_expr(self)
- class EnumCallExpr(Expression):
- """Named tuple expression Enum('name', 'val1 val2 ...')."""
- __slots__ = ("info", "items", "values")
- __match_args__ = ("info", "items", "values")
- # The class representation of this enumerated type
- info: TypeInfo
- # The item names (for debugging)
- items: list[str]
- values: list[Expression | None]
- def __init__(self, info: TypeInfo, items: list[str], values: list[Expression | None]) -> None:
- super().__init__()
- self.info = info
- self.items = items
- self.values = values
- def accept(self, visitor: ExpressionVisitor[T]) -> T:
- return visitor.visit_enum_call_expr(self)
- class PromoteExpr(Expression):
- """Ducktype class decorator expression _promote(...)."""
- __slots__ = ("type",)
- type: mypy.types.ProperType
- def __init__(self, type: mypy.types.ProperType) -> None:
- super().__init__()
- self.type = type
- def accept(self, visitor: ExpressionVisitor[T]) -> T:
- return visitor.visit__promote_expr(self)
- class NewTypeExpr(Expression):
- """NewType expression NewType(...)."""
- __slots__ = ("name", "old_type", "info")
- __match_args__ = ("name", "old_type", "info")
- name: str
- # The base type (the second argument to NewType)
- old_type: mypy.types.Type | None
- # The synthesized class representing the new type (inherits old_type)
- info: TypeInfo | None
- def __init__(
- self, name: str, old_type: mypy.types.Type | None, line: int, column: int
- ) -> None:
- super().__init__(line=line, column=column)
- self.name = name
- self.old_type = old_type
- self.info = None
- def accept(self, visitor: ExpressionVisitor[T]) -> T:
- return visitor.visit_newtype_expr(self)
- class AwaitExpr(Expression):
- """Await expression (await ...)."""
- __slots__ = ("expr",)
- __match_args__ = ("expr",)
- expr: Expression
- def __init__(self, expr: Expression) -> None:
- super().__init__()
- self.expr = expr
- def accept(self, visitor: ExpressionVisitor[T]) -> T:
- return visitor.visit_await_expr(self)
- # Constants
- class TempNode(Expression):
- """Temporary dummy node used during type checking.
- This node is not present in the original program; it is just an artifact
- of the type checker implementation. It only represents an opaque node with
- some fixed type.
- """
- __slots__ = ("type", "no_rhs")
- type: mypy.types.Type
- # Is this TempNode used to indicate absence of a right hand side in an annotated assignment?
- # (e.g. for 'x: int' the rvalue is TempNode(AnyType(TypeOfAny.special_form), no_rhs=True))
- no_rhs: bool
- def __init__(
- self, typ: mypy.types.Type, no_rhs: bool = False, *, context: Context | None = None
- ) -> None:
- """Construct a dummy node; optionally borrow line/column from context object."""
- super().__init__()
- self.type = typ
- self.no_rhs = no_rhs
- if context is not None:
- self.line = context.line
- self.column = context.column
- def __repr__(self) -> str:
- return "TempNode:%d(%s)" % (self.line, str(self.type))
- def accept(self, visitor: ExpressionVisitor[T]) -> T:
- return visitor.visit_temp_node(self)
- # Special attributes not collected as protocol members by Python 3.12
- # See typing._SPECIAL_NAMES
- EXCLUDED_PROTOCOL_ATTRIBUTES: Final = frozenset(
- {
- "__abstractmethods__",
- "__annotations__",
- "__dict__",
- "__doc__",
- "__init__",
- "__module__",
- "__new__",
- "__slots__",
- "__subclasshook__",
- "__weakref__",
- "__class_getitem__", # Since Python 3.9
- }
- )
- class TypeInfo(SymbolNode):
- """The type structure of a single class.
- Each TypeInfo corresponds one-to-one to a ClassDef, which
- represents the AST of the class.
- In type-theory terms, this is a "type constructor", and if the
- class is generic then it will be a type constructor of higher kind.
- Where the class is used in an actual type, it's in the form of an
- Instance, which amounts to a type application of the tycon to
- the appropriate number of arguments.
- """
- __slots__ = (
- "_fullname",
- "module_name",
- "defn",
- "mro",
- "_mro_refs",
- "bad_mro",
- "is_final",
- "declared_metaclass",
- "metaclass_type",
- "names",
- "is_abstract",
- "is_protocol",
- "runtime_protocol",
- "abstract_attributes",
- "deletable_attributes",
- "slots",
- "assuming",
- "assuming_proper",
- "inferring",
- "is_enum",
- "fallback_to_any",
- "meta_fallback_to_any",
- "type_vars",
- "has_param_spec_type",
- "bases",
- "_promote",
- "tuple_type",
- "special_alias",
- "is_named_tuple",
- "typeddict_type",
- "is_newtype",
- "is_intersection",
- "metadata",
- "alt_promote",
- "has_type_var_tuple_type",
- "type_var_tuple_prefix",
- "type_var_tuple_suffix",
- "self_type",
- "dataclass_transform_spec",
- )
- _fullname: str # Fully qualified name
- # Fully qualified name for the module this type was defined in. This
- # information is also in the fullname, but is harder to extract in the
- # case of nested class definitions.
- module_name: str
- defn: ClassDef # Corresponding ClassDef
- # Method Resolution Order: the order of looking up attributes. The first
- # value always to refers to this class.
- mro: list[TypeInfo]
- # Used to stash the names of the mro classes temporarily between
- # deserialization and fixup. See deserialize() for why.
- _mro_refs: list[str] | None
- bad_mro: bool # Could not construct full MRO
- is_final: bool
- declared_metaclass: mypy.types.Instance | None
- metaclass_type: mypy.types.Instance | None
- names: SymbolTable # Names defined directly in this type
- is_abstract: bool # Does the class have any abstract attributes?
- is_protocol: bool # Is this a protocol class?
- runtime_protocol: bool # Does this protocol support isinstance checks?
- # List of names of abstract attributes together with their abstract status.
- # The abstract status must be one of `NOT_ABSTRACT`, `IS_ABSTRACT`, `IMPLICITLY_ABSTRACT`.
- abstract_attributes: list[tuple[str, int]]
- deletable_attributes: list[str] # Used by mypyc only
- # Does this type have concrete `__slots__` defined?
- # If class does not have `__slots__` defined then it is `None`,
- # if it has empty `__slots__` then it is an empty set.
- slots: set[str] | None
- # The attributes 'assuming' and 'assuming_proper' represent structural subtype matrices.
- #
- # In languages with structural subtyping, one can keep a global subtype matrix like this:
- # . A B C .
- # A 1 0 0
- # B 1 1 1
- # C 1 0 1
- # .
- # where 1 indicates that the type in corresponding row is a subtype of the type
- # in corresponding column. This matrix typically starts filled with all 1's and
- # a typechecker tries to "disprove" every subtyping relation using atomic (or nominal) types.
- # However, we don't want to keep this huge global state. Instead, we keep the subtype
- # information in the form of list of pairs (subtype, supertype) shared by all Instances
- # with given supertype's TypeInfo. When we enter a subtype check we push a pair in this list
- # thus assuming that we started with 1 in corresponding matrix element. Such algorithm allows
- # to treat recursive and mutually recursive protocols and other kinds of complex situations.
- #
- # If concurrent/parallel type checking will be added in future,
- # then there should be one matrix per thread/process to avoid false negatives
- # during the type checking phase.
- assuming: list[tuple[mypy.types.Instance, mypy.types.Instance]]
- assuming_proper: list[tuple[mypy.types.Instance, mypy.types.Instance]]
- # Ditto for temporary 'inferring' stack of recursive constraint inference.
- # It contains Instances of protocol types that appeared as an argument to
- # constraints.infer_constraints(). We need 'inferring' to avoid infinite recursion for
- # recursive and mutually recursive protocols.
- #
- # We make 'assuming' and 'inferring' attributes here instead of passing they as kwargs,
- # since this would require to pass them in many dozens of calls. In particular,
- # there is a dependency infer_constraint -> is_subtype -> is_callable_subtype ->
- # -> infer_constraints.
- inferring: list[mypy.types.Instance]
- # 'inferring' and 'assuming' can't be made sets, since we need to use
- # is_same_type to correctly treat unions.
- # Classes inheriting from Enum shadow their true members with a __getattr__, so we
- # have to treat them as a special case.
- is_enum: bool
- # If true, any unknown attributes should have type 'Any' instead
- # of generating a type error. This would be true if there is a
- # base class with type 'Any', but other use cases may be
- # possible. This is similar to having __getattr__ that returns Any
- # (and __setattr__), but without the __getattr__ method.
- fallback_to_any: bool
- # Same as above but for cases where metaclass has type Any. This will suppress
- # all attribute errors only for *class object* access.
- meta_fallback_to_any: bool
- # Information related to type annotations.
- # Generic type variable names (full names)
- type_vars: list[str]
- # Whether this class has a ParamSpec type variable
- has_param_spec_type: bool
- # Direct base classes.
- bases: list[mypy.types.Instance]
- # Another type which this type will be treated as a subtype of,
- # even though it's not a subclass in Python. The non-standard
- # `@_promote` decorator introduces this, and there are also
- # several builtin examples, in particular `int` -> `float`.
- _promote: list[mypy.types.ProperType]
- # This is used for promoting native integer types such as 'i64' to
- # 'int'. (_promote is used for the other direction.) This only
- # supports one-step promotions (e.g., i64 -> int, not
- # i64 -> int -> float, and this isn't used to promote in joins.
- #
- # This results in some unintuitive results, such as that even
- # though i64 is compatible with int and int is compatible with
- # float, i64 is *not* compatible with float.
- alt_promote: mypy.types.Instance | None
- # Representation of a Tuple[...] base class, if the class has any
- # (e.g., for named tuples). If this is not None, the actual Type
- # object used for this class is not an Instance but a TupleType;
- # the corresponding Instance is set as the fallback type of the
- # tuple type.
- tuple_type: mypy.types.TupleType | None
- # Is this a named tuple type?
- is_named_tuple: bool
- # If this class is defined by the TypedDict type constructor,
- # then this is not None.
- typeddict_type: mypy.types.TypedDictType | None
- # Is this a newtype type?
- is_newtype: bool
- # Is this a synthesized intersection type?
- is_intersection: bool
- # This is a dictionary that will be serialized and un-serialized as is.
- # It is useful for plugins to add their data to save in the cache.
- metadata: dict[str, JsonDict]
- # Store type alias representing this type (for named tuples and TypedDicts).
- # Although definitions of these types are stored in symbol tables as TypeInfo,
- # when a type analyzer will find them, it should construct a TupleType, or
- # a TypedDict type. However, we can't use the plain types, since if the definition
- # is recursive, this will create an actual recursive structure of types (i.e. as
- # internal Python objects) causing infinite recursions everywhere during type checking.
- # To overcome this, we create a TypeAlias node, that will point to these types.
- # We store this node in the `special_alias` attribute, because it must be the same node
- # in case we are doing multiple semantic analysis passes.
- special_alias: TypeAlias | None
- # Shared type variable for typing.Self in this class (if used, otherwise None).
- self_type: mypy.types.TypeVarType | None
- # Added if the corresponding class is directly decorated with `typing.dataclass_transform`
- dataclass_transform_spec: DataclassTransformSpec | None
- FLAGS: Final = [
- "is_abstract",
- "is_enum",
- "fallback_to_any",
- "meta_fallback_to_any",
- "is_named_tuple",
- "is_newtype",
- "is_protocol",
- "runtime_protocol",
- "is_final",
- "is_intersection",
- ]
- def __init__(self, names: SymbolTable, defn: ClassDef, module_name: str) -> None:
- """Initialize a TypeInfo."""
- super().__init__()
- self._fullname = defn.fullname
- self.names = names
- self.defn = defn
- self.module_name = module_name
- self.type_vars = []
- self.has_param_spec_type = False
- self.has_type_var_tuple_type = False
- self.bases = []
- self.mro = []
- self._mro_refs = None
- self.bad_mro = False
- self.declared_metaclass = None
- self.metaclass_type = None
- self.is_abstract = False
- self.abstract_attributes = []
- self.deletable_attributes = []
- self.slots = None
- self.assuming = []
- self.assuming_proper = []
- self.inferring = []
- self.is_protocol = False
- self.runtime_protocol = False
- self.type_var_tuple_prefix: int | None = None
- self.type_var_tuple_suffix: int | None = None
- self.add_type_vars()
- self.is_final = False
- self.is_enum = False
- self.fallback_to_any = False
- self.meta_fallback_to_any = False
- self._promote = []
- self.alt_promote = None
- self.tuple_type = None
- self.special_alias = None
- self.is_named_tuple = False
- self.typeddict_type = None
- self.is_newtype = False
- self.is_intersection = False
- self.metadata = {}
- self.self_type = None
- self.dataclass_transform_spec = None
- def add_type_vars(self) -> None:
- self.has_type_var_tuple_type = False
- if self.defn.type_vars:
- for i, vd in enumerate(self.defn.type_vars):
- if isinstance(vd, mypy.types.ParamSpecType):
- self.has_param_spec_type = True
- if isinstance(vd, mypy.types.TypeVarTupleType):
- assert not self.has_type_var_tuple_type
- self.has_type_var_tuple_type = True
- self.type_var_tuple_prefix = i
- self.type_var_tuple_suffix = len(self.defn.type_vars) - i - 1
- self.type_vars.append(vd.name)
- assert not (
- self.has_param_spec_type and self.has_type_var_tuple_type
- ), "Mixing type var tuples and param specs not supported yet"
- @property
- def name(self) -> str:
- """Short name."""
- return self.defn.name
- @property
- def fullname(self) -> str:
- return self._fullname
- def is_generic(self) -> bool:
- """Is the type generic (i.e. does it have type variables)?"""
- return len(self.type_vars) > 0
- def get(self, name: str) -> SymbolTableNode | None:
- for cls in self.mro:
- n = cls.names.get(name)
- if n:
- return n
- return None
- def get_containing_type_info(self, name: str) -> TypeInfo | None:
- for cls in self.mro:
- if name in cls.names:
- return cls
- return None
- @property
- def protocol_members(self) -> list[str]:
- # Protocol members are names of all attributes/methods defined in a protocol
- # and in all its supertypes (except for 'object').
- members: set[str] = set()
- assert self.mro, "This property can be only accessed after MRO is (re-)calculated"
- for base in self.mro[:-1]: # we skip "object" since everyone implements it
- if base.is_protocol:
- for name, node in base.names.items():
- if isinstance(node.node, (TypeAlias, TypeVarExpr, MypyFile)):
- # These are auxiliary definitions (and type aliases are prohibited).
- continue
- if name in EXCLUDED_PROTOCOL_ATTRIBUTES:
- continue
- members.add(name)
- return sorted(list(members))
- def __getitem__(self, name: str) -> SymbolTableNode:
- n = self.get(name)
- if n:
- return n
- else:
- raise KeyError(name)
- def __repr__(self) -> str:
- return f"<TypeInfo {self.fullname}>"
- def __bool__(self) -> bool:
- # We defined this here instead of just overriding it in
- # FakeInfo so that mypyc can generate a direct call instead of
- # using the generic bool handling.
- return not isinstance(self, FakeInfo)
- def has_readable_member(self, name: str) -> bool:
- return self.get(name) is not None
- def get_method(self, name: str) -> FuncBase | Decorator | None:
- for cls in self.mro:
- if name in cls.names:
- node = cls.names[name].node
- if isinstance(node, FuncBase):
- return node
- elif isinstance(node, Decorator): # Two `if`s make `mypyc` happy
- return node
- else:
- return None
- return None
- def calculate_metaclass_type(self) -> mypy.types.Instance | None:
- declared = self.declared_metaclass
- if declared is not None and not declared.type.has_base("builtins.type"):
- return declared
- if self._fullname == "builtins.type":
- return mypy.types.Instance(self, [])
- candidates = [
- s.declared_metaclass
- for s in self.mro
- if s.declared_metaclass is not None and s.declared_metaclass.type is not None
- ]
- for c in candidates:
- if all(other.type in c.type.mro for other in candidates):
- return c
- return None
- def is_metaclass(self) -> bool:
- return (
- self.has_base("builtins.type")
- or self.fullname == "abc.ABCMeta"
- or self.fallback_to_any
- )
- def has_base(self, fullname: str) -> bool:
- """Return True if type has a base type with the specified name.
- This can be either via extension or via implementation.
- """
- for cls in self.mro:
- if cls.fullname == fullname:
- return True
- return False
- def direct_base_classes(self) -> list[TypeInfo]:
- """Return a direct base classes.
- Omit base classes of other base classes.
- """
- return [base.type for base in self.bases]
- def update_tuple_type(self, typ: mypy.types.TupleType) -> None:
- """Update tuple_type and special_alias as needed."""
- self.tuple_type = typ
- alias = TypeAlias.from_tuple_type(self)
- if not self.special_alias:
- self.special_alias = alias
- else:
- self.special_alias.target = alias.target
- def update_typeddict_type(self, typ: mypy.types.TypedDictType) -> None:
- """Update typeddict_type and special_alias as needed."""
- self.typeddict_type = typ
- alias = TypeAlias.from_typeddict_type(self)
- if not self.special_alias:
- self.special_alias = alias
- else:
- self.special_alias.target = alias.target
- def __str__(self) -> str:
- """Return a string representation of the type.
- This includes the most important information about the type.
- """
- options = Options()
- return self.dump(
- str_conv=mypy.strconv.StrConv(options=options),
- type_str_conv=mypy.types.TypeStrVisitor(options=options),
- )
- def dump(
- self, str_conv: mypy.strconv.StrConv, type_str_conv: mypy.types.TypeStrVisitor
- ) -> str:
- """Return a string dump of the contents of the TypeInfo."""
- base: str = ""
- def type_str(typ: mypy.types.Type) -> str:
- return typ.accept(type_str_conv)
- head = "TypeInfo" + str_conv.format_id(self)
- if self.bases:
- base = f"Bases({', '.join(type_str(base) for base in self.bases)})"
- mro = "Mro({})".format(
- ", ".join(item.fullname + str_conv.format_id(item) for item in self.mro)
- )
- names = []
- for name in sorted(self.names):
- description = name + str_conv.format_id(self.names[name].node)
- node = self.names[name].node
- if isinstance(node, Var) and node.type:
- description += f" ({type_str(node.type)})"
- names.append(description)
- items = [f"Name({self.fullname})", base, mro, ("Names", names)]
- if self.declared_metaclass:
- items.append(f"DeclaredMetaclass({type_str(self.declared_metaclass)})")
- if self.metaclass_type:
- items.append(f"MetaclassType({type_str(self.metaclass_type)})")
- return mypy.strconv.dump_tagged(items, head, str_conv=str_conv)
- def serialize(self) -> JsonDict:
- # NOTE: This is where all ClassDefs originate, so there shouldn't be duplicates.
- data = {
- ".class": "TypeInfo",
- "module_name": self.module_name,
- "fullname": self.fullname,
- "names": self.names.serialize(self.fullname),
- "defn": self.defn.serialize(),
- "abstract_attributes": self.abstract_attributes,
- "type_vars": self.type_vars,
- "has_param_spec_type": self.has_param_spec_type,
- "bases": [b.serialize() for b in self.bases],
- "mro": [c.fullname for c in self.mro],
- "_promote": [p.serialize() for p in self._promote],
- "alt_promote": None if self.alt_promote is None else self.alt_promote.serialize(),
- "declared_metaclass": (
- None if self.declared_metaclass is None else self.declared_metaclass.serialize()
- ),
- "metaclass_type": None
- if self.metaclass_type is None
- else self.metaclass_type.serialize(),
- "tuple_type": None if self.tuple_type is None else self.tuple_type.serialize(),
- "typeddict_type": None
- if self.typeddict_type is None
- else self.typeddict_type.serialize(),
- "flags": get_flags(self, TypeInfo.FLAGS),
- "metadata": self.metadata,
- "slots": list(sorted(self.slots)) if self.slots is not None else None,
- "deletable_attributes": self.deletable_attributes,
- "self_type": self.self_type.serialize() if self.self_type is not None else None,
- "dataclass_transform_spec": (
- self.dataclass_transform_spec.serialize()
- if self.dataclass_transform_spec is not None
- else None
- ),
- }
- return data
- @classmethod
- def deserialize(cls, data: JsonDict) -> TypeInfo:
- names = SymbolTable.deserialize(data["names"])
- defn = ClassDef.deserialize(data["defn"])
- module_name = data["module_name"]
- ti = TypeInfo(names, defn, module_name)
- ti._fullname = data["fullname"]
- # TODO: Is there a reason to reconstruct ti.subtypes?
- ti.abstract_attributes = [(attr[0], attr[1]) for attr in data["abstract_attributes"]]
- ti.type_vars = data["type_vars"]
- ti.has_param_spec_type = data["has_param_spec_type"]
- ti.bases = [mypy.types.Instance.deserialize(b) for b in data["bases"]]
- _promote = []
- for p in data["_promote"]:
- t = mypy.types.deserialize_type(p)
- assert isinstance(t, mypy.types.ProperType)
- _promote.append(t)
- ti._promote = _promote
- ti.alt_promote = (
- None
- if data["alt_promote"] is None
- else mypy.types.Instance.deserialize(data["alt_promote"])
- )
- ti.declared_metaclass = (
- None
- if data["declared_metaclass"] is None
- else mypy.types.Instance.deserialize(data["declared_metaclass"])
- )
- ti.metaclass_type = (
- None
- if data["metaclass_type"] is None
- else mypy.types.Instance.deserialize(data["metaclass_type"])
- )
- # NOTE: ti.mro will be set in the fixup phase based on these
- # names. The reason we need to store the mro instead of just
- # recomputing it from base classes has to do with a subtle
- # point about fine-grained incremental: the cache files might
- # not be loaded until after a class in the mro has changed its
- # bases, which causes the mro to change. If we recomputed our
- # mro, we would compute the *new* mro, which leaves us with no
- # way to detect that the mro has changed! Thus we need to make
- # sure to load the original mro so that once the class is
- # rechecked, it can tell that the mro has changed.
- ti._mro_refs = data["mro"]
- ti.tuple_type = (
- None
- if data["tuple_type"] is None
- else mypy.types.TupleType.deserialize(data["tuple_type"])
- )
- ti.typeddict_type = (
- None
- if data["typeddict_type"] is None
- else mypy.types.TypedDictType.deserialize(data["typeddict_type"])
- )
- ti.metadata = data["metadata"]
- ti.slots = set(data["slots"]) if data["slots"] is not None else None
- ti.deletable_attributes = data["deletable_attributes"]
- set_flags(ti, data["flags"])
- st = data["self_type"]
- ti.self_type = mypy.types.TypeVarType.deserialize(st) if st is not None else None
- if data.get("dataclass_transform_spec") is not None:
- ti.dataclass_transform_spec = DataclassTransformSpec.deserialize(
- data["dataclass_transform_spec"]
- )
- return ti
- class FakeInfo(TypeInfo):
- __slots__ = ("msg",)
- # types.py defines a single instance of this class, called types.NOT_READY.
- # This instance is used as a temporary placeholder in the process of de-serialization
- # of 'Instance' types. The de-serialization happens in two steps: In the first step,
- # Instance.type is set to NOT_READY. In the second step (in fixup.py) it is replaced by
- # an actual TypeInfo. If you see the assertion error below, then most probably something
- # went wrong during the second step and an 'Instance' that raised this error was not fixed.
- # Note:
- # 'None' is not used as a dummy value for two reasons:
- # 1. This will require around 80-100 asserts to make 'mypy --strict-optional mypy'
- # pass cleanly.
- # 2. If NOT_READY value is accidentally used somewhere, it will be obvious where the value
- # is from, whereas a 'None' value could come from anywhere.
- #
- # Additionally, this serves as a more general-purpose placeholder
- # for missing TypeInfos in a number of places where the excuses
- # for not being Optional are a little weaker.
- #
- # TypeInfo defines a __bool__ method that returns False for FakeInfo
- # so that it can be conveniently tested against in the same way that it
- # would be if things were properly optional.
- def __init__(self, msg: str) -> None:
- self.msg = msg
- def __getattribute__(self, attr: str) -> type:
- # Handle __class__ so that isinstance still works...
- if attr == "__class__":
- return object.__getattribute__(self, attr) # type: ignore[no-any-return]
- raise AssertionError(object.__getattribute__(self, "msg"))
- VAR_NO_INFO: Final[TypeInfo] = FakeInfo("Var is lacking info")
- CLASSDEF_NO_INFO: Final[TypeInfo] = FakeInfo("ClassDef is lacking info")
- FUNC_NO_INFO: Final[TypeInfo] = FakeInfo("FuncBase for non-methods lack info")
- class TypeAlias(SymbolNode):
- """
- A symbol node representing a type alias.
- Type alias is a static concept, in contrast to variables with types
- like Type[...]. Namely:
- * type aliases
- - can be used in type context (annotations)
- - cannot be re-assigned
- * variables with type Type[...]
- - cannot be used in type context
- - but can be re-assigned
- An alias can be defined only by an assignment to a name (not any other lvalues).
- Such assignment defines an alias by default. To define a variable,
- an explicit Type[...] annotation is required. As an exception,
- at non-global scope non-subscripted rvalue creates a variable even without
- an annotation. This exception exists to accommodate the common use case of
- class-valued attributes. See SemanticAnalyzerPass2.check_and_set_up_type_alias
- for details.
- Aliases can be generic. We use bound type variables for generic aliases, similar
- to classes. Essentially, type aliases work as macros that expand textually.
- The definition and expansion rules are following:
- 1. An alias targeting a generic class without explicit variables act as
- the given class (this doesn't apply to TypedDict, Tuple and Callable, which
- are not proper classes but special type constructors):
- A = List
- AA = List[Any]
- x: A # same as List[Any]
- x: A[int] # same as List[int]
- x: AA # same as List[Any]
- x: AA[int] # Error!
- C = Callable # Same as Callable[..., Any]
- T = Tuple # Same as Tuple[Any, ...]
- 2. An alias using explicit type variables in its rvalue expects
- replacements (type arguments) for these variables. If missing, they
- are treated as Any, like for other generics:
- B = List[Tuple[T, T]]
- x: B # same as List[Tuple[Any, Any]]
- x: B[int] # same as List[Tuple[int, int]]
- def f(x: B[T]) -> T: ... # without T, Any would be used here
- 3. An alias can be defined using another aliases. In the definition
- rvalue the Any substitution doesn't happen for top level unsubscripted
- generic classes:
- A = List
- B = A # here A is expanded to List, _not_ List[Any],
- # to match the Python runtime behaviour
- x: B[int] # same as List[int]
- C = List[A] # this expands to List[List[Any]]
- AA = List[T]
- D = AA # here AA expands to List[Any]
- x: D[int] # Error!
- Note: the fact that we support aliases like `A = List` means that the target
- type will be initially an instance type with wrong number of type arguments.
- Such instances are all fixed either during or after main semantic analysis passes.
- We therefore store the difference between `List` and `List[Any]` rvalues (targets)
- using the `no_args` flag. See also TypeAliasExpr.no_args.
- Meaning of other fields:
- target: The target type. For generic aliases contains bound type variables
- as nested types (currently TypeVar and ParamSpec are supported).
- _fullname: Qualified name of this type alias. This is used in particular
- to track fine grained dependencies from aliases.
- alias_tvars: Type variables used to define this alias.
- normalized: Used to distinguish between `A = List`, and `A = list`. Both
- are internally stored using `builtins.list` (because `typing.List` is
- itself an alias), while the second cannot be subscripted because of
- Python runtime limitation.
- line and column: Line and column on the original alias definition.
- eager: If True, immediately expand alias when referred to (useful for aliases
- within functions that can't be looked up from the symbol table)
- """
- __slots__ = (
- "target",
- "_fullname",
- "alias_tvars",
- "no_args",
- "normalized",
- "_is_recursive",
- "eager",
- "tvar_tuple_index",
- )
- __match_args__ = ("name", "target", "alias_tvars", "no_args")
- def __init__(
- self,
- target: mypy.types.Type,
- fullname: str,
- line: int,
- column: int,
- *,
- alias_tvars: list[mypy.types.TypeVarLikeType] | None = None,
- no_args: bool = False,
- normalized: bool = False,
- eager: bool = False,
- ) -> None:
- self._fullname = fullname
- self.target = target
- if alias_tvars is None:
- alias_tvars = []
- self.alias_tvars = alias_tvars
- self.no_args = no_args
- self.normalized = normalized
- # This attribute is manipulated by TypeAliasType. If non-None,
- # it is the cached value.
- self._is_recursive: bool | None = None
- self.eager = eager
- self.tvar_tuple_index = None
- for i, t in enumerate(alias_tvars):
- if isinstance(t, mypy.types.TypeVarTupleType):
- self.tvar_tuple_index = i
- super().__init__(line, column)
- @classmethod
- def from_tuple_type(cls, info: TypeInfo) -> TypeAlias:
- """Generate an alias to the tuple type described by a given TypeInfo.
- NOTE: this doesn't set type alias type variables (for generic tuple types),
- they must be set by the caller (when fully analyzed).
- """
- assert info.tuple_type
- # TODO: is it possible to refactor this to set the correct type vars here?
- return TypeAlias(
- info.tuple_type.copy_modified(fallback=mypy.types.Instance(info, info.defn.type_vars)),
- info.fullname,
- info.line,
- info.column,
- )
- @classmethod
- def from_typeddict_type(cls, info: TypeInfo) -> TypeAlias:
- """Generate an alias to the TypedDict type described by a given TypeInfo.
- NOTE: this doesn't set type alias type variables (for generic TypedDicts),
- they must be set by the caller (when fully analyzed).
- """
- assert info.typeddict_type
- # TODO: is it possible to refactor this to set the correct type vars here?
- return TypeAlias(
- info.typeddict_type.copy_modified(
- fallback=mypy.types.Instance(info, info.defn.type_vars)
- ),
- info.fullname,
- info.line,
- info.column,
- )
- @property
- def name(self) -> str:
- return self._fullname.split(".")[-1]
- @property
- def fullname(self) -> str:
- return self._fullname
- @property
- def has_param_spec_type(self) -> bool:
- return any(isinstance(v, mypy.types.ParamSpecType) for v in self.alias_tvars)
- def serialize(self) -> JsonDict:
- data: JsonDict = {
- ".class": "TypeAlias",
- "fullname": self._fullname,
- "target": self.target.serialize(),
- "alias_tvars": [v.serialize() for v in self.alias_tvars],
- "no_args": self.no_args,
- "normalized": self.normalized,
- "line": self.line,
- "column": self.column,
- }
- return data
- def accept(self, visitor: NodeVisitor[T]) -> T:
- return visitor.visit_type_alias(self)
- @classmethod
- def deserialize(cls, data: JsonDict) -> TypeAlias:
- assert data[".class"] == "TypeAlias"
- fullname = data["fullname"]
- alias_tvars = [mypy.types.deserialize_type(v) for v in data["alias_tvars"]]
- assert all(isinstance(t, mypy.types.TypeVarLikeType) for t in alias_tvars)
- target = mypy.types.deserialize_type(data["target"])
- no_args = data["no_args"]
- normalized = data["normalized"]
- line = data["line"]
- column = data["column"]
- return cls(
- target,
- fullname,
- line,
- column,
- alias_tvars=cast(List[mypy.types.TypeVarLikeType], alias_tvars),
- no_args=no_args,
- normalized=normalized,
- )
- class PlaceholderNode(SymbolNode):
- """Temporary symbol node that will later become a real SymbolNode.
- These are only present during semantic analysis when using the new
- semantic analyzer. These are created if some essential dependencies
- of a definition are not yet complete.
- A typical use is for names imported from a module which is still
- incomplete (within an import cycle):
- from m import f # Initially may create PlaceholderNode
- This is particularly important if the imported shadows a name from
- an enclosing scope or builtins:
- from m import int # Placeholder avoids mixups with builtins.int
- Another case where this is useful is when there is another definition
- or assignment:
- from m import f
- def f() -> None: ...
- In the above example, the presence of PlaceholderNode allows us to
- handle the second definition as a redefinition.
- They are also used to create PlaceholderType instances for types
- that refer to incomplete types. Example:
- class C(Sequence[C]): ...
- We create a PlaceholderNode (with becomes_typeinfo=True) for C so
- that the type C in Sequence[C] can be bound.
- Attributes:
- fullname: Full name of the PlaceholderNode.
- node: AST node that contains the definition that caused this to
- be created. This is useful for tracking order of incomplete definitions
- and for debugging.
- becomes_typeinfo: If True, this refers something that could later
- become a TypeInfo. It can't be used with type variables, in
- particular, as this would cause issues with class type variable
- detection.
- The long-term purpose of placeholder nodes/types is to evolve into
- something that can support general recursive types.
- """
- __slots__ = ("_fullname", "node", "becomes_typeinfo")
- def __init__(
- self, fullname: str, node: Node, line: int, *, becomes_typeinfo: bool = False
- ) -> None:
- self._fullname = fullname
- self.node = node
- self.becomes_typeinfo = becomes_typeinfo
- self.line = line
- @property
- def name(self) -> str:
- return self._fullname.split(".")[-1]
- @property
- def fullname(self) -> str:
- return self._fullname
- def serialize(self) -> JsonDict:
- assert False, "PlaceholderNode can't be serialized"
- def accept(self, visitor: NodeVisitor[T]) -> T:
- return visitor.visit_placeholder_node(self)
- class SymbolTableNode:
- """Description of a name binding in a symbol table.
- These are only used as values in module (global), function (local)
- and class symbol tables (see SymbolTable). The name that is bound is
- the key in SymbolTable.
- Symbol tables don't contain direct references to AST nodes primarily
- because there can be multiple symbol table references to a single
- AST node (due to imports and aliases), and different references can
- behave differently. This class describes the unique properties of
- each reference.
- The most fundamental attribute is 'node', which is the AST node that
- the name refers to.
- The kind is usually one of LDEF, GDEF or MDEF, depending on the scope
- of the definition. These three kinds can usually be used
- interchangeably and the difference between local, global and class
- scopes is mostly descriptive, with no semantic significance.
- However, some tools that consume mypy ASTs may care about these so
- they should be correct.
- Attributes:
- node: AST node of definition. Among others, this can be one of
- FuncDef, Var, TypeInfo, TypeVarExpr or MypyFile -- or None
- for cross_ref that hasn't been fixed up yet.
- kind: Kind of node. Possible values:
- - LDEF: local definition
- - GDEF: global (module-level) definition
- - MDEF: class member definition
- - UNBOUND_IMPORTED: temporary kind for imported names (we
- don't know the final kind yet)
- module_public: If False, this name won't be imported via
- 'from <module> import *'. This has no effect on names within
- classes.
- module_hidden: If True, the name will be never exported (needed for
- stub files)
- cross_ref: For deserialized MypyFile nodes, the referenced module
- name; for other nodes, optionally the name of the referenced object.
- implicit: Was this defined by assignment to self attribute?
- plugin_generated: Was this symbol generated by a plugin?
- (And therefore needs to be removed in aststrip.)
- no_serialize: Do not serialize this node if True. This is used to prevent
- keys in the cache that refer to modules on which this file does not
- depend. Currently this can happen if there is a module not in build
- used e.g. like this:
- import a.b.c # type: ignore
- This will add a submodule symbol to parent module `a` symbol table,
- but `a.b` is _not_ added as its dependency. Therefore, we should
- not serialize these symbols as they may not be found during fixup
- phase, instead they will be re-added during subsequent patch parents
- phase.
- TODO: Refactor build.py to make dependency tracking more transparent
- and/or refactor look-up functions to not require parent patching.
- NOTE: No other attributes should be added to this class unless they
- are shared by all node kinds.
- """
- __slots__ = (
- "kind",
- "node",
- "module_public",
- "module_hidden",
- "cross_ref",
- "implicit",
- "plugin_generated",
- "no_serialize",
- )
- def __init__(
- self,
- kind: int,
- node: SymbolNode | None,
- module_public: bool = True,
- implicit: bool = False,
- module_hidden: bool = False,
- *,
- plugin_generated: bool = False,
- no_serialize: bool = False,
- ) -> None:
- self.kind = kind
- self.node = node
- self.module_public = module_public
- self.implicit = implicit
- self.module_hidden = module_hidden
- self.cross_ref: str | None = None
- self.plugin_generated = plugin_generated
- self.no_serialize = no_serialize
- @property
- def fullname(self) -> str | None:
- if self.node is not None:
- return self.node.fullname
- else:
- return None
- @property
- def type(self) -> mypy.types.Type | None:
- node = self.node
- if isinstance(node, (Var, SYMBOL_FUNCBASE_TYPES)) and node.type is not None:
- return node.type
- elif isinstance(node, Decorator):
- return node.var.type
- else:
- return None
- def copy(self) -> SymbolTableNode:
- new = SymbolTableNode(
- self.kind, self.node, self.module_public, self.implicit, self.module_hidden
- )
- new.cross_ref = self.cross_ref
- return new
- def __str__(self) -> str:
- s = f"{node_kinds[self.kind]}/{short_type(self.node)}"
- if isinstance(self.node, SymbolNode):
- s += f" ({self.node.fullname})"
- # Include declared type of variables and functions.
- if self.type is not None:
- s += f" : {self.type}"
- return s
- def serialize(self, prefix: str, name: str) -> JsonDict:
- """Serialize a SymbolTableNode.
- Args:
- prefix: full name of the containing module or class; or None
- name: name of this object relative to the containing object
- """
- data: JsonDict = {".class": "SymbolTableNode", "kind": node_kinds[self.kind]}
- if self.module_hidden:
- data["module_hidden"] = True
- if not self.module_public:
- data["module_public"] = False
- if self.implicit:
- data["implicit"] = True
- if self.plugin_generated:
- data["plugin_generated"] = True
- if isinstance(self.node, MypyFile):
- data["cross_ref"] = self.node.fullname
- else:
- assert self.node is not None, f"{prefix}:{name}"
- if prefix is not None:
- fullname = self.node.fullname
- if (
- "." in fullname
- and fullname != prefix + "." + name
- and not (isinstance(self.node, Var) and self.node.from_module_getattr)
- ):
- assert not isinstance(
- self.node, PlaceholderNode
- ), f"Definition of {fullname} is unexpectedly incomplete"
- data["cross_ref"] = fullname
- return data
- data["node"] = self.node.serialize()
- return data
- @classmethod
- def deserialize(cls, data: JsonDict) -> SymbolTableNode:
- assert data[".class"] == "SymbolTableNode"
- kind = inverse_node_kinds[data["kind"]]
- if "cross_ref" in data:
- # This will be fixed up later.
- stnode = SymbolTableNode(kind, None)
- stnode.cross_ref = data["cross_ref"]
- else:
- assert "node" in data, data
- node = SymbolNode.deserialize(data["node"])
- stnode = SymbolTableNode(kind, node)
- if "module_hidden" in data:
- stnode.module_hidden = data["module_hidden"]
- if "module_public" in data:
- stnode.module_public = data["module_public"]
- if "implicit" in data:
- stnode.implicit = data["implicit"]
- if "plugin_generated" in data:
- stnode.plugin_generated = data["plugin_generated"]
- return stnode
- class SymbolTable(Dict[str, SymbolTableNode]):
- """Static representation of a namespace dictionary.
- This is used for module, class and function namespaces.
- """
- __slots__ = ()
- def __str__(self) -> str:
- a: list[str] = []
- for key, value in self.items():
- # Filter out the implicit import of builtins.
- if isinstance(value, SymbolTableNode):
- if (
- value.fullname != "builtins"
- and (value.fullname or "").split(".")[-1] not in implicit_module_attrs
- ):
- a.append(" " + str(key) + " : " + str(value))
- else:
- a.append(" <invalid item>")
- a = sorted(a)
- a.insert(0, "SymbolTable(")
- a[-1] += ")"
- return "\n".join(a)
- def copy(self) -> SymbolTable:
- return SymbolTable([(key, node.copy()) for key, node in self.items()])
- def serialize(self, fullname: str) -> JsonDict:
- data: JsonDict = {".class": "SymbolTable"}
- for key, value in self.items():
- # Skip __builtins__: it's a reference to the builtins
- # module that gets added to every module by
- # SemanticAnalyzerPass2.visit_file(), but it shouldn't be
- # accessed by users of the module.
- if key == "__builtins__" or value.no_serialize:
- continue
- data[key] = value.serialize(fullname, key)
- return data
- @classmethod
- def deserialize(cls, data: JsonDict) -> SymbolTable:
- assert data[".class"] == "SymbolTable"
- st = SymbolTable()
- for key, value in data.items():
- if key != ".class":
- st[key] = SymbolTableNode.deserialize(value)
- return st
- class DataclassTransformSpec:
- """Specifies how a dataclass-like transform should be applied. The fields here are based on the
- parameters accepted by `typing.dataclass_transform`."""
- __slots__ = (
- "eq_default",
- "order_default",
- "kw_only_default",
- "frozen_default",
- "field_specifiers",
- )
- def __init__(
- self,
- *,
- eq_default: bool | None = None,
- order_default: bool | None = None,
- kw_only_default: bool | None = None,
- field_specifiers: tuple[str, ...] | None = None,
- # Specified outside of PEP 681:
- # frozen_default was added to CPythonin https://github.com/python/cpython/pull/99958 citing
- # positive discussion in typing-sig
- frozen_default: bool | None = None,
- ):
- self.eq_default = eq_default if eq_default is not None else True
- self.order_default = order_default if order_default is not None else False
- self.kw_only_default = kw_only_default if kw_only_default is not None else False
- self.frozen_default = frozen_default if frozen_default is not None else False
- self.field_specifiers = field_specifiers if field_specifiers is not None else ()
- def serialize(self) -> JsonDict:
- return {
- "eq_default": self.eq_default,
- "order_default": self.order_default,
- "kw_only_default": self.kw_only_default,
- "frozen_default": self.frozen_default,
- "field_specifiers": list(self.field_specifiers),
- }
- @classmethod
- def deserialize(cls, data: JsonDict) -> DataclassTransformSpec:
- return DataclassTransformSpec(
- eq_default=data.get("eq_default"),
- order_default=data.get("order_default"),
- kw_only_default=data.get("kw_only_default"),
- frozen_default=data.get("frozen_default"),
- field_specifiers=tuple(data.get("field_specifiers", [])),
- )
- def get_flags(node: Node, names: list[str]) -> list[str]:
- return [name for name in names if getattr(node, name)]
- def set_flags(node: Node, flags: list[str]) -> None:
- for name in flags:
- setattr(node, name, True)
- def get_member_expr_fullname(expr: MemberExpr) -> str | None:
- """Return the qualified name representation of a member expression.
- Return a string of form foo.bar, foo.bar.baz, or similar, or None if the
- argument cannot be represented in this form.
- """
- initial: str | None = None
- if isinstance(expr.expr, NameExpr):
- initial = expr.expr.name
- elif isinstance(expr.expr, MemberExpr):
- initial = get_member_expr_fullname(expr.expr)
- else:
- return None
- return f"{initial}.{expr.name}"
- deserialize_map: Final = {
- key: obj.deserialize
- for key, obj in globals().items()
- if type(obj) is not FakeInfo
- and isinstance(obj, type)
- and issubclass(obj, SymbolNode)
- and obj is not SymbolNode
- }
- def check_arg_kinds(
- arg_kinds: list[ArgKind], nodes: list[T], fail: Callable[[str, T], None]
- ) -> None:
- is_var_arg = False
- is_kw_arg = False
- seen_named = False
- seen_opt = False
- for kind, node in zip(arg_kinds, nodes):
- if kind == ARG_POS:
- if is_var_arg or is_kw_arg or seen_named or seen_opt:
- fail(
- "Required positional args may not appear after default, named or var args",
- node,
- )
- break
- elif kind == ARG_OPT:
- if is_var_arg or is_kw_arg or seen_named:
- fail("Positional default args may not appear after named or var args", node)
- break
- seen_opt = True
- elif kind == ARG_STAR:
- if is_var_arg or is_kw_arg or seen_named:
- fail("Var args may not appear after named or var args", node)
- break
- is_var_arg = True
- elif kind == ARG_NAMED or kind == ARG_NAMED_OPT:
- seen_named = True
- if is_kw_arg:
- fail("A **kwargs argument must be the last argument", node)
- break
- elif kind == ARG_STAR2:
- if is_kw_arg:
- fail("You may only have one **kwargs argument", node)
- break
- is_kw_arg = True
- def check_arg_names(
- names: Sequence[str | None],
- nodes: list[T],
- fail: Callable[[str, T], None],
- description: str = "function definition",
- ) -> None:
- seen_names: set[str | None] = set()
- for name, node in zip(names, nodes):
- if name is not None and name in seen_names:
- fail(f'Duplicate argument "{name}" in {description}', node)
- break
- seen_names.add(name)
- def is_class_var(expr: NameExpr) -> bool:
- """Return whether the expression is ClassVar[...]"""
- if isinstance(expr.node, Var):
- return expr.node.is_classvar
- return False
- def is_final_node(node: SymbolNode | None) -> bool:
- """Check whether `node` corresponds to a final attribute."""
- return isinstance(node, (Var, FuncDef, OverloadedFuncDef, Decorator)) and node.is_final
- def local_definitions(
- names: SymbolTable, name_prefix: str, info: TypeInfo | None = None
- ) -> Iterator[Definition]:
- """Iterate over local definitions (not imported) in a symbol table.
- Recursively iterate over class members and nested classes.
- """
- # TODO: What should the name be? Or maybe remove it?
- for name, symnode in names.items():
- shortname = name
- if "-redef" in name:
- # Restore original name from mangled name of multiply defined function
- shortname = name.split("-redef")[0]
- fullname = name_prefix + "." + shortname
- node = symnode.node
- if node and node.fullname == fullname:
- yield fullname, symnode, info
- if isinstance(node, TypeInfo):
- yield from local_definitions(node.names, fullname, node)
|