omlish 0.0.0.dev1__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.

Potentially problematic release.


This version of omlish might be problematic. Click here for more details.

Files changed (187) hide show
  1. omlish/__about__.py +7 -0
  2. omlish/__init__.py +0 -0
  3. omlish/argparse.py +223 -0
  4. omlish/asyncs/__init__.py +17 -0
  5. omlish/asyncs/anyio.py +23 -0
  6. omlish/asyncs/asyncio.py +19 -0
  7. omlish/asyncs/asyncs.py +76 -0
  8. omlish/asyncs/futures.py +179 -0
  9. omlish/asyncs/trio.py +11 -0
  10. omlish/c3.py +173 -0
  11. omlish/cached.py +9 -0
  12. omlish/check.py +231 -0
  13. omlish/collections/__init__.py +63 -0
  14. omlish/collections/_abc.py +156 -0
  15. omlish/collections/_io_abc.py +78 -0
  16. omlish/collections/cache/__init__.py +11 -0
  17. omlish/collections/cache/descriptor.py +188 -0
  18. omlish/collections/cache/impl.py +485 -0
  19. omlish/collections/cache/types.py +37 -0
  20. omlish/collections/coerce.py +337 -0
  21. omlish/collections/frozen.py +148 -0
  22. omlish/collections/identity.py +106 -0
  23. omlish/collections/indexed.py +75 -0
  24. omlish/collections/mappings.py +127 -0
  25. omlish/collections/ordered.py +81 -0
  26. omlish/collections/persistent.py +36 -0
  27. omlish/collections/skiplist.py +193 -0
  28. omlish/collections/sorted.py +126 -0
  29. omlish/collections/treap.py +228 -0
  30. omlish/collections/treapmap.py +144 -0
  31. omlish/collections/unmodifiable.py +174 -0
  32. omlish/collections/utils.py +110 -0
  33. omlish/configs/__init__.py +0 -0
  34. omlish/configs/flattening.py +147 -0
  35. omlish/configs/props.py +64 -0
  36. omlish/dataclasses/__init__.py +83 -0
  37. omlish/dataclasses/impl/__init__.py +6 -0
  38. omlish/dataclasses/impl/api.py +260 -0
  39. omlish/dataclasses/impl/as_.py +76 -0
  40. omlish/dataclasses/impl/exceptions.py +2 -0
  41. omlish/dataclasses/impl/fields.py +148 -0
  42. omlish/dataclasses/impl/frozen.py +55 -0
  43. omlish/dataclasses/impl/hashing.py +85 -0
  44. omlish/dataclasses/impl/init.py +173 -0
  45. omlish/dataclasses/impl/internals.py +118 -0
  46. omlish/dataclasses/impl/main.py +150 -0
  47. omlish/dataclasses/impl/metaclass.py +126 -0
  48. omlish/dataclasses/impl/metadata.py +74 -0
  49. omlish/dataclasses/impl/order.py +47 -0
  50. omlish/dataclasses/impl/params.py +150 -0
  51. omlish/dataclasses/impl/processing.py +16 -0
  52. omlish/dataclasses/impl/reflect.py +173 -0
  53. omlish/dataclasses/impl/replace.py +40 -0
  54. omlish/dataclasses/impl/repr.py +34 -0
  55. omlish/dataclasses/impl/simple.py +92 -0
  56. omlish/dataclasses/impl/slots.py +80 -0
  57. omlish/dataclasses/impl/utils.py +167 -0
  58. omlish/defs.py +193 -0
  59. omlish/dispatch/__init__.py +3 -0
  60. omlish/dispatch/dispatch.py +137 -0
  61. omlish/dispatch/functions.py +52 -0
  62. omlish/dispatch/methods.py +162 -0
  63. omlish/docker.py +149 -0
  64. omlish/dynamic.py +220 -0
  65. omlish/graphs/__init__.py +0 -0
  66. omlish/graphs/dot/__init__.py +19 -0
  67. omlish/graphs/dot/items.py +162 -0
  68. omlish/graphs/dot/rendering.py +147 -0
  69. omlish/graphs/dot/utils.py +30 -0
  70. omlish/graphs/trees.py +249 -0
  71. omlish/http/__init__.py +0 -0
  72. omlish/http/consts.py +20 -0
  73. omlish/http/wsgi.py +34 -0
  74. omlish/inject/__init__.py +85 -0
  75. omlish/inject/binder.py +12 -0
  76. omlish/inject/bindings.py +49 -0
  77. omlish/inject/eagers.py +21 -0
  78. omlish/inject/elements.py +43 -0
  79. omlish/inject/exceptions.py +49 -0
  80. omlish/inject/impl/__init__.py +0 -0
  81. omlish/inject/impl/bindings.py +19 -0
  82. omlish/inject/impl/elements.py +154 -0
  83. omlish/inject/impl/injector.py +182 -0
  84. omlish/inject/impl/inspect.py +98 -0
  85. omlish/inject/impl/private.py +109 -0
  86. omlish/inject/impl/providers.py +132 -0
  87. omlish/inject/impl/scopes.py +198 -0
  88. omlish/inject/injector.py +40 -0
  89. omlish/inject/inspect.py +14 -0
  90. omlish/inject/keys.py +43 -0
  91. omlish/inject/managed.py +24 -0
  92. omlish/inject/overrides.py +18 -0
  93. omlish/inject/private.py +29 -0
  94. omlish/inject/providers.py +111 -0
  95. omlish/inject/proxy.py +48 -0
  96. omlish/inject/scopes.py +84 -0
  97. omlish/inject/types.py +21 -0
  98. omlish/iterators.py +184 -0
  99. omlish/json.py +194 -0
  100. omlish/lang/__init__.py +112 -0
  101. omlish/lang/cached.py +267 -0
  102. omlish/lang/classes/__init__.py +24 -0
  103. omlish/lang/classes/abstract.py +74 -0
  104. omlish/lang/classes/restrict.py +137 -0
  105. omlish/lang/classes/simple.py +120 -0
  106. omlish/lang/classes/test/__init__.py +0 -0
  107. omlish/lang/classes/test/test_abstract.py +89 -0
  108. omlish/lang/classes/test/test_restrict.py +71 -0
  109. omlish/lang/classes/test/test_simple.py +58 -0
  110. omlish/lang/classes/test/test_virtual.py +72 -0
  111. omlish/lang/classes/virtual.py +130 -0
  112. omlish/lang/clsdct.py +67 -0
  113. omlish/lang/cmp.py +63 -0
  114. omlish/lang/contextmanagers.py +249 -0
  115. omlish/lang/datetimes.py +67 -0
  116. omlish/lang/descriptors.py +52 -0
  117. omlish/lang/functions.py +126 -0
  118. omlish/lang/imports.py +153 -0
  119. omlish/lang/iterables.py +54 -0
  120. omlish/lang/maybes.py +136 -0
  121. omlish/lang/objects.py +103 -0
  122. omlish/lang/resolving.py +50 -0
  123. omlish/lang/strings.py +128 -0
  124. omlish/lang/typing.py +92 -0
  125. omlish/libc.py +532 -0
  126. omlish/logs/__init__.py +9 -0
  127. omlish/logs/_abc.py +247 -0
  128. omlish/logs/configs.py +62 -0
  129. omlish/logs/filters.py +9 -0
  130. omlish/logs/formatters.py +67 -0
  131. omlish/logs/utils.py +20 -0
  132. omlish/marshal/__init__.py +52 -0
  133. omlish/marshal/any.py +25 -0
  134. omlish/marshal/base.py +201 -0
  135. omlish/marshal/base64.py +25 -0
  136. omlish/marshal/dataclasses.py +115 -0
  137. omlish/marshal/datetimes.py +90 -0
  138. omlish/marshal/enums.py +43 -0
  139. omlish/marshal/exceptions.py +7 -0
  140. omlish/marshal/factories.py +129 -0
  141. omlish/marshal/global_.py +33 -0
  142. omlish/marshal/iterables.py +57 -0
  143. omlish/marshal/mappings.py +66 -0
  144. omlish/marshal/naming.py +17 -0
  145. omlish/marshal/objects.py +106 -0
  146. omlish/marshal/optionals.py +49 -0
  147. omlish/marshal/polymorphism.py +147 -0
  148. omlish/marshal/primitives.py +43 -0
  149. omlish/marshal/registries.py +57 -0
  150. omlish/marshal/standard.py +80 -0
  151. omlish/marshal/utils.py +23 -0
  152. omlish/marshal/uuids.py +29 -0
  153. omlish/marshal/values.py +30 -0
  154. omlish/math.py +184 -0
  155. omlish/os.py +32 -0
  156. omlish/reflect.py +359 -0
  157. omlish/replserver/__init__.py +5 -0
  158. omlish/replserver/__main__.py +4 -0
  159. omlish/replserver/console.py +247 -0
  160. omlish/replserver/server.py +146 -0
  161. omlish/runmodule.py +28 -0
  162. omlish/stats.py +342 -0
  163. omlish/term.py +222 -0
  164. omlish/testing/__init__.py +7 -0
  165. omlish/testing/pydevd.py +225 -0
  166. omlish/testing/pytest/__init__.py +8 -0
  167. omlish/testing/pytest/helpers.py +35 -0
  168. omlish/testing/pytest/inject/__init__.py +1 -0
  169. omlish/testing/pytest/inject/harness.py +159 -0
  170. omlish/testing/pytest/plugins/__init__.py +20 -0
  171. omlish/testing/pytest/plugins/_registry.py +6 -0
  172. omlish/testing/pytest/plugins/logging.py +13 -0
  173. omlish/testing/pytest/plugins/pycharm.py +54 -0
  174. omlish/testing/pytest/plugins/repeat.py +19 -0
  175. omlish/testing/pytest/plugins/skips.py +32 -0
  176. omlish/testing/pytest/plugins/spacing.py +19 -0
  177. omlish/testing/pytest/plugins/switches.py +70 -0
  178. omlish/testing/testing.py +102 -0
  179. omlish/text/__init__.py +0 -0
  180. omlish/text/delimit.py +171 -0
  181. omlish/text/indent.py +50 -0
  182. omlish/text/parts.py +265 -0
  183. omlish-0.0.0.dev1.dist-info/LICENSE +21 -0
  184. omlish-0.0.0.dev1.dist-info/METADATA +17 -0
  185. omlish-0.0.0.dev1.dist-info/RECORD +187 -0
  186. omlish-0.0.0.dev1.dist-info/WHEEL +5 -0
  187. omlish-0.0.0.dev1.dist-info/top_level.txt +1 -0
