2Tests interactions between Literal types and other typing features.
5# Specification: https://typing.readthedocs.io/en/latest/spec/literal.html#interactions-with-other-types-and-features
7from typing import IO, Any, Final, Generic, Literal, TypeVar, LiteralString, assert_type, overload
10def func1(v: tuple[int, str, list[bool]], a: Literal[0], b: Literal[5], c: Literal[-5]):
11 assert_type(v[a], int)
12 assert_type(v[2], list[bool])
14 v[b] # E: index out of range
[index-out-of-bounds] Index 5 is out of bounds for tuple `tuple[int, str, list[bool]]` with length 3
15 v[c] # E: index out of range
[index-out-of-bounds] Index -5 is out of bounds for tuple `tuple[int, str, list[bool]]` with length 3
16 v[4] # E: index out of range
[index-out-of-bounds] Index 4 is out of bounds for tuple `tuple[int, str, list[bool]]` with length 3
17 v[-4] # E: index out of range
[index-out-of-bounds] Index -4 is out of bounds for tuple `tuple[int, str, list[bool]]` with length 3
20_PathType = str | bytes | int
26 mode: Literal["r", "w", "a", "x", "r+", "w+", "a+", "x+"],
34 mode: Literal["rb", "wb", "ab", "xb", "r+b", "w+b", "a+b", "x+b"],
40def open(path: _PathType, mode: str) -> IO[Any]:
44def open(path: _PathType, mode: Any) -> Any:
45 raise NotImplementedError
48assert_type(open("path", "r"), IO[str])
49assert_type(open("path", "wb"), IO[bytes])
50assert_type(open("path", "other"), IO[Any])
53A = TypeVar("A", bound=int)
54B = TypeVar("B", bound=int)
55C = TypeVar("C", bound=int)
58class Matrix(Generic[A, B]):
59 def __add__(self, other: "Matrix[A, B]") -> "Matrix[A, B]":
60 raise NotImplementedError
62 def __matmul__(self, other: "Matrix[B, C]") -> "Matrix[A, C]":
63 raise NotImplementedError
65 def transpose(self) -> "Matrix[B, A]":
66 raise NotImplementedError
69def func2(a: Matrix[Literal[2], Literal[3]], b: Matrix[Literal[3], Literal[7]]):
71 assert_type(c, Matrix[Literal[2], Literal[7]])
74T = TypeVar("T", Literal["a"], Literal["b"], Literal["c"])
75S = TypeVar("S", bound=Literal["foo"])
84def parse_status1(s: str | Status) -> None:
85 if s is Status.SUCCESS:
86 assert_type(s, Literal[Status.SUCCESS])
87 elif s is Status.INVALID_DATA:
88 assert_type(s, Literal[Status.INVALID_DATA])
89 elif s is Status.FATAL_ERROR:
90 assert_type(s, Literal[Status.FATAL_ERROR])
95# > Type checkers may optionally perform additional analysis for both
96# > enum and non-enum Literal types beyond what is described in the section above.
98# > For example, it may be useful to perform narrowing based on things
99# > like containment or equality checks:
101def expects_bad_status(status: Literal["MALFORMED", "ABORTED"]):
105def expects_pending_status(status: Literal["PENDING"]):
109def parse_status2(status: LiteralString) -> None:
110 if status == "MALFORMED":
111 expects_bad_status(status) # E? narrowing the type here is sound, but optional per the spec
112 elif status == "ABORTED":
113 expects_bad_status(status) # E? narrowing the type here is sound, but optional per the spec
115 if status in ("MALFORMED", "ABORTED"):
116 expects_bad_status(status) # E? narrowing the type here is sound, but optional per the spec
118 if status == "PENDING":
119 expects_pending_status(status) # E? narrowing the type here is sound, but optional per the spec
122# Narrowing `str` to `Literal` strings is unsound given the possiblity of
123# user-defined `str` subclasses that could have custom equality semantics,
124# but is explicitly listed by the spec as optional analysis that type checkers
126def parse_status3(status: str) -> None:
127 if status == "MALFORMED":
128 expects_bad_status(status) # E? narrowing the type here is unsound, but allowed per the spec
[invalid-argument-type] Argument to function `expects_bad_status` is incorrect: Expected `Literal["MALFORMED", "ABORTED"]`, found `str`
129 elif status == "ABORTED":
130 expects_bad_status(status) # E? narrowing the type here is unsound, but allowed per the spec
[invalid-argument-type] Argument to function `expects_bad_status` is incorrect: Expected `Literal["MALFORMED", "ABORTED"]`, found `str & ~Literal["MALFORMED"]`
132 if status in ("MALFORMED", "ABORTED"):
133 expects_bad_status(status) # E? narrowing the type here is unsound, but allowed per the spec
[invalid-argument-type] Argument to function `expects_bad_status` is incorrect: Expected `Literal["MALFORMED", "ABORTED"]`, found `str`
135 if status == "PENDING":
136 expects_pending_status(status) # E? narrowing the type here is unsound, but allowed per the spec
[invalid-argument-type] Argument to function `expects_pending_status` is incorrect: Expected `Literal["PENDING"]`, found `str`
140assert_type(final_val1, Literal[3])
142final_val2: Final = True
143assert_type(final_val2, Literal[True])