|
5 | 5 | from .._compat import get_args, get_origin, is_generic |
6 | 6 |
|
7 | 7 |
|
| 8 | +def _tvar_has_default(tvar) -> bool: |
| 9 | + """Does `tvar` have a default? |
| 10 | +
|
| 11 | + In CPython 3.13+ and typing_extensions>=4.12.0: |
| 12 | + - TypeVars have a `no_default()` method for detecting |
| 13 | + if a TypeVar has a default |
| 14 | + - TypeVars with `default=None` have `__default__` set to `None` |
| 15 | + - TypeVars with no `default` parameter passed |
| 16 | + have `__default__` set to `typing(_extensions).NoDefault |
| 17 | +
|
| 18 | + On typing_exensions<4.12.0: |
| 19 | + - TypeVars do not have a `no_default()` method for detecting |
| 20 | + if a TypeVar has a default |
| 21 | + - TypeVars with `default=None` have `__default__` set to `NoneType` |
| 22 | + - TypeVars with no `default` parameter passed |
| 23 | + have `__default__` set to `typing(_extensions).NoDefault |
| 24 | + """ |
| 25 | + try: |
| 26 | + return tvar.has_default() |
| 27 | + except AttributeError: |
| 28 | + # compatibility for typing_extensions<4.12.0 |
| 29 | + return getattr(tvar, "__default__", None) is not None |
| 30 | + |
| 31 | + |
8 | 32 | def generate_mapping(cl: type, old_mapping: dict[str, type] = {}) -> dict[str, type]: |
9 | 33 | """Generate a mapping of typevars to actual types for a generic class.""" |
10 | 34 | mapping = dict(old_mapping) |
@@ -35,20 +59,15 @@ def generate_mapping(cl: type, old_mapping: dict[str, type] = {}) -> dict[str, t |
35 | 59 | base_args = base.__args__ |
36 | 60 | if hasattr(base.__origin__, "__parameters__"): |
37 | 61 | base_params = base.__origin__.__parameters__ |
38 | | - elif any( |
39 | | - getattr(base_arg, "__default__", None) is not None |
40 | | - for base_arg in base_args |
41 | | - ): |
| 62 | + elif any(_tvar_has_default(base_arg) for base_arg in base_args): |
42 | 63 | # TypeVar with a default e.g. PEP 696 |
43 | 64 | # https://www.python.org/dev/peps/pep-0696/ |
44 | 65 | # Extract the defaults for the TypeVars and insert |
45 | 66 | # them into the mapping |
46 | 67 | mapping_params = [ |
47 | 68 | (base_arg, base_arg.__default__) |
48 | 69 | for base_arg in base_args |
49 | | - # Note: None means no default was provided, since |
50 | | - # TypeVar("T", default=None) sets NoneType as the default |
51 | | - if getattr(base_arg, "__default__", None) is not None |
| 70 | + if _tvar_has_default(base_arg) |
52 | 71 | ] |
53 | 72 | base_params, base_args = zip(*mapping_params) |
54 | 73 | else: |
|
0 commit comments