88import re
99import sys
1010import tokenize
11- from typing import Any , List , Optional , Tuple , cast
11+ from typing import Any , List , Optional , Tuple , Union , cast
1212
1313from pytype .ast import debug
1414from pytype .pyi import conditions
@@ -61,6 +61,7 @@ class _TypeVariable:
6161 name : str
6262 bound : Optional [pytd .Type ]
6363 constraints : List [pytd .Type ]
64+ default : Optional [Union [pytd .Type , List [pytd .Type ]]]
6465
6566 @classmethod
6667 def from_call (cls , kind : str , node : astlib .Call ):
@@ -72,18 +73,20 @@ def from_call(cls, kind: str, node: astlib.Call):
7273 if not types .Pyval .is_str (name ):
7374 raise ParseError (f"Bad arguments to { kind } " )
7475 bound = None
75- # 'bound' is the only keyword argument we currently use.
76+ default = None
7677 # TODO(rechen): We should enforce the PEP 484 guideline that
7778 # len(constraints) != 1. However, this guideline is currently violated
7879 # in typeshed (see https://github.com/python/typeshed/pull/806).
7980 kws = {x .arg for x in node .keywords }
80- extra = kws - {"bound" , "covariant" , "contravariant" }
81+ extra = kws - {"bound" , "covariant" , "contravariant" , "default" }
8182 if extra :
8283 raise ParseError (f"Unrecognized keyword(s): { ', ' .join (extra )} " )
8384 for kw in node .keywords :
8485 if kw .arg == "bound" :
8586 bound = kw .value
86- return cls (kind , name .value , bound , constraints )
87+ elif kw .arg == "default" :
88+ default = kw .value
89+ return cls (kind , name .value , bound , constraints , default )
8790
8891#------------------------------------------------------
8992# Main tree visitor and generator code
@@ -674,6 +677,8 @@ def _convert_typevar_args(self, node: astlib.Call):
674677 for kw in node .keywords :
675678 if kw .arg == "bound" :
676679 kw .value = self .annotation_visitor .visit (kw .value )
680+ elif kw .arg == "default" :
681+ kw .value = self .annotation_visitor .visit (kw .value )
677682
678683 def _convert_typed_dict_args (self , node : astlib .Call ):
679684 for fields in node .args [1 :]:
@@ -682,7 +687,8 @@ def _convert_typed_dict_args(self, node: astlib.Call):
682687 def enter_Call (self , node ):
683688 node .func = self .annotation_visitor .visit (node .func )
684689 func = node .func .name or ""
685- if self .defs .matches_type (func , ("typing.TypeVar" , "typing.ParamSpec" )):
690+ if self .defs .matches_type (func , ("typing.TypeVar" , "typing.ParamSpec" ,
691+ "typing.TypeVarTuple" )):
686692 self ._convert_typevar_args (node )
687693 elif self .defs .matches_type (func , "typing.NamedTuple" ):
688694 self ._convert_typing_namedtuple_args (node )
0 commit comments