omlish 0.0.0.dev447__py3-none-any.whl → 0.0.0.dev493__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/README.md +199 -0
- omlish/__about__.py +21 -16
- 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/plans.py +2 -17
- omlish/dataclasses/impl/generation/processor.py +106 -25
- omlish/dataclasses/impl/processing/base.py +8 -0
- omlish/dataclasses/impl/processing/driving.py +19 -7
- omlish/dataclasses/specs.py +1 -0
- omlish/dataclasses/tools/modifiers.py +5 -0
- omlish/diag/_pycharm/runhack.py +1 -1
- 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 +57 -29
- omlish/inject/_dataclasses.py +5148 -0
- omlish/inject/binder.py +11 -52
- omlish/inject/eagers.py +2 -0
- 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/late.py +76 -0
- omlish/inject/{managed.py → helpers/managed.py} +10 -10
- omlish/inject/helpers/multis.py +143 -0
- omlish/inject/helpers/wrappers.py +54 -0
- omlish/inject/impl/elements.py +54 -21
- omlish/inject/impl/injector.py +29 -25
- 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 +180 -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/lifecycles/README.md +30 -0
- omlish/lifecycles/__init__.py +87 -13
- omlish/lifecycles/_dataclasses.py +1388 -0
- omlish/lifecycles/base.py +178 -64
- omlish/lifecycles/contextmanagers.py +113 -4
- omlish/lifecycles/controller.py +150 -87
- omlish/lifecycles/injection.py +143 -0
- omlish/lifecycles/listeners.py +56 -0
- omlish/lifecycles/managed.py +142 -0
- omlish/lifecycles/manager.py +218 -93
- omlish/lifecycles/states.py +2 -0
- omlish/lifecycles/transitions.py +3 -0
- omlish/lifecycles/unwrap.py +57 -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 +24 -0
- omlish/logs/_amalg.py +1 -1
- omlish/logs/all.py +25 -11
- omlish/logs/asyncs.py +73 -0
- omlish/logs/base.py +101 -12
- omlish/logs/contexts.py +4 -1
- omlish/logs/lists.py +125 -0
- omlish/logs/modules.py +19 -1
- omlish/logs/std/loggers.py +6 -1
- omlish/logs/std/noisy.py +11 -9
- omlish/logs/{standard.py → std/standard.py} +3 -4
- omlish/logs/utils.py +17 -2
- 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/__init__.py +43 -26
- omlish/reflect/ops.py +10 -1
- 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/__init__.py +24 -5
- omlish/sql/{tabledefs/alchemy.py → alchemy/tabledefs.py} +2 -2
- omlish/sql/api/dbapi.py +1 -1
- omlish/sql/dbapi/__init__.py +15 -0
- omlish/sql/{dbapi.py → dbapi/drivers.py} +2 -2
- omlish/sql/queries/__init__.py +3 -0
- 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/asyncs/plugin.py +2 -0
- 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 +91 -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.dev493.dist-info}/METADATA +36 -32
- {omlish-0.0.0.dev447.dist-info → omlish-0.0.0.dev493.dist-info}/RECORD +260 -199
- omlish/dataclasses/impl/generation/mangling.py +0 -18
- omlish/funcs/match.py +0 -227
- omlish/lifecycles/abstract.py +0 -86
- omlish/marshal/factories/match.py +0 -34
- omlish/marshal/factories/simple.py +0 -28
- /omlish/inject/{impl → helpers}/proxy.py +0 -0
- /omlish/inject/impl/{providers2.py → providersmap.py} +0 -0
- /omlish/sql/{abc.py → dbapi/abc.py} +0 -0
- {omlish-0.0.0.dev447.dist-info → omlish-0.0.0.dev493.dist-info}/WHEEL +0 -0
- {omlish-0.0.0.dev447.dist-info → omlish-0.0.0.dev493.dist-info}/entry_points.txt +0 -0
- {omlish-0.0.0.dev447.dist-info → omlish-0.0.0.dev493.dist-info}/licenses/LICENSE +0 -0
- {omlish-0.0.0.dev447.dist-info → omlish-0.0.0.dev493.dist-info}/top_level.txt +0 -0
omlish/concurrent/threadlets.py
CHANGED
|
@@ -75,7 +75,7 @@ class GreenletThreadlet(Threadlet):
|
|
|
75
75
|
|
|
76
76
|
@property
|
|
77
77
|
def parent(self) -> ta.Optional['GreenletThreadlet']:
|
|
78
|
-
return GreenletThreadlet(self.g.parent)
|
|
78
|
+
return GreenletThreadlet(p) if (p := self.g.parent) is not None else None
|
|
79
79
|
|
|
80
80
|
@property
|
|
81
81
|
def dead(self) -> bool:
|
omlish/daemons/reparent.py
CHANGED
|
@@ -10,13 +10,12 @@ def reparent_process(
|
|
|
10
10
|
no_close_stdio: bool = False,
|
|
11
11
|
) -> None:
|
|
12
12
|
if (pid := os.fork()): # noqa
|
|
13
|
-
|
|
14
|
-
raise RuntimeError('Unreachable') # noqa
|
|
13
|
+
raise SystemExit(0)
|
|
15
14
|
|
|
16
15
|
os.setsid()
|
|
17
16
|
|
|
18
17
|
if (pid := os.fork()): # noqa
|
|
19
|
-
|
|
18
|
+
raise SystemExit(0)
|
|
20
19
|
|
|
21
20
|
if not no_close_stdio:
|
|
22
21
|
rn_fd = os.open('/dev/null', os.O_RDONLY)
|
omlish/daemons/spawning.py
CHANGED
|
@@ -2,7 +2,6 @@ import abc
|
|
|
2
2
|
import enum
|
|
3
3
|
import functools
|
|
4
4
|
import os
|
|
5
|
-
import sys
|
|
6
5
|
import threading
|
|
7
6
|
import typing as ta
|
|
8
7
|
|
|
@@ -166,9 +165,9 @@ class ForkSpawner(Spawner, dc.Frozen):
|
|
|
166
165
|
try:
|
|
167
166
|
spawn.fn()
|
|
168
167
|
except BaseException: # noqa
|
|
169
|
-
|
|
168
|
+
raise SystemExit(1) from None
|
|
170
169
|
else:
|
|
171
|
-
|
|
170
|
+
raise SystemExit(0)
|
|
172
171
|
|
|
173
172
|
raise RuntimeError('Unreachable') # noqa
|
|
174
173
|
|
omlish/dataclasses/__init__.py
CHANGED
|
@@ -10,6 +10,7 @@ from ..... import lang
|
|
|
10
10
|
from ...._internals import STD_FIELDS_ATTR
|
|
11
11
|
from ...._internals import STD_PARAMS_ATTR
|
|
12
12
|
from ....specs import ClassSpec
|
|
13
|
+
from ....specs import ReprFn
|
|
13
14
|
from ...processing.driving import drive_cls_processing
|
|
14
15
|
from ...utils import class_decorator
|
|
15
16
|
from ..fields.building import build_cls_std_fields
|
|
@@ -53,6 +54,7 @@ def dataclass(
|
|
|
53
54
|
|
|
54
55
|
repr_id: bool | None = None,
|
|
55
56
|
terse_repr: bool | None = None,
|
|
57
|
+
default_repr_fn: ReprFn | None = None,
|
|
56
58
|
|
|
57
59
|
allow_redundant_decorator: bool | None = None,
|
|
58
60
|
|
|
@@ -158,6 +160,7 @@ def dataclass(
|
|
|
158
160
|
|
|
159
161
|
repr_id=repr_id,
|
|
160
162
|
terse_repr=terse_repr,
|
|
163
|
+
default_repr_fn=default_repr_fn,
|
|
161
164
|
|
|
162
165
|
allow_redundant_decorator=allow_redundant_decorator,
|
|
163
166
|
),
|
|
@@ -4,6 +4,7 @@ import sys
|
|
|
4
4
|
import types
|
|
5
5
|
import typing as ta
|
|
6
6
|
|
|
7
|
+
from ....specs import ReprFn
|
|
7
8
|
from .decorator import dataclass
|
|
8
9
|
|
|
9
10
|
|
|
@@ -53,6 +54,7 @@ def make_dataclass( # noqa
|
|
|
53
54
|
|
|
54
55
|
repr_id: bool | None = None,
|
|
55
56
|
terse_repr: bool | None = None,
|
|
57
|
+
default_repr_fn: ReprFn | None = None,
|
|
56
58
|
|
|
57
59
|
allow_redundant_decorator: bool | None = None,
|
|
58
60
|
|
|
@@ -174,6 +176,7 @@ def make_dataclass( # noqa
|
|
|
174
176
|
|
|
175
177
|
repr_id=repr_id,
|
|
176
178
|
terse_repr=terse_repr,
|
|
179
|
+
default_repr_fn=default_repr_fn,
|
|
177
180
|
|
|
178
181
|
allow_redundant_decorator=allow_redundant_decorator,
|
|
179
182
|
)
|
|
@@ -32,6 +32,7 @@ class ReprPlan(Plan):
|
|
|
32
32
|
|
|
33
33
|
id: bool = False
|
|
34
34
|
terse: bool = False
|
|
35
|
+
default_fn: OpRef[ReprFn] | None = None
|
|
35
36
|
|
|
36
37
|
|
|
37
38
|
@register_generator_type(ReprPlan)
|
|
@@ -66,11 +67,17 @@ class ReprGenerator(Generator[ReprPlan]):
|
|
|
66
67
|
fn=fnr,
|
|
67
68
|
))
|
|
68
69
|
|
|
70
|
+
drf: OpRef | None = None
|
|
71
|
+
if ctx.cs.default_repr_fn is not None:
|
|
72
|
+
drf = OpRef(f'repr.default_fn')
|
|
73
|
+
orm[drf] = ctx.cs.default_repr_fn
|
|
74
|
+
|
|
69
75
|
return PlanResult(
|
|
70
76
|
ReprPlan(
|
|
71
77
|
fields=tuple(rfs),
|
|
72
78
|
id=ctx.cs.repr_id,
|
|
73
79
|
terse=ctx.cs.terse_repr,
|
|
80
|
+
default_fn=drf,
|
|
74
81
|
),
|
|
75
82
|
orm,
|
|
76
83
|
)
|
|
@@ -85,10 +92,16 @@ class ReprGenerator(Generator[ReprPlan]):
|
|
|
85
92
|
if not (pl.terse and not f.kw_only):
|
|
86
93
|
pfx = f'{f.name}='
|
|
87
94
|
|
|
95
|
+
fn: OpRef[ReprFn] | None = None
|
|
88
96
|
if f.fn is not None:
|
|
89
|
-
|
|
97
|
+
fn = f.fn
|
|
98
|
+
elif pl.default_fn is not None:
|
|
99
|
+
fn = pl.default_fn
|
|
100
|
+
|
|
101
|
+
if fn is not None:
|
|
102
|
+
ors.add(fn)
|
|
90
103
|
part_lines.extend([
|
|
91
|
-
f' if (s := {
|
|
104
|
+
f' if (s := {fn.ident()}(self.{f.name})) is not None:',
|
|
92
105
|
f' parts.append(f"{pfx}{{s}}")',
|
|
93
106
|
])
|
|
94
107
|
else:
|
|
@@ -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
|
)
|
|
@@ -1,9 +1,4 @@
|
|
|
1
|
-
"""
|
|
2
|
-
TODO:
|
|
3
|
-
- sha1 is slow :/ key by repr but name by sha1
|
|
4
|
-
"""
|
|
5
1
|
import dataclasses as dc
|
|
6
|
-
import re
|
|
7
2
|
import typing as ta
|
|
8
3
|
|
|
9
4
|
from .... import lang
|
|
@@ -21,15 +16,5 @@ class Plans:
|
|
|
21
16
|
return iter(self.tup)
|
|
22
17
|
|
|
23
18
|
@lang.cached_function(no_wrapper_update=True)
|
|
24
|
-
def
|
|
25
|
-
return
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
##
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
_WS_PAT = re.compile(r'\s+')
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
def _render(plans: Plans) -> str:
|
|
35
|
-
return _WS_PAT.sub('', repr(plans.tup))
|
|
19
|
+
def repr(self) -> str:
|
|
20
|
+
return repr(self)
|
|
@@ -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
|
-
|
|
102
|
-
|
|
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
|
|
129
|
+
print(gp.prepare().plans.repr(), 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 = prep.plans.repr()
|
|
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()
|