← Back to index

generics_defaults.py

True Positive
False Positive
False Negative
Optional (detected)
Warning or Info
TP: 5
FP: 5
FN: 1
Optional: 0 / 0
1"""
2Tests for basic usage of default values for TypeVar-like's.
3"""
4
5# Specification: https://typing.readthedocs.io/en/latest/spec/generics.html#defaults-for-type-parameters.
6
7from typing import Any, Callable, Generic, Self, Unpack, assert_type
8from typing_extensions import TypeVar, ParamSpec, TypeVarTuple
9
11DefaultStrT = TypeVar("DefaultStrT", default=str)
12DefaultIntT = TypeVar("DefaultIntT", default=int)
13DefaultBoolT = TypeVar("DefaultBoolT", default=bool)
14T = TypeVar("T")
15T1 = TypeVar("T1")
16T2 = TypeVar("T2")
18# > The order for defaults should follow the standard function parameter
19# > rules, so a type parameter with no ``default`` cannot follow one with
20# > a ``default`` value. Doing so may raise a ``TypeError`` at runtime,
21# > and a type checker should flag this as an error.
24class NonDefaultFollowsDefault(Generic[DefaultStrT, T]): ... # E: non-default TypeVars cannot follow ones with defaults
[invalid-generic-class] Type parameter `T` without a default cannot follow earlier parameter `DefaultStrT` with a default
27class NoNonDefaults(Generic[DefaultStrT, DefaultIntT]): ...
30assert_type(NoNonDefaults, type[NoNonDefaults[str, int]])
31assert_type(NoNonDefaults[str], type[NoNonDefaults[str, int]])
32assert_type(NoNonDefaults[str, int], type[NoNonDefaults[str, int]])
35class OneDefault(Generic[T, DefaultBoolT]): ...
38assert_type(OneDefault[float], type[OneDefault[float, bool]])
39assert_type(OneDefault[float](), OneDefault[float, bool])
42class AllTheDefaults(Generic[T1, T2, DefaultStrT, DefaultIntT, DefaultBoolT]): ...
45assert_type(AllTheDefaults, type[AllTheDefaults[Any, Any, str, int, bool]])
Unexpected error [type-assertion-failure] Type `type[AllTheDefaults[Any, Any, str, int, bool]]` does not match asserted type `<class 'AllTheDefaults'>`
46assert_type(
47 AllTheDefaults[int, complex], type[AllTheDefaults[int, complex, str, int, bool]]
48)
50AllTheDefaults[int] # E: expected 2 arguments to AllTheDefaults
[invalid-type-arguments] No type argument provided for required type variable `T2` of class `AllTheDefaults`
52assert_type(
53 AllTheDefaults[int, complex], type[AllTheDefaults[int, complex, str, int, bool]]
54)
55assert_type(
56 AllTheDefaults[int, complex, str],
57 type[AllTheDefaults[int, complex, str, int, bool]],
58)
59assert_type(
60 AllTheDefaults[int, complex, str, int],
61 type[AllTheDefaults[int, complex, str, int, bool]],
62)
63assert_type(
64 AllTheDefaults[int, complex, str, int, bool],
65 type[AllTheDefaults[int, complex, str, int, bool]],
66)
69# > ``ParamSpec`` defaults are defined using the same syntax as
70# > ``TypeVar`` \ s but use a ``list`` of types or an ellipsis
71# > literal "``...``" or another in-scope ``ParamSpec``.
73DefaultP = ParamSpec("DefaultP", default=[str, int])
76class Class_ParamSpec(Generic[DefaultP]): ...
79assert_type(Class_ParamSpec, type[Class_ParamSpec[str, int]])
80assert_type(Class_ParamSpec(), Class_ParamSpec[str, int])
81assert_type(Class_ParamSpec[[bool, bool]](), Class_ParamSpec[bool, bool])
84# > ``TypeVarTuple`` defaults are defined using the same syntax as
85# > ``TypeVar`` \ s, but instead of a single type, they use an unpacked tuple
86# > of types or an unpacked, in-scope ``TypeVarTuple`` (see `Scoping Rules`_).
88DefaultTs = TypeVarTuple("DefaultTs", default=Unpack[tuple[str, int]])
91class Class_TypeVarTuple(Generic[*DefaultTs]): ...
94assert_type(Class_TypeVarTuple, type[Class_TypeVarTuple[*tuple[str, int]]])
Unexpected error [type-assertion-failure] Type `@Todo` does not match asserted type `<class 'Class_TypeVarTuple'>`
95assert_type(Class_TypeVarTuple(), Class_TypeVarTuple[str, int])
Unexpected error [type-assertion-failure] Type `@Todo` does not match asserted type `Class_TypeVarTuple`
96assert_type(Class_TypeVarTuple[int, bool](), Class_TypeVarTuple[int, bool])
99AnotherDefaultTs = TypeVarTuple("AnotherDefaultTs", default=Unpack[DefaultTs])
102# > If both ``bound`` and ``default`` are passed, ``default`` must be a
103# > subtype of ``bound``. If not, the type checker should generate an
104# > error.
106Ok1 = TypeVar("Ok1", bound=float, default=int) # OK
107Invalid1 = TypeVar("Invalid1", bound=str, default=int) # E: the bound and default are incompatible
[invalid-type-variable-default] TypeVar default is not assignable to the TypeVar's upper bound
109# > For constrained ``TypeVar``\ s, the default needs to be one of the
110# > constraints. A type checker should generate an error even if it is a
111# > subtype of one of the constraints.
113Ok2 = TypeVar("Ok2", float, str, default=float) # OK
114Invalid2 = TypeVar("Invalid2", float, str, default=int) # E: expected one of float or str got int
[invalid-type-variable-default] TypeVar default is inconsistent with the TypeVar's constraints: `int` is not one of the constraints of `Invalid2`
117# > In generic functions, type checkers may use a type parameter's default when the
118# > type parameter cannot be solved to anything. We leave the semantics of this
119# > usage unspecified, as ensuring the ``default`` is returned in every code path
120# > where the type parameter can go unsolved may be too hard to implement. Type
121# > checkers are free to either disallow this case or experiment with implementing
122# > support.
124T4 = TypeVar("T4", default=int)
127def func1(x: int | set[T4]) -> T4:
128 raise NotImplementedError
131assert_type(func1(0), int) # E[optional-default-use]
132assert_type(func1(0), Any) # E[optional-default-use]
Tag 'optional-default-use' [type-assertion-failure] Type `Any` does not match asserted type `int`
135# > A ``TypeVar`` that immediately follows a ``TypeVarTuple`` is not allowed
136# > to have a default, because it would be ambiguous whether a type argument
137# > should be bound to the ``TypeVarTuple`` or the defaulted ``TypeVar``.
139Ts = TypeVarTuple("Ts")
140T5 = TypeVar("T5", default=bool)
143class Foo5(Generic[*Ts, T5]): ... # E
Expected a ty diagnostic for this line
146# > It is allowed to have a ``ParamSpec`` with a default following a
147# > ``TypeVarTuple`` with a default, as there can be no ambiguity between a
148# > type argument for the ``ParamSpec`` and one for the ``TypeVarTuple``.
150P = ParamSpec("P", default=[float, bool])
153class Foo6(Generic[*Ts, P]): ... # OK
156assert_type(Foo6[int, str], type[Foo6[int, str, [float, bool]]])
Unexpected error [invalid-type-form] List literals are not allowed in this context in a type expression: Did you mean `tuple[int | float, bool]`?
157assert_type(Foo6[int, str, [bytes]], type[Foo6[int, str, [bytes]]])
Unexpected error [invalid-type-form] List literals are not allowed in this context in a type expression: Did you mean `list[bytes]`?
160# > Type parameter defaults should be bound by attribute access
161# > (including call and subscript).
164class Foo7(Generic[DefaultIntT]):
165 def meth(self, /) -> Self:
166 return self
168 attr: DefaultIntT
171foo7 = Foo7()
172assert_type(Foo7.meth(foo7), Foo7[int])
173assert_type(Foo7().attr, int)