from typing import Any, AnyStr, Generic, ParamSpec, TypeVar, TypeVarTuple from somewhere import SupportsRichComparisonT S = TypeVar("S", str, bytes) # constrained type variable T = TypeVar("T", bound=float) Ts = TypeVarTuple("Ts") P = ParamSpec("P") class A(Generic[T]): # Comments in a class body are preserved var: T class B(Generic[*Ts]): var: tuple[*Ts] class C(Generic[P]): var: P class Constrained(Generic[S]): var: S # This case gets a diagnostic but not a fix because we can't look up the bounds # or constraints on the TypeVar imported from another module class ExternalType(Generic[T, SupportsRichComparisonT]): var: T compare: SupportsRichComparisonT # typing.AnyStr is a common external type variable, so treat it specially as a # known TypeVar class MyStr(Generic[AnyStr]): s: AnyStr class MultipleGenerics(Generic[S, T, *Ts, P]): var: S typ: T tup: tuple[*Ts] pep: P class MultipleBaseClasses(list, Generic[T]): var: T # these are just for the MoreBaseClasses and MultipleBaseAndGenerics cases class Base1: ... class Base2: ... class Base3: ... class MoreBaseClasses(Base1, Base2, Base3, Generic[T]): var: T class MultipleBaseAndGenerics(Base1, Base2, Base3, Generic[S, T, *Ts, P]): var: S typ: T tup: tuple[*Ts] pep: P class A(Generic[T]): ... class B(A[S], Generic[S]): var: S class C(A[S], Generic[S, T]): var: tuple[S, T] class D(A[int], Generic[T]): var: T class NotLast(Generic[T], Base1): var: T class Sandwich(Base1, Generic[T], Base2): var: T # runtime `TypeError` to inherit from `Generic` multiple times, but we still # emit a diagnostic class TooManyGenerics(Generic[T], Generic[S]): var: T var: S # These cases are not handled class D(Generic[T, T]): # duplicate generic variable, runtime error pass # TODO(brent) we should also apply the fix to methods, but it will need a # little more work. these should be left alone for now but be fixed eventually. class NotGeneric: # -> generic_method[T: float](t: T) def generic_method(t: T) -> T: return t # This one is strange in particular because of the mix of old- and new-style # generics, but according to the PEP, this is okay "if the class, function, or # type alias does not use the new syntax." `more_generic` doesn't use the new # syntax, so it can use T from the module and U from the class scope. class MixedGenerics[U]: def more_generic(u: U, t: T) -> tuple[U, T]: return (u, t) # TODO(brent) default requires 3.13 V = TypeVar("V", default=Any, bound=str) class DefaultTypeVar(Generic[V]): # -> [V: str = Any] var: V # nested classes and functions are skipped class Outer: class Inner(Generic[T]): var: T