mit-ll-responsible-ai/hydra-zen

Problems encountered in handling inheritance

WhenMelancholy opened this issue · 2 comments

A minimal code example for reproducibility:

from dataclasses import dataclass, field
from typing import Type, Optional, Literal, Tuple, Any
import hydra_zen as zen
@dataclass
class A:
    x = 1

@dataclass
class B(A):
    son: Tuple[A, ...] = field(default_factory=tuple)
    
conf = zen.just(
    B(
        son=(A(), A()),
    )
)
print(to_yaml(conf))

Expected output:

_target_: __main__.B
son:
- _target_: __main__.A
- _target_: __main__.A

Actual output:

ValidationError: Invalid type assigned: Builds_A is not a subclass of A. value: 
    full_key: son[0]
    reference_type=Tuple[A, ...]
    object_type=list

Additional explanation: If the code is written in the way below, the problem can be avoided, but it would lose the advantages brought by type checking.

@dataclass
class B(A):
    son: Tuple[Any, ...] = field(default_factory=tuple)
rsokl commented

It might take me a while to look into this, and I suspect that a fix may be too messy. Here is a hack that you can do in the meantime:

from dataclasses import dataclass, field
from typing import Type, Optional, Literal, Tuple, Any, TYPE_CHECKING
from typing_extensions import TypeAlias
import hydra_zen as zen

@dataclass
class A:
    x :int = 1

TypeA: TypeAlias = A if TYPE_CHECKING else Any

@dataclass
class B(A):
    son: Tuple[TypeA, ...] = field(default_factory=tuple)
    
conf = zen.just(
    B(
        son=(A(), A()),
    )
)
print(to_yaml(conf))

This lets the type checkers see A and keeps Hydra's runtime checks from blocking you.

Closing this as I don't anticipate being able to find a solution for this and I think the above proposed work around is a reasonable one.