Search code examples
pythongenericstyping

Annotating specific dataclass subclass in a signature


from dataclasses import dataclass


@dataclass
class BaseProduct:
    ...


@dataclass
class ProductA(BaseProduct):
    a_specific_id: int


@dataclass
class ProductSubmissionCommand:
    product_id: str
    product: BaseProduct


class AProductRequestSubmitter:
    def __call__(self, job_id: int, cmd: ProductSubmissionCommand):
        ...
        cmd.product.a_specific_id

mypy error is: error: "BaseProduct" has no attribute "a_specific_id"

How to annotate AProductRequestSubmitter.__call__ properly? This class is specific for AProduct, there are other submitters for different product types.

Is it possible to use Generic types or Literal values somehow? Or maybe cast or assert is an only way to go?


Solution

  • You have 2 possible ways.

    1. Ignore static typint by using an explicit getattr call

       class AProductRequestSubmitter:
           def __call__(self, job_id: int, cmd: ProductSubmissionCommand):
               ...
               getattr(cmd.product, 'a_specific_id')
      
    2. Use Generic to specialize ProductSubmissionCommand on a static typing point of view:

       T = TypeVar("T", bound=BaseProduct)
      
      
       @dataclass
       class ProductSubmissionCommand(Generic[T]):
           product_id: str
           product: T
      
      
       class AProductRequestSubmitter:
           def __call__(self, job_id: int, cmd: ProductSubmissionCommand[ProductA]):
               pass