Let's say I have the following dataclasses:
@dataclass
class Product:
color: str
@dataclass
class Wrench(Product):
pass
@dataclass
class Hammer(Product):
pass
I'm trying to create a new dataclass called Order with two fields, both fields must have the same subclass of Product. I could create the Order class like so:
@dataclass
class Order:
primary_product: Product
secondary_product: Product
But this doesn't validate the same Product subclass condition I stated above:
product1 = Wrench(color="Yellow")
product2 = Hammer(color="Black")
order = Order(primary_product=product1, secondary_product=product2) # NO ERROR
The following implementation of Order with generics gets me some of the way there:
from typing import Generic, TypeVar
T = TypeVar("T")
@dataclass
class Order(Generic[T]):
primary_product: T
secondary_product: T
product1 = Wrench(color="Yellow")
product2 = Wrench(color="White")
product3 = Hammer(color="Black")
order1 = Order[Wrench](primary_product=product1, secondary_product=product2)
order2 = Order[Wrench](primary_product=product1, secondary_product=product3) # error: Argument "secondary_product" to "Order" has incompatible type "Hammer"; expected "Wrench"
It's annoying to pass the target Product subclass (Wrench in the case above) to Order on every object initialization. Moreover, this doesn't ensure both fields are products:
order1 = Order[int](primary_product=1, secondary_product=2) # NO ERROR
Is there anyway to achieve this or am I pushing the limits of mypy and Python's type hints too far?