omdev 0.0.0.dev440__py3-none-any.whl → 0.0.0.dev495__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 omdev might be problematic. Click here for more details.
- omdev/.omlish-manifests.json +18 -30
- omdev/README.md +51 -0
- omdev/__about__.py +11 -7
- omdev/amalg/gen/gen.py +49 -6
- omdev/amalg/gen/imports.py +1 -1
- omdev/amalg/gen/manifests.py +1 -1
- omdev/amalg/gen/resources.py +1 -1
- omdev/amalg/gen/srcfiles.py +13 -3
- omdev/amalg/gen/strip.py +1 -1
- omdev/amalg/gen/types.py +1 -1
- omdev/amalg/gen/typing.py +1 -1
- omdev/amalg/info.py +32 -0
- omdev/cache/data/actions.py +1 -1
- omdev/cache/data/specs.py +1 -1
- omdev/cexts/_boilerplate.cc +2 -3
- omdev/cexts/cmake.py +4 -1
- omdev/ci/cli.py +2 -3
- omdev/cli/clicli.py +37 -7
- omdev/cmdlog/cli.py +1 -2
- omdev/dataclasses/_dumping.py +1960 -0
- omdev/dataclasses/_template.py +22 -0
- omdev/dataclasses/cli.py +7 -2
- omdev/dataclasses/codegen.py +340 -60
- omdev/dataclasses/dumping.py +200 -0
- omdev/interp/cli.py +1 -1
- omdev/interp/types.py +3 -2
- omdev/interp/uv/provider.py +37 -0
- omdev/interp/venvs.py +1 -0
- omdev/irc/messages/base.py +50 -0
- omdev/irc/messages/formats.py +92 -0
- omdev/irc/messages/messages.py +775 -0
- omdev/irc/messages/parsing.py +99 -0
- omdev/irc/numerics/__init__.py +0 -0
- omdev/irc/numerics/formats.py +97 -0
- omdev/irc/numerics/numerics.py +865 -0
- omdev/irc/numerics/types.py +59 -0
- omdev/irc/protocol/LICENSE +11 -0
- omdev/irc/protocol/__init__.py +61 -0
- omdev/irc/protocol/consts.py +6 -0
- omdev/irc/protocol/errors.py +30 -0
- omdev/irc/protocol/message.py +21 -0
- omdev/irc/protocol/nuh.py +55 -0
- omdev/irc/protocol/parsing.py +158 -0
- omdev/irc/protocol/rendering.py +153 -0
- omdev/irc/protocol/tags.py +102 -0
- omdev/irc/protocol/utils.py +30 -0
- omdev/manifests/_dumping.py +125 -25
- omdev/manifests/main.py +1 -1
- omdev/markdown/__init__.py +0 -0
- omdev/markdown/incparse.py +116 -0
- omdev/markdown/tokens.py +51 -0
- omdev/packaging/marshal.py +8 -8
- omdev/packaging/requires.py +6 -6
- omdev/packaging/revisions.py +1 -1
- omdev/packaging/specifiers.py +2 -1
- omdev/packaging/versions.py +4 -4
- omdev/packaging/wheelfile.py +2 -0
- omdev/precheck/blanklines.py +66 -0
- omdev/precheck/caches.py +1 -1
- omdev/precheck/imports.py +14 -1
- omdev/precheck/main.py +4 -3
- omdev/precheck/unicode.py +39 -15
- omdev/py/asts/__init__.py +0 -0
- omdev/py/asts/parents.py +28 -0
- omdev/py/asts/toplevel.py +123 -0
- omdev/py/asts/visitors.py +18 -0
- omdev/py/attrdocs.py +1 -1
- omdev/py/bracepy.py +12 -4
- omdev/py/reprs.py +32 -0
- omdev/py/srcheaders.py +1 -1
- omdev/py/tokens/__init__.py +0 -0
- omdev/py/tools/mkrelimp.py +1 -1
- omdev/py/tools/pipdepup.py +686 -0
- omdev/pyproject/cli.py +1 -1
- omdev/pyproject/pkg.py +190 -45
- omdev/pyproject/reqs.py +31 -9
- omdev/pyproject/tools/__init__.py +0 -0
- omdev/pyproject/tools/aboutdeps.py +60 -0
- omdev/pyproject/venvs.py +8 -1
- omdev/rs/__init__.py +0 -0
- omdev/scripts/ci.py +752 -98
- omdev/scripts/interp.py +232 -39
- omdev/scripts/lib/inject.py +74 -27
- omdev/scripts/lib/logs.py +187 -43
- omdev/scripts/lib/marshal.py +67 -25
- omdev/scripts/pyproject.py +1369 -143
- omdev/tools/git/cli.py +10 -0
- omdev/tools/json/formats.py +2 -0
- omdev/tools/json/processing.py +5 -2
- omdev/tools/jsonview/cli.py +49 -65
- omdev/tools/jsonview/resources/jsonview.html.j2 +43 -0
- omdev/tools/pawk/README.md +195 -0
- omdev/tools/pawk/pawk.py +2 -2
- omdev/tools/pip.py +8 -0
- omdev/tui/__init__.py +0 -0
- omdev/tui/apps/__init__.py +0 -0
- omdev/tui/apps/edit/__init__.py +0 -0
- omdev/tui/apps/edit/main.py +167 -0
- omdev/tui/apps/irc/__init__.py +0 -0
- omdev/tui/apps/irc/__main__.py +4 -0
- omdev/tui/apps/irc/app.py +286 -0
- omdev/tui/apps/irc/client.py +187 -0
- omdev/tui/apps/irc/commands.py +175 -0
- omdev/tui/apps/irc/main.py +26 -0
- omdev/tui/apps/markdown/__init__.py +0 -0
- omdev/tui/apps/markdown/__main__.py +11 -0
- omdev/{ptk → tui/apps}/markdown/cli.py +5 -7
- omdev/tui/rich/__init__.py +46 -0
- omdev/tui/rich/console2.py +20 -0
- omdev/tui/rich/markdown2.py +186 -0
- omdev/tui/textual/__init__.py +265 -0
- omdev/tui/textual/app2.py +16 -0
- omdev/tui/textual/autocomplete/LICENSE +21 -0
- omdev/tui/textual/autocomplete/__init__.py +33 -0
- omdev/tui/textual/autocomplete/matching.py +226 -0
- omdev/tui/textual/autocomplete/paths.py +202 -0
- omdev/tui/textual/autocomplete/widget.py +612 -0
- omdev/tui/textual/debug/__init__.py +10 -0
- omdev/tui/textual/debug/dominfo.py +151 -0
- omdev/tui/textual/debug/screen.py +24 -0
- omdev/tui/textual/devtools.py +187 -0
- omdev/tui/textual/drivers2.py +55 -0
- omdev/tui/textual/logging2.py +20 -0
- omdev/tui/textual/types.py +45 -0
- {omdev-0.0.0.dev440.dist-info → omdev-0.0.0.dev495.dist-info}/METADATA +15 -9
- {omdev-0.0.0.dev440.dist-info → omdev-0.0.0.dev495.dist-info}/RECORD +135 -80
- omdev/ptk/__init__.py +0 -103
- omdev/ptk/apps/ncdu.py +0 -167
- omdev/ptk/confirm.py +0 -60
- omdev/ptk/markdown/LICENSE +0 -22
- omdev/ptk/markdown/__init__.py +0 -10
- omdev/ptk/markdown/__main__.py +0 -11
- omdev/ptk/markdown/border.py +0 -94
- omdev/ptk/markdown/markdown.py +0 -390
- omdev/ptk/markdown/parser.py +0 -42
- omdev/ptk/markdown/styles.py +0 -29
- omdev/ptk/markdown/tags.py +0 -299
- omdev/ptk/markdown/utils.py +0 -366
- omdev/pyproject/cexts.py +0 -110
- /omdev/{ptk/apps → irc}/__init__.py +0 -0
- /omdev/{tokens → irc/messages}/__init__.py +0 -0
- /omdev/{tokens → py/tokens}/all.py +0 -0
- /omdev/{tokens → py/tokens}/tokenizert.py +0 -0
- /omdev/{tokens → py/tokens}/utils.py +0 -0
- {omdev-0.0.0.dev440.dist-info → omdev-0.0.0.dev495.dist-info}/WHEEL +0 -0
- {omdev-0.0.0.dev440.dist-info → omdev-0.0.0.dev495.dist-info}/entry_points.txt +0 -0
- {omdev-0.0.0.dev440.dist-info → omdev-0.0.0.dev495.dist-info}/licenses/LICENSE +0 -0
- {omdev-0.0.0.dev440.dist-info → omdev-0.0.0.dev495.dist-info}/top_level.txt +0 -0
omdev/scripts/interp.py
CHANGED
|
@@ -27,6 +27,7 @@ import inspect
|
|
|
27
27
|
import itertools
|
|
28
28
|
import json
|
|
29
29
|
import logging
|
|
30
|
+
import operator
|
|
30
31
|
import os
|
|
31
32
|
import os.path
|
|
32
33
|
import re
|
|
@@ -49,6 +50,54 @@ if sys.version_info < (3, 8):
|
|
|
49
50
|
raise OSError(f'Requires python (3, 8), got {sys.version_info} from {sys.executable}') # noqa
|
|
50
51
|
|
|
51
52
|
|
|
53
|
+
def __omlish_amalg__(): # noqa
|
|
54
|
+
return dict(
|
|
55
|
+
src_files=[
|
|
56
|
+
dict(path='../packaging/versions.py', sha1='71627ad600b3529b829b0e227b0952f2c63c7271'),
|
|
57
|
+
dict(path='../../omlish/lite/abstract.py', sha1='a2fc3f3697fa8de5247761e9d554e70176f37aac'),
|
|
58
|
+
dict(path='../../omlish/lite/cached.py', sha1='0c33cf961ac8f0727284303c7a30c5ea98f714f2'),
|
|
59
|
+
dict(path='../../omlish/lite/check.py', sha1='bb6b6b63333699b84462951a854d99ae83195b94'),
|
|
60
|
+
dict(path='../../omlish/lite/json.py', sha1='57eeddc4d23a17931e00284ffa5cb6e3ce089486'),
|
|
61
|
+
dict(path='../../omlish/lite/reflect.py', sha1='c4fec44bf144e9d93293c996af06f6c65fc5e63d'),
|
|
62
|
+
dict(path='../../omlish/lite/strings.py', sha1='89831ecbc34ad80e118a865eceb390ed399dc4d6'),
|
|
63
|
+
dict(path='../../omlish/logs/levels.py', sha1='91405563d082a5eba874da82aac89d83ce7b6152'),
|
|
64
|
+
dict(path='../../omlish/logs/std/filters.py', sha1='f36aab646d84d31e295b33aaaaa6f8b67ff38b3d'),
|
|
65
|
+
dict(path='../../omlish/logs/std/proxy.py', sha1='3e7301a2aa351127f9c85f61b2f85dcc3f15aafb'),
|
|
66
|
+
dict(path='../packaging/specifiers.py', sha1='a56ab4e8c9b174adb523921f6280ac41e0fce749'),
|
|
67
|
+
dict(path='../../omlish/argparse/cli.py', sha1='f4dc3cd353d14386b5da0306768700e396afd2b3'),
|
|
68
|
+
dict(path='../../omlish/lite/maybes.py', sha1='bdf5136654ccd14b6a072588cad228925bdfbabd'),
|
|
69
|
+
dict(path='../../omlish/lite/runtime.py', sha1='2e752a27ae2bf89b1bb79b4a2da522a3ec360c70'),
|
|
70
|
+
dict(path='../../omlish/lite/timeouts.py', sha1='a0f673033a6943f242e35848d78a41892b9c62a1'),
|
|
71
|
+
dict(path='../../omlish/logs/protocols.py', sha1='05ca4d1d7feb50c4e3b9f22ee371aa7bf4b3dbd1'),
|
|
72
|
+
dict(path='../../omlish/logs/std/json.py', sha1='2a75553131e4d5331bb0cedde42aa183f403fc3b'),
|
|
73
|
+
dict(path='types.py', sha1='caf068a6e81fb6e221d777b341ac5777d92b8091'),
|
|
74
|
+
dict(path='../../omlish/asyncs/asyncio/timeouts.py', sha1='4d31b02b3c39b8f2fa7e94db36552fde6942e36a'),
|
|
75
|
+
dict(path='../../omlish/lite/inject.py', sha1='6f097e3170019a34ff6834d36fcc9cbeed3a7ab4'),
|
|
76
|
+
dict(path='../../omlish/logs/std/standard.py', sha1='5c97c1b9f7ead58d6127d047b873398f708f288d'),
|
|
77
|
+
dict(path='../../omlish/subprocesses/run.py', sha1='8200e48f0c49d164df3503cd0143038d0c4d30aa'),
|
|
78
|
+
dict(path='../../omlish/subprocesses/wrap.py', sha1='8a9b7d2255481fae15c05f5624b0cdc0766f4b3f'),
|
|
79
|
+
dict(path='providers/base.py', sha1='f5d068c21f230d742e9015b033cd6320f4c68898'),
|
|
80
|
+
dict(path='../../omlish/subprocesses/base.py', sha1='cb9f668be5422fecb27222caabb67daac6c1bab9'),
|
|
81
|
+
dict(path='resolvers.py', sha1='817b8e76401cd7a19eb43ca54d65272e4c8a4b0e'),
|
|
82
|
+
dict(path='../../omlish/subprocesses/asyncs.py', sha1='bba44d524c24c6ac73168aee6343488414e5bf48'),
|
|
83
|
+
dict(path='../../omlish/asyncs/asyncio/subprocesses.py', sha1='b6b5f9ae3fd0b9c83593bad2e04a08f726e5904d'),
|
|
84
|
+
dict(path='inspect.py', sha1='736287b4ec8d14a8c30afa0ba23996fdc0662caa'),
|
|
85
|
+
dict(path='pyenv/pyenv.py', sha1='d1f6e657c671c1b1a5b0e627284df656fe2d10d3'),
|
|
86
|
+
dict(path='uv/uv.py', sha1='8c6515cd6755efab3972da92a285e94ccb255515'),
|
|
87
|
+
dict(path='providers/running.py', sha1='85c9cc69ff6fbd6c8cf78ed6262619a30856c2f1'),
|
|
88
|
+
dict(path='providers/system.py', sha1='9638a154475ca98775159d27739563ac7fb2eb16'),
|
|
89
|
+
dict(path='pyenv/install.py', sha1='4a10a19717364b4ba9f3b8bf1d12621cf21ba8b8'),
|
|
90
|
+
dict(path='uv/provider.py', sha1='3c3980878ad2b9fd2cd02172f9424954759c7f06'),
|
|
91
|
+
dict(path='providers/inject.py', sha1='7cc9ebf58cf2ec09545321456bd9da9f9a3a79fb'),
|
|
92
|
+
dict(path='pyenv/provider.py', sha1='377542ce01a35849e2a5b4a4dbafedc26882f983'),
|
|
93
|
+
dict(path='uv/inject.py', sha1='e95d058c2340baa5a3155ec3440f311d1daa10a8'),
|
|
94
|
+
dict(path='pyenv/inject.py', sha1='b8fb68f5a7cae86c70fe1bad6c29a8b2dfc985c3'),
|
|
95
|
+
dict(path='inject.py', sha1='b039abbadf0b096d2724182af2e0ebda2a230852'),
|
|
96
|
+
dict(path='cli.py', sha1='6b747ba4f91e0ab6290b791c2c274f268d11c33e'),
|
|
97
|
+
],
|
|
98
|
+
)
|
|
99
|
+
|
|
100
|
+
|
|
52
101
|
########################################
|
|
53
102
|
|
|
54
103
|
|
|
@@ -60,8 +109,10 @@ VersionCmpLocalType = ta.Union['NegativeInfinityVersionType', _VersionCmpLocalTy
|
|
|
60
109
|
VersionCmpKey = ta.Tuple[int, ta.Tuple[int, ...], VersionCmpPrePostDevType, VersionCmpPrePostDevType, VersionCmpPrePostDevType, VersionCmpLocalType] # ta.TypeAlias # noqa
|
|
61
110
|
VersionComparisonMethod = ta.Callable[[VersionCmpKey, VersionCmpKey], bool] # ta.TypeAlias
|
|
62
111
|
|
|
63
|
-
# ../../omlish/lite/
|
|
112
|
+
# ../../omlish/lite/abstract.py
|
|
64
113
|
T = ta.TypeVar('T')
|
|
114
|
+
|
|
115
|
+
# ../../omlish/lite/cached.py
|
|
65
116
|
CallableT = ta.TypeVar('CallableT', bound=ta.Callable)
|
|
66
117
|
|
|
67
118
|
# ../../omlish/lite/check.py
|
|
@@ -213,12 +264,12 @@ class _BaseVersion:
|
|
|
213
264
|
|
|
214
265
|
def __lt__(self, other: '_BaseVersion') -> bool:
|
|
215
266
|
if not isinstance(other, _BaseVersion):
|
|
216
|
-
return NotImplemented
|
|
267
|
+
return NotImplemented
|
|
217
268
|
return self._key < other._key
|
|
218
269
|
|
|
219
270
|
def __le__(self, other: '_BaseVersion') -> bool:
|
|
220
271
|
if not isinstance(other, _BaseVersion):
|
|
221
|
-
return NotImplemented
|
|
272
|
+
return NotImplemented
|
|
222
273
|
return self._key <= other._key
|
|
223
274
|
|
|
224
275
|
def __eq__(self, other: object) -> bool:
|
|
@@ -228,12 +279,12 @@ class _BaseVersion:
|
|
|
228
279
|
|
|
229
280
|
def __ge__(self, other: '_BaseVersion') -> bool:
|
|
230
281
|
if not isinstance(other, _BaseVersion):
|
|
231
|
-
return NotImplemented
|
|
282
|
+
return NotImplemented
|
|
232
283
|
return self._key >= other._key
|
|
233
284
|
|
|
234
285
|
def __gt__(self, other: '_BaseVersion') -> bool:
|
|
235
286
|
if not isinstance(other, _BaseVersion):
|
|
236
|
-
return NotImplemented
|
|
287
|
+
return NotImplemented
|
|
237
288
|
return self._key > other._key
|
|
238
289
|
|
|
239
290
|
def __ne__(self, other: object) -> bool:
|
|
@@ -524,25 +575,49 @@ def is_abstract_method(obj: ta.Any) -> bool:
|
|
|
524
575
|
return bool(getattr(obj, _IS_ABSTRACT_METHOD_ATTR, False))
|
|
525
576
|
|
|
526
577
|
|
|
527
|
-
def
|
|
578
|
+
def compute_abstract_methods(cls: type) -> ta.FrozenSet[str]:
|
|
579
|
+
# ~> https://github.com/python/cpython/blob/f3476c6507381ca860eec0989f53647b13517423/Modules/_abc.c#L358
|
|
580
|
+
|
|
581
|
+
# Stage 1: direct abstract methods
|
|
582
|
+
|
|
583
|
+
abstracts = {
|
|
584
|
+
a
|
|
585
|
+
# Get items as a list to avoid mutation issues during iteration
|
|
586
|
+
for a, v in list(cls.__dict__.items())
|
|
587
|
+
if is_abstract_method(v)
|
|
588
|
+
}
|
|
589
|
+
|
|
590
|
+
# Stage 2: inherited abstract methods
|
|
591
|
+
|
|
592
|
+
for base in cls.__bases__:
|
|
593
|
+
# Get __abstractmethods__ from base if it exists
|
|
594
|
+
if (base_abstracts := getattr(base, _ABSTRACT_METHODS_ATTR, None)) is None:
|
|
595
|
+
continue
|
|
596
|
+
|
|
597
|
+
# Iterate over abstract methods in base
|
|
598
|
+
for key in base_abstracts:
|
|
599
|
+
# Check if this class has an attribute with this name
|
|
600
|
+
try:
|
|
601
|
+
value = getattr(cls, key)
|
|
602
|
+
except AttributeError:
|
|
603
|
+
# Attribute not found in this class, skip
|
|
604
|
+
continue
|
|
605
|
+
|
|
606
|
+
# Check if it's still abstract
|
|
607
|
+
if is_abstract_method(value):
|
|
608
|
+
abstracts.add(key)
|
|
609
|
+
|
|
610
|
+
return frozenset(abstracts)
|
|
611
|
+
|
|
612
|
+
|
|
613
|
+
def update_abstracts(cls: ta.Type[T], *, force: bool = False) -> ta.Type[T]:
|
|
528
614
|
if not force and not hasattr(cls, _ABSTRACT_METHODS_ATTR):
|
|
529
615
|
# Per stdlib: We check for __abstractmethods__ here because cls might by a C implementation or a python
|
|
530
616
|
# implementation (especially during testing), and we want to handle both cases.
|
|
531
617
|
return cls
|
|
532
618
|
|
|
533
|
-
abstracts
|
|
534
|
-
|
|
535
|
-
for scls in cls.__bases__:
|
|
536
|
-
for name in getattr(scls, _ABSTRACT_METHODS_ATTR, ()):
|
|
537
|
-
value = getattr(cls, name, None)
|
|
538
|
-
if getattr(value, _IS_ABSTRACT_METHOD_ATTR, False):
|
|
539
|
-
abstracts.add(name)
|
|
540
|
-
|
|
541
|
-
for name, value in cls.__dict__.items():
|
|
542
|
-
if getattr(value, _IS_ABSTRACT_METHOD_ATTR, False):
|
|
543
|
-
abstracts.add(name)
|
|
544
|
-
|
|
545
|
-
setattr(cls, _ABSTRACT_METHODS_ATTR, frozenset(abstracts))
|
|
619
|
+
abstracts = compute_abstract_methods(cls)
|
|
620
|
+
setattr(cls, _ABSTRACT_METHODS_ATTR, abstracts)
|
|
546
621
|
return cls
|
|
547
622
|
|
|
548
623
|
|
|
@@ -596,23 +671,26 @@ class Abstract:
|
|
|
596
671
|
super().__init_subclass__(**kwargs)
|
|
597
672
|
|
|
598
673
|
if not (Abstract in cls.__bases__ or abc.ABC in cls.__bases__):
|
|
599
|
-
ams
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
674
|
+
if ams := compute_abstract_methods(cls):
|
|
675
|
+
amd = {
|
|
676
|
+
a: mcls
|
|
677
|
+
for mcls in cls.__mro__[::-1]
|
|
678
|
+
for a in ams
|
|
679
|
+
if a in mcls.__dict__
|
|
680
|
+
}
|
|
605
681
|
|
|
606
|
-
if ams:
|
|
607
682
|
raise AbstractTypeError(
|
|
608
683
|
f'Cannot subclass abstract class {cls.__name__} with abstract methods: ' +
|
|
609
684
|
', '.join(sorted([
|
|
610
685
|
'.'.join([
|
|
611
|
-
*([
|
|
612
|
-
|
|
686
|
+
*([
|
|
687
|
+
*([m] if (m := getattr(c, '__module__')) else []),
|
|
688
|
+
getattr(c, '__qualname__', getattr(c, '__name__')),
|
|
689
|
+
] if c is not None else '?'),
|
|
613
690
|
a,
|
|
614
691
|
])
|
|
615
|
-
for a
|
|
692
|
+
for a in ams
|
|
693
|
+
for c in [amd.get(a)]
|
|
616
694
|
])),
|
|
617
695
|
)
|
|
618
696
|
|
|
@@ -686,6 +764,62 @@ def async_cached_nullary(fn): # ta.Callable[..., T]) -> ta.Callable[..., T]:
|
|
|
686
764
|
return _AsyncCachedNullary(fn)
|
|
687
765
|
|
|
688
766
|
|
|
767
|
+
##
|
|
768
|
+
|
|
769
|
+
|
|
770
|
+
cached_property = functools.cached_property
|
|
771
|
+
|
|
772
|
+
|
|
773
|
+
class _cached_property: # noqa
|
|
774
|
+
"""Backported to pick up https://github.com/python/cpython/commit/056dfc71dce15f81887f0bd6da09d6099d71f979 ."""
|
|
775
|
+
|
|
776
|
+
def __init__(self, func):
|
|
777
|
+
self.func = func
|
|
778
|
+
self.attrname = None # noqa
|
|
779
|
+
self.__doc__ = func.__doc__
|
|
780
|
+
self.__module__ = func.__module__
|
|
781
|
+
|
|
782
|
+
_NOT_FOUND = object()
|
|
783
|
+
|
|
784
|
+
def __set_name__(self, owner, name):
|
|
785
|
+
if self.attrname is None:
|
|
786
|
+
self.attrname = name # noqa
|
|
787
|
+
elif name != self.attrname:
|
|
788
|
+
raise TypeError(
|
|
789
|
+
f'Cannot assign the same cached_property to two different names ({self.attrname!r} and {name!r}).',
|
|
790
|
+
)
|
|
791
|
+
|
|
792
|
+
def __get__(self, instance, owner=None):
|
|
793
|
+
if instance is None:
|
|
794
|
+
return self
|
|
795
|
+
if self.attrname is None:
|
|
796
|
+
raise TypeError('Cannot use cached_property instance without calling __set_name__ on it.')
|
|
797
|
+
|
|
798
|
+
try:
|
|
799
|
+
cache = instance.__dict__
|
|
800
|
+
except AttributeError: # not all objects have __dict__ (e.g. class defines slots)
|
|
801
|
+
raise TypeError(
|
|
802
|
+
f"No '__dict__' attribute on {type(instance).__name__!r} instance to cache {self.attrname!r} property.",
|
|
803
|
+
) from None
|
|
804
|
+
|
|
805
|
+
val = cache.get(self.attrname, self._NOT_FOUND)
|
|
806
|
+
|
|
807
|
+
if val is self._NOT_FOUND:
|
|
808
|
+
val = self.func(instance)
|
|
809
|
+
try:
|
|
810
|
+
cache[self.attrname] = val
|
|
811
|
+
except TypeError:
|
|
812
|
+
raise TypeError(
|
|
813
|
+
f"The '__dict__' attribute on {type(instance).__name__!r} instance does not support item "
|
|
814
|
+
f"assignment for caching {self.attrname!r} property.",
|
|
815
|
+
) from None
|
|
816
|
+
|
|
817
|
+
return val
|
|
818
|
+
|
|
819
|
+
|
|
820
|
+
globals()['cached_property'] = _cached_property
|
|
821
|
+
|
|
822
|
+
|
|
689
823
|
########################################
|
|
690
824
|
# ../../../omlish/lite/check.py
|
|
691
825
|
"""
|
|
@@ -2050,7 +2184,7 @@ class SpecifierSet(BaseSpecifier):
|
|
|
2050
2184
|
if isinstance(other, str):
|
|
2051
2185
|
other = SpecifierSet(other)
|
|
2052
2186
|
elif not isinstance(other, SpecifierSet):
|
|
2053
|
-
return NotImplemented
|
|
2187
|
+
return NotImplemented
|
|
2054
2188
|
|
|
2055
2189
|
specifier = SpecifierSet()
|
|
2056
2190
|
specifier._specs = frozenset(self._specs | other._specs)
|
|
@@ -2070,6 +2204,7 @@ class SpecifierSet(BaseSpecifier):
|
|
|
2070
2204
|
if isinstance(other, (str, Specifier)):
|
|
2071
2205
|
other = SpecifierSet(str(other))
|
|
2072
2206
|
elif not isinstance(other, SpecifierSet):
|
|
2207
|
+
|
|
2073
2208
|
return NotImplemented
|
|
2074
2209
|
|
|
2075
2210
|
return self._specs == other._specs
|
|
@@ -2141,6 +2276,7 @@ TODO:
|
|
|
2141
2276
|
- pre-run, post-run hooks
|
|
2142
2277
|
- exitstack?
|
|
2143
2278
|
- suggestion - difflib.get_close_matches
|
|
2279
|
+
- add_argument_group - group kw on ArgparseKwarg?
|
|
2144
2280
|
"""
|
|
2145
2281
|
|
|
2146
2282
|
|
|
@@ -2151,6 +2287,7 @@ TODO:
|
|
|
2151
2287
|
class ArgparseArg:
|
|
2152
2288
|
args: ta.Sequence[ta.Any]
|
|
2153
2289
|
kwargs: ta.Mapping[str, ta.Any]
|
|
2290
|
+
group: ta.Optional[str] = None
|
|
2154
2291
|
dest: ta.Optional[str] = None
|
|
2155
2292
|
|
|
2156
2293
|
def __get__(self, instance, owner=None):
|
|
@@ -2160,7 +2297,11 @@ class ArgparseArg:
|
|
|
2160
2297
|
|
|
2161
2298
|
|
|
2162
2299
|
def argparse_arg(*args, **kwargs) -> ArgparseArg:
|
|
2163
|
-
return ArgparseArg(
|
|
2300
|
+
return ArgparseArg(
|
|
2301
|
+
args=args,
|
|
2302
|
+
group=kwargs.pop('group', None),
|
|
2303
|
+
kwargs=kwargs,
|
|
2304
|
+
)
|
|
2164
2305
|
|
|
2165
2306
|
|
|
2166
2307
|
def argparse_arg_(*args, **kwargs) -> ta.Any:
|
|
@@ -2330,6 +2471,10 @@ class ArgparseCli:
|
|
|
2330
2471
|
subparser.set_defaults(_cmd=obj)
|
|
2331
2472
|
|
|
2332
2473
|
elif isinstance(obj, ArgparseArg):
|
|
2474
|
+
if obj.group is not None:
|
|
2475
|
+
# FIXME: add_argument_group
|
|
2476
|
+
raise NotImplementedError
|
|
2477
|
+
|
|
2333
2478
|
if att in anns:
|
|
2334
2479
|
ann_kwargs = _get_argparse_arg_ann_kwargs(anns[att])
|
|
2335
2480
|
obj.kwargs = {**ann_kwargs, **obj.kwargs}
|
|
@@ -2375,7 +2520,7 @@ class ArgparseCli:
|
|
|
2375
2520
|
|
|
2376
2521
|
if self._unknown_args and not (cmd is not None and cmd.accepts_unknown):
|
|
2377
2522
|
msg = f'unrecognized arguments: {" ".join(self._unknown_args)}'
|
|
2378
|
-
if (parser := self.get_parser()).exit_on_error:
|
|
2523
|
+
if (parser := self.get_parser()).exit_on_error: # noqa
|
|
2379
2524
|
parser.error(msg)
|
|
2380
2525
|
else:
|
|
2381
2526
|
raise argparse.ArgumentError(None, msg)
|
|
@@ -2395,7 +2540,10 @@ class ArgparseCli:
|
|
|
2395
2540
|
return fn()
|
|
2396
2541
|
|
|
2397
2542
|
def cli_run_and_exit(self) -> ta.NoReturn:
|
|
2398
|
-
|
|
2543
|
+
rc = self.cli_run()
|
|
2544
|
+
if not isinstance(rc, int):
|
|
2545
|
+
rc = 0
|
|
2546
|
+
raise SystemExit(rc)
|
|
2399
2547
|
|
|
2400
2548
|
def __call__(self, *, exit: bool = False) -> ta.Optional[int]: # noqa
|
|
2401
2549
|
if exit:
|
|
@@ -2574,8 +2722,6 @@ class _JustMaybe(_Maybe[T]):
|
|
|
2574
2722
|
__slots__ = ('_v', '_hash')
|
|
2575
2723
|
|
|
2576
2724
|
def __init__(self, v: T) -> None:
|
|
2577
|
-
super().__init__()
|
|
2578
|
-
|
|
2579
2725
|
self._v = v
|
|
2580
2726
|
|
|
2581
2727
|
@property
|
|
@@ -2633,6 +2779,13 @@ class _EmptyMaybe(_Maybe[T]):
|
|
|
2633
2779
|
Maybe._empty = _EmptyMaybe() # noqa
|
|
2634
2780
|
|
|
2635
2781
|
|
|
2782
|
+
##
|
|
2783
|
+
|
|
2784
|
+
|
|
2785
|
+
setattr(Maybe, 'just', _JustMaybe) # noqa
|
|
2786
|
+
setattr(Maybe, 'empty', functools.partial(operator.attrgetter('_empty'), Maybe))
|
|
2787
|
+
|
|
2788
|
+
|
|
2636
2789
|
########################################
|
|
2637
2790
|
# ../../../omlish/lite/runtime.py
|
|
2638
2791
|
|
|
@@ -3022,9 +3175,10 @@ class InterpSpecifier:
|
|
|
3022
3175
|
def parse(cls, s: str) -> 'InterpSpecifier':
|
|
3023
3176
|
s, o = InterpOpts.parse_suffix(s)
|
|
3024
3177
|
if not any(s.startswith(o) for o in Specifier.OPERATORS):
|
|
3025
|
-
s = '~=' + s
|
|
3026
3178
|
if s.count('.') < 2:
|
|
3027
|
-
s
|
|
3179
|
+
s = '~=' + s + '.0'
|
|
3180
|
+
else:
|
|
3181
|
+
s = '==' + s
|
|
3028
3182
|
return cls(
|
|
3029
3183
|
specifier=Specifier(s),
|
|
3030
3184
|
opts=o,
|
|
@@ -4147,10 +4301,9 @@ inj = InjectionApi()
|
|
|
4147
4301
|
|
|
4148
4302
|
|
|
4149
4303
|
########################################
|
|
4150
|
-
# ../../../omlish/logs/standard.py
|
|
4304
|
+
# ../../../omlish/logs/std/standard.py
|
|
4151
4305
|
"""
|
|
4152
4306
|
TODO:
|
|
4153
|
-
- !! move to std !!
|
|
4154
4307
|
- structured
|
|
4155
4308
|
- prefixed
|
|
4156
4309
|
- debug
|
|
@@ -4538,6 +4691,10 @@ class VerboseCalledProcessError(subprocess.CalledProcessError):
|
|
|
4538
4691
|
class BaseSubprocesses(Abstract):
|
|
4539
4692
|
DEFAULT_LOGGER: ta.ClassVar[ta.Optional[LoggerLike]] = None
|
|
4540
4693
|
|
|
4694
|
+
PIPE: ta.ClassVar[int] = subprocess.PIPE
|
|
4695
|
+
STDOUT: ta.ClassVar[int] = subprocess.STDOUT
|
|
4696
|
+
DEVNULL: ta.ClassVar[int] = subprocess.DEVNULL
|
|
4697
|
+
|
|
4541
4698
|
def __init__(
|
|
4542
4699
|
self,
|
|
4543
4700
|
*,
|
|
@@ -5757,12 +5914,42 @@ uv run pip
|
|
|
5757
5914
|
uv run --python 3.11.6 pip
|
|
5758
5915
|
uv venv --python 3.11.6 --seed barf
|
|
5759
5916
|
python3 -m venv barf && barf/bin/pip install uv && barf/bin/uv venv --python 3.11.6 --seed barf2
|
|
5917
|
+
uv python find '3.13.10'
|
|
5918
|
+
uv python list --output-format=json
|
|
5760
5919
|
"""
|
|
5761
5920
|
|
|
5762
5921
|
|
|
5763
5922
|
##
|
|
5764
5923
|
|
|
5765
5924
|
|
|
5925
|
+
@dc.dataclass(frozen=True)
|
|
5926
|
+
class UvPythonListOutput:
|
|
5927
|
+
key: str
|
|
5928
|
+
version: str
|
|
5929
|
+
|
|
5930
|
+
@dc.dataclass(frozen=True)
|
|
5931
|
+
class VersionParts:
|
|
5932
|
+
major: int
|
|
5933
|
+
minor: int
|
|
5934
|
+
patch: int
|
|
5935
|
+
|
|
5936
|
+
version_parts: VersionParts
|
|
5937
|
+
|
|
5938
|
+
path: ta.Optional[str]
|
|
5939
|
+
symlink: ta.Optional[str]
|
|
5940
|
+
|
|
5941
|
+
url: str
|
|
5942
|
+
|
|
5943
|
+
os: str # emscripten linux macos
|
|
5944
|
+
variant: str # default freethreaded
|
|
5945
|
+
implementation: str # cpython graalpy pyodide pypy
|
|
5946
|
+
arch: str # aarch64 wasm32 x86_64
|
|
5947
|
+
libc: str # gnu musl none
|
|
5948
|
+
|
|
5949
|
+
|
|
5950
|
+
##
|
|
5951
|
+
|
|
5952
|
+
|
|
5766
5953
|
class UvInterpProvider(InterpProvider):
|
|
5767
5954
|
def __init__(
|
|
5768
5955
|
self,
|
|
@@ -5783,6 +5970,12 @@ class UvInterpProvider(InterpProvider):
|
|
|
5783
5970
|
async def get_installed_version(self, version: InterpVersion) -> Interp:
|
|
5784
5971
|
raise NotImplementedError
|
|
5785
5972
|
|
|
5973
|
+
# async def get_installable_versions(self, spec: InterpSpecifier) -> ta.Sequence[InterpVersion]:
|
|
5974
|
+
# return []
|
|
5975
|
+
|
|
5976
|
+
# async def install_version(self, version: InterpVersion) -> Interp:
|
|
5977
|
+
# raise TypeError
|
|
5978
|
+
|
|
5786
5979
|
|
|
5787
5980
|
########################################
|
|
5788
5981
|
# ../providers/inject.py
|
omdev/scripts/lib/inject.py
CHANGED
|
@@ -13,6 +13,7 @@ import contextvars
|
|
|
13
13
|
import dataclasses as dc
|
|
14
14
|
import functools
|
|
15
15
|
import inspect
|
|
16
|
+
import operator
|
|
16
17
|
import sys
|
|
17
18
|
import threading
|
|
18
19
|
import types
|
|
@@ -27,11 +28,25 @@ if sys.version_info < (3, 8):
|
|
|
27
28
|
raise OSError(f'Requires python (3, 8), got {sys.version_info} from {sys.executable}') # noqa
|
|
28
29
|
|
|
29
30
|
|
|
31
|
+
def __omlish_amalg__(): # noqa
|
|
32
|
+
return dict(
|
|
33
|
+
src_files=[
|
|
34
|
+
dict(path='abstract.py', sha1='a2fc3f3697fa8de5247761e9d554e70176f37aac'),
|
|
35
|
+
dict(path='check.py', sha1='bb6b6b63333699b84462951a854d99ae83195b94'),
|
|
36
|
+
dict(path='reflect.py', sha1='c4fec44bf144e9d93293c996af06f6c65fc5e63d'),
|
|
37
|
+
dict(path='maybes.py', sha1='bdf5136654ccd14b6a072588cad228925bdfbabd'),
|
|
38
|
+
dict(path='inject.py', sha1='6f097e3170019a34ff6834d36fcc9cbeed3a7ab4'),
|
|
39
|
+
],
|
|
40
|
+
)
|
|
41
|
+
|
|
42
|
+
|
|
30
43
|
########################################
|
|
31
44
|
|
|
32
45
|
|
|
33
|
-
#
|
|
46
|
+
# abstract.py
|
|
34
47
|
T = ta.TypeVar('T')
|
|
48
|
+
|
|
49
|
+
# check.py
|
|
35
50
|
SizedT = ta.TypeVar('SizedT', bound=ta.Sized)
|
|
36
51
|
CheckMessage = ta.Union[str, ta.Callable[..., ta.Optional[str]], None] # ta.TypeAlias
|
|
37
52
|
CheckLateConfigureFn = ta.Callable[['Checks'], None] # ta.TypeAlias
|
|
@@ -64,25 +79,49 @@ def is_abstract_method(obj: ta.Any) -> bool:
|
|
|
64
79
|
return bool(getattr(obj, _IS_ABSTRACT_METHOD_ATTR, False))
|
|
65
80
|
|
|
66
81
|
|
|
67
|
-
def
|
|
82
|
+
def compute_abstract_methods(cls: type) -> ta.FrozenSet[str]:
|
|
83
|
+
# ~> https://github.com/python/cpython/blob/f3476c6507381ca860eec0989f53647b13517423/Modules/_abc.c#L358
|
|
84
|
+
|
|
85
|
+
# Stage 1: direct abstract methods
|
|
86
|
+
|
|
87
|
+
abstracts = {
|
|
88
|
+
a
|
|
89
|
+
# Get items as a list to avoid mutation issues during iteration
|
|
90
|
+
for a, v in list(cls.__dict__.items())
|
|
91
|
+
if is_abstract_method(v)
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
# Stage 2: inherited abstract methods
|
|
95
|
+
|
|
96
|
+
for base in cls.__bases__:
|
|
97
|
+
# Get __abstractmethods__ from base if it exists
|
|
98
|
+
if (base_abstracts := getattr(base, _ABSTRACT_METHODS_ATTR, None)) is None:
|
|
99
|
+
continue
|
|
100
|
+
|
|
101
|
+
# Iterate over abstract methods in base
|
|
102
|
+
for key in base_abstracts:
|
|
103
|
+
# Check if this class has an attribute with this name
|
|
104
|
+
try:
|
|
105
|
+
value = getattr(cls, key)
|
|
106
|
+
except AttributeError:
|
|
107
|
+
# Attribute not found in this class, skip
|
|
108
|
+
continue
|
|
109
|
+
|
|
110
|
+
# Check if it's still abstract
|
|
111
|
+
if is_abstract_method(value):
|
|
112
|
+
abstracts.add(key)
|
|
113
|
+
|
|
114
|
+
return frozenset(abstracts)
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
def update_abstracts(cls: ta.Type[T], *, force: bool = False) -> ta.Type[T]:
|
|
68
118
|
if not force and not hasattr(cls, _ABSTRACT_METHODS_ATTR):
|
|
69
119
|
# Per stdlib: We check for __abstractmethods__ here because cls might by a C implementation or a python
|
|
70
120
|
# implementation (especially during testing), and we want to handle both cases.
|
|
71
121
|
return cls
|
|
72
122
|
|
|
73
|
-
abstracts
|
|
74
|
-
|
|
75
|
-
for scls in cls.__bases__:
|
|
76
|
-
for name in getattr(scls, _ABSTRACT_METHODS_ATTR, ()):
|
|
77
|
-
value = getattr(cls, name, None)
|
|
78
|
-
if getattr(value, _IS_ABSTRACT_METHOD_ATTR, False):
|
|
79
|
-
abstracts.add(name)
|
|
80
|
-
|
|
81
|
-
for name, value in cls.__dict__.items():
|
|
82
|
-
if getattr(value, _IS_ABSTRACT_METHOD_ATTR, False):
|
|
83
|
-
abstracts.add(name)
|
|
84
|
-
|
|
85
|
-
setattr(cls, _ABSTRACT_METHODS_ATTR, frozenset(abstracts))
|
|
123
|
+
abstracts = compute_abstract_methods(cls)
|
|
124
|
+
setattr(cls, _ABSTRACT_METHODS_ATTR, abstracts)
|
|
86
125
|
return cls
|
|
87
126
|
|
|
88
127
|
|
|
@@ -136,23 +175,26 @@ class Abstract:
|
|
|
136
175
|
super().__init_subclass__(**kwargs)
|
|
137
176
|
|
|
138
177
|
if not (Abstract in cls.__bases__ or abc.ABC in cls.__bases__):
|
|
139
|
-
ams
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
178
|
+
if ams := compute_abstract_methods(cls):
|
|
179
|
+
amd = {
|
|
180
|
+
a: mcls
|
|
181
|
+
for mcls in cls.__mro__[::-1]
|
|
182
|
+
for a in ams
|
|
183
|
+
if a in mcls.__dict__
|
|
184
|
+
}
|
|
145
185
|
|
|
146
|
-
if ams:
|
|
147
186
|
raise AbstractTypeError(
|
|
148
187
|
f'Cannot subclass abstract class {cls.__name__} with abstract methods: ' +
|
|
149
188
|
', '.join(sorted([
|
|
150
189
|
'.'.join([
|
|
151
|
-
*([
|
|
152
|
-
|
|
190
|
+
*([
|
|
191
|
+
*([m] if (m := getattr(c, '__module__')) else []),
|
|
192
|
+
getattr(c, '__qualname__', getattr(c, '__name__')),
|
|
193
|
+
] if c is not None else '?'),
|
|
153
194
|
a,
|
|
154
195
|
])
|
|
155
|
-
for a
|
|
196
|
+
for a in ams
|
|
197
|
+
for c in [amd.get(a)]
|
|
156
198
|
])),
|
|
157
199
|
)
|
|
158
200
|
|
|
@@ -896,8 +938,6 @@ class _JustMaybe(_Maybe[T]):
|
|
|
896
938
|
__slots__ = ('_v', '_hash')
|
|
897
939
|
|
|
898
940
|
def __init__(self, v: T) -> None:
|
|
899
|
-
super().__init__()
|
|
900
|
-
|
|
901
941
|
self._v = v
|
|
902
942
|
|
|
903
943
|
@property
|
|
@@ -955,6 +995,13 @@ class _EmptyMaybe(_Maybe[T]):
|
|
|
955
995
|
Maybe._empty = _EmptyMaybe() # noqa
|
|
956
996
|
|
|
957
997
|
|
|
998
|
+
##
|
|
999
|
+
|
|
1000
|
+
|
|
1001
|
+
setattr(Maybe, 'just', _JustMaybe) # noqa
|
|
1002
|
+
setattr(Maybe, 'empty', functools.partial(operator.attrgetter('_empty'), Maybe))
|
|
1003
|
+
|
|
1004
|
+
|
|
958
1005
|
########################################
|
|
959
1006
|
# inject.py
|
|
960
1007
|
|