omlish 0.0.0.dev284__py3-none-any.whl → 0.0.0.dev285__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- omlish/__about__.py +2 -2
- omlish/dataclasses/__init__.py +58 -60
- omlish/dataclasses/api/__init__.py +25 -0
- omlish/dataclasses/api/classes/__init__.py +0 -0
- omlish/dataclasses/api/classes/conversion.py +30 -0
- omlish/dataclasses/api/classes/decorator.py +145 -0
- omlish/dataclasses/api/classes/make.py +109 -0
- omlish/dataclasses/api/classes/metadata.py +133 -0
- omlish/dataclasses/api/classes/params.py +78 -0
- omlish/dataclasses/api/fields/__init__.py +0 -0
- omlish/dataclasses/api/fields/building.py +120 -0
- omlish/dataclasses/api/fields/constructor.py +56 -0
- omlish/dataclasses/api/fields/conversion.py +191 -0
- omlish/dataclasses/api/fields/metadata.py +94 -0
- omlish/dataclasses/concerns/__init__.py +17 -0
- omlish/dataclasses/concerns/abc.py +15 -0
- omlish/dataclasses/concerns/copy.py +63 -0
- omlish/dataclasses/concerns/doc.py +53 -0
- omlish/dataclasses/concerns/eq.py +60 -0
- omlish/dataclasses/concerns/fields.py +119 -0
- omlish/dataclasses/concerns/frozen.py +133 -0
- omlish/dataclasses/concerns/hash.py +165 -0
- omlish/dataclasses/concerns/init.py +453 -0
- omlish/dataclasses/concerns/matchargs.py +27 -0
- omlish/dataclasses/concerns/mro.py +16 -0
- omlish/dataclasses/concerns/order.py +87 -0
- omlish/dataclasses/concerns/override.py +98 -0
- omlish/dataclasses/concerns/params.py +14 -0
- omlish/dataclasses/concerns/replace.py +48 -0
- omlish/dataclasses/concerns/repr.py +95 -0
- omlish/dataclasses/{impl → concerns}/slots.py +25 -1
- omlish/dataclasses/debug.py +2 -0
- omlish/dataclasses/errors.py +115 -0
- omlish/dataclasses/generation/__init__.py +0 -0
- omlish/dataclasses/generation/base.py +38 -0
- omlish/dataclasses/generation/compilation.py +258 -0
- omlish/dataclasses/generation/execution.py +195 -0
- omlish/dataclasses/generation/globals.py +83 -0
- omlish/dataclasses/generation/idents.py +6 -0
- omlish/dataclasses/generation/mangling.py +18 -0
- omlish/dataclasses/generation/manifests.py +20 -0
- omlish/dataclasses/generation/ops.py +97 -0
- omlish/dataclasses/generation/plans.py +35 -0
- omlish/dataclasses/generation/processor.py +174 -0
- omlish/dataclasses/generation/registry.py +42 -0
- omlish/dataclasses/generation/utils.py +83 -0
- omlish/dataclasses/{impl/reflect.py → inspect.py} +53 -90
- omlish/dataclasses/{impl/internals.py → internals.py} +26 -32
- omlish/dataclasses/metaclass/__init__.py +0 -0
- omlish/dataclasses/metaclass/bases.py +69 -0
- omlish/dataclasses/metaclass/confer.py +65 -0
- omlish/dataclasses/metaclass/meta.py +115 -0
- omlish/dataclasses/metaclass/specs.py +38 -0
- omlish/dataclasses/processing/__init__.py +0 -0
- omlish/dataclasses/processing/base.py +83 -0
- omlish/dataclasses/processing/driving.py +45 -0
- omlish/dataclasses/processing/priority.py +13 -0
- omlish/dataclasses/processing/registry.py +81 -0
- omlish/dataclasses/reflection.py +81 -0
- omlish/dataclasses/specs.py +224 -0
- omlish/dataclasses/tools/__init__.py +0 -0
- omlish/dataclasses/{impl → tools}/as_.py +23 -8
- omlish/dataclasses/tools/iter.py +27 -0
- omlish/dataclasses/tools/modifiers.py +52 -0
- omlish/dataclasses/tools/replace.py +17 -0
- omlish/dataclasses/tools/repr.py +12 -0
- omlish/dataclasses/{static.py → tools/static.py} +25 -4
- omlish/dataclasses/utils.py +54 -109
- omlish/diag/__init__.py +4 -4
- omlish/inject/impl/origins.py +1 -1
- omlish/lang/cached/function.py +4 -2
- omlish/marshal/objects/dataclasses.py +3 -7
- omlish/marshal/objects/helpers.py +3 -3
- omlish/secrets/marshal.py +1 -1
- omlish/secrets/secrets.py +1 -1
- omlish/sql/queries/base.py +1 -1
- omlish/typedvalues/marshal.py +2 -2
- {omlish-0.0.0.dev284.dist-info → omlish-0.0.0.dev285.dist-info}/METADATA +1 -1
- {omlish-0.0.0.dev284.dist-info → omlish-0.0.0.dev285.dist-info}/RECORD +83 -43
- omlish/dataclasses/impl/LICENSE +0 -279
- omlish/dataclasses/impl/__init__.py +0 -33
- omlish/dataclasses/impl/api.py +0 -278
- omlish/dataclasses/impl/copy.py +0 -30
- omlish/dataclasses/impl/errors.py +0 -53
- omlish/dataclasses/impl/fields.py +0 -245
- omlish/dataclasses/impl/frozen.py +0 -93
- omlish/dataclasses/impl/hashing.py +0 -86
- omlish/dataclasses/impl/init.py +0 -199
- omlish/dataclasses/impl/main.py +0 -93
- omlish/dataclasses/impl/metaclass.py +0 -235
- omlish/dataclasses/impl/metadata.py +0 -75
- omlish/dataclasses/impl/order.py +0 -57
- omlish/dataclasses/impl/overrides.py +0 -53
- omlish/dataclasses/impl/params.py +0 -128
- omlish/dataclasses/impl/processing.py +0 -24
- omlish/dataclasses/impl/replace.py +0 -40
- omlish/dataclasses/impl/repr.py +0 -66
- omlish/dataclasses/impl/simple.py +0 -50
- omlish/dataclasses/impl/utils.py +0 -167
- {omlish-0.0.0.dev284.dist-info → omlish-0.0.0.dev285.dist-info}/WHEEL +0 -0
- {omlish-0.0.0.dev284.dist-info → omlish-0.0.0.dev285.dist-info}/entry_points.txt +0 -0
- {omlish-0.0.0.dev284.dist-info → omlish-0.0.0.dev285.dist-info}/licenses/LICENSE +0 -0
- {omlish-0.0.0.dev284.dist-info → omlish-0.0.0.dev285.dist-info}/top_level.txt +0 -0
omlish/dataclasses/impl/main.py
DELETED
@@ -1,93 +0,0 @@
|
|
1
|
-
import abc
|
2
|
-
import dataclasses as dc
|
3
|
-
import typing as ta
|
4
|
-
|
5
|
-
from ... import check
|
6
|
-
from ... import lang
|
7
|
-
from .copy import CopyProcessor
|
8
|
-
from .fields import FieldsProcessor
|
9
|
-
from .frozen import FrozenProcessor
|
10
|
-
from .hashing import HashProcessor
|
11
|
-
from .init import InitProcessor
|
12
|
-
from .internals import FIELDS_ATTR
|
13
|
-
from .internals import PARAMS_ATTR
|
14
|
-
from .internals import Params
|
15
|
-
from .order import OrderProcessor
|
16
|
-
from .overrides import OverridesProcessor
|
17
|
-
from .params import ParamsExtras
|
18
|
-
from .processing import Processor
|
19
|
-
from .reflect import ClassInfo
|
20
|
-
from .replace import ReplaceProcessor
|
21
|
-
from .repr import ReprProcessor
|
22
|
-
from .simple import DocProcessor
|
23
|
-
from .simple import EqProcessor
|
24
|
-
from .simple import MatchArgsProcessor
|
25
|
-
from .slots import add_slots
|
26
|
-
|
27
|
-
|
28
|
-
MISSING = dc.MISSING
|
29
|
-
|
30
|
-
|
31
|
-
class MainProcessor:
|
32
|
-
def __init__(self, cls: type) -> None:
|
33
|
-
super().__init__()
|
34
|
-
|
35
|
-
self._cls = check.isinstance(cls, type)
|
36
|
-
self._info = info = ClassInfo(cls, _constructing=True)
|
37
|
-
|
38
|
-
check.not_in(FIELDS_ATTR, cls.__dict__)
|
39
|
-
check.is_(check.isinstance(cls.__dict__[PARAMS_ATTR], Params), info.params)
|
40
|
-
check.is_(check.isinstance(check.not_none(info.cls_metadata)[ParamsExtras], ParamsExtras), info.params_extras) # noqa
|
41
|
-
|
42
|
-
def _check_params(self) -> None:
|
43
|
-
if self._info.params.order and not self._info.params.eq:
|
44
|
-
raise ValueError('eq must be true if order is true')
|
45
|
-
|
46
|
-
@lang.cached_function
|
47
|
-
def _transform_slots(self) -> None:
|
48
|
-
if self._info.params.weakref_slot and not self._info.params.slots:
|
49
|
-
raise TypeError('weakref_slot is True but slots is False')
|
50
|
-
if not self._info.params.slots:
|
51
|
-
return
|
52
|
-
self._cls = add_slots(
|
53
|
-
self._cls,
|
54
|
-
is_frozen=self._info.params.frozen,
|
55
|
-
weakref_slot=self._info.params.weakref_slot,
|
56
|
-
)
|
57
|
-
|
58
|
-
PROCESSOR_TYPES: ta.ClassVar[ta.Sequence[type[Processor]]] = [
|
59
|
-
FieldsProcessor,
|
60
|
-
InitProcessor,
|
61
|
-
OverridesProcessor,
|
62
|
-
ReprProcessor,
|
63
|
-
EqProcessor,
|
64
|
-
OrderProcessor,
|
65
|
-
FrozenProcessor,
|
66
|
-
HashProcessor,
|
67
|
-
DocProcessor,
|
68
|
-
MatchArgsProcessor,
|
69
|
-
ReplaceProcessor,
|
70
|
-
CopyProcessor,
|
71
|
-
]
|
72
|
-
|
73
|
-
@lang.cached_function
|
74
|
-
def process(self) -> type:
|
75
|
-
self._check_params()
|
76
|
-
|
77
|
-
ps = [pcls(self._info) for pcls in self.PROCESSOR_TYPES]
|
78
|
-
|
79
|
-
for p in ps:
|
80
|
-
p.check()
|
81
|
-
|
82
|
-
for p in ps:
|
83
|
-
p.process()
|
84
|
-
|
85
|
-
self._transform_slots()
|
86
|
-
|
87
|
-
abc.update_abstractmethods(self._cls) # noqa
|
88
|
-
|
89
|
-
return self._cls
|
90
|
-
|
91
|
-
|
92
|
-
def process_class(cls: type) -> type:
|
93
|
-
return MainProcessor(cls).process()
|
@@ -1,235 +0,0 @@
|
|
1
|
-
"""
|
2
|
-
TODO:
|
3
|
-
- Rewrite lol
|
4
|
-
- Enum - enforce Abstract or Final
|
5
|
-
"""
|
6
|
-
import abc
|
7
|
-
import collections
|
8
|
-
import dataclasses as dc
|
9
|
-
import typing as ta
|
10
|
-
|
11
|
-
from ... import lang
|
12
|
-
from .api import MISSING
|
13
|
-
from .api import dataclass
|
14
|
-
from .api import field # noqa
|
15
|
-
from .params import MetaclassParams
|
16
|
-
from .params import get_metaclass_params
|
17
|
-
from .params import get_params
|
18
|
-
from .params import get_params_extras
|
19
|
-
|
20
|
-
|
21
|
-
T = ta.TypeVar('T')
|
22
|
-
|
23
|
-
|
24
|
-
##
|
25
|
-
|
26
|
-
|
27
|
-
_CONFER_PARAMS: tuple[str, ...] = (
|
28
|
-
'eq',
|
29
|
-
'frozen',
|
30
|
-
'kw_only',
|
31
|
-
)
|
32
|
-
|
33
|
-
_CONFER_PARAMS_EXTRAS: tuple[str, ...] = (
|
34
|
-
'reorder',
|
35
|
-
'cache_hash',
|
36
|
-
'generic_init',
|
37
|
-
'override',
|
38
|
-
)
|
39
|
-
|
40
|
-
_CONFER_METACLASS_PARAMS: tuple[str, ...] = (
|
41
|
-
'confer',
|
42
|
-
'final_subclasses',
|
43
|
-
'abstract_immediate_subclasses',
|
44
|
-
)
|
45
|
-
|
46
|
-
|
47
|
-
def confer_kwarg(out: dict[str, ta.Any], k: str, v: ta.Any) -> None:
|
48
|
-
if k in out:
|
49
|
-
if out[k] != v:
|
50
|
-
raise ValueError
|
51
|
-
else:
|
52
|
-
out[k] = v
|
53
|
-
|
54
|
-
|
55
|
-
def confer_kwargs(
|
56
|
-
bases: ta.Sequence[type],
|
57
|
-
kwargs: ta.Mapping[str, ta.Any],
|
58
|
-
) -> dict[str, ta.Any]:
|
59
|
-
out: dict[str, ta.Any] = {}
|
60
|
-
for base in bases:
|
61
|
-
if not dc.is_dataclass(base):
|
62
|
-
continue
|
63
|
-
|
64
|
-
if not (bmp := get_metaclass_params(base)).confer:
|
65
|
-
continue
|
66
|
-
|
67
|
-
for ck in bmp.confer:
|
68
|
-
if ck in kwargs:
|
69
|
-
continue
|
70
|
-
|
71
|
-
if ck in _CONFER_PARAMS:
|
72
|
-
confer_kwarg(out, ck, getattr(get_params(base), ck))
|
73
|
-
|
74
|
-
elif ck in _CONFER_PARAMS_EXTRAS:
|
75
|
-
confer_kwarg(out, ck, getattr(get_params_extras(base), ck))
|
76
|
-
|
77
|
-
elif ck in _CONFER_METACLASS_PARAMS:
|
78
|
-
confer_kwarg(out, ck, getattr(bmp, ck))
|
79
|
-
|
80
|
-
else:
|
81
|
-
raise KeyError(ck)
|
82
|
-
|
83
|
-
return out
|
84
|
-
|
85
|
-
|
86
|
-
##
|
87
|
-
|
88
|
-
|
89
|
-
class DataMeta(abc.ABCMeta):
|
90
|
-
def __new__(
|
91
|
-
mcls,
|
92
|
-
name,
|
93
|
-
bases,
|
94
|
-
namespace,
|
95
|
-
*,
|
96
|
-
|
97
|
-
abstract=False,
|
98
|
-
sealed=False,
|
99
|
-
final=False,
|
100
|
-
|
101
|
-
metadata=None,
|
102
|
-
**kwargs,
|
103
|
-
):
|
104
|
-
ckw = confer_kwargs(bases, kwargs)
|
105
|
-
nkw = {**kwargs, **ckw}
|
106
|
-
|
107
|
-
mcp = MetaclassParams(**{
|
108
|
-
mpa: nkw.pop(mpa)
|
109
|
-
for mpa in _CONFER_METACLASS_PARAMS
|
110
|
-
if mpa in nkw
|
111
|
-
})
|
112
|
-
|
113
|
-
mmd = {
|
114
|
-
MetaclassParams: mcp,
|
115
|
-
}
|
116
|
-
if metadata is not None:
|
117
|
-
metadata = collections.ChainMap(mmd, metadata)
|
118
|
-
else:
|
119
|
-
metadata = mmd
|
120
|
-
|
121
|
-
#
|
122
|
-
|
123
|
-
xbs: list[type] = []
|
124
|
-
|
125
|
-
if any(get_metaclass_params(b).abstract_immediate_subclasses for b in bases if dc.is_dataclass(b)):
|
126
|
-
abstract = True
|
127
|
-
|
128
|
-
final |= (mcp.final_subclasses and not abstract)
|
129
|
-
|
130
|
-
if final and abstract:
|
131
|
-
raise TypeError(f'Class cannot be abstract and final: {name!r}')
|
132
|
-
|
133
|
-
if abstract:
|
134
|
-
xbs.append(lang.Abstract)
|
135
|
-
if sealed:
|
136
|
-
xbs.append(lang.Sealed)
|
137
|
-
if final:
|
138
|
-
xbs.append(lang.Final)
|
139
|
-
|
140
|
-
if xbs:
|
141
|
-
if bases and bases[-1] is ta.Generic:
|
142
|
-
bases = (*bases[:-1], *xbs, bases[-1])
|
143
|
-
else:
|
144
|
-
bases = (*bases, *xbs)
|
145
|
-
if ob := namespace.get('__orig_bases__'):
|
146
|
-
if getattr(ob[-1], '__origin__', None) is ta.Generic:
|
147
|
-
namespace['__orig_bases__'] = (*ob[:-1], *xbs, ob[-1])
|
148
|
-
else:
|
149
|
-
namespace['__orig_bases__'] = (*ob, *xbs)
|
150
|
-
|
151
|
-
#
|
152
|
-
|
153
|
-
ofs: set[str] = set()
|
154
|
-
if any(issubclass(b, lang.Abstract) for b in bases) and nkw.get('override'):
|
155
|
-
ofs.update(a for a in namespace.get('__annotations__', []) if a not in namespace)
|
156
|
-
namespace.update((a, MISSING) for a in ofs)
|
157
|
-
|
158
|
-
#
|
159
|
-
|
160
|
-
cls = lang.super_meta(
|
161
|
-
super(),
|
162
|
-
mcls,
|
163
|
-
name,
|
164
|
-
bases,
|
165
|
-
namespace,
|
166
|
-
)
|
167
|
-
|
168
|
-
#
|
169
|
-
|
170
|
-
for a in ofs:
|
171
|
-
delattr(cls, a)
|
172
|
-
|
173
|
-
#
|
174
|
-
|
175
|
-
return dataclass(cls, metadata=metadata, **nkw)
|
176
|
-
|
177
|
-
|
178
|
-
##
|
179
|
-
|
180
|
-
|
181
|
-
# @ta.dataclass_transform(field_specifiers=(field,)) # FIXME: ctor
|
182
|
-
class Data(
|
183
|
-
eq=False,
|
184
|
-
order=False,
|
185
|
-
confer=frozenset([
|
186
|
-
'confer',
|
187
|
-
'final_subclasses',
|
188
|
-
]),
|
189
|
-
metaclass=DataMeta,
|
190
|
-
):
|
191
|
-
def __init__(self, *args, **kwargs):
|
192
|
-
# Typechecking barrier
|
193
|
-
super().__init__(*args, **kwargs)
|
194
|
-
|
195
|
-
def __init_subclass__(cls, **kwargs):
|
196
|
-
# Typechecking barrier
|
197
|
-
super().__init_subclass__(**kwargs)
|
198
|
-
|
199
|
-
|
200
|
-
class Frozen(
|
201
|
-
Data,
|
202
|
-
frozen=True,
|
203
|
-
eq=False,
|
204
|
-
order=False,
|
205
|
-
confer=frozenset([
|
206
|
-
*get_metaclass_params(Data).confer,
|
207
|
-
'frozen',
|
208
|
-
'reorder',
|
209
|
-
'cache_hash',
|
210
|
-
'override',
|
211
|
-
]),
|
212
|
-
):
|
213
|
-
pass
|
214
|
-
|
215
|
-
|
216
|
-
class Case(
|
217
|
-
Frozen,
|
218
|
-
abstract=True,
|
219
|
-
override=True,
|
220
|
-
final_subclasses=True,
|
221
|
-
abstract_immediate_subclasses=True,
|
222
|
-
):
|
223
|
-
pass
|
224
|
-
|
225
|
-
|
226
|
-
class Box(
|
227
|
-
Frozen,
|
228
|
-
ta.Generic[T],
|
229
|
-
generic_init=True,
|
230
|
-
confer=frozenset([
|
231
|
-
*get_metaclass_params(Frozen).confer,
|
232
|
-
'generic_init',
|
233
|
-
]),
|
234
|
-
):
|
235
|
-
v: T
|
@@ -1,75 +0,0 @@
|
|
1
|
-
import types
|
2
|
-
import typing as ta
|
3
|
-
|
4
|
-
from ... import lang
|
5
|
-
|
6
|
-
|
7
|
-
METADATA_ATTR = '__dataclass_metadata__'
|
8
|
-
|
9
|
-
Metadata: ta.TypeAlias = ta.Mapping[ta.Any, ta.Any]
|
10
|
-
|
11
|
-
EMPTY_METADATA: Metadata = types.MappingProxyType({})
|
12
|
-
|
13
|
-
_CLASS_MERGED_KEYS: set[str] = set()
|
14
|
-
CLASS_MERGED_KEYS: ta.AbstractSet = _CLASS_MERGED_KEYS
|
15
|
-
|
16
|
-
|
17
|
-
def _class_merged(o):
|
18
|
-
_CLASS_MERGED_KEYS.add(o)
|
19
|
-
return o
|
20
|
-
|
21
|
-
|
22
|
-
def get_merged_metadata(obj: ta.Any) -> Metadata:
|
23
|
-
cls = obj if isinstance(obj, type) else type(obj)
|
24
|
-
dct: dict[ta.Any, ta.Any] = {}
|
25
|
-
for cur in cls.__mro__[::-1]:
|
26
|
-
if not (smd := cur.__dict__.get(METADATA_ATTR)):
|
27
|
-
continue
|
28
|
-
for k, v in smd.items():
|
29
|
-
if k in CLASS_MERGED_KEYS:
|
30
|
-
dct.setdefault(k, []).extend(v)
|
31
|
-
else:
|
32
|
-
dct[k] = v
|
33
|
-
return dct
|
34
|
-
|
35
|
-
|
36
|
-
def _append_cls_md(k, v):
|
37
|
-
lang.get_caller_cls_dct(1).setdefault(METADATA_ATTR, {}).setdefault(k, []).append(v)
|
38
|
-
|
39
|
-
|
40
|
-
##
|
41
|
-
|
42
|
-
|
43
|
-
@_class_merged
|
44
|
-
class UserMetadata(lang.Marker):
|
45
|
-
pass
|
46
|
-
|
47
|
-
|
48
|
-
@lang.cls_dct_fn()
|
49
|
-
def metadata(cls_dct, *args) -> None:
|
50
|
-
cls_dct.setdefault(METADATA_ATTR, {}).setdefault(UserMetadata, []).extend(args)
|
51
|
-
|
52
|
-
|
53
|
-
##
|
54
|
-
|
55
|
-
|
56
|
-
@_class_merged
|
57
|
-
class Validate(lang.Marker):
|
58
|
-
pass
|
59
|
-
|
60
|
-
|
61
|
-
def validate(fn: ta.Callable[..., bool] | staticmethod) -> None:
|
62
|
-
_append_cls_md(Validate, fn)
|
63
|
-
|
64
|
-
|
65
|
-
##
|
66
|
-
|
67
|
-
|
68
|
-
@_class_merged
|
69
|
-
class Init(lang.Marker):
|
70
|
-
pass
|
71
|
-
|
72
|
-
|
73
|
-
def init(obj):
|
74
|
-
_append_cls_md(Init, obj)
|
75
|
-
return obj
|
omlish/dataclasses/impl/order.py
DELETED
@@ -1,57 +0,0 @@
|
|
1
|
-
import typing as ta
|
2
|
-
|
3
|
-
from .processing import Processor
|
4
|
-
from .utils import Namespace
|
5
|
-
from .utils import create_fn
|
6
|
-
from .utils import set_new_attribute
|
7
|
-
from .utils import tuple_str
|
8
|
-
|
9
|
-
|
10
|
-
def cmp_fn(
|
11
|
-
name: str,
|
12
|
-
op: str,
|
13
|
-
self_tuple: str,
|
14
|
-
other_tuple: str,
|
15
|
-
globals: Namespace, # noqa
|
16
|
-
) -> ta.Callable:
|
17
|
-
return create_fn(
|
18
|
-
name,
|
19
|
-
('self', 'other'),
|
20
|
-
[
|
21
|
-
'if other.__class__ is self.__class__:',
|
22
|
-
f' return {self_tuple}{op}{other_tuple}',
|
23
|
-
'return NotImplemented',
|
24
|
-
],
|
25
|
-
globals=globals,
|
26
|
-
)
|
27
|
-
|
28
|
-
|
29
|
-
class OrderProcessor(Processor):
|
30
|
-
def _process(self) -> None:
|
31
|
-
if not self._info.params.order:
|
32
|
-
return
|
33
|
-
|
34
|
-
flds = [f for f in self._info.instance_fields if f.compare]
|
35
|
-
self_tuple = tuple_str('self', flds)
|
36
|
-
other_tuple = tuple_str('other', flds)
|
37
|
-
for name, op in [
|
38
|
-
('__lt__', '<'),
|
39
|
-
('__le__', '<='),
|
40
|
-
('__gt__', '>'),
|
41
|
-
('__ge__', '>='),
|
42
|
-
]:
|
43
|
-
if set_new_attribute(
|
44
|
-
self._cls, # noqa
|
45
|
-
name,
|
46
|
-
cmp_fn(
|
47
|
-
name,
|
48
|
-
op,
|
49
|
-
self_tuple,
|
50
|
-
other_tuple,
|
51
|
-
globals=self._info.globals,
|
52
|
-
),
|
53
|
-
):
|
54
|
-
raise TypeError(
|
55
|
-
f'Cannot overwrite attribute {name} in class {self._cls.__name__}. '
|
56
|
-
f'Consider using functools.total_ordering',
|
57
|
-
)
|
@@ -1,53 +0,0 @@
|
|
1
|
-
from ... import lang
|
2
|
-
from .fields import field_assign
|
3
|
-
from .params import get_field_extras
|
4
|
-
from .processing import Processor
|
5
|
-
from .utils import create_fn
|
6
|
-
from .utils import set_new_attribute
|
7
|
-
|
8
|
-
|
9
|
-
class OverridesProcessor(Processor):
|
10
|
-
def _process(self) -> None:
|
11
|
-
for f in self._info.instance_fields:
|
12
|
-
fx = get_field_extras(f)
|
13
|
-
if not (fx.override or self._info.params_extras.override):
|
14
|
-
continue
|
15
|
-
|
16
|
-
if self._info.params.slots:
|
17
|
-
raise TypeError
|
18
|
-
|
19
|
-
self_name = '__dataclass_self__' if 'self' in self._info.fields else 'self'
|
20
|
-
|
21
|
-
getter = create_fn(
|
22
|
-
f.name,
|
23
|
-
(self_name,),
|
24
|
-
[f'return {self_name}.__dict__[{f.name!r}]'],
|
25
|
-
globals=self._info.globals,
|
26
|
-
return_type=lang.just(f.type),
|
27
|
-
)
|
28
|
-
prop = property(getter)
|
29
|
-
|
30
|
-
if not self._info.params.frozen:
|
31
|
-
setter = create_fn(
|
32
|
-
f.name,
|
33
|
-
(self_name, f'{f.name}: __dataclass_type_{f.name}__'),
|
34
|
-
[
|
35
|
-
field_assign(
|
36
|
-
self._info.params.frozen,
|
37
|
-
f.name,
|
38
|
-
f.name,
|
39
|
-
self_name,
|
40
|
-
True,
|
41
|
-
),
|
42
|
-
],
|
43
|
-
globals=self._info.globals,
|
44
|
-
locals={f'__dataclass_type_{f.name}__': f.type},
|
45
|
-
return_type=lang.just(None),
|
46
|
-
)
|
47
|
-
prop = prop.setter(setter)
|
48
|
-
|
49
|
-
set_new_attribute(
|
50
|
-
self._cls,
|
51
|
-
f.name,
|
52
|
-
prop,
|
53
|
-
)
|
@@ -1,128 +0,0 @@
|
|
1
|
-
"""
|
2
|
-
@dc.dataclass(frozen=True)
|
3
|
-
class Field_:
|
4
|
-
name: str | None = None
|
5
|
-
type: Any = None
|
6
|
-
default: Any | MISSING = MISSING
|
7
|
-
default_factory: Any | MISSING = MISSING
|
8
|
-
repr: bool = True
|
9
|
-
hash: bool | None = None
|
10
|
-
init: bool = True
|
11
|
-
compare: bool = True
|
12
|
-
metadata: Metadata | None = None
|
13
|
-
kw_only: bool | MISSING = MISSING
|
14
|
-
|
15
|
-
if sys.version_info >= (3, 13):
|
16
|
-
doc: str | None = None
|
17
|
-
|
18
|
-
_field_type: Any = None
|
19
|
-
|
20
|
-
|
21
|
-
@dc.dataclass(frozen=True)
|
22
|
-
class Params_:
|
23
|
-
init: bool = True
|
24
|
-
repr: bool = True
|
25
|
-
eq: bool = True
|
26
|
-
order: bool = False
|
27
|
-
unsafe_hash: bool = False
|
28
|
-
frozen: bool = False
|
29
|
-
|
30
|
-
match_args: bool = True
|
31
|
-
kw_only: bool = False
|
32
|
-
slots: bool = False
|
33
|
-
weakref_slot: bool = False
|
34
|
-
"""
|
35
|
-
import dataclasses as dc
|
36
|
-
import typing as ta
|
37
|
-
|
38
|
-
from ... import lang
|
39
|
-
from .internals import PARAMS_ATTR
|
40
|
-
from .internals import Params
|
41
|
-
from .metadata import EMPTY_METADATA
|
42
|
-
from .metadata import METADATA_ATTR
|
43
|
-
|
44
|
-
|
45
|
-
##
|
46
|
-
|
47
|
-
|
48
|
-
@dc.dataclass(frozen=True, kw_only=True)
|
49
|
-
class FieldExtras(lang.Final):
|
50
|
-
derive: ta.Callable[..., ta.Any] | None = None # TODO
|
51
|
-
coerce: bool | ta.Callable[[ta.Any], ta.Any] | None = None
|
52
|
-
validate: ta.Callable[[ta.Any], bool] | None = None
|
53
|
-
check_type: bool | type | tuple[type | None, ...] | None = None
|
54
|
-
override: bool = False
|
55
|
-
repr_fn: ta.Callable[[ta.Any], str | None] | None = None
|
56
|
-
repr_priority: int | None = None
|
57
|
-
frozen: bool | None = None # TODO
|
58
|
-
|
59
|
-
|
60
|
-
DEFAULT_FIELD_EXTRAS = FieldExtras()
|
61
|
-
|
62
|
-
|
63
|
-
def get_field_extras(f: dc.Field) -> FieldExtras:
|
64
|
-
if not isinstance(f, dc.Field):
|
65
|
-
raise TypeError(f)
|
66
|
-
return f.metadata.get(FieldExtras, DEFAULT_FIELD_EXTRAS)
|
67
|
-
|
68
|
-
|
69
|
-
##
|
70
|
-
|
71
|
-
|
72
|
-
def get_params_cls(obj: ta.Any) -> type | None:
|
73
|
-
if not isinstance(obj, type):
|
74
|
-
obj = type(obj)
|
75
|
-
for cur in obj.__mro__:
|
76
|
-
if PARAMS_ATTR in cur.__dict__:
|
77
|
-
return cur
|
78
|
-
return None
|
79
|
-
|
80
|
-
|
81
|
-
def get_params(obj: ta.Any) -> Params:
|
82
|
-
if not hasattr(obj, PARAMS_ATTR):
|
83
|
-
raise TypeError(obj)
|
84
|
-
return getattr(obj, PARAMS_ATTR)
|
85
|
-
|
86
|
-
|
87
|
-
##
|
88
|
-
|
89
|
-
|
90
|
-
@dc.dataclass(frozen=True, kw_only=True)
|
91
|
-
class ParamsExtras(lang.Final):
|
92
|
-
reorder: bool = False
|
93
|
-
cache_hash: bool = False
|
94
|
-
generic_init: bool = False
|
95
|
-
override: bool = False
|
96
|
-
repr_id: bool = False
|
97
|
-
|
98
|
-
|
99
|
-
DEFAULT_PARAMS_EXTRAS = ParamsExtras()
|
100
|
-
|
101
|
-
|
102
|
-
def get_params_extras(obj: ta.Any) -> ParamsExtras:
|
103
|
-
if (pcls := get_params_cls(obj)) is None:
|
104
|
-
raise TypeError(pcls)
|
105
|
-
|
106
|
-
md = pcls.__dict__.get(METADATA_ATTR, EMPTY_METADATA)
|
107
|
-
return md.get(ParamsExtras, DEFAULT_PARAMS_EXTRAS)
|
108
|
-
|
109
|
-
|
110
|
-
##
|
111
|
-
|
112
|
-
|
113
|
-
@dc.dataclass(frozen=True)
|
114
|
-
class MetaclassParams:
|
115
|
-
confer: frozenset[str] = frozenset()
|
116
|
-
final_subclasses: bool = False
|
117
|
-
abstract_immediate_subclasses: bool = False
|
118
|
-
|
119
|
-
|
120
|
-
DEFAULT_METACLASS_PARAMS = MetaclassParams()
|
121
|
-
|
122
|
-
|
123
|
-
def get_metaclass_params(obj: ta.Any) -> MetaclassParams:
|
124
|
-
if (pcls := get_params_cls(obj)) is None:
|
125
|
-
raise TypeError(pcls)
|
126
|
-
|
127
|
-
md = pcls.__dict__.get(METADATA_ATTR, EMPTY_METADATA)
|
128
|
-
return md.get(MetaclassParams, DEFAULT_METACLASS_PARAMS)
|
@@ -1,24 +0,0 @@
|
|
1
|
-
import typing as ta
|
2
|
-
|
3
|
-
from ... import lang
|
4
|
-
|
5
|
-
|
6
|
-
if ta.TYPE_CHECKING:
|
7
|
-
from .reflect import ClassInfo
|
8
|
-
|
9
|
-
|
10
|
-
class Processor(lang.Abstract):
|
11
|
-
def __init__(self, info: 'ClassInfo') -> None:
|
12
|
-
super().__init__()
|
13
|
-
self._cls = info.cls
|
14
|
-
self._info = info
|
15
|
-
|
16
|
-
def check(self) -> None:
|
17
|
-
pass
|
18
|
-
|
19
|
-
@lang.cached_function
|
20
|
-
def process(self) -> None:
|
21
|
-
self._process()
|
22
|
-
|
23
|
-
def _process(self) -> None:
|
24
|
-
raise NotImplementedError
|
@@ -1,40 +0,0 @@
|
|
1
|
-
import dataclasses as dc
|
2
|
-
|
3
|
-
from .fields import field_type
|
4
|
-
from .internals import FIELDS_ATTR
|
5
|
-
from .internals import FieldType
|
6
|
-
from .internals import is_dataclass_instance
|
7
|
-
from .processing import Processor
|
8
|
-
from .utils import set_new_attribute
|
9
|
-
|
10
|
-
|
11
|
-
MISSING = dc.MISSING
|
12
|
-
|
13
|
-
|
14
|
-
def replace(obj, /, **changes): # noqa
|
15
|
-
if not is_dataclass_instance(obj):
|
16
|
-
raise TypeError('replace() should be called on dataclass instances')
|
17
|
-
return _replace(obj, **changes)
|
18
|
-
|
19
|
-
|
20
|
-
def _replace(obj, /, **changes):
|
21
|
-
for f in getattr(obj, FIELDS_ATTR).values():
|
22
|
-
if (ft := field_type(f)) is FieldType.CLASS:
|
23
|
-
continue
|
24
|
-
|
25
|
-
if not f.init:
|
26
|
-
if f.name in changes:
|
27
|
-
raise TypeError(f'field {f.name} is declared with init=False, it cannot be specified with replace()')
|
28
|
-
continue
|
29
|
-
|
30
|
-
if f.name not in changes:
|
31
|
-
if ft is FieldType.INIT and f.default is MISSING:
|
32
|
-
raise TypeError(f'InitVar {f.name!r} must be specified with replace()')
|
33
|
-
changes[f.name] = getattr(obj, f.name)
|
34
|
-
|
35
|
-
return obj.__class__(**changes)
|
36
|
-
|
37
|
-
|
38
|
-
class ReplaceProcessor(Processor):
|
39
|
-
def _process(self) -> None:
|
40
|
-
set_new_attribute(self._cls, '__replace__', _replace)
|