@@ -1765,6 +1765,23 @@ def __call__(self, *args, **kwargs):
17651765# 3.8-3.9
17661766if not hasattr (typing , 'Concatenate' ):
17671767 # Inherits from list as a workaround for Callable checks in Python < 3.9.2.
1768+
1769+ # 3.9.0-1
1770+ if not hasattr (typing , '_type_convert' ):
1771+ def _type_convert (arg , module = None , * , allow_special_forms = False ):
1772+ """For converting None to type(None), and strings to ForwardRef."""
1773+ if arg is None :
1774+ return type (None )
1775+ if isinstance (arg , str ):
1776+ if sys .version_info <= (3 , 9 , 6 ):
1777+ return ForwardRef (arg )
1778+ if sys .version_info <= (3 , 9 , 7 ):
1779+ return ForwardRef (arg , module = module )
1780+ return ForwardRef (arg , module = module , is_class = allow_special_forms )
1781+ return arg
1782+ else :
1783+ _type_convert = typing ._type_convert
1784+
17681785 class _ConcatenateGenericAlias (list ):
17691786
17701787 # Trick Generic into looking into this for __parameters__.
@@ -1795,27 +1812,122 @@ def __parameters__(self):
17951812 return tuple (
17961813 tp for tp in self .__args__ if isinstance (tp , (typing .TypeVar , ParamSpec ))
17971814 )
1815+
1816+ # 3.8; needed for typing._subst_tvars
1817+ # 3.9 used by __getitem__ below
1818+ def copy_with (self , params ):
1819+ if isinstance (params [- 1 ], _ConcatenateGenericAlias ):
1820+ params = (* params [:- 1 ], * params [- 1 ].__args__ )
1821+ elif isinstance (params [- 1 ], (list , tuple )):
1822+ return (* params [:- 1 ], * params [- 1 ])
1823+ elif (not (params [- 1 ] is ... or isinstance (params [- 1 ], ParamSpec ))):
1824+ raise TypeError ("The last parameter to Concatenate should be a "
1825+ "ParamSpec variable or ellipsis." )
1826+ return self .__class__ (self .__origin__ , params )
1827+
1828+ # 3.9; accessed during GenericAlias.__getitem__ when substituting
1829+ def __getitem__ (self , args ):
1830+ if self .__origin__ in (Generic , Protocol ):
1831+ # Can't subscript Generic[...] or Protocol[...].
1832+ raise TypeError (f"Cannot subscript already-subscripted { self } " )
1833+ if not self .__parameters__ :
1834+ raise TypeError (f"{ self } is not a generic class" )
1835+
1836+ if not isinstance (args , tuple ):
1837+ args = (args ,)
1838+ args = _unpack_args (* (_type_convert (p ) for p in args ))
1839+ params = self .__parameters__
1840+ for param in params :
1841+ prepare = getattr (param , "__typing_prepare_subst__" , None )
1842+ if prepare is not None :
1843+ args = prepare (self , args )
1844+ # 3.8 - 3.9 & typing.ParamSpec
1845+ elif isinstance (param , ParamSpec ):
1846+ i = params .index (param )
1847+ if (
1848+ i == len (args )
1849+ and getattr (param , '__default__' , NoDefault ) is not NoDefault
1850+ ):
1851+ args = [* args , param .__default__ ]
1852+ if i >= len (args ):
1853+ raise TypeError (f"Too few arguments for { self } " )
1854+ # Special case for Z[[int, str, bool]] == Z[int, str, bool]
1855+ if len (params ) == 1 and not _is_param_expr (args [0 ]):
1856+ assert i == 0
1857+ args = (args ,)
1858+ elif (
1859+ isinstance (args [i ], list )
1860+ # 3.8 - 3.9
1861+ # This class inherits from list do not convert
1862+ and not isinstance (args [i ], _ConcatenateGenericAlias )
1863+ ):
1864+ args = (* args [:i ], tuple (args [i ]), * args [i + 1 :])
1865+
1866+ alen = len (args )
1867+ plen = len (params )
1868+ if alen != plen :
1869+ raise TypeError (
1870+ f"Too { 'many' if alen > plen else 'few' } arguments for { self } ;"
1871+ f" actual { alen } , expected { plen } "
1872+ )
1873+
1874+ subst = dict (zip (self .__parameters__ , args ))
1875+ # determine new args
1876+ new_args = []
1877+ for arg in self .__args__ :
1878+ if isinstance (arg , type ):
1879+ new_args .append (arg )
1880+ continue
1881+ if isinstance (arg , TypeVar ):
1882+ arg = subst [arg ]
1883+ if (
1884+ (isinstance (arg , typing ._GenericAlias ) and _is_unpack (arg ))
1885+ or (
1886+ hasattr (_types , "GenericAlias" )
1887+ and isinstance (arg , _types .GenericAlias )
1888+ and getattr (arg , "__unpacked__" , False )
1889+ )
1890+ ):
1891+ raise TypeError (f"{ arg } is not valid as type argument" )
1892+
1893+ elif isinstance (arg ,
1894+ typing ._GenericAlias
1895+ if not hasattr (_types , "GenericAlias" ) else
1896+ (typing ._GenericAlias , _types .GenericAlias )
1897+ ):
1898+ subparams = arg .__parameters__
1899+ if subparams :
1900+ subargs = tuple (subst [x ] for x in subparams )
1901+ arg = arg [subargs ]
1902+ new_args .append (arg )
1903+ return self .copy_with (tuple (new_args ))
1904+
17981905# 3.10+
17991906else :
18001907 _ConcatenateGenericAlias = typing ._ConcatenateGenericAlias
18011908
18021909 # 3.10
18031910 if sys .version_info < (3 , 11 ):
1804- _typing_ConcatenateGenericAlias = _ConcatenateGenericAlias
18051911
1806- class _ConcatenateGenericAlias (_typing_ConcatenateGenericAlias , _root = True ):
1912+ class _ConcatenateGenericAlias (typing . _ConcatenateGenericAlias , _root = True ):
18071913 # needed for checks in collections.abc.Callable to accept this class
18081914 __module__ = "typing"
18091915
18101916 def copy_with (self , params ):
18111917 if isinstance (params [- 1 ], (list , tuple )):
18121918 return (* params [:- 1 ], * params [- 1 ])
1813- if isinstance (params [- 1 ], _ConcatenateGenericAlias ):
1919+ if isinstance (params [- 1 ], typing . _ConcatenateGenericAlias ):
18141920 params = (* params [:- 1 ], * params [- 1 ].__args__ )
18151921 elif not (params [- 1 ] is ... or isinstance (params [- 1 ], ParamSpec )):
18161922 raise TypeError ("The last parameter to Concatenate should be a "
18171923 "ParamSpec variable or ellipsis." )
1818- return super (_typing_ConcatenateGenericAlias , self ).copy_with (params )
1924+ return super (typing ._ConcatenateGenericAlias , self ).copy_with (params )
1925+
1926+ def __getitem__ (self , args ):
1927+ value = super ().__getitem__ (args )
1928+ if isinstance (value , tuple ) and any (_is_unpack (t ) for t in value ):
1929+ return tuple (_unpack_args (* (n for n in value )))
1930+ return value
18191931
18201932
18211933# 3.8-3.9.2
@@ -2496,6 +2608,17 @@ def _is_unpack(obj):
24962608 class _UnpackAlias (typing ._GenericAlias , _root = True ):
24972609 __class__ = typing .TypeVar
24982610
2611+ @property
2612+ def __typing_unpacked_tuple_args__ (self ):
2613+ assert self .__origin__ is Unpack
2614+ assert len (self .__args__ ) == 1
2615+ arg , = self .__args__
2616+ if isinstance (arg , typing ._GenericAlias ):
2617+ if arg .__origin__ is not tuple :
2618+ raise TypeError ("Unpack[...] must be used with a tuple type" )
2619+ return arg .__args__
2620+ return None
2621+
24992622 @property
25002623 def __typing_is_unpacked_typevartuple__ (self ):
25012624 assert self .__origin__ is Unpack
@@ -2519,21 +2642,22 @@ def _is_unpack(obj):
25192642 return isinstance (obj , _UnpackAlias )
25202643
25212644
2645+ def _unpack_args (* args ):
2646+ newargs = []
2647+ for arg in args :
2648+ subargs = getattr (arg , '__typing_unpacked_tuple_args__' , None )
2649+ if subargs is not None and (not (subargs and subargs [- 1 ] is ...)):
2650+ newargs .extend (subargs )
2651+ else :
2652+ newargs .append (arg )
2653+ return newargs
2654+
2655+
25222656if _PEP_696_IMPLEMENTED :
25232657 from typing import TypeVarTuple
25242658
25252659elif hasattr (typing , "TypeVarTuple" ): # 3.11+
25262660
2527- def _unpack_args (* args ):
2528- newargs = []
2529- for arg in args :
2530- subargs = getattr (arg , '__typing_unpacked_tuple_args__' , None )
2531- if subargs is not None and not (subargs and subargs [- 1 ] is ...):
2532- newargs .extend (subargs )
2533- else :
2534- newargs .append (arg )
2535- return newargs
2536-
25372661 # Add default parameter - PEP 696
25382662 class TypeVarTuple (metaclass = _TypeVarLikeMeta ):
25392663 """Type variable tuple."""
@@ -3024,6 +3148,7 @@ def _is_param_expr(arg):
30243148 ),
30253149 )
30263150
3151+
30273152# We have to do some monkey patching to deal with the dual nature of
30283153# Unpack/TypeVarTuple:
30293154# - We want Unpack to be a kind of TypeVar so it gets accepted in
@@ -3199,6 +3324,13 @@ def _collect_type_vars(types, typevar_types=None):
31993324 tvars .append (t )
32003325 if _should_collect_from_parameters (t ):
32013326 tvars .extend ([t for t in t .__parameters__ if t not in tvars ])
3327+ elif isinstance (t , tuple ):
3328+ # Collect nested type_vars
3329+ # tuple wrapped by _prepare_paramspec_params(cls, params)
3330+ for x in t :
3331+ for collected in _collect_type_vars ([x ]):
3332+ if collected not in tvars :
3333+ tvars .append (collected )
32023334 return tuple (tvars )
32033335
32043336 typing ._collect_type_vars = _collect_type_vars
0 commit comments