1 """Utility to create classes from which frozen or mutable dataclasses can be derived.
3 This module enabled a non-breaking transition from mutable to frozen dataclasses
4 derived from EntityDescription and sub classes thereof.
7 from __future__
import annotations
11 from typing
import TYPE_CHECKING, Any, cast, dataclass_transform
14 from _typeshed
import DataclassInstance
17 def _class_fields(cls: type, kw_only: bool) -> list[tuple[str, Any, Any]]:
18 """Return a list of dataclass fields.
20 Extracted from dataclasses._process_class.
22 cls_annotations = cls.__dict__.
get(
"__annotations__", {})
24 cls_fields: list[dataclasses.Field[Any]] = []
26 _dataclasses = sys.modules[dataclasses.__name__]
27 for name, _type
in cls_annotations.items():
29 if dataclasses._is_kw_only(type, _dataclasses)
or (
30 isinstance(_type, str)
31 and dataclasses._is_type(
36 dataclasses._is_kw_only,
42 cls_fields.append(dataclasses._get_field(cls, name, _type, kw_only))
44 return [(field.name, field.type, field)
for field
in cls_fields]
47 @dataclass_transform(
field_specifiers=(dataclasses.field, dataclasses.Field),
52 """Metaclass which which makes classes which behave like a dataclass.
54 This allows child classes to be either mutable or frozen dataclasses.
57 def _make_dataclass(cls, name: str, bases: tuple[type, ...], kw_only: bool) ->
None:
59 dataclass_bases = [getattr(base,
"_dataclass", base)
for base
in bases]
60 cls.
_dataclass_dataclass = dataclasses.make_dataclass(
61 name, class_fields, bases=
tuple(dataclass_bases), frozen=
True
67 bases: tuple[type, ...],
68 namespace: dict[Any, Any],
69 frozen_or_thawed: bool =
False,
72 """Pop frozen_or_thawed and store it in the namespace."""
73 namespace[
"_FrozenOrThawed__frozen_or_thawed"] = frozen_or_thawed
74 return super().
__new__(mcs, name, bases, namespace)
79 bases: tuple[type, ...],
80 namespace: dict[Any, Any],
83 """Optionally create a dataclass and store it in cls._dataclass.
85 A dataclass will be created if frozen_or_thawed is set, if not we assume the
86 class will be a real dataclass, i.e. it's decorated with @dataclass.
88 if not namespace[
"_FrozenOrThawed__frozen_or_thawed"]:
90 if all(dataclasses.is_dataclass(base)
for base
in bases):
94 annotations: dict = {}
95 for parent
in cls.__mro__[::-1]:
98 annotations |= parent.__annotations__
108 def __new__(*args: Any, **kwargs: Any) -> object:
109 """Create a new instance.
111 The function has no named arguments to avoid name collisions with dataclass
115 if dataclasses.is_dataclass(cls):
117 cls = cast(type[DataclassInstance], cls)
118 return object.__new__(cls)
119 return cls.
_dataclass_dataclass(*_args, **kwargs)
123
Any __new__(mcs, str name, tuple[type,...] bases, dict[Any, Any] namespace, bool frozen_or_thawed=False, **Any kwargs)
None __init__(cls, str name, tuple[type,...] bases, dict[Any, Any] namespace, **Any kwargs)
None _make_dataclass(cls, str name, tuple[type,...] bases, bool kw_only)
web.Response get(self, web.Request request, str config_key)
list[tuple[str, Any, Any]] _class_fields(type cls, bool kw_only)