Create a list of new type arguments.
(self, args, new_arg_by_param)
| 1479 | return tuple(self._make_substitution(self.__args__, new_arg_by_param)) |
| 1480 | |
| 1481 | def _make_substitution(self, args, new_arg_by_param): |
| 1482 | """Create a list of new type arguments.""" |
| 1483 | new_args = [] |
| 1484 | for old_arg in args: |
| 1485 | if isinstance(old_arg, type): |
| 1486 | new_args.append(old_arg) |
| 1487 | continue |
| 1488 | |
| 1489 | substfunc = getattr(old_arg, '__typing_subst__', None) |
| 1490 | if substfunc: |
| 1491 | new_arg = substfunc(new_arg_by_param[old_arg]) |
| 1492 | else: |
| 1493 | subparams = getattr(old_arg, '__parameters__', ()) |
| 1494 | if not subparams: |
| 1495 | new_arg = old_arg |
| 1496 | else: |
| 1497 | subargs = [] |
| 1498 | for x in subparams: |
| 1499 | if isinstance(x, TypeVarTuple): |
| 1500 | subargs.extend(new_arg_by_param[x]) |
| 1501 | else: |
| 1502 | subargs.append(new_arg_by_param[x]) |
| 1503 | new_arg = old_arg[tuple(subargs)] |
| 1504 | |
| 1505 | if self.__origin__ == collections.abc.Callable and isinstance(new_arg, tuple): |
| 1506 | # Consider the following `Callable`. |
| 1507 | # C = Callable[[int], str] |
| 1508 | # Here, `C.__args__` should be (int, str) - NOT ([int], str). |
| 1509 | # That means that if we had something like... |
| 1510 | # P = ParamSpec('P') |
| 1511 | # T = TypeVar('T') |
| 1512 | # C = Callable[P, T] |
| 1513 | # D = C[[int, str], float] |
| 1514 | # ...we need to be careful; `new_args` should end up as |
| 1515 | # `(int, str, float)` rather than `([int, str], float)`. |
| 1516 | new_args.extend(new_arg) |
| 1517 | elif _is_unpacked_typevartuple(old_arg): |
| 1518 | # Consider the following `_GenericAlias`, `B`: |
| 1519 | # class A(Generic[*Ts]): ... |
| 1520 | # B = A[T, *Ts] |
| 1521 | # If we then do: |
| 1522 | # B[float, int, str] |
| 1523 | # The `new_arg` corresponding to `T` will be `float`, and the |
| 1524 | # `new_arg` corresponding to `*Ts` will be `(int, str)`. We |
| 1525 | # should join all these types together in a flat list |
| 1526 | # `(float, int, str)` - so again, we should `extend`. |
| 1527 | new_args.extend(new_arg) |
| 1528 | elif isinstance(old_arg, tuple): |
| 1529 | # Corner case: |
| 1530 | # P = ParamSpec('P') |
| 1531 | # T = TypeVar('T') |
| 1532 | # class Base(Generic[P]): ... |
| 1533 | # Can be substituted like this: |
| 1534 | # X = Base[[int, T]] |
| 1535 | # In this case, `old_arg` will be a tuple: |
| 1536 | new_args.append( |
| 1537 | tuple(self._make_substitution(old_arg, new_arg_by_param)), |
| 1538 | ) |
no test coverage detected