python / mypy

Optional static typing for Python
https://www.mypy-lang.org/
Other
18.5k stars 2.83k forks source link

Support frozen=TYPE_CHECKING for dataclasses #16224

Open MGChecker opened 1 year ago

MGChecker commented 1 year ago

Feature

In a project I am working on, we would like to be able to annotate dataclasses such that usually, there values should not be changed, while allowing to do so at runtime (for some construction methods and testing, more or less.

To do so, we would like to specify @dataclasses.dataclass(frozen=typing.TYPE_CHECKING)

Pitch

This could help to detect misuse of classes without introducing strict runtime guarantees.

AlexWaygood commented 1 year ago

I think this would be doable on mypy's side, but I don't much like the idea. It seems pretty unsafe.

Have you considered using object.__setattr__ for your construction methods and tests? It can be used as an awkward workaround at runtime to set attributes on frozen dataclasses:

Python 3.11.5 (tags/v3.11.5:cce6ba9, Aug 24 2023, 14:38:34) [MSC v.1936 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> from dataclasses import dataclass
>>> @dataclass(frozen=True)
... class Foo: ...
...
>>> f = Foo()
>>> f.bar = 42
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<string>", line 4, in __setattr__
dataclasses.FrozenInstanceError: cannot assign to field 'bar'
>>> object.__setattr__(f, "bar", 42)
>>> f.bar
42
tmke8 commented 1 year ago

I think a workaround to achieve this is to create a wrapper around dataclass(...) and then annotate that wrapper with dataclass_transform where frozen_default is set to True. Though I'm actually not completely sure mypy already supports frozen_default.