The crux of the issue is that mypy does not support the following (working) pattern:
import msgspec as ms
class Base(ms.Struct, frozen=True):
...
class Child(Base): # error: Cannot inherit non-frozen dataclass from a frozen one [misc]
...
assert Child.__struct_config__.frozen is True
<...>frozen.py:8: error: Cannot inherit non-frozen dataclass from a frozen one [misc]
Found 1 error in 1 file (checked 1 source file)
From what I can gather, my options are to either add a # type: ignore[misc] everytime I inherit from my base class or directly inherit from Struct and dupe the config every time. But neither of those are satisfactory, so I’m opening this discussion in hopes of finding something better.
I get a different error from mypy when trying to reproduce this with some dummy fields
inherit_frozen_dataclass.py:10: error: Unexpected keyword argument "frozen" for "__init_subclass__" of "object" [call-arg]
inherit_frozen_dataclass.py:18: error: "type[Child]" has no attribute "__struct_config__" [attr-defined]
msgspec relies on dataclass_transform for typing, which makes assumptions that these behave like dataclasses and in that case frozen wouldn’t be inherited.
I think you should be able to use dataclass_transform with frozen_default=True like this to appease mypy.
import msgspec as ms
from typing import dataclass_transform
@dataclass_transform(field_specifiers=(ms.field,), frozen_default=True)
class Base(ms.Struct, frozen=True):
...
class Child(Base):
...
assert Child.__struct_config__.frozen is True