Since 1.1.328 Pyright type checker has become more strict w.r.t. to detecting incompatible variable overrides.
Specifically code like this:
class MyParent:
my_field: int | str
class MyChild(MyParent):
my_field: int # `reportIncompatibleVariableOverride` detected here
Now triggers a type error, because of this failure scenario:
def mutate_parent(p: MyParent) -> None:
p.my_field = "foo"
def process_child(c: MyChild) -> None:
mutate_parent(c)
c.my_field # the typechecker believes the type is `int`, but the actual value at runtime is `"foo"` and the type is `str`
However, if MyParent
was a frozen dataclass everything would be fine β because Pyright would be convinced that the value isn't mutated when processing the value using the wider parent type.
A scenario where this is useful is interaction between GraphQL types and interfaces they implement. It's common for a GraphQL interface to be wider than the specific type that implements this. In order to represent this through Python inheritance, any such fields needs to be implemented as a Python method, rather than instance/class variables. This is because the return types of the former are interpreted as immutable by Pyright.
Therefore, I suggest that dataclasses created to represent Strawberry GraphQL types are frozen dataclasses. I don't think there is any real use case for mutating field values in an already constructed Python object.
I'm sure the solution is somewhere in PEP 681, especially because there are plenty of occurrences of the term frozen
in its text. However, it's not immediately clear to me how this should be done β I've never written a dataclass transform myself.
Happy to dig into it a little bit myself, if nobody else has an immediate idea how to do it though. :)
Pay now to fund the work behind this issue.
Get updates on progress being made.
Maintainer is rewarded once the issue is completed.
You're funding impactful open source efforts
You want to contribute to this effort
You want to get funding like this too