omlish 0.0.0.dev447__py3-none-any.whl → 0.0.0.dev484__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.
- omlish/.omlish-manifests.json +12 -0
- omlish/__about__.py +15 -15
- omlish/argparse/all.py +17 -9
- omlish/argparse/cli.py +16 -3
- omlish/argparse/utils.py +21 -0
- omlish/asyncs/asyncio/rlock.py +110 -0
- omlish/asyncs/asyncio/sync.py +43 -0
- omlish/asyncs/asyncio/utils.py +2 -0
- omlish/asyncs/sync.py +25 -0
- omlish/bootstrap/_marshal.py +1 -1
- omlish/bootstrap/diag.py +12 -21
- omlish/bootstrap/main.py +2 -5
- omlish/bootstrap/sys.py +27 -28
- omlish/cexts/__init__.py +0 -0
- omlish/cexts/include/omlish/omlish.hh +1 -0
- omlish/collections/__init__.py +13 -1
- omlish/collections/attrregistry.py +210 -0
- omlish/collections/cache/impl.py +1 -0
- omlish/collections/identity.py +1 -0
- omlish/collections/mappings.py +28 -0
- omlish/collections/trie.py +5 -1
- omlish/collections/utils.py +77 -0
- omlish/concurrent/all.py +2 -1
- omlish/concurrent/futures.py +25 -0
- omlish/concurrent/threadlets.py +1 -1
- omlish/daemons/reparent.py +2 -3
- omlish/daemons/spawning.py +2 -3
- omlish/dataclasses/__init__.py +2 -0
- omlish/dataclasses/impl/api/classes/decorator.py +3 -0
- omlish/dataclasses/impl/api/classes/make.py +3 -0
- omlish/dataclasses/impl/concerns/repr.py +15 -2
- omlish/dataclasses/impl/configs.py +97 -37
- omlish/dataclasses/impl/generation/compilation.py +21 -19
- omlish/dataclasses/impl/generation/globals.py +1 -0
- omlish/dataclasses/impl/generation/ops.py +1 -0
- omlish/dataclasses/impl/generation/processor.py +105 -24
- omlish/dataclasses/impl/processing/base.py +8 -0
- omlish/dataclasses/impl/processing/driving.py +8 -8
- omlish/dataclasses/specs.py +1 -0
- omlish/dataclasses/tools/modifiers.py +5 -0
- omlish/diag/cmds/__init__.py +0 -0
- omlish/diag/{lslocks.py → cmds/lslocks.py} +6 -6
- omlish/diag/{lsof.py → cmds/lsof.py} +6 -6
- omlish/diag/{ps.py → cmds/ps.py} +6 -6
- omlish/diag/pycharm.py +16 -2
- omlish/diag/pydevd.py +58 -40
- omlish/diag/replserver/console.py +1 -1
- omlish/dispatch/__init__.py +18 -12
- omlish/dispatch/methods.py +50 -140
- omlish/dom/rendering.py +1 -1
- omlish/formats/dotenv.py +1 -1
- omlish/formats/json/stream/__init__.py +13 -0
- omlish/funcs/guard.py +225 -0
- omlish/graphs/dot/rendering.py +1 -1
- omlish/http/all.py +44 -4
- omlish/http/clients/asyncs.py +33 -27
- omlish/http/clients/base.py +17 -1
- omlish/http/clients/coro/__init__.py +0 -0
- omlish/http/clients/coro/sync.py +171 -0
- omlish/http/clients/default.py +208 -29
- omlish/http/clients/executor.py +56 -0
- omlish/http/clients/httpx.py +72 -11
- omlish/http/clients/middleware.py +181 -0
- omlish/http/clients/sync.py +33 -27
- omlish/http/clients/syncasync.py +49 -0
- omlish/http/clients/urllib.py +6 -3
- omlish/http/coro/client/connection.py +15 -6
- omlish/http/coro/io.py +2 -0
- omlish/http/flasky/__init__.py +40 -0
- omlish/http/flasky/_compat.py +2 -0
- omlish/http/flasky/api.py +82 -0
- omlish/http/flasky/app.py +203 -0
- omlish/http/flasky/cvs.py +59 -0
- omlish/http/flasky/requests.py +20 -0
- omlish/http/flasky/responses.py +23 -0
- omlish/http/flasky/routes.py +23 -0
- omlish/http/flasky/types.py +15 -0
- omlish/http/urls.py +67 -0
- omlish/inject/__init__.py +38 -18
- omlish/inject/_dataclasses.py +4986 -0
- omlish/inject/binder.py +4 -48
- omlish/inject/elements.py +27 -0
- omlish/inject/helpers/__init__.py +0 -0
- omlish/inject/{utils.py → helpers/constfn.py} +3 -3
- omlish/inject/{tags.py → helpers/id.py} +2 -2
- omlish/inject/helpers/multis.py +143 -0
- omlish/inject/helpers/wrappers.py +54 -0
- omlish/inject/impl/elements.py +47 -17
- omlish/inject/impl/injector.py +20 -19
- omlish/inject/impl/inspect.py +10 -1
- omlish/inject/impl/maysync.py +3 -4
- omlish/inject/impl/multis.py +3 -0
- omlish/inject/impl/sync.py +3 -4
- omlish/inject/injector.py +31 -2
- omlish/inject/inspect.py +35 -0
- omlish/inject/maysync.py +2 -4
- omlish/inject/multis.py +8 -0
- omlish/inject/overrides.py +3 -3
- omlish/inject/privates.py +6 -0
- omlish/inject/providers.py +3 -2
- omlish/inject/sync.py +5 -4
- omlish/io/buffers.py +118 -0
- omlish/io/readers.py +29 -0
- omlish/iterators/transforms.py +2 -2
- omlish/lang/__init__.py +178 -97
- omlish/lang/_asyncs.cc +186 -0
- omlish/lang/asyncs.py +17 -0
- omlish/lang/casing.py +11 -0
- omlish/lang/contextmanagers.py +28 -4
- omlish/lang/functions.py +31 -22
- omlish/lang/imports/_capture.cc +11 -9
- omlish/lang/imports/capture.py +363 -170
- omlish/lang/imports/proxy.py +455 -152
- omlish/lang/lazyglobals.py +22 -9
- omlish/lang/params.py +17 -0
- omlish/lang/recursion.py +0 -1
- omlish/lang/sequences.py +124 -0
- omlish/lite/abstract.py +54 -24
- omlish/lite/asyncs.py +2 -2
- omlish/lite/attrops.py +2 -0
- omlish/lite/contextmanagers.py +4 -4
- omlish/lite/dataclasses.py +44 -0
- omlish/lite/maybes.py +8 -0
- omlish/lite/maysync.py +1 -5
- omlish/lite/pycharm.py +1 -1
- omlish/lite/typing.py +6 -0
- omlish/logs/all.py +1 -1
- omlish/logs/utils.py +1 -1
- omlish/manifests/loading.py +2 -1
- omlish/marshal/__init__.py +33 -13
- omlish/marshal/_dataclasses.py +2774 -0
- omlish/marshal/base/configs.py +12 -0
- omlish/marshal/base/contexts.py +36 -21
- omlish/marshal/base/funcs.py +8 -11
- omlish/marshal/base/options.py +8 -0
- omlish/marshal/base/registries.py +146 -44
- omlish/marshal/base/types.py +40 -16
- omlish/marshal/composite/iterables.py +33 -20
- omlish/marshal/composite/literals.py +20 -18
- omlish/marshal/composite/mappings.py +36 -23
- omlish/marshal/composite/maybes.py +29 -19
- omlish/marshal/composite/newtypes.py +16 -16
- omlish/marshal/composite/optionals.py +14 -14
- omlish/marshal/composite/special.py +15 -15
- omlish/marshal/composite/unions/__init__.py +0 -0
- omlish/marshal/composite/unions/literals.py +93 -0
- omlish/marshal/composite/unions/primitives.py +103 -0
- omlish/marshal/factories/invalidate.py +18 -68
- omlish/marshal/factories/method.py +26 -0
- omlish/marshal/factories/moduleimport/factories.py +22 -65
- omlish/marshal/factories/multi.py +13 -25
- omlish/marshal/factories/recursive.py +42 -56
- omlish/marshal/factories/typecache.py +29 -74
- omlish/marshal/factories/typemap.py +42 -43
- omlish/marshal/objects/dataclasses.py +129 -106
- omlish/marshal/objects/marshal.py +18 -14
- omlish/marshal/objects/namedtuples.py +48 -42
- omlish/marshal/objects/unmarshal.py +19 -15
- omlish/marshal/polymorphism/marshal.py +9 -11
- omlish/marshal/polymorphism/metadata.py +16 -5
- omlish/marshal/polymorphism/standard.py +13 -1
- omlish/marshal/polymorphism/unions.py +15 -105
- omlish/marshal/polymorphism/unmarshal.py +9 -10
- omlish/marshal/singular/enums.py +14 -18
- omlish/marshal/standard.py +10 -6
- omlish/marshal/trivial/any.py +1 -1
- omlish/marshal/trivial/forbidden.py +21 -26
- omlish/metadata.py +23 -1
- omlish/os/forkhooks.py +4 -0
- omlish/os/pidfiles/pinning.py +2 -2
- omlish/reflect/types.py +1 -0
- omlish/secrets/marshal.py +1 -1
- omlish/specs/jmespath/__init__.py +12 -3
- omlish/specs/jmespath/_dataclasses.py +2893 -0
- omlish/specs/jmespath/ast.py +1 -1
- omlish/specs/jsonrpc/__init__.py +13 -0
- omlish/specs/jsonrpc/_marshal.py +32 -23
- omlish/specs/jsonrpc/conns.py +10 -7
- omlish/specs/jsonschema/_marshal.py +1 -1
- omlish/specs/jsonschema/keywords/__init__.py +7 -0
- omlish/specs/jsonschema/keywords/_dataclasses.py +1644 -0
- omlish/specs/openapi/_marshal.py +31 -22
- omlish/sql/{tabledefs/alchemy.py → alchemy/tabledefs.py} +2 -2
- omlish/sql/queries/_marshal.py +2 -2
- omlish/sql/queries/rendering.py +1 -1
- omlish/sql/tabledefs/_marshal.py +1 -1
- omlish/subprocesses/base.py +4 -0
- omlish/subprocesses/editor.py +1 -1
- omlish/sync.py +155 -21
- omlish/term/alt.py +60 -0
- omlish/term/confirm.py +8 -8
- omlish/term/pager.py +235 -0
- omlish/term/terminfo.py +935 -0
- omlish/term/termstate.py +67 -0
- omlish/term/vt100/terminal.py +0 -3
- omlish/testing/pytest/plugins/asyncs/fixtures.py +4 -1
- omlish/testing/pytest/plugins/skips.py +2 -1
- omlish/testing/unittest/main.py +3 -3
- omlish/text/docwrap/__init__.py +3 -0
- omlish/text/docwrap/__main__.py +11 -0
- omlish/text/docwrap/api.py +83 -0
- omlish/text/docwrap/cli.py +86 -0
- omlish/text/docwrap/groups.py +84 -0
- omlish/text/docwrap/lists.py +167 -0
- omlish/text/docwrap/parts.py +146 -0
- omlish/text/docwrap/reflowing.py +106 -0
- omlish/text/docwrap/rendering.py +151 -0
- omlish/text/docwrap/utils.py +11 -0
- omlish/text/docwrap/wrapping.py +59 -0
- omlish/text/filecache.py +2 -2
- omlish/text/lorem.py +6 -0
- omlish/text/parts.py +2 -2
- omlish/text/textwrap.py +51 -0
- omlish/typedvalues/marshal.py +85 -59
- omlish/typedvalues/values.py +2 -1
- {omlish-0.0.0.dev447.dist-info → omlish-0.0.0.dev484.dist-info}/METADATA +29 -28
- {omlish-0.0.0.dev447.dist-info → omlish-0.0.0.dev484.dist-info}/RECORD +222 -171
- omlish/dataclasses/impl/generation/mangling.py +0 -18
- omlish/funcs/match.py +0 -227
- omlish/marshal/factories/match.py +0 -34
- omlish/marshal/factories/simple.py +0 -28
- /omlish/inject/impl/{providers2.py → providersmap.py} +0 -0
- {omlish-0.0.0.dev447.dist-info → omlish-0.0.0.dev484.dist-info}/WHEEL +0 -0
- {omlish-0.0.0.dev447.dist-info → omlish-0.0.0.dev484.dist-info}/entry_points.txt +0 -0
- {omlish-0.0.0.dev447.dist-info → omlish-0.0.0.dev484.dist-info}/licenses/LICENSE +0 -0
- {omlish-0.0.0.dev447.dist-info → omlish-0.0.0.dev484.dist-info}/top_level.txt +0 -0
|
@@ -1,6 +1,14 @@
|
|
|
1
|
+
"""
|
|
2
|
+
TODO:
|
|
3
|
+
- better support anonymous / weakref'd / unlaoded modules / etc.
|
|
4
|
+
- anonymous=False on class spec?
|
|
5
|
+
"""
|
|
1
6
|
import dataclasses as dc
|
|
7
|
+
import threading
|
|
2
8
|
import typing as ta
|
|
3
9
|
|
|
10
|
+
from ... import check
|
|
11
|
+
|
|
4
12
|
|
|
5
13
|
##
|
|
6
14
|
|
|
@@ -19,52 +27,104 @@ DEFAULT_PACKAGE_CONFIG = PackageConfig()
|
|
|
19
27
|
##
|
|
20
28
|
|
|
21
29
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
30
|
+
@dc.dataclass(frozen=True)
|
|
31
|
+
class NamedPackageConfig:
|
|
32
|
+
pkg: str | None
|
|
33
|
+
cfg: PackageConfig
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
DEFAULT_NAMED_PACKAGE_CONFIG = NamedPackageConfig(None, DEFAULT_PACKAGE_CONFIG)
|
|
29
37
|
|
|
30
38
|
|
|
31
39
|
##
|
|
32
40
|
|
|
33
41
|
|
|
42
|
+
@ta.final
|
|
34
43
|
class PackageConfigCache:
|
|
35
44
|
def __init__(self) -> None:
|
|
36
45
|
super().__init__()
|
|
37
46
|
|
|
38
|
-
self.
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
47
|
+
self._lock = threading.Lock()
|
|
48
|
+
self._root = PackageConfigCache._Node('', None)
|
|
49
|
+
self._nodes: dict[str, PackageConfigCache._Node] = {}
|
|
50
|
+
|
|
51
|
+
@ta.final
|
|
52
|
+
class _Node:
|
|
53
|
+
def __init__(self, pkg: str, n_cfg: NamedPackageConfig | None) -> None:
|
|
54
|
+
self.pkg = pkg
|
|
55
|
+
self.n_cfg = n_cfg
|
|
56
|
+
|
|
57
|
+
self.children: dict[str, PackageConfigCache._Node] = {}
|
|
58
|
+
|
|
59
|
+
def __repr__(self) -> str:
|
|
60
|
+
return f'{self.__class__.__name__}(pkg={self.pkg!r}, n_cfg={self.n_cfg!r})'
|
|
61
|
+
|
|
62
|
+
def _navigate(self, *parts: str) -> _Node:
|
|
63
|
+
node = self._root
|
|
64
|
+
for i, p in enumerate(parts):
|
|
65
|
+
if (child := node.children.get(p)) is None:
|
|
66
|
+
child_pkg = '.'.join(parts[:i + 1])
|
|
67
|
+
check.not_in(child_pkg, self._nodes)
|
|
68
|
+
child = node.children[p] = self._nodes[child_pkg] = PackageConfigCache._Node(child_pkg, node.n_cfg)
|
|
69
|
+
node = child
|
|
70
|
+
return node
|
|
71
|
+
|
|
72
|
+
def put(self, pkg: str, cfg: PackageConfig) -> None:
|
|
73
|
+
n_cfg = NamedPackageConfig(pkg, cfg)
|
|
74
|
+
check.non_empty_str(pkg)
|
|
75
|
+
with self._lock:
|
|
76
|
+
check.not_in(pkg, self._nodes)
|
|
77
|
+
parts = pkg.split('.')
|
|
78
|
+
parent = self._navigate(*parts[:-1])
|
|
79
|
+
check.not_in(parts[-1], parent.children)
|
|
80
|
+
parent.children[parts[-1]] = self._nodes[pkg] = PackageConfigCache._Node(pkg, n_cfg)
|
|
81
|
+
|
|
82
|
+
def get(self, pkg: str) -> NamedPackageConfig | None:
|
|
83
|
+
if not pkg:
|
|
84
|
+
return None
|
|
85
|
+
|
|
86
|
+
try:
|
|
87
|
+
node = self._nodes[pkg]
|
|
88
|
+
except KeyError:
|
|
89
|
+
pass
|
|
90
|
+
else:
|
|
91
|
+
return node.n_cfg
|
|
92
|
+
|
|
93
|
+
# Flimsy - if no config anywhere for root package then don't cache. Want to support unlimited anonymous modules
|
|
94
|
+
# which may be unloaded without polluting cache forever.
|
|
95
|
+
parts = pkg.split('.')
|
|
96
|
+
if parts[0] not in self._root.children:
|
|
97
|
+
return None
|
|
98
|
+
|
|
99
|
+
with self._lock:
|
|
100
|
+
try:
|
|
101
|
+
node = self._nodes[pkg]
|
|
102
|
+
except KeyError:
|
|
103
|
+
pass
|
|
104
|
+
else:
|
|
105
|
+
return node.n_cfg
|
|
106
|
+
|
|
107
|
+
node = self._navigate(*pkg.split('.'))
|
|
108
|
+
return node.n_cfg
|
|
68
109
|
|
|
69
110
|
|
|
70
111
|
PACKAGE_CONFIG_CACHE = PackageConfigCache()
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
##
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
def init_package(
|
|
118
|
+
init_globals: ta.MutableMapping[str, ta.Any],
|
|
119
|
+
*,
|
|
120
|
+
codegen: bool = False,
|
|
121
|
+
) -> None:
|
|
122
|
+
pkg = check.non_empty_str(init_globals['__package__'])
|
|
123
|
+
if init_globals['__name__'] not in (pkg, '__main__'):
|
|
124
|
+
raise NameError('Must call dataclasses.init_package from __init__')
|
|
125
|
+
|
|
126
|
+
pkg_cfg = PackageConfig(
|
|
127
|
+
codegen=codegen,
|
|
128
|
+
)
|
|
129
|
+
|
|
130
|
+
PACKAGE_CONFIG_CACHE.put(pkg, pkg_cfg)
|
|
@@ -64,7 +64,6 @@ class OpCompiler:
|
|
|
64
64
|
f'import {i}'
|
|
65
65
|
for i in FN_GLOBAL_IMPORTS
|
|
66
66
|
],
|
|
67
|
-
'\n',
|
|
68
67
|
]
|
|
69
68
|
|
|
70
69
|
def globals_ns(self) -> ta.Mapping[str, ta.Any]:
|
|
@@ -84,11 +83,14 @@ class OpCompiler:
|
|
|
84
83
|
def style(self) -> Style:
|
|
85
84
|
return self._style
|
|
86
85
|
|
|
87
|
-
@dc.dataclass(frozen=True)
|
|
86
|
+
@dc.dataclass(frozen=True, kw_only=True)
|
|
88
87
|
class CompileResult:
|
|
89
88
|
fn_name: str
|
|
90
|
-
|
|
91
|
-
|
|
89
|
+
fn_params: ta.Sequence[str]
|
|
90
|
+
|
|
91
|
+
hdr_lines: ta.Sequence[str]
|
|
92
|
+
fn_lines: ta.Sequence[str]
|
|
93
|
+
|
|
92
94
|
refs: frozenset[Ref]
|
|
93
95
|
|
|
94
96
|
@dc.dataclass(frozen=True)
|
|
@@ -137,7 +139,10 @@ class OpCompiler:
|
|
|
137
139
|
) -> CompileResult:
|
|
138
140
|
body_lines: list[str] = []
|
|
139
141
|
|
|
140
|
-
for op in ops:
|
|
142
|
+
for i, op in enumerate(ops):
|
|
143
|
+
if i:
|
|
144
|
+
body_lines.append('')
|
|
145
|
+
|
|
141
146
|
if isinstance(op, SetAttrOp):
|
|
142
147
|
if isinstance(v := op.value, OpRef):
|
|
143
148
|
vs = v.ident()
|
|
@@ -202,8 +207,6 @@ class OpCompiler:
|
|
|
202
207
|
else:
|
|
203
208
|
raise TypeError(op)
|
|
204
209
|
|
|
205
|
-
body_lines.append('')
|
|
206
|
-
|
|
207
210
|
#
|
|
208
211
|
|
|
209
212
|
refs = frozenset.union(*[get_op_refs(o) for o in ops])
|
|
@@ -226,14 +229,12 @@ class OpCompiler:
|
|
|
226
229
|
src=f'{k.ident}={v.src}' if not v.src.startswith('.') else k.ident,
|
|
227
230
|
noqa=k.ident != k.ident.lower() or not v.src.startswith('.'),
|
|
228
231
|
)
|
|
229
|
-
for k, v in FN_GLOBALS.items()
|
|
232
|
+
for k, v in sorted(FN_GLOBALS.items(), key=lambda t: t[0])
|
|
230
233
|
])
|
|
231
234
|
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
lines.extend(self._style.header_lines())
|
|
235
|
+
#
|
|
235
236
|
|
|
236
|
-
|
|
237
|
+
fn_lines = [
|
|
237
238
|
f'def {fn_name}(',
|
|
238
239
|
f' *,',
|
|
239
240
|
*[
|
|
@@ -245,15 +246,16 @@ class OpCompiler:
|
|
|
245
246
|
f' {l}'
|
|
246
247
|
for l in body_lines
|
|
247
248
|
],
|
|
248
|
-
]
|
|
249
|
+
]
|
|
249
250
|
|
|
250
251
|
#
|
|
251
252
|
|
|
252
|
-
src = '\n'.join(lines)
|
|
253
|
-
|
|
254
253
|
return self.CompileResult(
|
|
255
|
-
fn_name,
|
|
256
|
-
[p.name for p in params],
|
|
257
|
-
|
|
258
|
-
|
|
254
|
+
fn_name=fn_name,
|
|
255
|
+
fn_params=[p.name for p in params],
|
|
256
|
+
|
|
257
|
+
hdr_lines=self._style.header_lines(),
|
|
258
|
+
fn_lines=fn_lines,
|
|
259
|
+
|
|
260
|
+
refs=refs,
|
|
259
261
|
)
|
|
@@ -10,6 +10,7 @@ import typing as ta
|
|
|
10
10
|
|
|
11
11
|
from .... import check
|
|
12
12
|
from .... import lang
|
|
13
|
+
from ....logs import all as logs
|
|
13
14
|
from ..processing.base import ProcessingContext
|
|
14
15
|
from ..processing.base import ProcessingOption
|
|
15
16
|
from ..processing.base import Processor
|
|
@@ -21,7 +22,6 @@ from .execution import OpExecutor
|
|
|
21
22
|
from .globals import FN_GLOBALS
|
|
22
23
|
from .globals import FnGlobal
|
|
23
24
|
from .idents import CLS_IDENT
|
|
24
|
-
from .mangling import IDENT_MANGLER
|
|
25
25
|
from .ops import Op
|
|
26
26
|
from .ops import OpRef
|
|
27
27
|
from .ops import OpRefMap
|
|
@@ -30,6 +30,9 @@ from .registry import all_generator_types
|
|
|
30
30
|
from .registry import generator_type_for_plan_type
|
|
31
31
|
|
|
32
32
|
|
|
33
|
+
log = logs.get_module_logger(globals())
|
|
34
|
+
|
|
35
|
+
|
|
33
36
|
##
|
|
34
37
|
|
|
35
38
|
|
|
@@ -38,9 +41,10 @@ class PlanOnly(ProcessingOption):
|
|
|
38
41
|
b: bool
|
|
39
42
|
|
|
40
43
|
|
|
41
|
-
@dc.dataclass(frozen=True)
|
|
42
|
-
class
|
|
43
|
-
|
|
44
|
+
@dc.dataclass(frozen=True, kw_only=True)
|
|
45
|
+
class Verbosity(ProcessingOption):
|
|
46
|
+
warn: bool = False
|
|
47
|
+
debug: bool = False
|
|
44
48
|
|
|
45
49
|
|
|
46
50
|
class CompileCallback(ta.Protocol):
|
|
@@ -53,13 +57,21 @@ class CompileCallback(ta.Protocol):
|
|
|
53
57
|
...
|
|
54
58
|
|
|
55
59
|
|
|
56
|
-
@dc.dataclass(frozen=True)
|
|
60
|
+
@dc.dataclass(frozen=True, kw_only=True)
|
|
57
61
|
class Codegen(ProcessingOption):
|
|
58
|
-
|
|
62
|
+
style: ta.Literal['jit', 'aot'] = 'jit'
|
|
63
|
+
|
|
64
|
+
force: bool = False
|
|
65
|
+
callback: CompileCallback | None = None
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
##
|
|
59
69
|
|
|
60
70
|
|
|
61
71
|
@register_processor_type(priority=ProcessorPriority.GENERATION)
|
|
62
72
|
class GeneratorProcessor(Processor):
|
|
73
|
+
PROCESS_FN_NAME: ta.ClassVar[str] = '_process_dataclass'
|
|
74
|
+
|
|
63
75
|
class Mode(lang.Abstract):
|
|
64
76
|
@abc.abstractmethod
|
|
65
77
|
def _process(self, gp: 'GeneratorProcessor', cls: type) -> None:
|
|
@@ -85,36 +97,52 @@ class GeneratorProcessor(Processor):
|
|
|
85
97
|
|
|
86
98
|
self._codegen = codegen
|
|
87
99
|
|
|
100
|
+
@classmethod
|
|
101
|
+
def build_standard_kwargs(cls, dc_cls: type) -> dict[str, ta.Any]:
|
|
102
|
+
kw: dict = {CLS_IDENT: dc_cls}
|
|
103
|
+
kw.update({
|
|
104
|
+
k.ident: v.value
|
|
105
|
+
for k, v in FN_GLOBALS.items()
|
|
106
|
+
})
|
|
107
|
+
return kw
|
|
108
|
+
|
|
88
109
|
def _process(self, gp: 'GeneratorProcessor', cls: type) -> None:
|
|
89
|
-
|
|
90
|
-
OpCompiler.
|
|
91
|
-
|
|
92
|
-
)
|
|
110
|
+
style: OpCompiler.Style = {
|
|
111
|
+
'jit': OpCompiler.JitStyle,
|
|
112
|
+
'aot': OpCompiler.AotStyle,
|
|
113
|
+
}[self._codegen.style]()
|
|
93
114
|
|
|
94
|
-
|
|
115
|
+
compiler = OpCompiler(style)
|
|
95
116
|
|
|
96
117
|
comp = compiler.compile(
|
|
97
|
-
|
|
118
|
+
GeneratorProcessor.PROCESS_FN_NAME,
|
|
98
119
|
gp.ops(),
|
|
99
120
|
)
|
|
100
121
|
|
|
101
|
-
|
|
122
|
+
comp_src = '\n'.join([
|
|
123
|
+
*comp.hdr_lines,
|
|
124
|
+
*(['', ''] if comp.hdr_lines else []),
|
|
125
|
+
*comp.fn_lines,
|
|
126
|
+
])
|
|
127
|
+
|
|
128
|
+
if (vo := gp._ctx.option(Verbosity)) is not None and vo.debug: # noqa
|
|
102
129
|
print(gp.prepare().plans.render(), file=sys.stderr)
|
|
103
130
|
print(file=sys.stderr)
|
|
104
|
-
print(
|
|
131
|
+
print(comp_src, file=sys.stderr)
|
|
105
132
|
print(file=sys.stderr)
|
|
106
133
|
|
|
107
134
|
ns: dict = {}
|
|
108
135
|
ns.update(compiler.style.globals_ns()) # noqa
|
|
109
136
|
|
|
110
|
-
exec(
|
|
111
|
-
o_fn = ns[
|
|
137
|
+
exec(comp_src, ns)
|
|
138
|
+
o_fn = ns[GeneratorProcessor.PROCESS_FN_NAME]
|
|
112
139
|
|
|
113
140
|
if cls.__module__ in sys.modules:
|
|
114
141
|
gl = sys.modules[cls.__module__].__dict__
|
|
115
142
|
else:
|
|
116
143
|
gl = {}
|
|
117
144
|
|
|
145
|
+
# TODO: comment why lol
|
|
118
146
|
fn = lang.new_function(**{
|
|
119
147
|
**lang.new_function_kwargs(o_fn),
|
|
120
148
|
**dict(
|
|
@@ -122,12 +150,8 @@ class GeneratorProcessor(Processor):
|
|
|
122
150
|
),
|
|
123
151
|
})
|
|
124
152
|
|
|
125
|
-
kw
|
|
126
|
-
|
|
127
|
-
k.ident: v.value
|
|
128
|
-
for k, v in FN_GLOBALS.items()
|
|
129
|
-
# if v.src.startswith('.')
|
|
130
|
-
})
|
|
153
|
+
kw = self.build_standard_kwargs(cls)
|
|
154
|
+
|
|
131
155
|
orm = gp.prepare().ref_map
|
|
132
156
|
for r in comp.refs:
|
|
133
157
|
if isinstance(r, OpRef):
|
|
@@ -140,7 +164,7 @@ class GeneratorProcessor(Processor):
|
|
|
140
164
|
fn(**kw)
|
|
141
165
|
|
|
142
166
|
if (cg := self._codegen) is not None and (cb := cg.callback) is not None:
|
|
143
|
-
cb(
|
|
167
|
+
cb( # noqa
|
|
144
168
|
gp._ctx, # noqa
|
|
145
169
|
gp.prepare(),
|
|
146
170
|
comp,
|
|
@@ -194,13 +218,70 @@ class GeneratorProcessor(Processor):
|
|
|
194
218
|
|
|
195
219
|
#
|
|
196
220
|
|
|
221
|
+
def _process_from_codegen(self, cls: type) -> bool:
|
|
222
|
+
cg_pkg = check.not_none(self._ctx.pkg_cfg.pkg)
|
|
223
|
+
cg_mod_spec = f'{cg_pkg}._dataclasses'
|
|
224
|
+
|
|
225
|
+
try:
|
|
226
|
+
__import__(cg_mod_spec)
|
|
227
|
+
except ImportError:
|
|
228
|
+
if (vo := self._ctx.option(Verbosity)) is not None and vo.warn: # noqa
|
|
229
|
+
log.warning(lambda: f'Codegen module missing for {cls.__module__}.{cls.__qualname__} at {cg_mod_spec}')
|
|
230
|
+
return False
|
|
231
|
+
|
|
232
|
+
cg_mod = sys.modules[cg_mod_spec]
|
|
233
|
+
cg_fn_reg = cg_mod.REGISTRY
|
|
234
|
+
|
|
235
|
+
#
|
|
236
|
+
|
|
237
|
+
prep = self.prepare()
|
|
238
|
+
prep_plan_repr = repr(prep.plans)
|
|
239
|
+
|
|
240
|
+
#
|
|
241
|
+
|
|
242
|
+
try:
|
|
243
|
+
cg_reg_item = cg_fn_reg[prep_plan_repr]
|
|
244
|
+
except KeyError:
|
|
245
|
+
if (vo := self._ctx.option(Verbosity)) is not None and vo.warn: # noqa
|
|
246
|
+
log.warning(lambda: f'Codegen missing for {cls.__module__}.{cls.__qualname__} in {cg_mod_spec}')
|
|
247
|
+
return False
|
|
248
|
+
|
|
249
|
+
cg_kw, cg_fn = cg_reg_item
|
|
250
|
+
|
|
251
|
+
#
|
|
252
|
+
|
|
253
|
+
ref_map = {
|
|
254
|
+
ref.ident(): v
|
|
255
|
+
for ref, v in prep.ref_map.items()
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
#
|
|
259
|
+
|
|
260
|
+
fn_kw = {
|
|
261
|
+
**GeneratorProcessor.CompilerMode.build_standard_kwargs(cls),
|
|
262
|
+
**{k: ref_map[k] for k in cg_kw['op_ref_idents']},
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
fn = cg_fn()
|
|
266
|
+
fn(**fn_kw)
|
|
267
|
+
|
|
268
|
+
return True
|
|
269
|
+
|
|
270
|
+
#
|
|
271
|
+
|
|
197
272
|
def process(self, cls: type) -> type:
|
|
198
273
|
if (po := self._ctx.option(PlanOnly)) is not None and po.b:
|
|
199
274
|
self.prepare()
|
|
200
275
|
return cls
|
|
201
276
|
|
|
277
|
+
cg = self._ctx.option(Codegen)
|
|
278
|
+
|
|
279
|
+
if not (cg is not None and cg.force) and self._ctx.pkg_cfg.cfg.codegen:
|
|
280
|
+
if self._process_from_codegen(cls):
|
|
281
|
+
return cls
|
|
282
|
+
|
|
202
283
|
mode: GeneratorProcessor.Mode
|
|
203
|
-
if
|
|
284
|
+
if cg is not None: # noqa
|
|
204
285
|
mode = GeneratorProcessor.CompilerMode(codegen=cg)
|
|
205
286
|
else:
|
|
206
287
|
mode = GeneratorProcessor.ExecutorMode()
|
|
@@ -10,6 +10,8 @@ import typing as ta
|
|
|
10
10
|
from .... import check
|
|
11
11
|
from .... import lang
|
|
12
12
|
from ...specs import ClassSpec
|
|
13
|
+
from ..configs import DEFAULT_NAMED_PACKAGE_CONFIG
|
|
14
|
+
from ..configs import NamedPackageConfig
|
|
13
15
|
|
|
14
16
|
|
|
15
17
|
T = ta.TypeVar('T')
|
|
@@ -33,6 +35,7 @@ class ProcessingContext:
|
|
|
33
35
|
cs: ClassSpec,
|
|
34
36
|
item_factories: ta.Mapping[type, ProcessingContextItemFactory],
|
|
35
37
|
*,
|
|
38
|
+
pkg_cfg: NamedPackageConfig = DEFAULT_NAMED_PACKAGE_CONFIG,
|
|
36
39
|
options: ta.Sequence[ProcessingOption] | None = None,
|
|
37
40
|
) -> None:
|
|
38
41
|
super().__init__()
|
|
@@ -40,6 +43,7 @@ class ProcessingContext:
|
|
|
40
43
|
self._cls = cls
|
|
41
44
|
self._cs = cs
|
|
42
45
|
self._item_factories = item_factories
|
|
46
|
+
self._pkg_cfg = pkg_cfg
|
|
43
47
|
|
|
44
48
|
options_dct: dict = {}
|
|
45
49
|
for o in options or ():
|
|
@@ -57,6 +61,10 @@ class ProcessingContext:
|
|
|
57
61
|
def cs(self) -> ClassSpec:
|
|
58
62
|
return self._cs
|
|
59
63
|
|
|
64
|
+
@property
|
|
65
|
+
def pkg_cfg(self) -> NamedPackageConfig:
|
|
66
|
+
return self._pkg_cfg
|
|
67
|
+
|
|
60
68
|
def __getitem__(self, ty: type[T]) -> T:
|
|
61
69
|
try:
|
|
62
70
|
return self._items[ty]
|
|
@@ -5,7 +5,7 @@ import typing as ta
|
|
|
5
5
|
from .... import lang
|
|
6
6
|
from ...specs import ClassSpec
|
|
7
7
|
from .. import concerns as _concerns # noqa # imported for registration
|
|
8
|
-
from ..configs import
|
|
8
|
+
from ..configs import DEFAULT_NAMED_PACKAGE_CONFIG
|
|
9
9
|
from ..configs import PACKAGE_CONFIG_CACHE
|
|
10
10
|
from ..generation import processor as gp
|
|
11
11
|
from .base import ProcessingContext
|
|
@@ -41,21 +41,20 @@ def drive_cls_processing(
|
|
|
41
41
|
cs: ClassSpec,
|
|
42
42
|
*,
|
|
43
43
|
plan_only: bool = False,
|
|
44
|
-
|
|
44
|
+
warn: bool = False,
|
|
45
|
+
debug: bool = False,
|
|
45
46
|
) -> type:
|
|
46
47
|
options: list[ProcessingOption] = list(_OPTIONS_CONTEXT_VAR.get())
|
|
47
48
|
if plan_only:
|
|
48
49
|
options.append(gp.PlanOnly(True))
|
|
49
|
-
if
|
|
50
|
-
options.append(gp.
|
|
50
|
+
if warn or debug:
|
|
51
|
+
options.append(gp.Verbosity(warn=warn, debug=debug))
|
|
51
52
|
|
|
52
53
|
#
|
|
53
54
|
|
|
54
|
-
pkg_config = DEFAULT_PACKAGE_CONFIG
|
|
55
55
|
cls_mod = cls.__module__
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
pkg_cfg = PACKAGE_CONFIG_CACHE.get(cls_pkg, pkg_config) # noqa
|
|
56
|
+
cls_pkg = cls_mod.rpartition('.')[0]
|
|
57
|
+
pkg_cfg = lang.coalesce(PACKAGE_CONFIG_CACHE.get(cls_pkg), DEFAULT_NAMED_PACKAGE_CONFIG)
|
|
59
58
|
|
|
60
59
|
#
|
|
61
60
|
|
|
@@ -63,6 +62,7 @@ def drive_cls_processing(
|
|
|
63
62
|
cls,
|
|
64
63
|
cs,
|
|
65
64
|
all_processing_context_item_factories(),
|
|
65
|
+
pkg_cfg=pkg_cfg,
|
|
66
66
|
options=options,
|
|
67
67
|
)
|
|
68
68
|
|
omlish/dataclasses/specs.py
CHANGED
|
@@ -3,6 +3,7 @@ import typing as ta
|
|
|
3
3
|
|
|
4
4
|
from ... import check
|
|
5
5
|
from ... import lang
|
|
6
|
+
from ...lite.dataclasses import is_immediate_dataclass
|
|
6
7
|
|
|
7
8
|
|
|
8
9
|
if ta.TYPE_CHECKING:
|
|
@@ -40,6 +41,8 @@ def update_fields(
|
|
|
40
41
|
def inner(cls):
|
|
41
42
|
if issubclass(cls, meta.DataMeta):
|
|
42
43
|
raise TypeError('update_fields() cannot be used on DataMeta subclasses')
|
|
44
|
+
if is_immediate_dataclass(cls):
|
|
45
|
+
raise TypeError('update_fields() cannot be used on already processed dataclasses')
|
|
43
46
|
|
|
44
47
|
if fields is None:
|
|
45
48
|
for a, v in list(cls.__dict__.items()):
|
|
@@ -51,6 +54,8 @@ def update_fields(
|
|
|
51
54
|
try:
|
|
52
55
|
v = cls.__dict__[a]
|
|
53
56
|
except KeyError:
|
|
57
|
+
if hasattr(cls, a):
|
|
58
|
+
raise TypeError('update_fields() cannot be used on parent dataclass fields') from None
|
|
54
59
|
v = dc.field()
|
|
55
60
|
else:
|
|
56
61
|
if not isinstance(v, dc.Field):
|
|
File without changes
|
|
@@ -7,12 +7,12 @@ import dataclasses as dc
|
|
|
7
7
|
import json
|
|
8
8
|
import typing as ta
|
|
9
9
|
|
|
10
|
-
from
|
|
11
|
-
from
|
|
12
|
-
from
|
|
13
|
-
from
|
|
14
|
-
from
|
|
15
|
-
from
|
|
10
|
+
from ...lite.check import check
|
|
11
|
+
from ...lite.marshal import OBJ_MARSHALER_FIELD_KEY
|
|
12
|
+
from ...lite.marshal import unmarshal_obj
|
|
13
|
+
from ...subprocesses.run import SubprocessRun
|
|
14
|
+
from ...subprocesses.run import SubprocessRunnable
|
|
15
|
+
from ...subprocesses.run import SubprocessRunOutput
|
|
16
16
|
|
|
17
17
|
|
|
18
18
|
##
|
|
@@ -7,12 +7,12 @@ import dataclasses as dc
|
|
|
7
7
|
import enum
|
|
8
8
|
import typing as ta
|
|
9
9
|
|
|
10
|
-
from
|
|
11
|
-
from
|
|
12
|
-
from
|
|
13
|
-
from
|
|
14
|
-
from
|
|
15
|
-
from
|
|
10
|
+
from ...lite.check import check
|
|
11
|
+
from ...lite.dataclasses import dataclass_repr_omit_falsey
|
|
12
|
+
from ...lite.marshal import OBJ_MARSHALER_OMIT_IF_NONE
|
|
13
|
+
from ...subprocesses.run import SubprocessRun
|
|
14
|
+
from ...subprocesses.run import SubprocessRunnable
|
|
15
|
+
from ...subprocesses.run import SubprocessRunOutput
|
|
16
16
|
|
|
17
17
|
|
|
18
18
|
##
|
omlish/diag/{ps.py → cmds/ps.py}
RENAMED
|
@@ -4,12 +4,12 @@ import dataclasses as dc
|
|
|
4
4
|
import os
|
|
5
5
|
import typing as ta
|
|
6
6
|
|
|
7
|
-
from
|
|
8
|
-
from
|
|
9
|
-
from
|
|
10
|
-
from
|
|
11
|
-
from
|
|
12
|
-
from
|
|
7
|
+
from ...lite.check import check
|
|
8
|
+
from ...lite.timeouts import Timeout
|
|
9
|
+
from ...subprocesses.run import SubprocessRun
|
|
10
|
+
from ...subprocesses.run import SubprocessRunnable
|
|
11
|
+
from ...subprocesses.run import SubprocessRunOutput
|
|
12
|
+
from ...subprocesses.sync import subprocesses
|
|
13
13
|
|
|
14
14
|
|
|
15
15
|
##
|
omlish/diag/pycharm.py
CHANGED
|
@@ -191,9 +191,23 @@ def pycharm_remote_debugger_attach(prd: PycharmRemoteDebugger) -> None:
|
|
|
191
191
|
else:
|
|
192
192
|
pydevd_pycharm = _import_pydevd_pycharm(version=version)
|
|
193
193
|
|
|
194
|
+
import inspect
|
|
195
|
+
st_sig = inspect.signature(pydevd_pycharm.settrace)
|
|
196
|
+
|
|
197
|
+
kw: dict = {}
|
|
198
|
+
if 'stdoutToServer' in st_sig.parameters:
|
|
199
|
+
kw.update(
|
|
200
|
+
stdoutToServer=True,
|
|
201
|
+
stderrToServer=True,
|
|
202
|
+
)
|
|
203
|
+
else:
|
|
204
|
+
kw.update(
|
|
205
|
+
stdout_to_server=True,
|
|
206
|
+
stderr_to_server=True,
|
|
207
|
+
)
|
|
208
|
+
|
|
194
209
|
pydevd_pycharm.settrace(
|
|
195
210
|
host,
|
|
196
211
|
port=prd.port,
|
|
197
|
-
|
|
198
|
-
stderrToServer=True,
|
|
212
|
+
**kw,
|
|
199
213
|
)
|