@@ -85,11 +85,27 @@ def is_literal(tp: Any, /) -> bool:
85
85
return _is_typing_name (get_origin (tp ), name = 'Literal' )
86
86
87
87
88
- # TODO remove and replace with `get_args` when we drop support for Python 3.8
89
- # (see https://docs.python.org/3/whatsnew/3.9.html#id4).
90
88
def literal_values (tp : Any , / ) -> list [Any ]:
91
- """Return the values contained in the provided `Literal` special form."""
89
+ """Return the values contained in the provided `Literal` special form.
90
+
91
+ If one of the literal values is a PEP 695 type alias, recursively parse
92
+ the type alias' `__value__` to unpack literal values as well. This function
93
+ *doesn't* check that the type alias is referencing a `Literal` special form,
94
+ so unexpected values could be unpacked.
95
+ """
96
+ # TODO When we drop support for Python 3.8, there's no need to check of `is_literal`
97
+ # here, as Python unpacks nested `Literal` forms in 3.9+.
98
+ # (see https://docs.python.org/3/whatsnew/3.9.html#id4).
92
99
if not is_literal (tp ):
100
+ # Note: we could also check for generic aliases with a type alias as an origin.
101
+ # However, it is very unlikely that this happens as type variables can't appear in
102
+ # `Literal` forms, so the only valid (but unnecessary) use case would be something like:
103
+ # `type Test[T] = Literal['a']` (and then use `Test[SomeType]`).
104
+ if is_type_alias_type (tp ):
105
+ # Note: accessing `__value__` could raise a `NameError`, but we just let
106
+ # the exception be raised as there's not much we can do if this happens.
107
+ return literal_values (tp .__value__ )
108
+
93
109
return [tp ]
94
110
95
111
values = get_args (tp )
0 commit comments