When a metaclass __get__ returns Intersection[_T, type[SomeGeneric[TypeVar]]], dataclass_transform field inheritance breaks for child classes.
from __future__ import annotations
from typing import TYPE_CHECKING, Any, ClassVar, Generic, dataclass_transform
from typing_extensions import TypeVar
import dataclasses
if TYPE_CHECKING:
from ty_extensions import Intersection
_T = TypeVar("_T")
_P = TypeVar("_P", default=Any)
_O = TypeVar("_O")
class Makeable(Generic[_P]):
def make(self) -> _P: ...
class MyMeta(type):
if TYPE_CHECKING:
def __get__(cls: _T, obj: object, owner: type[_O]) -> Intersection[_T, type[Makeable[_O]]]:
return cls
@dataclass_transform(kw_only_default=True)
class FigMeta(MyMeta):
def __new__(mcls, name, bases, attrs, **kw):
cls = super().__new__(mcls, name, bases, attrs)
if "__slots__" not in cls.__dict__:
cls = dataclasses.dataclass(cls, kw_only=True, slots=True)
return cls
class Fig(Makeable[_P], metaclass=FigMeta):
__slots__: ClassVar[tuple[str, ...]] = ()
class Parent:
class Config(Fig):
x: int = 0
class Child(Parent):
class Config(Parent.Config):
y: int = 1
Child.Config(x=1, y=2) # warning: y is unknown-argument
Parent's field x is recognized. Child's own field y is not.
The trigger is specifically a TypeVar inside a parameterized generic inside type[] inside the Intersection. Replacing Makeable[_O] with any of these makes the warning disappear:
Makeable[Any]
Makeable (bare)
object
Expected behavior: Child class fields should be recognized regardless of what Intersection contains.
Workaround: moving @dataclass_transform from the metaclass to the base class avoids the issue:
# Instead of:
@dataclass_transform(kw_only_default=True)
class FigMeta(MyMeta): ...
class Fig(Makeable[_P], metaclass=FigMeta): ...
# Do:
class FigMeta(MyMeta): ...
@dataclass_transform(kw_only_default=True)
class Fig(Makeable[_P], metaclass=FigMeta): ...
Both placements are valid per PEP 681, but only the base class placement works when the metaclass has __get__ returning Intersection[_T, type[Generic[TypeVar]]].
ty version: 0.0.30
When a metaclass
__get__returnsIntersection[_T, type[SomeGeneric[TypeVar]]],dataclass_transformfield inheritance breaks for child classes.Parent's field
xis recognized. Child's own fieldyis not.The trigger is specifically a
TypeVarinside a parameterized generic insidetype[]inside theIntersection. ReplacingMakeable[_O]with any of these makes the warning disappear:Makeable[Any]Makeable(bare)objectExpected behavior: Child class fields should be recognized regardless of what
Intersectioncontains.Workaround: moving
@dataclass_transformfrom the metaclass to the base class avoids the issue:Both placements are valid per PEP 681, but only the base class placement works when the metaclass has
__get__returningIntersection[_T, type[Generic[TypeVar]]].ty version: 0.0.30