| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
1 parent 1d1bb95 commit 8f2fb7d
5 files changed
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -772,20 +772,42 @@ class C(Generic[*Ts]): pass | |||
| 772 | 772 | ('generic[*Ts]', '[*Ts]', 'generic[*Ts]'), | |
| 773 | 773 | ('generic[*Ts]', '[T, *Ts]', 'generic[T, *Ts]'), | |
| 774 | 774 | ('generic[*Ts]', '[*Ts, T]', 'generic[*Ts, T]'), | |
| 775 | + ('generic[T, *Ts]', '[()]', 'TypeError'), | ||
| 775 | 776 | ('generic[T, *Ts]', '[int]', 'generic[int]'), | |
| 776 | 777 | ('generic[T, *Ts]', '[int, str]', 'generic[int, str]'), | |
| 777 | 778 | ('generic[T, *Ts]', '[int, str, bool]', 'generic[int, str, bool]'), | |
| 779 | + ('generic[list[T], *Ts]', '[()]', 'TypeError'), | ||
| 778 | 780 | ('generic[list[T], *Ts]', '[int]', 'generic[list[int]]'), | |
| 779 | 781 | ('generic[list[T], *Ts]', '[int, str]', 'generic[list[int], str]'), | |
| 780 | 782 | ('generic[list[T], *Ts]', '[int, str, bool]', 'generic[list[int], str, bool]'), | |
| 781 | 783 | ||
| 784 | + ('generic[*Ts, T]', '[()]', 'TypeError'), | ||
| 782 | 785 | ('generic[*Ts, T]', '[int]', 'generic[int]'), | |
| 783 | 786 | ('generic[*Ts, T]', '[int, str]', 'generic[int, str]'), | |
| 784 | 787 | ('generic[*Ts, T]', '[int, str, bool]', 'generic[int, str, bool]'), | |
| 788 | + ('generic[*Ts, list[T]]', '[()]', 'TypeError'), | ||
| 785 | 789 | ('generic[*Ts, list[T]]', '[int]', 'generic[list[int]]'), | |
| 786 | 790 | ('generic[*Ts, list[T]]', '[int, str]', 'generic[int, list[str]]'), | |
| 787 | 791 | ('generic[*Ts, list[T]]', '[int, str, bool]', 'generic[int, str, list[bool]]'), | |
| 788 | 792 | ||
| 793 | + ('generic[T1, T2, *Ts]', '[()]', 'TypeError'), | ||
| 794 | + ('generic[T1, T2, *Ts]', '[int]', 'TypeError'), | ||
| 795 | + ('generic[T1, T2, *Ts]', '[int, str]', 'generic[int, str]'), | ||
| 796 | + ('generic[T1, T2, *Ts]', '[int, str, bool]', 'generic[int, str, bool]'), | ||
| 797 | + ('generic[T1, T2, *Ts]', '[int, str, bool, bytes]', 'generic[int, str, bool, bytes]'), | ||
| 798 | + | ||
| 799 | + ('generic[*Ts, T1, T2]', '[()]', 'TypeError'), | ||
| 800 | + ('generic[*Ts, T1, T2]', '[int]', 'TypeError'), | ||
| 801 | + ('generic[*Ts, T1, T2]', '[int, str]', 'generic[int, str]'), | ||
| 802 | + ('generic[*Ts, T1, T2]', '[int, str, bool]', 'generic[int, str, bool]'), | ||
| 803 | + ('generic[*Ts, T1, T2]', '[int, str, bool, bytes]', 'generic[int, str, bool, bytes]'), | ||
| 804 | + | ||
| 805 | + ('generic[T1, *Ts, T2]', '[()]', 'TypeError'), | ||
| 806 | + ('generic[T1, *Ts, T2]', '[int]', 'TypeError'), | ||
| 807 | + ('generic[T1, *Ts, T2]', '[int, str]', 'generic[int, str]'), | ||
| 808 | + ('generic[T1, *Ts, T2]', '[int, str, bool]', 'generic[int, str, bool]'), | ||
| 809 | + ('generic[T1, *Ts, T2]', '[int, str, bool, bytes]', 'generic[int, str, bool, bytes]'), | ||
| 810 | + | ||
| 789 | 811 | ('generic[T, *Ts]', '[*tuple_type[int, ...]]', 'generic[int, *tuple_type[int, ...]]'), | |
| 790 | 812 | ('generic[T, *Ts]', '[str, *tuple_type[int, ...]]', 'generic[str, *tuple_type[int, ...]]'), | |
| 791 | 813 | ('generic[T, *Ts]', '[*tuple_type[int, ...], str]', 'generic[int, *tuple_type[int, ...], str]'), | |
@@ -7241,6 +7263,65 @@ class X(Generic[P, P2]): | |||
| 7241 | 7263 | self.assertEqual(G1.__args__, ((int, str), (bytes,))) | |
| 7242 | 7264 | self.assertEqual(G2.__args__, ((int,), (str, bytes))) | |
| 7243 | 7265 | ||
| 7266 | + def test_typevartuple_and_paramspecs_in_user_generics(self): | ||
| 7267 | + Ts = TypeVarTuple("Ts") | ||
| 7268 | + P = ParamSpec("P") | ||
| 7269 | + | ||
| 7270 | + class X(Generic[*Ts, P]): | ||
| 7271 | + f: Callable[P, int] | ||
| 7272 | + g: Tuple[*Ts] | ||
| 7273 | + | ||
| 7274 | + G1 = X[int, [bytes]] | ||
| 7275 | + self.assertEqual(G1.__args__, (int, (bytes,))) | ||
| 7276 | + G2 = X[int, str, [bytes]] | ||
| 7277 | + self.assertEqual(G2.__args__, (int, str, (bytes,))) | ||
| 7278 | + G3 = X[[bytes]] | ||
| 7279 | + self.assertEqual(G3.__args__, ((bytes,),)) | ||
| 7280 | + G4 = X[[]] | ||
| 7281 | + self.assertEqual(G4.__args__, ((),)) | ||
| 7282 | + with self.assertRaises(TypeError): | ||
| 7283 | + X[()] | ||
| 7284 | + | ||
| 7285 | + class Y(Generic[P, *Ts]): | ||
| 7286 | + f: Callable[P, int] | ||
| 7287 | + g: Tuple[*Ts] | ||
| 7288 | + | ||
| 7289 | + G1 = Y[[bytes], int] | ||
| 7290 | + self.assertEqual(G1.__args__, ((bytes,), int)) | ||
| 7291 | + G2 = Y[[bytes], int, str] | ||
| 7292 | + self.assertEqual(G2.__args__, ((bytes,), int, str)) | ||
| 7293 | + G3 = Y[[bytes]] | ||
| 7294 | + self.assertEqual(G3.__args__, ((bytes,),)) | ||
| 7295 | + G4 = Y[[]] | ||
| 7296 | + self.assertEqual(G4.__args__, ((),)) | ||
| 7297 | + with self.assertRaises(TypeError): | ||
| 7298 | + Y[()] | ||
| 7299 | + | ||
| 7300 | + def test_typevartuple_and_paramspecs_in_generic_aliases(self): | ||
| 7301 | + P = ParamSpec('P') | ||
| 7302 | + T = TypeVar('T') | ||
| 7303 | + Ts = TypeVarTuple('Ts') | ||
| 7304 | + | ||
| 7305 | + for C in Callable, collections.abc.Callable: | ||
| 7306 | + with self.subTest(generic=C): | ||
| 7307 | + A = C[P, Tuple[*Ts]] | ||
| 7308 | + B = A[[int, str], bytes, float] | ||
| 7309 | + self.assertEqual(B.__args__, (int, str, Tuple[bytes, float])) | ||
| 7310 | + | ||
| 7311 | + class X(Generic[T, P]): | ||
| 7312 | + pass | ||
| 7313 | + | ||
| 7314 | + A = X[Tuple[*Ts], P] | ||
| 7315 | + B = A[bytes, float, [int, str]] | ||
| 7316 | + self.assertEqual(B.__args__, (Tuple[bytes, float], (int, str,))) | ||
| 7317 | + | ||
| 7318 | + class Y(Generic[P, T]): | ||
| 7319 | + pass | ||
| 7320 | + | ||
| 7321 | + A = Y[P, Tuple[*Ts]] | ||
| 7322 | + B = A[[int, str], bytes, float] | ||
| 7323 | + self.assertEqual(B.__args__, ((int, str,), Tuple[bytes, float])) | ||
| 7324 | + | ||
| 7244 | 7325 | def test_var_substitution(self): | |
| 7245 | 7326 | T = TypeVar("T") | |
| 7246 | 7327 | P = ParamSpec("P") | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -284,25 +284,6 @@ def _unpack_args(args): | |||
| 284 | 284 | newargs.append(arg) | |
| 285 | 285 | return newargs | |
| 286 | 286 | ||
| 287 | - def _prepare_paramspec_params(cls, params): | ||
| 288 | - """Prepares the parameters for a Generic containing ParamSpec | ||
| 289 | - variables (internal helper). | ||
| 290 | - """ | ||
| 291 | - # Special case where Z[[int, str, bool]] == Z[int, str, bool] in PEP 612. | ||
| 292 | - if (len(cls.__parameters__) == 1 | ||
| 293 | - and params and not _is_param_expr(params[0])): | ||
| 294 | - assert isinstance(cls.__parameters__[0], ParamSpec) | ||
| 295 | - return (params,) | ||
| 296 | - else: | ||
| 297 | - _check_generic(cls, params, len(cls.__parameters__)) | ||
| 298 | - _params = [] | ||
| 299 | - # Convert lists to tuples to help other libraries cache the results. | ||
| 300 | - for p, tvar in zip(params, cls.__parameters__): | ||
| 301 | - if isinstance(tvar, ParamSpec) and isinstance(p, list): | ||
| 302 | - p = tuple(p) | ||
| 303 | - _params.append(p) | ||
| 304 | - return tuple(_params) | ||
| 305 | - | ||
| 306 | 287 | def _deduplicate(params): | |
| 307 | 288 | # Weed out strict duplicates, preserving the first of each occurrence. | |
| 308 | 289 | all_params = set(params) | |
@@ -1238,7 +1219,18 @@ def __typing_subst__(self, arg): | |||
| 1238 | 1219 | return arg | |
| 1239 | 1220 | ||
| 1240 | 1221 | def __typing_prepare_subst__(self, alias, args): | |
| 1241 | - return _prepare_paramspec_params(alias, args) | ||
| 1222 | + params = alias.__parameters__ | ||
| 1223 | + i = params.index(self) | ||
| 1224 | + if i >= len(args): | ||
| 1225 | + raise TypeError(f"Too few arguments for {alias}") | ||
| 1226 | + # Special case where Z[[int, str, bool]] == Z[int, str, bool] in PEP 612. | ||
| 1227 | + if len(params) == 1 and not _is_param_expr(args[0]): | ||
| 1228 | + assert i == 0 | ||
| 1229 | + args = (args,) | ||
| 1230 | + # Convert lists to tuples to help other libraries cache the results. | ||
| 1231 | + elif isinstance(args[i], list): | ||
| 1232 | + args = (*args[:i], tuple(args[i]), *args[i+1:]) | ||
| 1233 | + return args | ||
| 1242 | 1234 | ||
| 1243 | 1235 | def _is_dunder(attr): | |
| 1244 | 1236 | return attr.startswith('__') and attr.endswith('__') | |
@@ -1801,23 +1793,13 @@ def __class_getitem__(cls, params): | |||
| 1801 | 1793 | if not isinstance(params, tuple): | |
| 1802 | 1794 | params = (params,) | |
| 1803 | 1795 | ||
| 1804 | - if not params: | ||
| 1805 | - # We're only ok with `params` being empty if the class's only type | ||
| 1806 | - # parameter is a `TypeVarTuple` (which can contain zero types). | ||
| 1807 | - class_params = getattr(cls, "__parameters__", None) | ||
| 1808 | - only_class_parameter_is_typevartuple = ( | ||
| 1809 | - class_params is not None | ||
| 1810 | - and len(class_params) == 1 | ||
| 1811 | - and isinstance(class_params[0], TypeVarTuple) | ||
| 1812 | - ) | ||
| 1813 | - if not only_class_parameter_is_typevartuple: | ||
| 1814 | - raise TypeError( | ||
| 1815 | - f"Parameter list to {cls.__qualname__}[...] cannot be empty" | ||
| 1816 | - ) | ||
| 1817 | - | ||
| 1818 | 1796 | params = tuple(_type_convert(p) for p in params) | |
| 1819 | 1797 | if cls in (Generic, Protocol): | |
| 1820 | 1798 | # Generic and Protocol can only be subscripted with unique type variables. | |
| 1799 | + if not params: | ||
| 1800 | + raise TypeError( | ||
| 1801 | + f"Parameter list to {cls.__qualname__}[...] cannot be empty" | ||
| 1802 | + ) | ||
| 1821 | 1803 | if not all(_is_typevar_like(p) for p in params): | |
| 1822 | 1804 | raise TypeError( | |
| 1823 | 1805 | f"Parameters to {cls.__name__}[...] must all be type variables " | |
@@ -1827,13 +1809,20 @@ def __class_getitem__(cls, params): | |||
| 1827 | 1809 | f"Parameters to {cls.__name__}[...] must all be unique") | |
| 1828 | 1810 | else: | |
| 1829 | 1811 | # Subscripting a regular Generic subclass. | |
| 1830 | - if any(isinstance(t, ParamSpec) for t in cls.__parameters__): | ||
| 1831 | - params = _prepare_paramspec_params(cls, params) | ||
| 1832 | - elif not any(isinstance(p, TypeVarTuple) for p in cls.__parameters__): | ||
| 1833 | - # We only run this if there are no TypeVarTuples, because we | ||
| 1834 | - # don't check variadic generic arity at runtime (to reduce | ||
| 1835 | - # complexity of typing.py). | ||
| 1836 | - _check_generic(cls, params, len(cls.__parameters__)) | ||
| 1812 | + for param in cls.__parameters__: | ||
| 1813 | + prepare = getattr(param, '__typing_prepare_subst__', None) | ||
| 1814 | + if prepare is not None: | ||
| 1815 | + params = prepare(cls, params) | ||
| 1816 | + _check_generic(cls, params, len(cls.__parameters__)) | ||
| 1817 | + | ||
| 1818 | + new_args = [] | ||
| 1819 | + for param, new_arg in zip(cls.__parameters__, params): | ||
| 1820 | + if isinstance(param, TypeVarTuple): | ||
| 1821 | + new_args.extend(new_arg) | ||
| 1822 | + else: | ||
| 1823 | + new_args.append(new_arg) | ||
| 1824 | + params = tuple(new_args) | ||
| 1825 | + | ||
| 1837 | 1826 | return _GenericAlias(cls, params, | |
| 1838 | 1827 | _paramspec_tvars=True) | |
| 1839 | 1828 | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -0,0 +1,2 @@ | |||
| 1 | + Fix substitution of :class:`~typing.TypeVarTuple` and | ||
| 2 | + :class:`~typing.ParamSpec` together in user generics. | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -0,0 +1,2 @@ | |||
| 1 | + Fix substitution of :class:`~typing.ParamSpec` followed by | ||
| 2 | + :class:`~typing.TypeVarTuple` in generic aliases. | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -0,0 +1,2 @@ | |||
| 1 | + Check the number of arguments in substitution in user generics containing a | ||
| 2 | + :class:`~typing.TypeVarTuple` and one or more :class:`~typing.TypeVar`. | ||
| Back | FazBrowse Home | New Git URL |
0 commit comments