Quantity is a subclass of numpy.ndarray which is a subclass of Generic in the stubs, but not at runtime:
>>> import numpy as np
>>> np.ndarray.mro()
[<class 'numpy.ndarray'>, <class 'object'>]
IIUC, a type checker would consider Quantity as Generic and have inherited 2 type parameters with defaults.
Question
If u.km is not assignable to tuple[int, ...] [1], is a type checker expected to ignore the issue because of a __class_getitem__?
The runtime implementation makes me think they’d be better served by (PEP 835: Shorthand syntax for Annotated type metadata).
Using preserving-units as an example, something like this possible today and not much of a mouthful [2] if you alias some symbols:
Show a few generics
from typing import Annotated as A, Literal as L
import numpy as np
class Quantity(np.ndarray): ...
class Unit[T]:
def __init__(self, arg: T) -> None:
self.arg: T = arg
class PhysicalType[T]:
def __init__(self, arg: T) -> None:
self.arg: T = arg
type m = Unit[L["m"]]
type length = PhysicalType[L["length"]]
>>> A[Quantity, m]
typing.Annotated[__main__.Quantity, m]
>>> A[Quantity, length]
typing.Annotated[__main__.Quantity, length]
_ShapeT_co’s bound ↩︎which seems like the goal for defining
__class_getitem__in the first place ↩︎