@@ -0,0 +1,148 @@
1
+ import dataclasses as dc
2
+ import types
3
+ import typing as ta
4
+
5
+ from ... import check as check_
6
+ from ... import lang
7
+ from .internals import FieldType
8
+ from .internals import is_classvar
9
+ from .internals import is_initvar
10
+ from .params import get_field_extras
11
+
12
+ if ta.TYPE_CHECKING:
13
+ from . import api
14
+ else:
15
+ api = lang.proxy_import('.api', __package__)
16
+
17
+
18
+ MISSING = dc.MISSING
19
+
20
+
21
+ def field_type(f: dc.Field) -> FieldType:
22
+ if (ft := getattr(f, '_field_type')) is not None:
23
+ return FieldType(ft)
24
+ else:
25
+ return FieldType.INSTANCE
26
+
27
+
28
+ def has_default(f: dc.Field) -> bool:
29
+ return not (f.default is MISSING and f.default_factory is MISSING)
30
+
31
+
32
+ def preprocess_field(
33
+ cls: type,
34
+ a_name: str,
35
+ a_type: ta.Any,
36
+ default_kw_only: bool,
37
+ ) -> dc.Field:
38
+ default = getattr(cls, a_name, MISSING)
39
+ if isinstance(default, dc.Field):
40
+ f = default
41
+ else:
42
+ if isinstance(default, types.MemberDescriptorType):
43
+ # This is a field in __slots__, so it has no default value.
44
+ default = MISSING
45
+ f = api.field(default=default)
46
+
47
+ f.name = a_name
48
+ f.type = a_type
49
+
50
+ ft = FieldType.INSTANCE
51
+ if is_classvar(cls, f.type):
52
+ ft = FieldType.CLASS
53
+ if is_initvar(cls, f.type):
54
+ ft = FieldType.INIT
55
+ if ft in (FieldType.CLASS, FieldType.INIT):
56
+ if f.default_factory is not MISSING:
57
+ raise TypeError(f'field {f.name} cannot have a default factory')
58
+ f._field_type = ft.value # type: ignore
59
+
60
+ if ft in (FieldType.INSTANCE, FieldType.INIT):
61
+ if f.kw_only is MISSING:
62
+ f.kw_only = default_kw_only
63
+ else:
64
+ check_.arg(ft is FieldType.CLASS)
65
+ if f.kw_only is not MISSING:
66
+ raise TypeError(f'field {f.name} is a ClassVar but specifies kw_only')
67
+
68
+ if ft is FieldType.INSTANCE and f.default is not MISSING and f.default.__class__.__hash__ is None:
69
+ raise ValueError(f'mutable default {type(f.default)} for field {f.name} is not allowed: use default_factory')
70
+
71
+ return f
72
+
73
+
74
+ def field_assign(
75
+ frozen: bool,
76
+ name: str,
77
+ value: ta.Any,
78
+ self_name: str,
79
+ override: bool,
80
+ ) -> str:
81
+ if override:
82
+ return f'{self_name}.__dict__[{name!r}] = {value}'
83
+ if frozen:
84
+ return f'__dataclass_builtins_object__.__setattr__({self_name}, {name!r}, {value})'
85
+ return f'{self_name}.{name} = {value}'
86
+
87
+
88
+ def field_init(
89
+ f: dc.Field,
90
+ frozen: bool,
91
+ locals: dict[str, ta.Any],
92
+ self_name: str,
93
+ slots: bool,
94
+ ) -> ta.Sequence[str]:
95
+ default_name = f'__dataclass_dflt_{f.name}__'
96
+ fx = get_field_extras(f)
97
+
98
+ lines = []
99
+
100
+ if fx.coerce is not None:
101
+ cn = f'__dataclass_coerce__{f.name}__'
102
+ locals[cn] = fx.coerce
103
+ lines.append(f'{f.name} = {cn}({f.name})')
104
+
105
+ if fx.check is not None:
106
+ cn = f'__dataclass_check__{f.name}__'
107
+ locals[cn] = fx.check
108
+ lines.append(f'if not {cn}({f.name}): raise __dataclass_CheckException__')
109
+
110
+ if fx.check_type:
111
+ cn = f'__dataclass_check_type__{f.name}__'
112
+ locals[cn] = f.type
113
+ lines.append(
114
+ f'if not __dataclass_builtins_isinstance__({f.name}, {cn}): '
115
+ f'raise __dataclass_builtins_TypeError__({f.name}, {cn})'
116
+ )
117
+
118
+ value: str | None = None
119
+ if f.default_factory is not MISSING:
120
+ if f.init:
121
+ locals[default_name] = f.default_factory
122
+ value = (
123
+ f'{default_name}() '
124
+ f'if {f.name} is __dataclass_HAS_DEFAULT_FACTORY__ '
125
+ f'else {f.name}'
126
+ )
127
+ else:
128
+ locals[default_name] = f.default_factory
129
+ value = f'{default_name}()'
130
+
131
+ elif f.init:
132
+ if f.default is MISSING:
133
+ value = f.name
134
+ elif f.default is not MISSING:
135
+ locals[default_name] = f.default
136
+ value = f.name
137
+
138
+ else:
139
+ if slots and f.default is not MISSING:
140
+ locals[default_name] = f.default
141
+ value = default_name
142
+ else:
143
+ pass
144
+
145
+ if value is not None and field_type(f) is not FieldType.INIT:
146
+ lines.append(field_assign(frozen, f.name, value, self_name, fx.override)) # noqa
147
+
148
+ return lines
@@ -0,0 +1,55 @@
1
+ import dataclasses as dc
2
+ import typing as ta
3
+
4
+ from .processing import Processor
5
+ from .utils import Namespace
6
+ from .utils import create_fn
7
+ from .utils import set_new_attribute
8
+
9
+
10
+ def frozen_get_del_attr(
11
+ cls: type,
12
+ fields: ta.Sequence[dc.Field],
13
+ globals: Namespace,
14
+ ) -> tuple[ta.Callable, ta.Callable]:
15
+ locals = {
16
+ 'cls': cls,
17
+ 'FrozenInstanceError': dc.FrozenInstanceError,
18
+ }
19
+ condition = 'type(self) is cls'
20
+ if fields:
21
+ condition += ' or name in {' + ', '.join(repr(f.name) for f in fields) + '}'
22
+ return (
23
+ create_fn(
24
+ '__setattr__',
25
+ ('self', 'name', 'value'),
26
+ [
27
+ f'if {condition}:',
28
+ ' raise FrozenInstanceError(f"cannot assign to field {name!r}")',
29
+ f'super(cls, self).__setattr__(name, value)',
30
+ ],
31
+ locals=locals,
32
+ globals=globals,
33
+ ),
34
+ create_fn(
35
+ '__delattr__',
36
+ ('self', 'name'),
37
+ [
38
+ f'if {condition}:',
39
+ ' raise FrozenInstanceError(f"cannot delete field {name!r}")',
40
+ f'super(cls, self).__delattr__(name)',
41
+ ],
42
+ locals=locals,
43
+ globals=globals,
44
+ ),
45
+ )
46
+
47
+
48
+ class FrozenProcessor(Processor):
49
+ def _process(self) -> None:
50
+ if not self._info.params.frozen:
51
+ return
52
+
53
+ for fn in frozen_get_del_attr(self._cls, self._info.instance_fields, self._info.globals):
54
+ if set_new_attribute(self._cls, fn.__name__, fn):
55
+ raise TypeError(f'Cannot overwrite attribute {fn.__name__} in class {self._cls.__name__}')
@@ -0,0 +1,85 @@
1
+ import dataclasses as dc
2
+ import enum
3
+ import typing as ta
4
+
5
+ from .processing import Processor
6
+ from .utils import create_fn
7
+ from .utils import set_qualname
8
+ from .utils import tuple_str
9
+
10
+
11
+ class HashAction(enum.Enum):
12
+ SET_NONE = enum.auto()
13
+ ADD = enum.auto()
14
+ EXCEPTION = enum.auto()
15
+
16
+
17
+ # See https://bugs.python.org/issue32929#msg312829 for an if-statement version of this table.
18
+ HASH_ACTIONS: ta.Mapping[tuple[bool, bool, bool, bool], HashAction | None] = {
19
+ #
20
+ # +-------------------------------------- unsafe_hash?
21
+ # | +------------------------------- eq?
22
+ # | | +------------------------ frozen?
23
+ # | | | +---------------- has-explicit-hash?
24
+ # v v v v
25
+ (False, False, False, False): None,
26
+ (False, False, False, True): None,
27
+ (False, False, True, False): None,
28
+ (False, False, True, True): None,
29
+ (False, True, False, False): HashAction.SET_NONE,
30
+ (False, True, False, True): None,
31
+ (False, True, True, False): HashAction.ADD,
32
+ (False, True, True, True): None,
33
+ (True, False, False, False): HashAction.ADD,
34
+ (True, False, False, True): HashAction.EXCEPTION,
35
+ (True, False, True, False): HashAction.ADD,
36
+ (True, False, True, True): HashAction.EXCEPTION,
37
+ (True, True, False, False): HashAction.ADD,
38
+ (True, True, False, True): HashAction.EXCEPTION,
39
+ (True, True, True, False): HashAction.ADD,
40
+ (True, True, True, True): HashAction.EXCEPTION,
41
+ }
42
+
43
+
44
+ class HashProcessor(Processor):
45
+ CACHED_HASH_ATTR = '__dataclass_hash__'
46
+
47
+ def _build_hash_fn(self) -> ta.Callable:
48
+ flds = [f for f in self._info.instance_fields if (f.compare if f.hash is None else f.hash)]
49
+ self_tuple = tuple_str('self', flds)
50
+ if self._info.params_extras.cache_hash:
51
+ body = [
52
+ f'try: return self.{self.CACHED_HASH_ATTR}',
53
+ f'except AttributeError: object.__setattr__(self, {self.CACHED_HASH_ATTR!r}, h := hash({self_tuple}))',
54
+ f'return h',
55
+ ]
56
+ else:
57
+ body = [f'return hash({self_tuple})']
58
+ hash_fn = create_fn(
59
+ '__hash__',
60
+ ('self',),
61
+ body,
62
+ globals=self._info.globals,
63
+ )
64
+ return set_qualname(self._cls, hash_fn) # noqa
65
+
66
+ def _process(self) -> None:
67
+ class_hash = self._cls.__dict__.get('__hash__', dc.MISSING)
68
+ has_explicit_hash = not (class_hash is dc.MISSING or (class_hash is None and '__eq__' in self._cls.__dict__))
69
+
70
+ match (hash_action := HASH_ACTIONS[(
71
+ bool(self._info.params.unsafe_hash),
72
+ bool(self._info.params.eq),
73
+ bool(self._info.params.frozen),
74
+ has_explicit_hash,
75
+ )]):
76
+ case HashAction.SET_NONE:
77
+ self._cls.__hash__ = None # type: ignore
78
+ case HashAction.ADD:
79
+ self._cls.__hash__ = self._build_hash_fn() # type: ignore
80
+ case HashAction.EXCEPTION:
81
+ raise TypeError(f'Cannot overwrite attribute __hash__ in class {self._cls.__name__}')
82
+ case None:
83
+ pass
84
+ case _:
85
+ raise ValueError(hash_action)
@@ -0,0 +1,173 @@
1
+ import dataclasses as dc
2
+ import inspect
3
+ import typing as ta
4
+
5
+ from ... import lang
6
+ from .exceptions import CheckException
7
+ from .fields import field_init
8
+ from .fields import field_type
9
+ from .fields import has_default
10
+ from .internals import FieldType
11
+ from .internals import HAS_DEFAULT_FACTORY
12
+ from .internals import POST_INIT_NAME
13
+ from .metadata import Check
14
+ from .metadata import Init
15
+ from .processing import Processor
16
+ from .reflect import ClassInfo
17
+ from .utils import Namespace
18
+ from .utils import create_fn
19
+ from .utils import set_new_attribute
20
+
21
+
22
+ MISSING = dc.MISSING
23
+
24
+
25
+ class InitFields(ta.NamedTuple):
26
+ all: ta.Sequence[dc.Field]
27
+ ordered: ta.Sequence[dc.Field]
28
+ std: ta.Sequence[dc.Field]
29
+ kw_only: ta.Sequence[dc.Field]
30
+
31
+
32
+ def get_init_fields(fields: ta.Iterable[dc.Field], *, reorder: bool = False) -> InitFields:
33
+ all_init_fields = [f for f in fields if field_type(f) in (FieldType.INSTANCE, FieldType.INIT)]
34
+ ordered_init_fields = list(all_init_fields)
35
+ if reorder:
36
+ ordered_init_fields.sort(key=lambda f: (has_default(f), not f.kw_only))
37
+ std_init_fields, kw_only_init_fields = (
38
+ tuple(f1 for f1 in ordered_init_fields if f1.init and not f1.kw_only),
39
+ tuple(f1 for f1 in ordered_init_fields if f1.init and f1.kw_only),
40
+ )
41
+ return InitFields(
42
+ all=all_init_fields,
43
+ ordered=ordered_init_fields,
44
+ std=std_init_fields,
45
+ kw_only=kw_only_init_fields,
46
+ )
47
+
48
+
49
+ def init_param(f: dc.Field) -> str:
50
+ if not has_default(f):
51
+ default = ''
52
+ elif f.default is not MISSING:
53
+ default = f' = __dataclass_dflt_{f.name}__'
54
+ elif f.default_factory is not MISSING:
55
+ default = ' = __dataclass_HAS_DEFAULT_FACTORY__'
56
+ return f'{f.name}: __dataclass_type_{f.name}__{default}' # noqa
57
+
58
+
59
+ class InitBuilder:
60
+
61
+ def __init__(
62
+ self,
63
+ info: ClassInfo,
64
+ fields: ta.Mapping[str, dc.Field],
65
+ has_post_init: bool,
66
+ self_name: str,
67
+ globals: Namespace,
68
+ ) -> None:
69
+ super().__init__()
70
+
71
+ self._info = info
72
+ self._fields = fields
73
+ self._has_post_init = has_post_init
74
+ self._self_name = self_name
75
+ self._globals = globals
76
+
77
+ @lang.cached_function
78
+ def build(self) -> ta.Callable:
79
+ ifs = get_init_fields(self._fields.values(), reorder=self._info.params_extras.reorder)
80
+
81
+ seen_default = None
82
+ for f in ifs.std:
83
+ if f.init:
84
+ if has_default(f):
85
+ seen_default = f
86
+ elif seen_default:
87
+ raise TypeError(f'non-default argument {f.name!r} follows default argument {seen_default.name!r}')
88
+
89
+ locals: dict[str, ta.Any] = {}
90
+
91
+ if self._info.params_extras.generic_init:
92
+ get_fty = lambda f: self._info.generic_replaced_field_annotations[f.name]
93
+ else:
94
+ get_fty = lambda f: f.type
95
+ locals.update({f'__dataclass_type_{f.name}__': get_fty(f) for f in ifs.all})
96
+
97
+ locals.update({
98
+ '__dataclass_HAS_DEFAULT_FACTORY__': HAS_DEFAULT_FACTORY,
99
+ '__dataclass_builtins_object__': object,
100
+ '__dataclass_builtins_isinstance__': isinstance,
101
+ '__dataclass_builtins_TypeError__': TypeError,
102
+ '__dataclass_CheckException__': CheckException,
103
+ })
104
+
105
+ body_lines: list[str] = []
106
+ for f in ifs.all:
107
+ f_lines = field_init(
108
+ f,
109
+ self._info.params.frozen,
110
+ locals,
111
+ self._self_name,
112
+ self._info.params12.slots,
113
+ )
114
+
115
+ if f_lines:
116
+ body_lines.extend(f_lines)
117
+
118
+ if self._has_post_init:
119
+ params_str = ','.join(f.name for f in ifs.all if field_type(f) is FieldType.INIT)
120
+ body_lines.append(f'{self._self_name}.{POST_INIT_NAME}({params_str})')
121
+
122
+ for i, fn in enumerate(self._info.merged_metadata.get(Check, [])):
123
+ if isinstance(fn, staticmethod):
124
+ fn = fn.__func__
125
+ cn = f'__dataclass_check_{i}__'
126
+ locals[cn] = fn
127
+ csig = inspect.signature(fn)
128
+ cas = ', '.join(p.name for p in csig.parameters.values())
129
+ body_lines.append(f'if not {cn}({cas}): raise __dataclass_CheckException__')
130
+
131
+ for i, fn in enumerate(self._info.merged_metadata.get(Init, [])):
132
+ cn = f'__dataclass_init_{i}__'
133
+ locals[cn] = fn
134
+ body_lines.append(f'{cn}({self._self_name})')
135
+
136
+ if not body_lines:
137
+ body_lines = ['pass']
138
+
139
+ _init_params = [init_param(f) for f in ifs.std]
140
+ if ifs.kw_only:
141
+ _init_params += ['*']
142
+ _init_params += [init_param(f) for f in ifs.kw_only]
143
+
144
+ return create_fn(
145
+ '__init__',
146
+ [self._self_name] + _init_params,
147
+ body_lines,
148
+ locals=locals,
149
+ globals=self._globals,
150
+ return_type=lang.just(None),
151
+ )
152
+
153
+
154
+ class InitProcessor(Processor):
155
+ def _process(self) -> None:
156
+ if not self._info.params.init:
157
+ return
158
+
159
+ has_post_init = hasattr(self._cls, POST_INIT_NAME)
160
+ self_name = '__dataclass_self__' if 'self' in self._info.fields else 'self'
161
+
162
+ init = InitBuilder(
163
+ ClassInfo(self._cls),
164
+ self._info.fields,
165
+ has_post_init,
166
+ self_name,
167
+ self._info.globals,
168
+ ).build()
169
+ set_new_attribute(
170
+ self._cls,
171
+ '__init__',
172
+ init,
173
+ )
@@ -0,0 +1,118 @@
1
+ import dataclasses as dc
2
+ import enum
3
+ import sys
4
+ import types
5
+ import typing as ta
6
+
7
+
8
+ ##
9
+
10
+
11
+ HAS_DEFAULT_FACTORY = dc._HAS_DEFAULT_FACTORY # type: ignore # noqa
12
+
13
+ FIELDS_ATTR = dc._FIELDS # type: ignore # noqa
14
+ PARAMS_ATTR = dc._PARAMS # type: ignore # noqa
15
+
16
+ POST_INIT_NAME = dc._POST_INIT_NAME # type: ignore # noqa
17
+
18
+ Params = dc._DataclassParams # type: ignore # noqa
19
+
20
+
21
+ ##
22
+
23
+
24
+ is_dataclass_instance = dc._is_dataclass_instance # type: ignore # noqa
25
+
26
+
27
+ ##
28
+
29
+
30
+ ATOMIC_TYPES: ta.FrozenSet[type]
31
+
32
+ if hasattr(dc, '_ATOMIC_TYPES'):
33
+ ATOMIC_TYPES = getattr(dc, '_ATOMIC_TYPES')
34
+
35
+ else:
36
+ ATOMIC_TYPES = frozenset({
37
+ types.NoneType,
38
+ bool,
39
+ int,
40
+ float,
41
+ str,
42
+
43
+ complex,
44
+ bytes,
45
+
46
+ types.EllipsisType,
47
+ types.NotImplementedType,
48
+ types.CodeType,
49
+ types.BuiltinFunctionType,
50
+ types.FunctionType,
51
+ type,
52
+ range,
53
+ property,
54
+ })
55
+
56
+
57
+ ##
58
+
59
+
60
+ def _patch_missing_ctor() -> None:
61
+ # dc.asdict uses copy.deepcopy which instantiates new _MISSING_TYPE objects which do not pass the 'foo is MISSING'
62
+ # checks used throughout dataclasses code. Code should not depend on this behavior but it is a debugging landmine.
63
+ if dc._MISSING_TYPE.__new__ is object.__new__: # noqa
64
+ def _MISSING_TYPE_new(cls): # noqa
65
+ return dc.MISSING
66
+ dc._MISSING_TYPE.__new__ = _MISSING_TYPE_new # type: ignore # noqa
67
+
68
+
69
+ ##
70
+
71
+
72
+ class FieldType(enum.Enum):
73
+ INSTANCE = dc._FIELD # type: ignore # noqa
74
+ CLASS = dc._FIELD_CLASSVAR # type: ignore # noqa
75
+ INIT = dc._FIELD_INITVAR # type: ignore # noqa
76
+
77
+
78
+ _SELF_MODULE = None
79
+
80
+
81
+ def _self_module():
82
+ global _SELF_MODULE
83
+ if _SELF_MODULE is None:
84
+ _SELF_MODULE = sys.modules[__package__.rpartition('.')[0]]
85
+ return _SELF_MODULE
86
+
87
+
88
+ def is_classvar(cls: type, ty: ta.Any) -> bool:
89
+ return (
90
+ dc._is_classvar(ty, ta) # type: ignore # noqa
91
+ or (isinstance(ty, str) and dc._is_type(ty, cls, ta, ta.ClassVar, dc._is_classvar)) # type: ignore # noqa
92
+ )
93
+
94
+
95
+ def is_initvar(cls: type, ty: ta.Any) -> bool:
96
+ return (
97
+ dc._is_initvar(ty, dc) # type: ignore # noqa
98
+ or (
99
+ isinstance(ty, str)
100
+ and any(
101
+ dc._is_type(ty, cls, mod, dc.InitVar, dc._is_initvar) # type: ignore # noqa
102
+ for mod in (dc, _self_module())
103
+ )
104
+ )
105
+ )
106
+
107
+
108
+ def is_kw_only(cls: type, ty: ta.Any) -> bool:
109
+ return (
110
+ dc._is_kw_only(ty, dc) # type: ignore # noqa
111
+ or (
112
+ isinstance(ty, str)
113
+ and any(
114
+ dc._is_type(ty, cls, mod, dc.KW_ONLY, dc._is_kw_only) # type: ignore # noqa
115
+ for mod in (dc, _self_module())
116
+ )
117
+ )
118
+ )