omdev 0.0.0.dev416__py3-none-any.whl → 0.0.0.dev500__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/{.manifests.json → .omlish-manifests.json} +23 -47
- omdev/README.md +51 -0
- omdev/__about__.py +12 -8
- omdev/amalg/cli/main.py +1 -2
- 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 +26 -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/compute/storage.py +3 -1
- omdev/cache/data/actions.py +1 -1
- omdev/cache/data/cache.py +2 -2
- omdev/cache/data/specs.py +1 -1
- omdev/cexts/_boilerplate.cc +2 -3
- omdev/cexts/_distutils/build_ext.py +5 -2
- omdev/cexts/_distutils/compilers/ccompiler.py +5 -2
- omdev/cexts/_distutils/compilers/options.py +3 -0
- omdev/cexts/_distutils/compilers/unixccompiler.py +6 -2
- omdev/cexts/_distutils/dir_util.py +6 -2
- omdev/cexts/_distutils/errors.py +3 -0
- omdev/cexts/_distutils/extension.py +3 -0
- omdev/cexts/_distutils/file_util.py +6 -2
- omdev/cexts/_distutils/modified.py +3 -0
- omdev/cexts/_distutils/spawn.py +6 -2
- omdev/cexts/_distutils/sysconfig.py +3 -0
- omdev/cexts/_distutils/util.py +6 -2
- omdev/cexts/_distutils/version.py +3 -0
- omdev/cexts/cmake.py +5 -3
- omdev/cexts/scan.py +1 -2
- omdev/ci/cache.py +7 -3
- omdev/ci/cli.py +6 -4
- omdev/ci/docker/buildcaching.py +3 -1
- omdev/ci/docker/cache.py +2 -1
- omdev/ci/docker/cacheserved/cache.py +4 -1
- omdev/ci/docker/cacheserved/manifests.py +2 -2
- omdev/ci/docker/dataserver.py +2 -2
- omdev/ci/docker/imagepulling.py +2 -1
- omdev/ci/docker/packing.py +1 -1
- omdev/ci/docker/repositories.py +2 -1
- omdev/ci/github/api/clients.py +8 -4
- omdev/ci/github/api/v1/client.py +4 -1
- omdev/ci/github/api/v2/api.py +2 -0
- omdev/ci/github/api/v2/azure.py +4 -1
- omdev/ci/github/api/v2/client.py +4 -1
- omdev/cli/clicli.py +37 -7
- omdev/clipboard/clipboard.py +1 -1
- omdev/cmake.py +2 -1
- 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 +342 -62
- omdev/dataclasses/dumping.py +200 -0
- omdev/dataserver/handlers.py +3 -2
- omdev/dataserver/targets.py +2 -2
- omdev/imgur.py +2 -2
- omdev/interp/cli.py +1 -1
- omdev/interp/inspect.py +2 -1
- omdev/interp/providers/base.py +3 -2
- omdev/interp/providers/standalone.py +4 -1
- omdev/interp/providers/system.py +2 -2
- omdev/interp/pyenv/install.py +2 -1
- omdev/interp/pyenv/provider.py +2 -2
- omdev/interp/types.py +3 -2
- omdev/interp/uv/provider.py +40 -2
- omdev/interp/uv/uv.py +2 -2
- omdev/interp/venvs.py +3 -2
- 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/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 +529 -136
- omdev/manifests/building.py +6 -3
- 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/oci/data.py +2 -2
- omdev/oci/datarefs.py +2 -2
- omdev/oci/media.py +2 -2
- omdev/oci/repositories.py +3 -2
- omdev/packaging/marshal.py +9 -9
- omdev/packaging/requires.py +6 -6
- omdev/packaging/revisions.py +5 -2
- omdev/packaging/specifiers.py +41 -42
- omdev/packaging/versions.py +10 -10
- omdev/packaging/wheelfile.py +4 -2
- omdev/precheck/blanklines.py +66 -0
- omdev/precheck/caches.py +1 -1
- omdev/precheck/imports.py +14 -1
- omdev/precheck/lite.py +2 -2
- omdev/precheck/main.py +5 -5
- 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 +6 -7
- omdev/py/bracepy.py +12 -4
- omdev/py/docstrings/numpydoc.py +4 -4
- omdev/py/reprs.py +32 -0
- omdev/py/scripts/execstat.py +31 -26
- omdev/py/srcheaders.py +1 -1
- omdev/py/tokens/__init__.py +0 -0
- omdev/{tokens → py/tokens}/utils.py +2 -1
- omdev/py/tools/importscan.py +2 -2
- omdev/py/tools/mkrelimp.py +3 -4
- omdev/py/tools/pipdepup.py +686 -0
- omdev/pyproject/cli.py +1 -1
- omdev/pyproject/pkg.py +197 -48
- omdev/pyproject/reqs.py +36 -10
- omdev/pyproject/tools/__init__.py +0 -0
- omdev/pyproject/tools/aboutdeps.py +60 -0
- omdev/pyproject/venvs.py +12 -2
- omdev/rs/__init__.py +0 -0
- omdev/scripts/ci.py +9551 -6982
- omdev/scripts/interp.py +1323 -892
- omdev/scripts/lib/__init__.py +0 -0
- omdev/scripts/lib/inject.py +2086 -0
- omdev/scripts/lib/logs.py +2175 -0
- omdev/scripts/lib/marshal.py +1731 -0
- omdev/scripts/pyproject.py +4979 -1874
- omdev/tools/docker.py +19 -7
- omdev/tools/git/cli.py +56 -16
- omdev/tools/git/messages.py +2 -2
- omdev/tools/json/cli.py +6 -6
- omdev/tools/json/formats.py +2 -0
- omdev/tools/json/parsing.py +5 -5
- omdev/tools/json/processing.py +6 -3
- omdev/tools/json/rendering.py +2 -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.dev416.dist-info → omdev-0.0.0.dev500.dist-info}/METADATA +18 -12
- omdev-0.0.0.dev500.dist-info/RECORD +386 -0
- 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/tools/antlr/__main__.py +0 -11
- omdev/tools/antlr/cli.py +0 -62
- omdev/tools/antlr/consts.py +0 -7
- omdev/tools/antlr/gen.py +0 -188
- omdev-0.0.0.dev416.dist-info/RECORD +0 -332
- /omdev/{ptk/apps → irc}/__init__.py +0 -0
- /omdev/{tokens → irc/messages}/__init__.py +0 -0
- /omdev/{tools/antlr → irc/numerics}/__init__.py +0 -0
- /omdev/{tokens → py/tokens}/all.py +0 -0
- /omdev/{tokens → py/tokens}/tokenizert.py +0 -0
- {omdev-0.0.0.dev416.dist-info → omdev-0.0.0.dev500.dist-info}/WHEEL +0 -0
- {omdev-0.0.0.dev416.dist-info → omdev-0.0.0.dev500.dist-info}/entry_points.txt +0 -0
- {omdev-0.0.0.dev416.dist-info → omdev-0.0.0.dev500.dist-info}/licenses/LICENSE +0 -0
- {omdev-0.0.0.dev416.dist-info → omdev-0.0.0.dev500.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,19 +50,69 @@ 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
|
|
|
55
104
|
# ../packaging/versions.py
|
|
56
|
-
VersionLocalType = ta.Tuple[ta.Union[int, str], ...]
|
|
57
|
-
VersionCmpPrePostDevType = ta.Union['InfinityVersionType', 'NegativeInfinityVersionType', ta.Tuple[str, int]]
|
|
58
|
-
_VersionCmpLocalType0 = ta.Tuple[ta.Union[ta.Tuple[int, str], ta.Tuple['NegativeInfinityVersionType', ta.Union[int, str]]], ...] # noqa
|
|
59
|
-
VersionCmpLocalType = ta.Union['NegativeInfinityVersionType', _VersionCmpLocalType0]
|
|
60
|
-
VersionCmpKey = ta.Tuple[int, ta.Tuple[int, ...], VersionCmpPrePostDevType, VersionCmpPrePostDevType, VersionCmpPrePostDevType, VersionCmpLocalType] # noqa
|
|
61
|
-
VersionComparisonMethod = ta.Callable[[VersionCmpKey, VersionCmpKey], bool]
|
|
105
|
+
VersionLocalType = ta.Tuple[ta.Union[int, str], ...] # ta.TypeAlias
|
|
106
|
+
VersionCmpPrePostDevType = ta.Union['InfinityVersionType', 'NegativeInfinityVersionType', ta.Tuple[str, int]] # ta.TypeAlias # noqa
|
|
107
|
+
_VersionCmpLocalType0 = ta.Tuple[ta.Union[ta.Tuple[int, str], ta.Tuple['NegativeInfinityVersionType', ta.Union[int, str]]], ...] # ta.TypeAlias # noqa
|
|
108
|
+
VersionCmpLocalType = ta.Union['NegativeInfinityVersionType', _VersionCmpLocalType0] # ta.TypeAlias
|
|
109
|
+
VersionCmpKey = ta.Tuple[int, ta.Tuple[int, ...], VersionCmpPrePostDevType, VersionCmpPrePostDevType, VersionCmpPrePostDevType, VersionCmpLocalType] # ta.TypeAlias # noqa
|
|
110
|
+
VersionComparisonMethod = ta.Callable[[VersionCmpKey, VersionCmpKey], bool] # ta.TypeAlias
|
|
111
|
+
|
|
112
|
+
# ../../omlish/lite/abstract.py
|
|
113
|
+
T = ta.TypeVar('T')
|
|
62
114
|
|
|
63
115
|
# ../../omlish/lite/cached.py
|
|
64
|
-
T = ta.TypeVar('T')
|
|
65
116
|
CallableT = ta.TypeVar('CallableT', bound=ta.Callable)
|
|
66
117
|
|
|
67
118
|
# ../../omlish/lite/check.py
|
|
@@ -72,28 +123,31 @@ CheckOnRaiseFn = ta.Callable[[Exception], None] # ta.TypeAlias
|
|
|
72
123
|
CheckExceptionFactory = ta.Callable[..., Exception] # ta.TypeAlias
|
|
73
124
|
CheckArgsRenderer = ta.Callable[..., ta.Optional[str]] # ta.TypeAlias
|
|
74
125
|
|
|
75
|
-
# ../../omlish/
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
# ../../omlish/lite/timeouts.py
|
|
79
|
-
TimeoutLike = ta.Union['Timeout', ta.Type['Timeout.DEFAULT'], ta.Iterable['TimeoutLike'], float, None] # ta.TypeAlias
|
|
126
|
+
# ../../omlish/logs/levels.py
|
|
127
|
+
LogLevel = int # ta.TypeAlias
|
|
80
128
|
|
|
81
129
|
# ../packaging/specifiers.py
|
|
82
|
-
UnparsedVersion = ta.Union['Version', str]
|
|
130
|
+
UnparsedVersion = ta.Union['Version', str] # ta.TypeAlias
|
|
83
131
|
UnparsedVersionVar = ta.TypeVar('UnparsedVersionVar', bound=UnparsedVersion)
|
|
84
|
-
CallableVersionOperator = ta.Callable[['Version', str], bool]
|
|
132
|
+
CallableVersionOperator = ta.Callable[['Version', str], bool] # ta.TypeAlias
|
|
85
133
|
|
|
86
134
|
# ../../omlish/argparse/cli.py
|
|
87
135
|
ArgparseCmdFn = ta.Callable[[], ta.Optional[int]] # ta.TypeAlias
|
|
88
136
|
|
|
137
|
+
# ../../omlish/lite/maybes.py
|
|
138
|
+
U = ta.TypeVar('U')
|
|
139
|
+
|
|
140
|
+
# ../../omlish/lite/timeouts.py
|
|
141
|
+
TimeoutLike = ta.Union['Timeout', ta.Type['Timeout.DEFAULT'], ta.Iterable['TimeoutLike'], float, None] # ta.TypeAlias
|
|
142
|
+
|
|
89
143
|
# ../../omlish/asyncs/asyncio/timeouts.py
|
|
90
144
|
AwaitableT = ta.TypeVar('AwaitableT', bound=ta.Awaitable)
|
|
91
145
|
|
|
92
146
|
# ../../omlish/lite/inject.py
|
|
93
|
-
InjectorKeyCls = ta.Union[type, ta.NewType]
|
|
94
|
-
InjectorProviderFn = ta.Callable[['Injector'], ta.Any]
|
|
95
|
-
InjectorProviderFnMap = ta.Mapping['InjectorKey', 'InjectorProviderFn']
|
|
96
|
-
InjectorBindingOrBindings = ta.Union['InjectorBinding', 'InjectorBindings']
|
|
147
|
+
InjectorKeyCls = ta.Union[type, ta.NewType] # ta.TypeAlias
|
|
148
|
+
InjectorProviderFn = ta.Callable[['Injector'], ta.Any] # ta.TypeAlias
|
|
149
|
+
InjectorProviderFnMap = ta.Mapping['InjectorKey', 'InjectorProviderFn'] # ta.TypeAlias
|
|
150
|
+
InjectorBindingOrBindings = ta.Union['InjectorBinding', 'InjectorBindings'] # ta.TypeAlias
|
|
97
151
|
|
|
98
152
|
# ../../omlish/subprocesses/base.py
|
|
99
153
|
SubprocessChannelOption = ta.Literal['pipe', 'stdout', 'devnull'] # ta.TypeAlias
|
|
@@ -210,12 +264,12 @@ class _BaseVersion:
|
|
|
210
264
|
|
|
211
265
|
def __lt__(self, other: '_BaseVersion') -> bool:
|
|
212
266
|
if not isinstance(other, _BaseVersion):
|
|
213
|
-
return NotImplemented
|
|
267
|
+
return NotImplemented
|
|
214
268
|
return self._key < other._key
|
|
215
269
|
|
|
216
270
|
def __le__(self, other: '_BaseVersion') -> bool:
|
|
217
271
|
if not isinstance(other, _BaseVersion):
|
|
218
|
-
return NotImplemented
|
|
272
|
+
return NotImplemented
|
|
219
273
|
return self._key <= other._key
|
|
220
274
|
|
|
221
275
|
def __eq__(self, other: object) -> bool:
|
|
@@ -225,12 +279,12 @@ class _BaseVersion:
|
|
|
225
279
|
|
|
226
280
|
def __ge__(self, other: '_BaseVersion') -> bool:
|
|
227
281
|
if not isinstance(other, _BaseVersion):
|
|
228
|
-
return NotImplemented
|
|
282
|
+
return NotImplemented
|
|
229
283
|
return self._key >= other._key
|
|
230
284
|
|
|
231
285
|
def __gt__(self, other: '_BaseVersion') -> bool:
|
|
232
286
|
if not isinstance(other, _BaseVersion):
|
|
233
|
-
return NotImplemented
|
|
287
|
+
return NotImplemented
|
|
234
288
|
return self._key > other._key
|
|
235
289
|
|
|
236
290
|
def __ne__(self, other: object) -> bool:
|
|
@@ -506,6 +560,153 @@ def canonicalize_version(
|
|
|
506
560
|
return ''.join(parts)
|
|
507
561
|
|
|
508
562
|
|
|
563
|
+
########################################
|
|
564
|
+
# ../../../omlish/lite/abstract.py
|
|
565
|
+
|
|
566
|
+
|
|
567
|
+
##
|
|
568
|
+
|
|
569
|
+
|
|
570
|
+
_ABSTRACT_METHODS_ATTR = '__abstractmethods__'
|
|
571
|
+
_IS_ABSTRACT_METHOD_ATTR = '__isabstractmethod__'
|
|
572
|
+
|
|
573
|
+
|
|
574
|
+
def is_abstract_method(obj: ta.Any) -> bool:
|
|
575
|
+
return bool(getattr(obj, _IS_ABSTRACT_METHOD_ATTR, False))
|
|
576
|
+
|
|
577
|
+
|
|
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]:
|
|
614
|
+
if not force and not hasattr(cls, _ABSTRACT_METHODS_ATTR):
|
|
615
|
+
# Per stdlib: We check for __abstractmethods__ here because cls might by a C implementation or a python
|
|
616
|
+
# implementation (especially during testing), and we want to handle both cases.
|
|
617
|
+
return cls
|
|
618
|
+
|
|
619
|
+
abstracts = compute_abstract_methods(cls)
|
|
620
|
+
setattr(cls, _ABSTRACT_METHODS_ATTR, abstracts)
|
|
621
|
+
return cls
|
|
622
|
+
|
|
623
|
+
|
|
624
|
+
#
|
|
625
|
+
|
|
626
|
+
|
|
627
|
+
class AbstractTypeError(TypeError):
|
|
628
|
+
pass
|
|
629
|
+
|
|
630
|
+
|
|
631
|
+
_FORCE_ABSTRACT_ATTR = '__forceabstract__'
|
|
632
|
+
|
|
633
|
+
|
|
634
|
+
class Abstract:
|
|
635
|
+
"""
|
|
636
|
+
Different from, but interoperable with, abc.ABC / abc.ABCMeta:
|
|
637
|
+
|
|
638
|
+
- This raises AbstractTypeError during class creation, not instance instantiation - unless Abstract or abc.ABC are
|
|
639
|
+
explicitly present in the class's direct bases.
|
|
640
|
+
- This will forbid instantiation of classes with Abstract in their direct bases even if there are no
|
|
641
|
+
abstractmethods left on the class.
|
|
642
|
+
- This is a mixin, not a metaclass.
|
|
643
|
+
- As it is not an ABCMeta, this does not support virtual base classes. As a result, operations like `isinstance`
|
|
644
|
+
and `issubclass` are ~7x faster.
|
|
645
|
+
- It additionally enforces a base class order of (Abstract, abc.ABC) to preemptively prevent common mro conflicts.
|
|
646
|
+
|
|
647
|
+
If not mixed-in with an ABCMeta, it will update __abstractmethods__ itself.
|
|
648
|
+
"""
|
|
649
|
+
|
|
650
|
+
__slots__ = ()
|
|
651
|
+
|
|
652
|
+
__abstractmethods__: ta.ClassVar[ta.FrozenSet[str]] = frozenset()
|
|
653
|
+
|
|
654
|
+
#
|
|
655
|
+
|
|
656
|
+
def __forceabstract__(self):
|
|
657
|
+
raise TypeError
|
|
658
|
+
|
|
659
|
+
# This is done manually, rather than through @abc.abstractmethod, to mask it from static analysis.
|
|
660
|
+
setattr(__forceabstract__, _IS_ABSTRACT_METHOD_ATTR, True)
|
|
661
|
+
|
|
662
|
+
#
|
|
663
|
+
|
|
664
|
+
def __init_subclass__(cls, **kwargs: ta.Any) -> None:
|
|
665
|
+
setattr(
|
|
666
|
+
cls,
|
|
667
|
+
_FORCE_ABSTRACT_ATTR,
|
|
668
|
+
getattr(Abstract, _FORCE_ABSTRACT_ATTR) if Abstract in cls.__bases__ else False,
|
|
669
|
+
)
|
|
670
|
+
|
|
671
|
+
super().__init_subclass__(**kwargs)
|
|
672
|
+
|
|
673
|
+
if not (Abstract in cls.__bases__ or abc.ABC in cls.__bases__):
|
|
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
|
+
}
|
|
681
|
+
|
|
682
|
+
raise AbstractTypeError(
|
|
683
|
+
f'Cannot subclass abstract class {cls.__name__} with abstract methods: ' +
|
|
684
|
+
', '.join(sorted([
|
|
685
|
+
'.'.join([
|
|
686
|
+
*([
|
|
687
|
+
*([m] if (m := getattr(c, '__module__')) else []),
|
|
688
|
+
getattr(c, '__qualname__', getattr(c, '__name__')),
|
|
689
|
+
] if c is not None else '?'),
|
|
690
|
+
a,
|
|
691
|
+
])
|
|
692
|
+
for a in ams
|
|
693
|
+
for c in [amd.get(a)]
|
|
694
|
+
])),
|
|
695
|
+
)
|
|
696
|
+
|
|
697
|
+
xbi = (Abstract, abc.ABC) # , ta.Generic ?
|
|
698
|
+
bis = [(cls.__bases__.index(b), b) for b in xbi if b in cls.__bases__]
|
|
699
|
+
if bis != sorted(bis):
|
|
700
|
+
raise TypeError(
|
|
701
|
+
f'Abstract subclass {cls.__name__} must have proper base class order of '
|
|
702
|
+
f'({", ".join(getattr(b, "__name__") for b in xbi)}), got: '
|
|
703
|
+
f'({", ".join(getattr(b, "__name__") for _, b in sorted(bis))})',
|
|
704
|
+
)
|
|
705
|
+
|
|
706
|
+
if not isinstance(cls, abc.ABCMeta):
|
|
707
|
+
update_abstracts(cls, force=True)
|
|
708
|
+
|
|
709
|
+
|
|
509
710
|
########################################
|
|
510
711
|
# ../../../omlish/lite/cached.py
|
|
511
712
|
|
|
@@ -524,7 +725,7 @@ class _AbstractCachedNullary:
|
|
|
524
725
|
def __call__(self, *args, **kwargs): # noqa
|
|
525
726
|
raise TypeError
|
|
526
727
|
|
|
527
|
-
def __get__(self, instance, owner): # noqa
|
|
728
|
+
def __get__(self, instance, owner=None): # noqa
|
|
528
729
|
bound = instance.__dict__[self._fn.__name__] = self.__class__(self._fn.__get__(instance, owner))
|
|
529
730
|
return bound
|
|
530
731
|
|
|
@@ -563,6 +764,62 @@ def async_cached_nullary(fn): # ta.Callable[..., T]) -> ta.Callable[..., T]:
|
|
|
563
764
|
return _AsyncCachedNullary(fn)
|
|
564
765
|
|
|
565
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
|
+
|
|
566
823
|
########################################
|
|
567
824
|
# ../../../omlish/lite/check.py
|
|
568
825
|
"""
|
|
@@ -1086,311 +1343,92 @@ json_dumps_compact: ta.Callable[..., str] = functools.partial(json.dumps, **JSON
|
|
|
1086
1343
|
|
|
1087
1344
|
|
|
1088
1345
|
########################################
|
|
1089
|
-
# ../../../omlish/lite/
|
|
1346
|
+
# ../../../omlish/lite/reflect.py
|
|
1090
1347
|
|
|
1091
1348
|
|
|
1092
1349
|
##
|
|
1093
1350
|
|
|
1094
1351
|
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1352
|
+
_GENERIC_ALIAS_TYPES = (
|
|
1353
|
+
ta._GenericAlias, # type: ignore # noqa
|
|
1354
|
+
*([ta._SpecialGenericAlias] if hasattr(ta, '_SpecialGenericAlias') else []), # noqa
|
|
1355
|
+
)
|
|
1099
1356
|
|
|
1100
|
-
#
|
|
1101
1357
|
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1358
|
+
def is_generic_alias(obj: ta.Any, *, origin: ta.Any = None) -> bool:
|
|
1359
|
+
return (
|
|
1360
|
+
isinstance(obj, _GENERIC_ALIAS_TYPES) and
|
|
1361
|
+
(origin is None or ta.get_origin(obj) is origin)
|
|
1362
|
+
)
|
|
1106
1363
|
|
|
1107
|
-
@abc.abstractmethod
|
|
1108
|
-
def must(self) -> T:
|
|
1109
|
-
raise NotImplementedError
|
|
1110
1364
|
|
|
1111
|
-
|
|
1365
|
+
is_callable_alias = functools.partial(is_generic_alias, origin=ta.Callable)
|
|
1112
1366
|
|
|
1113
|
-
@abc.abstractmethod
|
|
1114
|
-
def __repr__(self) -> str:
|
|
1115
|
-
raise NotImplementedError
|
|
1116
1367
|
|
|
1117
|
-
|
|
1118
|
-
def __hash__(self) -> int:
|
|
1119
|
-
raise NotImplementedError
|
|
1368
|
+
##
|
|
1120
1369
|
|
|
1121
|
-
@abc.abstractmethod
|
|
1122
|
-
def __eq__(self, other) -> bool:
|
|
1123
|
-
raise NotImplementedError
|
|
1124
1370
|
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
|
|
1371
|
+
_UNION_ALIAS_ORIGINS = frozenset([
|
|
1372
|
+
ta.get_origin(ta.Optional[int]),
|
|
1373
|
+
*(
|
|
1374
|
+
[
|
|
1375
|
+
ta.get_origin(int | None),
|
|
1376
|
+
ta.get_origin(getattr(ta, 'TypeVar')('_T') | None),
|
|
1377
|
+
] if sys.version_info >= (3, 10) else ()
|
|
1378
|
+
),
|
|
1379
|
+
])
|
|
1128
1380
|
|
|
1129
|
-
#
|
|
1130
1381
|
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
return not (self == other)
|
|
1382
|
+
def is_union_alias(obj: ta.Any) -> bool:
|
|
1383
|
+
return ta.get_origin(obj) in _UNION_ALIAS_ORIGINS
|
|
1134
1384
|
|
|
1135
|
-
@ta.final
|
|
1136
|
-
def __iter__(self) -> ta.Iterator[T]:
|
|
1137
|
-
if self.present:
|
|
1138
|
-
yield self.must()
|
|
1139
1385
|
|
|
1140
|
-
|
|
1141
|
-
def __bool__(self) -> ta.NoReturn:
|
|
1142
|
-
raise TypeError
|
|
1386
|
+
#
|
|
1143
1387
|
|
|
1144
|
-
#
|
|
1145
1388
|
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
|
|
1389
|
+
def is_optional_alias(spec: ta.Any) -> bool:
|
|
1390
|
+
return (
|
|
1391
|
+
is_union_alias(spec) and
|
|
1392
|
+
len(ta.get_args(spec)) == 2 and
|
|
1393
|
+
any(a in (None, type(None)) for a in ta.get_args(spec))
|
|
1394
|
+
)
|
|
1150
1395
|
|
|
1151
|
-
@ta.final
|
|
1152
|
-
def filter(self, predicate: ta.Callable[[T], bool]) -> 'Maybe[T]':
|
|
1153
|
-
if self.present and predicate(self.must()):
|
|
1154
|
-
return self
|
|
1155
|
-
else:
|
|
1156
|
-
return Maybe.empty()
|
|
1157
1396
|
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
return Maybe.just(mapper(self.must()))
|
|
1162
|
-
else:
|
|
1163
|
-
return Maybe.empty()
|
|
1397
|
+
def get_optional_alias_arg(spec: ta.Any) -> ta.Any:
|
|
1398
|
+
[it] = [it for it in ta.get_args(spec) if it not in (None, type(None))]
|
|
1399
|
+
return it
|
|
1164
1400
|
|
|
1165
|
-
@ta.final
|
|
1166
|
-
def flat_map(self, mapper: ta.Callable[[T], 'Maybe[U]']) -> 'Maybe[U]':
|
|
1167
|
-
if self.present:
|
|
1168
|
-
if not isinstance(v := mapper(self.must()), Maybe):
|
|
1169
|
-
raise TypeError(v)
|
|
1170
|
-
return v
|
|
1171
|
-
else:
|
|
1172
|
-
return Maybe.empty()
|
|
1173
1401
|
|
|
1174
|
-
|
|
1175
|
-
def or_else(self, other: ta.Union[T, U]) -> ta.Union[T, U]:
|
|
1176
|
-
if self.present:
|
|
1177
|
-
return self.must()
|
|
1178
|
-
else:
|
|
1179
|
-
return other
|
|
1402
|
+
##
|
|
1180
1403
|
|
|
1181
|
-
@ta.final
|
|
1182
|
-
def or_else_get(self, supplier: ta.Callable[[], ta.Union[T, U]]) -> ta.Union[T, U]:
|
|
1183
|
-
if self.present:
|
|
1184
|
-
return self.must()
|
|
1185
|
-
else:
|
|
1186
|
-
return supplier()
|
|
1187
1404
|
|
|
1188
|
-
|
|
1189
|
-
|
|
1190
|
-
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
|
|
1405
|
+
def is_new_type(spec: ta.Any) -> bool:
|
|
1406
|
+
if isinstance(ta.NewType, type):
|
|
1407
|
+
return isinstance(spec, ta.NewType)
|
|
1408
|
+
else:
|
|
1409
|
+
# Before https://github.com/python/cpython/commit/c2f33dfc83ab270412bf243fb21f724037effa1a
|
|
1410
|
+
return isinstance(spec, types.FunctionType) and spec.__code__ is ta.NewType.__code__.co_consts[1] # type: ignore # noqa
|
|
1194
1411
|
|
|
1195
|
-
#
|
|
1196
1412
|
|
|
1197
|
-
|
|
1198
|
-
|
|
1199
|
-
if v is not None:
|
|
1200
|
-
return cls.just(v)
|
|
1201
|
-
else:
|
|
1202
|
-
return cls.empty()
|
|
1413
|
+
def get_new_type_supertype(spec: ta.Any) -> ta.Any:
|
|
1414
|
+
return spec.__supertype__
|
|
1203
1415
|
|
|
1204
|
-
@classmethod
|
|
1205
|
-
def just(cls, v: T) -> 'Maybe[T]':
|
|
1206
|
-
return _JustMaybe(v)
|
|
1207
1416
|
|
|
1208
|
-
|
|
1417
|
+
##
|
|
1209
1418
|
|
|
1210
|
-
@classmethod
|
|
1211
|
-
def empty(cls) -> 'Maybe[T]':
|
|
1212
|
-
return Maybe._empty
|
|
1213
1419
|
|
|
1420
|
+
def is_literal_type(spec: ta.Any) -> bool:
|
|
1421
|
+
if hasattr(ta, '_LiteralGenericAlias'):
|
|
1422
|
+
return isinstance(spec, ta._LiteralGenericAlias) # noqa
|
|
1423
|
+
else:
|
|
1424
|
+
return (
|
|
1425
|
+
isinstance(spec, ta._GenericAlias) and # type: ignore # noqa
|
|
1426
|
+
spec.__origin__ is ta.Literal
|
|
1427
|
+
)
|
|
1214
1428
|
|
|
1215
|
-
##
|
|
1216
1429
|
|
|
1217
|
-
|
|
1218
|
-
|
|
1219
|
-
def __lt__(self, other):
|
|
1220
|
-
if not isinstance(other, _Maybe):
|
|
1221
|
-
return NotImplemented
|
|
1222
|
-
sp = self.present
|
|
1223
|
-
op = other.present
|
|
1224
|
-
if self.present and other.present:
|
|
1225
|
-
return self.must() < other.must()
|
|
1226
|
-
else:
|
|
1227
|
-
return op and not sp
|
|
1228
|
-
|
|
1229
|
-
|
|
1230
|
-
class _JustMaybe(_Maybe[T]):
|
|
1231
|
-
__slots__ = ('_v', '_hash')
|
|
1232
|
-
|
|
1233
|
-
def __init__(self, v: T) -> None:
|
|
1234
|
-
super().__init__()
|
|
1235
|
-
|
|
1236
|
-
self._v = v
|
|
1237
|
-
|
|
1238
|
-
@property
|
|
1239
|
-
def present(self) -> bool:
|
|
1240
|
-
return True
|
|
1241
|
-
|
|
1242
|
-
def must(self) -> T:
|
|
1243
|
-
return self._v
|
|
1244
|
-
|
|
1245
|
-
#
|
|
1246
|
-
|
|
1247
|
-
def __repr__(self) -> str:
|
|
1248
|
-
return f'just({self._v!r})'
|
|
1249
|
-
|
|
1250
|
-
_hash: int
|
|
1251
|
-
|
|
1252
|
-
def __hash__(self) -> int:
|
|
1253
|
-
try:
|
|
1254
|
-
return self._hash
|
|
1255
|
-
except AttributeError:
|
|
1256
|
-
pass
|
|
1257
|
-
h = self._hash = hash((_JustMaybe, self._v))
|
|
1258
|
-
return h
|
|
1259
|
-
|
|
1260
|
-
def __eq__(self, other):
|
|
1261
|
-
return (
|
|
1262
|
-
self.__class__ is other.__class__ and
|
|
1263
|
-
self._v == other._v # noqa
|
|
1264
|
-
)
|
|
1265
|
-
|
|
1266
|
-
|
|
1267
|
-
class _EmptyMaybe(_Maybe[T]):
|
|
1268
|
-
__slots__ = ()
|
|
1269
|
-
|
|
1270
|
-
@property
|
|
1271
|
-
def present(self) -> bool:
|
|
1272
|
-
return False
|
|
1273
|
-
|
|
1274
|
-
def must(self) -> T:
|
|
1275
|
-
raise Maybe.ValueNotPresentError
|
|
1276
|
-
|
|
1277
|
-
#
|
|
1278
|
-
|
|
1279
|
-
def __repr__(self) -> str:
|
|
1280
|
-
return 'empty()'
|
|
1281
|
-
|
|
1282
|
-
def __hash__(self) -> int:
|
|
1283
|
-
return hash(_EmptyMaybe)
|
|
1284
|
-
|
|
1285
|
-
def __eq__(self, other):
|
|
1286
|
-
return self.__class__ is other.__class__
|
|
1287
|
-
|
|
1288
|
-
|
|
1289
|
-
Maybe._empty = _EmptyMaybe() # noqa
|
|
1290
|
-
|
|
1291
|
-
|
|
1292
|
-
########################################
|
|
1293
|
-
# ../../../omlish/lite/reflect.py
|
|
1294
|
-
|
|
1295
|
-
|
|
1296
|
-
##
|
|
1297
|
-
|
|
1298
|
-
|
|
1299
|
-
_GENERIC_ALIAS_TYPES = (
|
|
1300
|
-
ta._GenericAlias, # type: ignore # noqa
|
|
1301
|
-
*([ta._SpecialGenericAlias] if hasattr(ta, '_SpecialGenericAlias') else []), # noqa
|
|
1302
|
-
)
|
|
1303
|
-
|
|
1304
|
-
|
|
1305
|
-
def is_generic_alias(obj: ta.Any, *, origin: ta.Any = None) -> bool:
|
|
1306
|
-
return (
|
|
1307
|
-
isinstance(obj, _GENERIC_ALIAS_TYPES) and
|
|
1308
|
-
(origin is None or ta.get_origin(obj) is origin)
|
|
1309
|
-
)
|
|
1310
|
-
|
|
1311
|
-
|
|
1312
|
-
is_callable_alias = functools.partial(is_generic_alias, origin=ta.Callable)
|
|
1313
|
-
|
|
1314
|
-
|
|
1315
|
-
##
|
|
1316
|
-
|
|
1317
|
-
|
|
1318
|
-
_UNION_ALIAS_ORIGINS = frozenset([
|
|
1319
|
-
ta.get_origin(ta.Optional[int]),
|
|
1320
|
-
*(
|
|
1321
|
-
[
|
|
1322
|
-
ta.get_origin(int | None),
|
|
1323
|
-
ta.get_origin(getattr(ta, 'TypeVar')('_T') | None),
|
|
1324
|
-
] if sys.version_info >= (3, 10) else ()
|
|
1325
|
-
),
|
|
1326
|
-
])
|
|
1327
|
-
|
|
1328
|
-
|
|
1329
|
-
def is_union_alias(obj: ta.Any) -> bool:
|
|
1330
|
-
return ta.get_origin(obj) in _UNION_ALIAS_ORIGINS
|
|
1331
|
-
|
|
1332
|
-
|
|
1333
|
-
#
|
|
1334
|
-
|
|
1335
|
-
|
|
1336
|
-
def is_optional_alias(spec: ta.Any) -> bool:
|
|
1337
|
-
return (
|
|
1338
|
-
is_union_alias(spec) and
|
|
1339
|
-
len(ta.get_args(spec)) == 2 and
|
|
1340
|
-
any(a in (None, type(None)) for a in ta.get_args(spec))
|
|
1341
|
-
)
|
|
1342
|
-
|
|
1343
|
-
|
|
1344
|
-
def get_optional_alias_arg(spec: ta.Any) -> ta.Any:
|
|
1345
|
-
[it] = [it for it in ta.get_args(spec) if it not in (None, type(None))]
|
|
1346
|
-
return it
|
|
1347
|
-
|
|
1348
|
-
|
|
1349
|
-
##
|
|
1350
|
-
|
|
1351
|
-
|
|
1352
|
-
def is_new_type(spec: ta.Any) -> bool:
|
|
1353
|
-
if isinstance(ta.NewType, type):
|
|
1354
|
-
return isinstance(spec, ta.NewType)
|
|
1355
|
-
else:
|
|
1356
|
-
# Before https://github.com/python/cpython/commit/c2f33dfc83ab270412bf243fb21f724037effa1a
|
|
1357
|
-
return isinstance(spec, types.FunctionType) and spec.__code__ is ta.NewType.__code__.co_consts[1] # type: ignore # noqa
|
|
1358
|
-
|
|
1359
|
-
|
|
1360
|
-
def get_new_type_supertype(spec: ta.Any) -> ta.Any:
|
|
1361
|
-
return spec.__supertype__
|
|
1362
|
-
|
|
1363
|
-
|
|
1364
|
-
##
|
|
1365
|
-
|
|
1366
|
-
|
|
1367
|
-
def is_literal_type(spec: ta.Any) -> bool:
|
|
1368
|
-
if hasattr(ta, '_LiteralGenericAlias'):
|
|
1369
|
-
return isinstance(spec, ta._LiteralGenericAlias) # noqa
|
|
1370
|
-
else:
|
|
1371
|
-
return (
|
|
1372
|
-
isinstance(spec, ta._GenericAlias) and # type: ignore # noqa
|
|
1373
|
-
spec.__origin__ is ta.Literal
|
|
1374
|
-
)
|
|
1375
|
-
|
|
1376
|
-
|
|
1377
|
-
def get_literal_type_args(spec: ta.Any) -> ta.Iterable[ta.Any]:
|
|
1378
|
-
return spec.__args__
|
|
1379
|
-
|
|
1380
|
-
|
|
1381
|
-
##
|
|
1382
|
-
|
|
1383
|
-
|
|
1384
|
-
def deep_subclasses(cls: ta.Type[T]) -> ta.Iterator[ta.Type[T]]:
|
|
1385
|
-
seen = set()
|
|
1386
|
-
todo = list(reversed(cls.__subclasses__()))
|
|
1387
|
-
while todo:
|
|
1388
|
-
cur = todo.pop()
|
|
1389
|
-
if cur in seen:
|
|
1390
|
-
continue
|
|
1391
|
-
seen.add(cur)
|
|
1392
|
-
yield cur
|
|
1393
|
-
todo.extend(reversed(cur.__subclasses__()))
|
|
1430
|
+
def get_literal_type_args(spec: ta.Any) -> ta.Iterable[ta.Any]:
|
|
1431
|
+
return spec.__args__
|
|
1394
1432
|
|
|
1395
1433
|
|
|
1396
1434
|
########################################
|
|
@@ -1469,13 +1507,6 @@ def split_keep_delimiter(s, d):
|
|
|
1469
1507
|
##
|
|
1470
1508
|
|
|
1471
1509
|
|
|
1472
|
-
def attr_repr(obj: ta.Any, *attrs: str) -> str:
|
|
1473
|
-
return f'{type(obj).__name__}({", ".join(f"{attr}={getattr(obj, attr)!r}" for attr in attrs)})'
|
|
1474
|
-
|
|
1475
|
-
|
|
1476
|
-
##
|
|
1477
|
-
|
|
1478
|
-
|
|
1479
1510
|
FORMAT_NUM_BYTES_SUFFIXES: ta.Sequence[str] = ['B', 'kB', 'MB', 'GB', 'TB', 'PB', 'EB']
|
|
1480
1511
|
|
|
1481
1512
|
|
|
@@ -1492,212 +1523,114 @@ def format_num_bytes(num_bytes: int) -> str:
|
|
|
1492
1523
|
|
|
1493
1524
|
|
|
1494
1525
|
########################################
|
|
1495
|
-
# ../../../omlish/
|
|
1496
|
-
"""
|
|
1497
|
-
TODO:
|
|
1498
|
-
- Event (/ Predicate)
|
|
1499
|
-
"""
|
|
1526
|
+
# ../../../omlish/logs/levels.py
|
|
1500
1527
|
|
|
1501
1528
|
|
|
1502
1529
|
##
|
|
1503
1530
|
|
|
1504
1531
|
|
|
1505
|
-
|
|
1506
|
-
|
|
1507
|
-
|
|
1508
|
-
|
|
1509
|
-
|
|
1532
|
+
@ta.final
|
|
1533
|
+
class NamedLogLevel(int):
|
|
1534
|
+
# logging.getLevelNamesMapping (or, as that is unavailable <3.11, logging._nameToLevel) includes the deprecated
|
|
1535
|
+
# aliases.
|
|
1536
|
+
_NAMES_BY_INT: ta.ClassVar[ta.Mapping[LogLevel, str]] = dict(sorted(logging._levelToName.items(), key=lambda t: -t[0])) # noqa
|
|
1510
1537
|
|
|
1511
|
-
|
|
1538
|
+
_INTS_BY_NAME: ta.ClassVar[ta.Mapping[str, LogLevel]] = {v: k for k, v in _NAMES_BY_INT.items()}
|
|
1512
1539
|
|
|
1513
|
-
|
|
1514
|
-
def expired(self) -> bool:
|
|
1515
|
-
"""Return whether or not this timeout has expired."""
|
|
1540
|
+
_NAME_INT_PAIRS: ta.ClassVar[ta.Sequence[ta.Tuple[str, LogLevel]]] = list(_INTS_BY_NAME.items())
|
|
1516
1541
|
|
|
1517
|
-
|
|
1542
|
+
#
|
|
1518
1543
|
|
|
1519
|
-
|
|
1520
|
-
def remaining(self) -> float:
|
|
1521
|
-
"""Returns the time (in seconds) remaining until the timeout expires. May be negative and/or infinite."""
|
|
1544
|
+
_CACHE: ta.ClassVar[ta.MutableMapping[int, 'NamedLogLevel']] = {}
|
|
1522
1545
|
|
|
1523
|
-
|
|
1546
|
+
@ta.overload
|
|
1547
|
+
def __new__(cls, name: str, offset: int = 0, /) -> 'NamedLogLevel':
|
|
1548
|
+
...
|
|
1524
1549
|
|
|
1525
|
-
@
|
|
1526
|
-
def
|
|
1527
|
-
|
|
1550
|
+
@ta.overload
|
|
1551
|
+
def __new__(cls, i: int, /) -> 'NamedLogLevel':
|
|
1552
|
+
...
|
|
1528
1553
|
|
|
1529
|
-
|
|
1554
|
+
def __new__(cls, x, offset=0, /):
|
|
1555
|
+
if isinstance(x, str):
|
|
1556
|
+
return cls(cls._INTS_BY_NAME[x.upper()] + offset)
|
|
1557
|
+
elif not offset and (c := cls._CACHE.get(x)) is not None:
|
|
1558
|
+
return c
|
|
1559
|
+
else:
|
|
1560
|
+
return super().__new__(cls, x + offset)
|
|
1530
1561
|
|
|
1531
|
-
|
|
1532
|
-
def or_(self, o: ta.Any) -> ta.Any:
|
|
1533
|
-
"""Evaluates time remaining via remaining() if this timeout can expire, otherwise returns `o`."""
|
|
1562
|
+
#
|
|
1534
1563
|
|
|
1535
|
-
|
|
1564
|
+
_name_and_offset: ta.Tuple[str, int]
|
|
1536
1565
|
|
|
1537
|
-
|
|
1566
|
+
@property
|
|
1567
|
+
def name_and_offset(self) -> ta.Tuple[str, int]:
|
|
1568
|
+
try:
|
|
1569
|
+
return self._name_and_offset
|
|
1570
|
+
except AttributeError:
|
|
1571
|
+
pass
|
|
1538
1572
|
|
|
1539
|
-
|
|
1540
|
-
|
|
1541
|
-
|
|
1573
|
+
if (n := self._NAMES_BY_INT.get(self)) is not None:
|
|
1574
|
+
t = (n, 0)
|
|
1575
|
+
else:
|
|
1576
|
+
for n, i in self._NAME_INT_PAIRS: # noqa
|
|
1577
|
+
if self >= i:
|
|
1578
|
+
t = (n, (self - i))
|
|
1579
|
+
break
|
|
1580
|
+
else:
|
|
1581
|
+
t = ('NOTSET', int(self))
|
|
1582
|
+
|
|
1583
|
+
self._name_and_offset = t
|
|
1584
|
+
return t
|
|
1585
|
+
|
|
1586
|
+
@property
|
|
1587
|
+
def exact_name(self) -> ta.Optional[str]:
|
|
1588
|
+
n, o = self.name_and_offset
|
|
1589
|
+
return n if not o else None
|
|
1590
|
+
|
|
1591
|
+
@property
|
|
1592
|
+
def effective_name(self) -> str:
|
|
1593
|
+
n, _ = self.name_and_offset
|
|
1594
|
+
return n
|
|
1542
1595
|
|
|
1543
1596
|
#
|
|
1544
1597
|
|
|
1545
|
-
|
|
1546
|
-
|
|
1547
|
-
raise TypeError
|
|
1598
|
+
def __str__(self) -> str:
|
|
1599
|
+
return self.exact_name or f'{self.effective_name}{int(self):+}'
|
|
1548
1600
|
|
|
1549
|
-
|
|
1550
|
-
|
|
1551
|
-
|
|
1601
|
+
def __repr__(self) -> str:
|
|
1602
|
+
n, o = self.name_and_offset
|
|
1603
|
+
return f'{self.__class__.__name__}({n!r}{f", {int(o)}" if o else ""})'
|
|
1552
1604
|
|
|
1553
|
-
|
|
1554
|
-
def of(
|
|
1555
|
-
cls,
|
|
1556
|
-
obj: TimeoutLike,
|
|
1557
|
-
default: ta.Union[TimeoutLike, ta.Type[_NOT_SPECIFIED]] = _NOT_SPECIFIED,
|
|
1558
|
-
) -> 'Timeout':
|
|
1559
|
-
if obj is None:
|
|
1560
|
-
return InfiniteTimeout()
|
|
1605
|
+
#
|
|
1561
1606
|
|
|
1562
|
-
|
|
1563
|
-
|
|
1607
|
+
CRITICAL: ta.ClassVar['NamedLogLevel']
|
|
1608
|
+
ERROR: ta.ClassVar['NamedLogLevel']
|
|
1609
|
+
WARNING: ta.ClassVar['NamedLogLevel']
|
|
1610
|
+
INFO: ta.ClassVar['NamedLogLevel']
|
|
1611
|
+
DEBUG: ta.ClassVar['NamedLogLevel']
|
|
1612
|
+
NOTSET: ta.ClassVar['NamedLogLevel']
|
|
1564
1613
|
|
|
1565
|
-
elif isinstance(obj, (float, int)):
|
|
1566
|
-
return DeadlineTimeout(cls._now() + obj)
|
|
1567
1614
|
|
|
1568
|
-
|
|
1569
|
-
|
|
1615
|
+
NamedLogLevel.CRITICAL = NamedLogLevel(logging.CRITICAL)
|
|
1616
|
+
NamedLogLevel.ERROR = NamedLogLevel(logging.ERROR)
|
|
1617
|
+
NamedLogLevel.WARNING = NamedLogLevel(logging.WARNING)
|
|
1618
|
+
NamedLogLevel.INFO = NamedLogLevel(logging.INFO)
|
|
1619
|
+
NamedLogLevel.DEBUG = NamedLogLevel(logging.DEBUG)
|
|
1620
|
+
NamedLogLevel.NOTSET = NamedLogLevel(logging.NOTSET)
|
|
1570
1621
|
|
|
1571
|
-
elif obj is Timeout.DEFAULT:
|
|
1572
|
-
if default is Timeout._NOT_SPECIFIED or default is Timeout.DEFAULT:
|
|
1573
|
-
raise RuntimeError('Must specify a default timeout')
|
|
1574
1622
|
|
|
1575
|
-
|
|
1576
|
-
return Timeout.of(default) # type: ignore[arg-type]
|
|
1623
|
+
NamedLogLevel._CACHE.update({i: NamedLogLevel(i) for i in NamedLogLevel._NAMES_BY_INT}) # noqa
|
|
1577
1624
|
|
|
1578
|
-
else:
|
|
1579
|
-
raise TypeError(obj)
|
|
1580
1625
|
|
|
1581
|
-
|
|
1582
|
-
|
|
1583
|
-
return DeadlineTimeout(deadline)
|
|
1626
|
+
########################################
|
|
1627
|
+
# ../../../omlish/logs/std/filters.py
|
|
1584
1628
|
|
|
1585
|
-
@classmethod
|
|
1586
|
-
def of_predicate(cls, expired_fn: ta.Callable[[], bool]) -> 'PredicateTimeout':
|
|
1587
|
-
return PredicateTimeout(expired_fn)
|
|
1588
1629
|
|
|
1630
|
+
##
|
|
1589
1631
|
|
|
1590
|
-
class DeadlineTimeout(Timeout):
|
|
1591
|
-
def __init__(
|
|
1592
|
-
self,
|
|
1593
|
-
deadline: float,
|
|
1594
|
-
exc: ta.Union[ta.Type[BaseException], BaseException] = TimeoutError,
|
|
1595
|
-
) -> None:
|
|
1596
|
-
super().__init__()
|
|
1597
|
-
|
|
1598
|
-
self.deadline = deadline
|
|
1599
|
-
self.exc = exc
|
|
1600
|
-
|
|
1601
|
-
@property
|
|
1602
|
-
def can_expire(self) -> bool:
|
|
1603
|
-
return True
|
|
1604
|
-
|
|
1605
|
-
def expired(self) -> bool:
|
|
1606
|
-
return not (self.remaining() > 0)
|
|
1607
|
-
|
|
1608
|
-
def remaining(self) -> float:
|
|
1609
|
-
return self.deadline - self._now()
|
|
1610
|
-
|
|
1611
|
-
def __call__(self) -> float:
|
|
1612
|
-
if (rem := self.remaining()) > 0:
|
|
1613
|
-
return rem
|
|
1614
|
-
raise self.exc
|
|
1615
|
-
|
|
1616
|
-
def or_(self, o: ta.Any) -> ta.Any:
|
|
1617
|
-
return self()
|
|
1618
|
-
|
|
1619
|
-
|
|
1620
|
-
class InfiniteTimeout(Timeout):
|
|
1621
|
-
@property
|
|
1622
|
-
def can_expire(self) -> bool:
|
|
1623
|
-
return False
|
|
1624
|
-
|
|
1625
|
-
def expired(self) -> bool:
|
|
1626
|
-
return False
|
|
1627
|
-
|
|
1628
|
-
def remaining(self) -> float:
|
|
1629
|
-
return float('inf')
|
|
1630
|
-
|
|
1631
|
-
def __call__(self) -> float:
|
|
1632
|
-
return float('inf')
|
|
1633
|
-
|
|
1634
|
-
def or_(self, o: ta.Any) -> ta.Any:
|
|
1635
|
-
return o
|
|
1636
|
-
|
|
1637
|
-
|
|
1638
|
-
class CompositeTimeout(Timeout):
|
|
1639
|
-
def __init__(self, *children: Timeout) -> None:
|
|
1640
|
-
super().__init__()
|
|
1641
|
-
|
|
1642
|
-
self.children = children
|
|
1643
|
-
|
|
1644
|
-
@property
|
|
1645
|
-
def can_expire(self) -> bool:
|
|
1646
|
-
return any(c.can_expire for c in self.children)
|
|
1647
|
-
|
|
1648
|
-
def expired(self) -> bool:
|
|
1649
|
-
return any(c.expired() for c in self.children)
|
|
1650
|
-
|
|
1651
|
-
def remaining(self) -> float:
|
|
1652
|
-
return min(c.remaining() for c in self.children)
|
|
1653
|
-
|
|
1654
|
-
def __call__(self) -> float:
|
|
1655
|
-
return min(c() for c in self.children)
|
|
1656
|
-
|
|
1657
|
-
def or_(self, o: ta.Any) -> ta.Any:
|
|
1658
|
-
if self.can_expire:
|
|
1659
|
-
return self()
|
|
1660
|
-
return o
|
|
1661
|
-
|
|
1662
|
-
|
|
1663
|
-
class PredicateTimeout(Timeout):
|
|
1664
|
-
def __init__(
|
|
1665
|
-
self,
|
|
1666
|
-
expired_fn: ta.Callable[[], bool],
|
|
1667
|
-
exc: ta.Union[ta.Type[BaseException], BaseException] = TimeoutError,
|
|
1668
|
-
) -> None:
|
|
1669
|
-
super().__init__()
|
|
1670
|
-
|
|
1671
|
-
self.expired_fn = expired_fn
|
|
1672
|
-
self.exc = exc
|
|
1673
|
-
|
|
1674
|
-
@property
|
|
1675
|
-
def can_expire(self) -> bool:
|
|
1676
|
-
return True
|
|
1677
|
-
|
|
1678
|
-
def expired(self) -> bool:
|
|
1679
|
-
return self.expired_fn()
|
|
1680
|
-
|
|
1681
|
-
def remaining(self) -> float:
|
|
1682
|
-
return float('inf')
|
|
1683
|
-
|
|
1684
|
-
def __call__(self) -> float:
|
|
1685
|
-
if not self.expired_fn():
|
|
1686
|
-
return float('inf')
|
|
1687
|
-
raise self.exc
|
|
1688
|
-
|
|
1689
|
-
def or_(self, o: ta.Any) -> ta.Any:
|
|
1690
|
-
return self()
|
|
1691
|
-
|
|
1692
|
-
|
|
1693
|
-
########################################
|
|
1694
|
-
# ../../../omlish/logs/filters.py
|
|
1695
|
-
|
|
1696
|
-
|
|
1697
|
-
##
|
|
1698
1632
|
|
|
1699
|
-
|
|
1700
|
-
class TidLogFilter(logging.Filter):
|
|
1633
|
+
class TidLoggingFilter(logging.Filter):
|
|
1701
1634
|
def filter(self, record):
|
|
1702
1635
|
# FIXME: handle better - missing from wasm and cosmos
|
|
1703
1636
|
if hasattr(threading, 'get_native_id'):
|
|
@@ -1708,13 +1641,13 @@ class TidLogFilter(logging.Filter):
|
|
|
1708
1641
|
|
|
1709
1642
|
|
|
1710
1643
|
########################################
|
|
1711
|
-
# ../../../omlish/logs/proxy.py
|
|
1644
|
+
# ../../../omlish/logs/std/proxy.py
|
|
1712
1645
|
|
|
1713
1646
|
|
|
1714
1647
|
##
|
|
1715
1648
|
|
|
1716
1649
|
|
|
1717
|
-
class
|
|
1650
|
+
class ProxyLoggingFilterer(logging.Filterer):
|
|
1718
1651
|
def __init__(self, underlying: logging.Filterer) -> None: # noqa
|
|
1719
1652
|
self._underlying = underlying
|
|
1720
1653
|
|
|
@@ -1740,9 +1673,9 @@ class ProxyLogFilterer(logging.Filterer):
|
|
|
1740
1673
|
return self._underlying.filter(record)
|
|
1741
1674
|
|
|
1742
1675
|
|
|
1743
|
-
class
|
|
1676
|
+
class ProxyLoggingHandler(ProxyLoggingFilterer, logging.Handler):
|
|
1744
1677
|
def __init__(self, underlying: logging.Handler) -> None: # noqa
|
|
1745
|
-
|
|
1678
|
+
ProxyLoggingFilterer.__init__(self, underlying)
|
|
1746
1679
|
|
|
1747
1680
|
_underlying: logging.Handler
|
|
1748
1681
|
|
|
@@ -1833,7 +1766,7 @@ class ProxyLogHandler(ProxyLogFilterer, logging.Handler):
|
|
|
1833
1766
|
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. This file is dual licensed under the terms of the
|
|
1834
1767
|
# Apache License, Version 2.0, and the BSD License. See the LICENSE file in the root of this repository for complete
|
|
1835
1768
|
# details.
|
|
1836
|
-
# https://github.com/pypa/packaging/blob/
|
|
1769
|
+
# https://github.com/pypa/packaging/blob/48125006684bb2d7d28c50af48a03176da45942d/src/packaging/specifiers.py
|
|
1837
1770
|
|
|
1838
1771
|
|
|
1839
1772
|
##
|
|
@@ -1981,7 +1914,7 @@ class Specifier(BaseSpecifier):
|
|
|
1981
1914
|
) -> None:
|
|
1982
1915
|
match = self._regex.search(spec)
|
|
1983
1916
|
if not match:
|
|
1984
|
-
raise InvalidSpecifier(f
|
|
1917
|
+
raise InvalidSpecifier(f'Invalid specifier: {spec!r}')
|
|
1985
1918
|
|
|
1986
1919
|
self._spec: ta.Tuple[str, str] = (
|
|
1987
1920
|
match.group('operator').strip(),
|
|
@@ -1996,7 +1929,7 @@ class Specifier(BaseSpecifier):
|
|
|
1996
1929
|
return self._prereleases
|
|
1997
1930
|
|
|
1998
1931
|
operator, version = self._spec
|
|
1999
|
-
if operator in ['==', '>=', '<=', '~=', '===']:
|
|
1932
|
+
if operator in ['==', '>=', '<=', '~=', '===', '>', '<']:
|
|
2000
1933
|
if operator == '==' and version.endswith('.*'):
|
|
2001
1934
|
version = version[:-2]
|
|
2002
1935
|
|
|
@@ -2122,40 +2055,38 @@ class Specifier(BaseSpecifier):
|
|
|
2122
2055
|
return self.contains(item)
|
|
2123
2056
|
|
|
2124
2057
|
def contains(self, item: UnparsedVersion, prereleases: ta.Optional[bool] = None) -> bool:
|
|
2125
|
-
|
|
2126
|
-
prereleases = self.prereleases
|
|
2127
|
-
|
|
2128
|
-
normalized_item = _coerce_version(item)
|
|
2129
|
-
|
|
2130
|
-
if normalized_item.is_prerelease and not prereleases:
|
|
2131
|
-
return False
|
|
2132
|
-
|
|
2133
|
-
operator_callable: CallableVersionOperator = self._get_operator(self.operator)
|
|
2134
|
-
return operator_callable(normalized_item, self.version)
|
|
2058
|
+
return bool(list(self.filter([item], prereleases=prereleases)))
|
|
2135
2059
|
|
|
2136
2060
|
def filter(
|
|
2137
2061
|
self,
|
|
2138
2062
|
iterable: ta.Iterable[UnparsedVersionVar],
|
|
2139
2063
|
prereleases: ta.Optional[bool] = None,
|
|
2140
2064
|
) -> ta.Iterator[UnparsedVersionVar]:
|
|
2141
|
-
|
|
2142
|
-
|
|
2065
|
+
prereleases_versions = []
|
|
2066
|
+
found_non_prereleases = False
|
|
2067
|
+
|
|
2068
|
+
include_prereleases = (
|
|
2069
|
+
prereleases if prereleases is not None else self.prereleases
|
|
2070
|
+
)
|
|
2143
2071
|
|
|
2144
|
-
|
|
2072
|
+
operator_callable = self._get_operator(self.operator)
|
|
2145
2073
|
|
|
2146
2074
|
for version in iterable:
|
|
2147
2075
|
parsed_version = _coerce_version(version)
|
|
2148
2076
|
|
|
2149
|
-
if
|
|
2150
|
-
if parsed_version.is_prerelease
|
|
2151
|
-
|
|
2152
|
-
else:
|
|
2153
|
-
yielded = True
|
|
2077
|
+
if operator_callable(parsed_version, self.version):
|
|
2078
|
+
if not parsed_version.is_prerelease or include_prereleases:
|
|
2079
|
+
found_non_prereleases = True
|
|
2154
2080
|
yield version
|
|
2081
|
+
elif prereleases is None and self._prereleases is not False:
|
|
2082
|
+
prereleases_versions.append(version)
|
|
2155
2083
|
|
|
2156
|
-
if
|
|
2157
|
-
|
|
2158
|
-
|
|
2084
|
+
if (
|
|
2085
|
+
not found_non_prereleases and
|
|
2086
|
+
prereleases is None and
|
|
2087
|
+
self._prereleases is not False
|
|
2088
|
+
):
|
|
2089
|
+
yield from prereleases_versions
|
|
2159
2090
|
|
|
2160
2091
|
|
|
2161
2092
|
_version_prefix_regex = re.compile(r'^([0-9]+)((?:a|b|c|rc)[0-9]+)$')
|
|
@@ -2206,12 +2137,15 @@ def _pad_version(left: ta.List[str], right: ta.List[str]) -> ta.Tuple[ta.List[st
|
|
|
2206
2137
|
class SpecifierSet(BaseSpecifier):
|
|
2207
2138
|
def __init__(
|
|
2208
2139
|
self,
|
|
2209
|
-
specifiers: str = '',
|
|
2140
|
+
specifiers: ta.Union[str, ta.Iterable['Specifier']] = '',
|
|
2210
2141
|
prereleases: ta.Optional[bool] = None,
|
|
2211
2142
|
) -> None:
|
|
2212
|
-
|
|
2143
|
+
if isinstance(specifiers, str):
|
|
2144
|
+
split_specifiers = [s.strip() for s in specifiers.split(',') if s.strip()]
|
|
2145
|
+
self._specs = frozenset(map(Specifier, split_specifiers))
|
|
2146
|
+
else:
|
|
2147
|
+
self._specs = frozenset(specifiers)
|
|
2213
2148
|
|
|
2214
|
-
self._specs = frozenset(map(Specifier, split_specifiers))
|
|
2215
2149
|
self._prereleases = prereleases
|
|
2216
2150
|
|
|
2217
2151
|
@property
|
|
@@ -2222,7 +2156,10 @@ class SpecifierSet(BaseSpecifier):
|
|
|
2222
2156
|
if not self._specs:
|
|
2223
2157
|
return None
|
|
2224
2158
|
|
|
2225
|
-
|
|
2159
|
+
if any(s.prereleases for s in self._specs):
|
|
2160
|
+
return True
|
|
2161
|
+
|
|
2162
|
+
return None
|
|
2226
2163
|
|
|
2227
2164
|
@prereleases.setter
|
|
2228
2165
|
def prereleases(self, value: bool) -> None:
|
|
@@ -2247,7 +2184,7 @@ class SpecifierSet(BaseSpecifier):
|
|
|
2247
2184
|
if isinstance(other, str):
|
|
2248
2185
|
other = SpecifierSet(other)
|
|
2249
2186
|
elif not isinstance(other, SpecifierSet):
|
|
2250
|
-
return NotImplemented
|
|
2187
|
+
return NotImplemented
|
|
2251
2188
|
|
|
2252
2189
|
specifier = SpecifierSet()
|
|
2253
2190
|
specifier._specs = frozenset(self._specs | other._specs)
|
|
@@ -2267,6 +2204,7 @@ class SpecifierSet(BaseSpecifier):
|
|
|
2267
2204
|
if isinstance(other, (str, Specifier)):
|
|
2268
2205
|
other = SpecifierSet(str(other))
|
|
2269
2206
|
elif not isinstance(other, SpecifierSet):
|
|
2207
|
+
|
|
2270
2208
|
return NotImplemented
|
|
2271
2209
|
|
|
2272
2210
|
return self._specs == other._specs
|
|
@@ -2289,28 +2227,22 @@ class SpecifierSet(BaseSpecifier):
|
|
|
2289
2227
|
if not isinstance(item, Version):
|
|
2290
2228
|
item = Version(item)
|
|
2291
2229
|
|
|
2292
|
-
if prereleases is None:
|
|
2293
|
-
prereleases = self.prereleases
|
|
2294
|
-
|
|
2295
|
-
if not prereleases and item.is_prerelease:
|
|
2296
|
-
return False
|
|
2297
|
-
|
|
2298
2230
|
if installed and item.is_prerelease:
|
|
2299
|
-
|
|
2231
|
+
prereleases = True
|
|
2300
2232
|
|
|
2301
|
-
return
|
|
2233
|
+
return bool(list(self.filter([item], prereleases=prereleases)))
|
|
2302
2234
|
|
|
2303
2235
|
def filter(
|
|
2304
2236
|
self,
|
|
2305
2237
|
iterable: ta.Iterable[UnparsedVersionVar],
|
|
2306
2238
|
prereleases: ta.Optional[bool] = None,
|
|
2307
2239
|
) -> ta.Iterator[UnparsedVersionVar]:
|
|
2308
|
-
if prereleases is None:
|
|
2240
|
+
if prereleases is None and self.prereleases is not None:
|
|
2309
2241
|
prereleases = self.prereleases
|
|
2310
2242
|
|
|
2311
2243
|
if self._specs:
|
|
2312
2244
|
for spec in self._specs:
|
|
2313
|
-
iterable = spec.filter(iterable, prereleases=
|
|
2245
|
+
iterable = spec.filter(iterable, prereleases=prereleases)
|
|
2314
2246
|
return iter(iterable)
|
|
2315
2247
|
|
|
2316
2248
|
else:
|
|
@@ -2344,6 +2276,7 @@ TODO:
|
|
|
2344
2276
|
- pre-run, post-run hooks
|
|
2345
2277
|
- exitstack?
|
|
2346
2278
|
- suggestion - difflib.get_close_matches
|
|
2279
|
+
- add_argument_group - group kw on ArgparseKwarg?
|
|
2347
2280
|
"""
|
|
2348
2281
|
|
|
2349
2282
|
|
|
@@ -2354,6 +2287,7 @@ TODO:
|
|
|
2354
2287
|
class ArgparseArg:
|
|
2355
2288
|
args: ta.Sequence[ta.Any]
|
|
2356
2289
|
kwargs: ta.Mapping[str, ta.Any]
|
|
2290
|
+
group: ta.Optional[str] = None
|
|
2357
2291
|
dest: ta.Optional[str] = None
|
|
2358
2292
|
|
|
2359
2293
|
def __get__(self, instance, owner=None):
|
|
@@ -2363,7 +2297,11 @@ class ArgparseArg:
|
|
|
2363
2297
|
|
|
2364
2298
|
|
|
2365
2299
|
def argparse_arg(*args, **kwargs) -> ArgparseArg:
|
|
2366
|
-
return ArgparseArg(
|
|
2300
|
+
return ArgparseArg(
|
|
2301
|
+
args=args,
|
|
2302
|
+
group=kwargs.pop('group', None),
|
|
2303
|
+
kwargs=kwargs,
|
|
2304
|
+
)
|
|
2367
2305
|
|
|
2368
2306
|
|
|
2369
2307
|
def argparse_arg_(*args, **kwargs) -> ta.Any:
|
|
@@ -2533,101 +2471,733 @@ class ArgparseCli:
|
|
|
2533
2471
|
subparser.set_defaults(_cmd=obj)
|
|
2534
2472
|
|
|
2535
2473
|
elif isinstance(obj, ArgparseArg):
|
|
2474
|
+
if obj.group is not None:
|
|
2475
|
+
# FIXME: add_argument_group
|
|
2476
|
+
raise NotImplementedError
|
|
2477
|
+
|
|
2536
2478
|
if att in anns:
|
|
2537
2479
|
ann_kwargs = _get_argparse_arg_ann_kwargs(anns[att])
|
|
2538
2480
|
obj.kwargs = {**ann_kwargs, **obj.kwargs}
|
|
2539
2481
|
|
|
2540
|
-
if not obj.dest:
|
|
2541
|
-
if 'dest' in obj.kwargs:
|
|
2542
|
-
obj.dest = obj.kwargs['dest']
|
|
2543
|
-
else:
|
|
2544
|
-
obj.dest = obj.kwargs['dest'] = att # type: ignore
|
|
2482
|
+
if not obj.dest:
|
|
2483
|
+
if 'dest' in obj.kwargs:
|
|
2484
|
+
obj.dest = obj.kwargs['dest']
|
|
2485
|
+
else:
|
|
2486
|
+
obj.dest = obj.kwargs['dest'] = att # type: ignore
|
|
2487
|
+
|
|
2488
|
+
parser.add_argument(*obj.args, **obj.kwargs)
|
|
2489
|
+
|
|
2490
|
+
else:
|
|
2491
|
+
raise TypeError(obj)
|
|
2492
|
+
|
|
2493
|
+
#
|
|
2494
|
+
|
|
2495
|
+
_parser: ta.ClassVar[argparse.ArgumentParser]
|
|
2496
|
+
|
|
2497
|
+
@classmethod
|
|
2498
|
+
def get_parser(cls) -> argparse.ArgumentParser:
|
|
2499
|
+
return cls._parser
|
|
2500
|
+
|
|
2501
|
+
@property
|
|
2502
|
+
def argv(self) -> ta.Sequence[str]:
|
|
2503
|
+
return self._argv
|
|
2504
|
+
|
|
2505
|
+
@property
|
|
2506
|
+
def args(self) -> argparse.Namespace:
|
|
2507
|
+
return self._args
|
|
2508
|
+
|
|
2509
|
+
@property
|
|
2510
|
+
def unknown_args(self) -> ta.Sequence[str]:
|
|
2511
|
+
return self._unknown_args
|
|
2512
|
+
|
|
2513
|
+
#
|
|
2514
|
+
|
|
2515
|
+
def _bind_cli_cmd(self, cmd: ArgparseCmd) -> ta.Callable:
|
|
2516
|
+
return cmd.__get__(self, type(self))
|
|
2517
|
+
|
|
2518
|
+
def prepare_cli_run(self) -> ta.Optional[ta.Callable]:
|
|
2519
|
+
cmd = getattr(self.args, '_cmd', None)
|
|
2520
|
+
|
|
2521
|
+
if self._unknown_args and not (cmd is not None and cmd.accepts_unknown):
|
|
2522
|
+
msg = f'unrecognized arguments: {" ".join(self._unknown_args)}'
|
|
2523
|
+
if (parser := self.get_parser()).exit_on_error: # noqa
|
|
2524
|
+
parser.error(msg)
|
|
2525
|
+
else:
|
|
2526
|
+
raise argparse.ArgumentError(None, msg)
|
|
2527
|
+
|
|
2528
|
+
if cmd is None:
|
|
2529
|
+
self.get_parser().print_help()
|
|
2530
|
+
return None
|
|
2531
|
+
|
|
2532
|
+
return self._bind_cli_cmd(cmd)
|
|
2533
|
+
|
|
2534
|
+
#
|
|
2535
|
+
|
|
2536
|
+
def cli_run(self) -> ta.Optional[int]:
|
|
2537
|
+
if (fn := self.prepare_cli_run()) is None:
|
|
2538
|
+
return 0
|
|
2539
|
+
|
|
2540
|
+
return fn()
|
|
2541
|
+
|
|
2542
|
+
def cli_run_and_exit(self) -> ta.NoReturn:
|
|
2543
|
+
rc = self.cli_run()
|
|
2544
|
+
if not isinstance(rc, int):
|
|
2545
|
+
rc = 0
|
|
2546
|
+
raise SystemExit(rc)
|
|
2547
|
+
|
|
2548
|
+
def __call__(self, *, exit: bool = False) -> ta.Optional[int]: # noqa
|
|
2549
|
+
if exit:
|
|
2550
|
+
return self.cli_run_and_exit()
|
|
2551
|
+
else:
|
|
2552
|
+
return self.cli_run()
|
|
2553
|
+
|
|
2554
|
+
#
|
|
2555
|
+
|
|
2556
|
+
async def async_cli_run(
|
|
2557
|
+
self,
|
|
2558
|
+
*,
|
|
2559
|
+
force_async: bool = False,
|
|
2560
|
+
) -> ta.Optional[int]:
|
|
2561
|
+
if (fn := self.prepare_cli_run()) is None:
|
|
2562
|
+
return 0
|
|
2563
|
+
|
|
2564
|
+
if force_async:
|
|
2565
|
+
is_async = True
|
|
2566
|
+
else:
|
|
2567
|
+
tfn = fn
|
|
2568
|
+
if isinstance(tfn, ArgparseCmd):
|
|
2569
|
+
tfn = tfn.fn
|
|
2570
|
+
is_async = inspect.iscoroutinefunction(tfn)
|
|
2571
|
+
|
|
2572
|
+
if is_async:
|
|
2573
|
+
return await fn()
|
|
2574
|
+
else:
|
|
2575
|
+
return fn()
|
|
2576
|
+
|
|
2577
|
+
|
|
2578
|
+
########################################
|
|
2579
|
+
# ../../../omlish/lite/maybes.py
|
|
2580
|
+
|
|
2581
|
+
|
|
2582
|
+
##
|
|
2583
|
+
|
|
2584
|
+
|
|
2585
|
+
@functools.total_ordering
|
|
2586
|
+
class Maybe(ta.Generic[T]):
|
|
2587
|
+
class ValueNotPresentError(BaseException):
|
|
2588
|
+
pass
|
|
2589
|
+
|
|
2590
|
+
#
|
|
2591
|
+
|
|
2592
|
+
@property
|
|
2593
|
+
@abc.abstractmethod
|
|
2594
|
+
def present(self) -> bool:
|
|
2595
|
+
raise NotImplementedError
|
|
2596
|
+
|
|
2597
|
+
@abc.abstractmethod
|
|
2598
|
+
def must(self) -> T:
|
|
2599
|
+
raise NotImplementedError
|
|
2600
|
+
|
|
2601
|
+
#
|
|
2602
|
+
|
|
2603
|
+
@abc.abstractmethod
|
|
2604
|
+
def __repr__(self) -> str:
|
|
2605
|
+
raise NotImplementedError
|
|
2606
|
+
|
|
2607
|
+
@abc.abstractmethod
|
|
2608
|
+
def __hash__(self) -> int:
|
|
2609
|
+
raise NotImplementedError
|
|
2610
|
+
|
|
2611
|
+
@abc.abstractmethod
|
|
2612
|
+
def __eq__(self, other) -> bool:
|
|
2613
|
+
raise NotImplementedError
|
|
2614
|
+
|
|
2615
|
+
@abc.abstractmethod
|
|
2616
|
+
def __lt__(self, other) -> bool:
|
|
2617
|
+
raise NotImplementedError
|
|
2618
|
+
|
|
2619
|
+
#
|
|
2620
|
+
|
|
2621
|
+
@ta.final
|
|
2622
|
+
def __ne__(self, other):
|
|
2623
|
+
return not (self == other)
|
|
2624
|
+
|
|
2625
|
+
@ta.final
|
|
2626
|
+
def __iter__(self) -> ta.Iterator[T]:
|
|
2627
|
+
if self.present:
|
|
2628
|
+
yield self.must()
|
|
2629
|
+
|
|
2630
|
+
@ta.final
|
|
2631
|
+
def __bool__(self) -> ta.NoReturn:
|
|
2632
|
+
raise TypeError
|
|
2633
|
+
|
|
2634
|
+
#
|
|
2635
|
+
|
|
2636
|
+
@ta.final
|
|
2637
|
+
def if_present(self, consumer: ta.Callable[[T], None]) -> None:
|
|
2638
|
+
if self.present:
|
|
2639
|
+
consumer(self.must())
|
|
2640
|
+
|
|
2641
|
+
@ta.final
|
|
2642
|
+
def filter(self, predicate: ta.Callable[[T], bool]) -> 'Maybe[T]':
|
|
2643
|
+
if self.present and predicate(self.must()):
|
|
2644
|
+
return self
|
|
2645
|
+
else:
|
|
2646
|
+
return Maybe.empty()
|
|
2647
|
+
|
|
2648
|
+
@ta.final
|
|
2649
|
+
def map(self, mapper: ta.Callable[[T], U]) -> 'Maybe[U]':
|
|
2650
|
+
if self.present:
|
|
2651
|
+
return Maybe.just(mapper(self.must()))
|
|
2652
|
+
else:
|
|
2653
|
+
return Maybe.empty()
|
|
2654
|
+
|
|
2655
|
+
@ta.final
|
|
2656
|
+
def flat_map(self, mapper: ta.Callable[[T], 'Maybe[U]']) -> 'Maybe[U]':
|
|
2657
|
+
if self.present:
|
|
2658
|
+
if not isinstance(v := mapper(self.must()), Maybe):
|
|
2659
|
+
raise TypeError(v)
|
|
2660
|
+
return v
|
|
2661
|
+
else:
|
|
2662
|
+
return Maybe.empty()
|
|
2663
|
+
|
|
2664
|
+
@ta.final
|
|
2665
|
+
def or_else(self, other: ta.Union[T, U]) -> ta.Union[T, U]:
|
|
2666
|
+
if self.present:
|
|
2667
|
+
return self.must()
|
|
2668
|
+
else:
|
|
2669
|
+
return other
|
|
2670
|
+
|
|
2671
|
+
@ta.final
|
|
2672
|
+
def or_else_get(self, supplier: ta.Callable[[], ta.Union[T, U]]) -> ta.Union[T, U]:
|
|
2673
|
+
if self.present:
|
|
2674
|
+
return self.must()
|
|
2675
|
+
else:
|
|
2676
|
+
return supplier()
|
|
2677
|
+
|
|
2678
|
+
@ta.final
|
|
2679
|
+
def or_else_raise(self, exception_supplier: ta.Callable[[], Exception]) -> T:
|
|
2680
|
+
if self.present:
|
|
2681
|
+
return self.must()
|
|
2682
|
+
else:
|
|
2683
|
+
raise exception_supplier()
|
|
2684
|
+
|
|
2685
|
+
#
|
|
2686
|
+
|
|
2687
|
+
@classmethod
|
|
2688
|
+
def of_optional(cls, v: ta.Optional[T]) -> 'Maybe[T]':
|
|
2689
|
+
if v is not None:
|
|
2690
|
+
return cls.just(v)
|
|
2691
|
+
else:
|
|
2692
|
+
return cls.empty()
|
|
2693
|
+
|
|
2694
|
+
@classmethod
|
|
2695
|
+
def just(cls, v: T) -> 'Maybe[T]':
|
|
2696
|
+
return _JustMaybe(v)
|
|
2697
|
+
|
|
2698
|
+
_empty: ta.ClassVar['Maybe']
|
|
2699
|
+
|
|
2700
|
+
@classmethod
|
|
2701
|
+
def empty(cls) -> 'Maybe[T]':
|
|
2702
|
+
return Maybe._empty
|
|
2703
|
+
|
|
2704
|
+
|
|
2705
|
+
##
|
|
2706
|
+
|
|
2707
|
+
|
|
2708
|
+
class _Maybe(Maybe[T], Abstract):
|
|
2709
|
+
def __lt__(self, other):
|
|
2710
|
+
if not isinstance(other, _Maybe):
|
|
2711
|
+
return NotImplemented
|
|
2712
|
+
sp = self.present
|
|
2713
|
+
op = other.present
|
|
2714
|
+
if self.present and other.present:
|
|
2715
|
+
return self.must() < other.must()
|
|
2716
|
+
else:
|
|
2717
|
+
return op and not sp
|
|
2718
|
+
|
|
2719
|
+
|
|
2720
|
+
@ta.final
|
|
2721
|
+
class _JustMaybe(_Maybe[T]):
|
|
2722
|
+
__slots__ = ('_v', '_hash')
|
|
2723
|
+
|
|
2724
|
+
def __init__(self, v: T) -> None:
|
|
2725
|
+
self._v = v
|
|
2726
|
+
|
|
2727
|
+
@property
|
|
2728
|
+
def present(self) -> bool:
|
|
2729
|
+
return True
|
|
2730
|
+
|
|
2731
|
+
def must(self) -> T:
|
|
2732
|
+
return self._v
|
|
2733
|
+
|
|
2734
|
+
#
|
|
2735
|
+
|
|
2736
|
+
def __repr__(self) -> str:
|
|
2737
|
+
return f'just({self._v!r})'
|
|
2738
|
+
|
|
2739
|
+
_hash: int
|
|
2740
|
+
|
|
2741
|
+
def __hash__(self) -> int:
|
|
2742
|
+
try:
|
|
2743
|
+
return self._hash
|
|
2744
|
+
except AttributeError:
|
|
2745
|
+
pass
|
|
2746
|
+
h = self._hash = hash((_JustMaybe, self._v))
|
|
2747
|
+
return h
|
|
2748
|
+
|
|
2749
|
+
def __eq__(self, other):
|
|
2750
|
+
return (
|
|
2751
|
+
self.__class__ is other.__class__ and
|
|
2752
|
+
self._v == other._v # noqa
|
|
2753
|
+
)
|
|
2754
|
+
|
|
2755
|
+
|
|
2756
|
+
@ta.final
|
|
2757
|
+
class _EmptyMaybe(_Maybe[T]):
|
|
2758
|
+
__slots__ = ()
|
|
2759
|
+
|
|
2760
|
+
@property
|
|
2761
|
+
def present(self) -> bool:
|
|
2762
|
+
return False
|
|
2763
|
+
|
|
2764
|
+
def must(self) -> T:
|
|
2765
|
+
raise Maybe.ValueNotPresentError
|
|
2766
|
+
|
|
2767
|
+
#
|
|
2768
|
+
|
|
2769
|
+
def __repr__(self) -> str:
|
|
2770
|
+
return 'empty()'
|
|
2771
|
+
|
|
2772
|
+
def __hash__(self) -> int:
|
|
2773
|
+
return hash(_EmptyMaybe)
|
|
2774
|
+
|
|
2775
|
+
def __eq__(self, other):
|
|
2776
|
+
return self.__class__ is other.__class__
|
|
2777
|
+
|
|
2778
|
+
|
|
2779
|
+
Maybe._empty = _EmptyMaybe() # noqa
|
|
2780
|
+
|
|
2781
|
+
|
|
2782
|
+
##
|
|
2783
|
+
|
|
2784
|
+
|
|
2785
|
+
setattr(Maybe, 'just', _JustMaybe) # noqa
|
|
2786
|
+
setattr(Maybe, 'empty', functools.partial(operator.attrgetter('_empty'), Maybe))
|
|
2787
|
+
|
|
2788
|
+
|
|
2789
|
+
########################################
|
|
2790
|
+
# ../../../omlish/lite/runtime.py
|
|
2791
|
+
|
|
2792
|
+
|
|
2793
|
+
##
|
|
2794
|
+
|
|
2795
|
+
|
|
2796
|
+
@cached_nullary
|
|
2797
|
+
def is_debugger_attached() -> bool:
|
|
2798
|
+
return any(frame[1].endswith('pydevd.py') for frame in inspect.stack())
|
|
2799
|
+
|
|
2800
|
+
|
|
2801
|
+
LITE_REQUIRED_PYTHON_VERSION = (3, 8)
|
|
2802
|
+
|
|
2803
|
+
|
|
2804
|
+
def check_lite_runtime_version() -> None:
|
|
2805
|
+
if sys.version_info < LITE_REQUIRED_PYTHON_VERSION:
|
|
2806
|
+
raise OSError(f'Requires python {LITE_REQUIRED_PYTHON_VERSION}, got {sys.version_info} from {sys.executable}') # noqa
|
|
2807
|
+
|
|
2808
|
+
|
|
2809
|
+
########################################
|
|
2810
|
+
# ../../../omlish/lite/timeouts.py
|
|
2811
|
+
"""
|
|
2812
|
+
TODO:
|
|
2813
|
+
- Event (/ Predicate)
|
|
2814
|
+
"""
|
|
2815
|
+
|
|
2816
|
+
|
|
2817
|
+
##
|
|
2818
|
+
|
|
2819
|
+
|
|
2820
|
+
class Timeout(Abstract):
|
|
2821
|
+
@property
|
|
2822
|
+
@abc.abstractmethod
|
|
2823
|
+
def can_expire(self) -> bool:
|
|
2824
|
+
"""Indicates whether or not this timeout will ever expire."""
|
|
2825
|
+
|
|
2826
|
+
raise NotImplementedError
|
|
2827
|
+
|
|
2828
|
+
@abc.abstractmethod
|
|
2829
|
+
def expired(self) -> bool:
|
|
2830
|
+
"""Return whether or not this timeout has expired."""
|
|
2831
|
+
|
|
2832
|
+
raise NotImplementedError
|
|
2833
|
+
|
|
2834
|
+
@abc.abstractmethod
|
|
2835
|
+
def remaining(self) -> float:
|
|
2836
|
+
"""Returns the time (in seconds) remaining until the timeout expires. May be negative and/or infinite."""
|
|
2837
|
+
|
|
2838
|
+
raise NotImplementedError
|
|
2839
|
+
|
|
2840
|
+
@abc.abstractmethod
|
|
2841
|
+
def __call__(self) -> float:
|
|
2842
|
+
"""Returns the time (in seconds) remaining until the timeout expires, or raises if the timeout has expired."""
|
|
2843
|
+
|
|
2844
|
+
raise NotImplementedError
|
|
2845
|
+
|
|
2846
|
+
@abc.abstractmethod
|
|
2847
|
+
def or_(self, o: ta.Any) -> ta.Any:
|
|
2848
|
+
"""Evaluates time remaining via remaining() if this timeout can expire, otherwise returns `o`."""
|
|
2849
|
+
|
|
2850
|
+
raise NotImplementedError
|
|
2851
|
+
|
|
2852
|
+
#
|
|
2853
|
+
|
|
2854
|
+
@classmethod
|
|
2855
|
+
def _now(cls) -> float:
|
|
2856
|
+
return time.monotonic()
|
|
2857
|
+
|
|
2858
|
+
#
|
|
2859
|
+
|
|
2860
|
+
class DEFAULT: # Noqa
|
|
2861
|
+
def __new__(cls, *args, **kwargs): # noqa
|
|
2862
|
+
raise TypeError
|
|
2863
|
+
|
|
2864
|
+
class _NOT_SPECIFIED: # noqa
|
|
2865
|
+
def __new__(cls, *args, **kwargs): # noqa
|
|
2866
|
+
raise TypeError
|
|
2867
|
+
|
|
2868
|
+
@classmethod
|
|
2869
|
+
def of(
|
|
2870
|
+
cls,
|
|
2871
|
+
obj: TimeoutLike,
|
|
2872
|
+
default: ta.Union[TimeoutLike, ta.Type[_NOT_SPECIFIED]] = _NOT_SPECIFIED,
|
|
2873
|
+
) -> 'Timeout':
|
|
2874
|
+
if obj is None:
|
|
2875
|
+
return InfiniteTimeout()
|
|
2876
|
+
|
|
2877
|
+
elif isinstance(obj, Timeout):
|
|
2878
|
+
return obj
|
|
2879
|
+
|
|
2880
|
+
elif isinstance(obj, (float, int)):
|
|
2881
|
+
return DeadlineTimeout(cls._now() + obj)
|
|
2882
|
+
|
|
2883
|
+
elif isinstance(obj, ta.Iterable):
|
|
2884
|
+
return CompositeTimeout(*[Timeout.of(c) for c in obj])
|
|
2885
|
+
|
|
2886
|
+
elif obj is Timeout.DEFAULT:
|
|
2887
|
+
if default is Timeout._NOT_SPECIFIED or default is Timeout.DEFAULT:
|
|
2888
|
+
raise RuntimeError('Must specify a default timeout')
|
|
2889
|
+
|
|
2890
|
+
else:
|
|
2891
|
+
return Timeout.of(default) # type: ignore[arg-type]
|
|
2892
|
+
|
|
2893
|
+
else:
|
|
2894
|
+
raise TypeError(obj)
|
|
2895
|
+
|
|
2896
|
+
@classmethod
|
|
2897
|
+
def of_deadline(cls, deadline: float) -> 'DeadlineTimeout':
|
|
2898
|
+
return DeadlineTimeout(deadline)
|
|
2899
|
+
|
|
2900
|
+
@classmethod
|
|
2901
|
+
def of_predicate(cls, expired_fn: ta.Callable[[], bool]) -> 'PredicateTimeout':
|
|
2902
|
+
return PredicateTimeout(expired_fn)
|
|
2903
|
+
|
|
2904
|
+
|
|
2905
|
+
class DeadlineTimeout(Timeout):
|
|
2906
|
+
def __init__(
|
|
2907
|
+
self,
|
|
2908
|
+
deadline: float,
|
|
2909
|
+
exc: ta.Union[ta.Type[BaseException], BaseException] = TimeoutError,
|
|
2910
|
+
) -> None:
|
|
2911
|
+
super().__init__()
|
|
2912
|
+
|
|
2913
|
+
self.deadline = deadline
|
|
2914
|
+
self.exc = exc
|
|
2915
|
+
|
|
2916
|
+
@property
|
|
2917
|
+
def can_expire(self) -> bool:
|
|
2918
|
+
return True
|
|
2919
|
+
|
|
2920
|
+
def expired(self) -> bool:
|
|
2921
|
+
return not (self.remaining() > 0)
|
|
2922
|
+
|
|
2923
|
+
def remaining(self) -> float:
|
|
2924
|
+
return self.deadline - self._now()
|
|
2925
|
+
|
|
2926
|
+
def __call__(self) -> float:
|
|
2927
|
+
if (rem := self.remaining()) > 0:
|
|
2928
|
+
return rem
|
|
2929
|
+
raise self.exc
|
|
2930
|
+
|
|
2931
|
+
def or_(self, o: ta.Any) -> ta.Any:
|
|
2932
|
+
return self()
|
|
2933
|
+
|
|
2934
|
+
|
|
2935
|
+
class InfiniteTimeout(Timeout):
|
|
2936
|
+
@property
|
|
2937
|
+
def can_expire(self) -> bool:
|
|
2938
|
+
return False
|
|
2939
|
+
|
|
2940
|
+
def expired(self) -> bool:
|
|
2941
|
+
return False
|
|
2942
|
+
|
|
2943
|
+
def remaining(self) -> float:
|
|
2944
|
+
return float('inf')
|
|
2945
|
+
|
|
2946
|
+
def __call__(self) -> float:
|
|
2947
|
+
return float('inf')
|
|
2948
|
+
|
|
2949
|
+
def or_(self, o: ta.Any) -> ta.Any:
|
|
2950
|
+
return o
|
|
2951
|
+
|
|
2952
|
+
|
|
2953
|
+
class CompositeTimeout(Timeout):
|
|
2954
|
+
def __init__(self, *children: Timeout) -> None:
|
|
2955
|
+
super().__init__()
|
|
2956
|
+
|
|
2957
|
+
self.children = children
|
|
2958
|
+
|
|
2959
|
+
@property
|
|
2960
|
+
def can_expire(self) -> bool:
|
|
2961
|
+
return any(c.can_expire for c in self.children)
|
|
2962
|
+
|
|
2963
|
+
def expired(self) -> bool:
|
|
2964
|
+
return any(c.expired() for c in self.children)
|
|
2965
|
+
|
|
2966
|
+
def remaining(self) -> float:
|
|
2967
|
+
return min(c.remaining() for c in self.children)
|
|
2968
|
+
|
|
2969
|
+
def __call__(self) -> float:
|
|
2970
|
+
return min(c() for c in self.children)
|
|
2971
|
+
|
|
2972
|
+
def or_(self, o: ta.Any) -> ta.Any:
|
|
2973
|
+
if self.can_expire:
|
|
2974
|
+
return self()
|
|
2975
|
+
return o
|
|
2976
|
+
|
|
2977
|
+
|
|
2978
|
+
class PredicateTimeout(Timeout):
|
|
2979
|
+
def __init__(
|
|
2980
|
+
self,
|
|
2981
|
+
expired_fn: ta.Callable[[], bool],
|
|
2982
|
+
exc: ta.Union[ta.Type[BaseException], BaseException] = TimeoutError,
|
|
2983
|
+
) -> None:
|
|
2984
|
+
super().__init__()
|
|
2985
|
+
|
|
2986
|
+
self.expired_fn = expired_fn
|
|
2987
|
+
self.exc = exc
|
|
2988
|
+
|
|
2989
|
+
@property
|
|
2990
|
+
def can_expire(self) -> bool:
|
|
2991
|
+
return True
|
|
2992
|
+
|
|
2993
|
+
def expired(self) -> bool:
|
|
2994
|
+
return self.expired_fn()
|
|
2995
|
+
|
|
2996
|
+
def remaining(self) -> float:
|
|
2997
|
+
return float('inf')
|
|
2998
|
+
|
|
2999
|
+
def __call__(self) -> float:
|
|
3000
|
+
if not self.expired_fn():
|
|
3001
|
+
return float('inf')
|
|
3002
|
+
raise self.exc
|
|
3003
|
+
|
|
3004
|
+
def or_(self, o: ta.Any) -> ta.Any:
|
|
3005
|
+
return self()
|
|
3006
|
+
|
|
3007
|
+
|
|
3008
|
+
########################################
|
|
3009
|
+
# ../../../omlish/logs/protocols.py
|
|
3010
|
+
|
|
3011
|
+
|
|
3012
|
+
##
|
|
3013
|
+
|
|
3014
|
+
|
|
3015
|
+
@ta.runtime_checkable
|
|
3016
|
+
class LoggerLike(ta.Protocol):
|
|
3017
|
+
"""Satisfied by both our Logger and stdlib logging.Logger."""
|
|
3018
|
+
|
|
3019
|
+
def isEnabledFor(self, level: LogLevel) -> bool: ... # noqa
|
|
3020
|
+
|
|
3021
|
+
def getEffectiveLevel(self) -> LogLevel: ... # noqa
|
|
3022
|
+
|
|
3023
|
+
#
|
|
3024
|
+
|
|
3025
|
+
def log(self, level: LogLevel, msg: str, /, *args: ta.Any, **kwargs: ta.Any) -> None: ... # noqa
|
|
3026
|
+
|
|
3027
|
+
def debug(self, msg: str, /, *args: ta.Any, **kwargs: ta.Any) -> None: ... # noqa
|
|
3028
|
+
|
|
3029
|
+
def info(self, msg: str, /, *args: ta.Any, **kwargs: ta.Any) -> None: ... # noqa
|
|
3030
|
+
|
|
3031
|
+
def warning(self, msg: str, /, *args: ta.Any, **kwargs: ta.Any) -> None: ... # noqa
|
|
3032
|
+
|
|
3033
|
+
def error(self, msg: str, /, *args: ta.Any, **kwargs: ta.Any) -> None: ... # noqa
|
|
3034
|
+
|
|
3035
|
+
def exception(self, msg: str, /, *args: ta.Any, **kwargs: ta.Any) -> None: ... # noqa
|
|
3036
|
+
|
|
3037
|
+
def critical(self, msg: str, /, *args: ta.Any, **kwargs: ta.Any) -> None: ... # noqa
|
|
3038
|
+
|
|
3039
|
+
|
|
3040
|
+
########################################
|
|
3041
|
+
# ../../../omlish/logs/std/json.py
|
|
3042
|
+
"""
|
|
3043
|
+
TODO:
|
|
3044
|
+
- translate json keys
|
|
3045
|
+
"""
|
|
3046
|
+
|
|
3047
|
+
|
|
3048
|
+
##
|
|
3049
|
+
|
|
3050
|
+
|
|
3051
|
+
class JsonLoggingFormatter(logging.Formatter):
|
|
3052
|
+
KEYS: ta.Mapping[str, bool] = {
|
|
3053
|
+
'name': False,
|
|
3054
|
+
'msg': False,
|
|
3055
|
+
'args': False,
|
|
3056
|
+
'levelname': False,
|
|
3057
|
+
'levelno': False,
|
|
3058
|
+
'pathname': False,
|
|
3059
|
+
'filename': False,
|
|
3060
|
+
'module': False,
|
|
3061
|
+
'exc_info': True,
|
|
3062
|
+
'exc_text': True,
|
|
3063
|
+
'stack_info': True,
|
|
3064
|
+
'lineno': False,
|
|
3065
|
+
'funcName': False,
|
|
3066
|
+
'created': False,
|
|
3067
|
+
'msecs': False,
|
|
3068
|
+
'relativeCreated': False,
|
|
3069
|
+
'thread': False,
|
|
3070
|
+
'threadName': False,
|
|
3071
|
+
'processName': False,
|
|
3072
|
+
'process': False,
|
|
3073
|
+
}
|
|
3074
|
+
|
|
3075
|
+
def __init__(
|
|
3076
|
+
self,
|
|
3077
|
+
*args: ta.Any,
|
|
3078
|
+
json_dumps: ta.Optional[ta.Callable[[ta.Any], str]] = None,
|
|
3079
|
+
**kwargs: ta.Any,
|
|
3080
|
+
) -> None:
|
|
3081
|
+
super().__init__(*args, **kwargs)
|
|
3082
|
+
|
|
3083
|
+
if json_dumps is None:
|
|
3084
|
+
json_dumps = json_dumps_compact
|
|
3085
|
+
self._json_dumps = json_dumps
|
|
3086
|
+
|
|
3087
|
+
def format(self, record: logging.LogRecord) -> str:
|
|
3088
|
+
dct = {
|
|
3089
|
+
k: v
|
|
3090
|
+
for k, o in self.KEYS.items()
|
|
3091
|
+
for v in [getattr(record, k)]
|
|
3092
|
+
if not (o and v is None)
|
|
3093
|
+
}
|
|
3094
|
+
return self._json_dumps(dct)
|
|
3095
|
+
|
|
3096
|
+
|
|
3097
|
+
########################################
|
|
3098
|
+
# ../types.py
|
|
3099
|
+
|
|
3100
|
+
|
|
3101
|
+
##
|
|
2545
3102
|
|
|
2546
|
-
parser.add_argument(*obj.args, **obj.kwargs)
|
|
2547
3103
|
|
|
2548
|
-
|
|
2549
|
-
|
|
3104
|
+
# See https://peps.python.org/pep-3149/
|
|
3105
|
+
INTERP_OPT_GLYPHS_BY_ATTR: ta.Mapping[str, str] = collections.OrderedDict([
|
|
3106
|
+
('debug', 'd'),
|
|
3107
|
+
('threaded', 't'),
|
|
3108
|
+
])
|
|
2550
3109
|
|
|
2551
|
-
|
|
3110
|
+
INTERP_OPT_ATTRS_BY_GLYPH: ta.Mapping[str, str] = collections.OrderedDict(
|
|
3111
|
+
(g, a) for a, g in INTERP_OPT_GLYPHS_BY_ATTR.items()
|
|
3112
|
+
)
|
|
2552
3113
|
|
|
2553
|
-
|
|
3114
|
+
|
|
3115
|
+
@dc.dataclass(frozen=True)
|
|
3116
|
+
class InterpOpts:
|
|
3117
|
+
threaded: bool = False
|
|
3118
|
+
debug: bool = False
|
|
3119
|
+
|
|
3120
|
+
def __str__(self) -> str:
|
|
3121
|
+
return ''.join(g for a, g in INTERP_OPT_GLYPHS_BY_ATTR.items() if getattr(self, a))
|
|
2554
3122
|
|
|
2555
3123
|
@classmethod
|
|
2556
|
-
def
|
|
2557
|
-
return cls
|
|
3124
|
+
def parse(cls, s: str) -> 'InterpOpts':
|
|
3125
|
+
return cls(**{INTERP_OPT_ATTRS_BY_GLYPH[g]: True for g in s})
|
|
2558
3126
|
|
|
2559
|
-
@
|
|
2560
|
-
def
|
|
2561
|
-
|
|
3127
|
+
@classmethod
|
|
3128
|
+
def parse_suffix(cls, s: str) -> ta.Tuple[str, 'InterpOpts']:
|
|
3129
|
+
kw = {}
|
|
3130
|
+
while s and (a := INTERP_OPT_ATTRS_BY_GLYPH.get(s[-1])):
|
|
3131
|
+
s, kw[a] = s[:-1], True
|
|
3132
|
+
return s, cls(**kw)
|
|
2562
3133
|
|
|
2563
|
-
@property
|
|
2564
|
-
def args(self) -> argparse.Namespace:
|
|
2565
|
-
return self._args
|
|
2566
3134
|
|
|
2567
|
-
|
|
2568
|
-
def unknown_args(self) -> ta.Sequence[str]:
|
|
2569
|
-
return self._unknown_args
|
|
3135
|
+
##
|
|
2570
3136
|
|
|
2571
|
-
#
|
|
2572
3137
|
|
|
2573
|
-
|
|
2574
|
-
|
|
3138
|
+
@dc.dataclass(frozen=True)
|
|
3139
|
+
class InterpVersion:
|
|
3140
|
+
version: Version
|
|
3141
|
+
opts: InterpOpts
|
|
2575
3142
|
|
|
2576
|
-
def
|
|
2577
|
-
|
|
3143
|
+
def __str__(self) -> str:
|
|
3144
|
+
return str(self.version) + str(self.opts)
|
|
2578
3145
|
|
|
2579
|
-
|
|
2580
|
-
|
|
2581
|
-
|
|
2582
|
-
|
|
2583
|
-
|
|
2584
|
-
|
|
3146
|
+
@classmethod
|
|
3147
|
+
def parse(cls, s: str) -> 'InterpVersion':
|
|
3148
|
+
s, o = InterpOpts.parse_suffix(s)
|
|
3149
|
+
v = Version(s)
|
|
3150
|
+
return cls(
|
|
3151
|
+
version=v,
|
|
3152
|
+
opts=o,
|
|
3153
|
+
)
|
|
2585
3154
|
|
|
2586
|
-
|
|
2587
|
-
|
|
3155
|
+
@classmethod
|
|
3156
|
+
def try_parse(cls, s: str) -> ta.Optional['InterpVersion']:
|
|
3157
|
+
try:
|
|
3158
|
+
return cls.parse(s)
|
|
3159
|
+
except (KeyError, InvalidVersion):
|
|
2588
3160
|
return None
|
|
2589
3161
|
|
|
2590
|
-
return self._bind_cli_cmd(cmd)
|
|
2591
3162
|
|
|
2592
|
-
|
|
3163
|
+
##
|
|
2593
3164
|
|
|
2594
|
-
def cli_run(self) -> ta.Optional[int]:
|
|
2595
|
-
if (fn := self.prepare_cli_run()) is None:
|
|
2596
|
-
return 0
|
|
2597
3165
|
|
|
2598
|
-
|
|
3166
|
+
@dc.dataclass(frozen=True)
|
|
3167
|
+
class InterpSpecifier:
|
|
3168
|
+
specifier: Specifier
|
|
3169
|
+
opts: InterpOpts
|
|
2599
3170
|
|
|
2600
|
-
def
|
|
2601
|
-
|
|
3171
|
+
def __str__(self) -> str:
|
|
3172
|
+
return str(self.specifier) + str(self.opts)
|
|
2602
3173
|
|
|
2603
|
-
|
|
2604
|
-
|
|
2605
|
-
|
|
2606
|
-
|
|
2607
|
-
|
|
3174
|
+
@classmethod
|
|
3175
|
+
def parse(cls, s: str) -> 'InterpSpecifier':
|
|
3176
|
+
s, o = InterpOpts.parse_suffix(s)
|
|
3177
|
+
if not any(s.startswith(o) for o in Specifier.OPERATORS):
|
|
3178
|
+
if s.count('.') < 2:
|
|
3179
|
+
s = '~=' + s + '.0'
|
|
3180
|
+
else:
|
|
3181
|
+
s = '==' + s
|
|
3182
|
+
return cls(
|
|
3183
|
+
specifier=Specifier(s),
|
|
3184
|
+
opts=o,
|
|
3185
|
+
)
|
|
2608
3186
|
|
|
2609
|
-
|
|
3187
|
+
def contains(self, iv: InterpVersion) -> bool:
|
|
3188
|
+
return self.specifier.contains(iv.version) and self.opts == iv.opts
|
|
2610
3189
|
|
|
2611
|
-
|
|
2612
|
-
|
|
2613
|
-
*,
|
|
2614
|
-
force_async: bool = False,
|
|
2615
|
-
) -> ta.Optional[int]:
|
|
2616
|
-
if (fn := self.prepare_cli_run()) is None:
|
|
2617
|
-
return 0
|
|
3190
|
+
def __contains__(self, iv: InterpVersion) -> bool:
|
|
3191
|
+
return self.contains(iv)
|
|
2618
3192
|
|
|
2619
|
-
if force_async:
|
|
2620
|
-
is_async = True
|
|
2621
|
-
else:
|
|
2622
|
-
tfn = fn
|
|
2623
|
-
if isinstance(tfn, ArgparseCmd):
|
|
2624
|
-
tfn = tfn.fn
|
|
2625
|
-
is_async = inspect.iscoroutinefunction(tfn)
|
|
2626
3193
|
|
|
2627
|
-
|
|
2628
|
-
|
|
2629
|
-
|
|
2630
|
-
|
|
3194
|
+
##
|
|
3195
|
+
|
|
3196
|
+
|
|
3197
|
+
@dc.dataclass(frozen=True)
|
|
3198
|
+
class Interp:
|
|
3199
|
+
exe: str
|
|
3200
|
+
version: InterpVersion
|
|
2631
3201
|
|
|
2632
3202
|
|
|
2633
3203
|
########################################
|
|
@@ -2680,7 +3250,7 @@ def check_valid_injector_key_cls(cls: T) -> T:
|
|
|
2680
3250
|
##
|
|
2681
3251
|
|
|
2682
3252
|
|
|
2683
|
-
class InjectorProvider(
|
|
3253
|
+
class InjectorProvider(Abstract):
|
|
2684
3254
|
@abc.abstractmethod
|
|
2685
3255
|
def provider_fn(self) -> InjectorProviderFn:
|
|
2686
3256
|
raise NotImplementedError
|
|
@@ -2699,7 +3269,7 @@ class InjectorBinding:
|
|
|
2699
3269
|
check.isinstance(self.provider, InjectorProvider)
|
|
2700
3270
|
|
|
2701
3271
|
|
|
2702
|
-
class InjectorBindings(
|
|
3272
|
+
class InjectorBindings(Abstract):
|
|
2703
3273
|
@abc.abstractmethod
|
|
2704
3274
|
def bindings(self) -> ta.Iterator[InjectorBinding]:
|
|
2705
3275
|
raise NotImplementedError
|
|
@@ -2707,7 +3277,7 @@ class InjectorBindings(abc.ABC):
|
|
|
2707
3277
|
##
|
|
2708
3278
|
|
|
2709
3279
|
|
|
2710
|
-
class Injector(
|
|
3280
|
+
class Injector(Abstract):
|
|
2711
3281
|
@abc.abstractmethod
|
|
2712
3282
|
def try_provide(self, key: ta.Any) -> Maybe[ta.Any]:
|
|
2713
3283
|
raise NotImplementedError
|
|
@@ -2966,14 +3536,12 @@ def injector_override(p: InjectorBindings, *args: InjectorBindingOrBindings) ->
|
|
|
2966
3536
|
# scopes
|
|
2967
3537
|
|
|
2968
3538
|
|
|
2969
|
-
class InjectorScope(
|
|
3539
|
+
class InjectorScope(Abstract):
|
|
2970
3540
|
def __init__(
|
|
2971
3541
|
self,
|
|
2972
3542
|
*,
|
|
2973
3543
|
_i: Injector,
|
|
2974
3544
|
) -> None:
|
|
2975
|
-
check.not_in(abc.ABC, type(self).__bases__)
|
|
2976
|
-
|
|
2977
3545
|
super().__init__()
|
|
2978
3546
|
|
|
2979
3547
|
self._i = _i
|
|
@@ -3004,7 +3572,7 @@ class InjectorScope(abc.ABC): # noqa
|
|
|
3004
3572
|
raise NotImplementedError
|
|
3005
3573
|
|
|
3006
3574
|
|
|
3007
|
-
class ExclusiveInjectorScope(InjectorScope,
|
|
3575
|
+
class ExclusiveInjectorScope(InjectorScope, Abstract):
|
|
3008
3576
|
_st: ta.Optional[InjectorScope.State] = None
|
|
3009
3577
|
|
|
3010
3578
|
def state(self) -> InjectorScope.State:
|
|
@@ -3020,12 +3588,13 @@ class ExclusiveInjectorScope(InjectorScope, abc.ABC):
|
|
|
3020
3588
|
self._st = None
|
|
3021
3589
|
|
|
3022
3590
|
|
|
3023
|
-
class ContextvarInjectorScope(InjectorScope,
|
|
3591
|
+
class ContextvarInjectorScope(InjectorScope, Abstract):
|
|
3024
3592
|
_cv: contextvars.ContextVar
|
|
3025
3593
|
|
|
3026
3594
|
def __init_subclass__(cls, **kwargs: ta.Any) -> None:
|
|
3027
3595
|
super().__init_subclass__(**kwargs)
|
|
3028
3596
|
|
|
3597
|
+
check.not_in(Abstract, cls.__bases__)
|
|
3029
3598
|
check.not_in(abc.ABC, cls.__bases__)
|
|
3030
3599
|
check.state(not hasattr(cls, '_cv'))
|
|
3031
3600
|
cls._cv = contextvars.ContextVar(f'{cls.__name__}_cv')
|
|
@@ -3531,7 +4100,7 @@ class InjectorBinder:
|
|
|
3531
4100
|
pws: ta.List[ta.Any] = []
|
|
3532
4101
|
if in_ is not None:
|
|
3533
4102
|
check.issubclass(in_, InjectorScope)
|
|
3534
|
-
check.not_in(
|
|
4103
|
+
check.not_in(Abstract, in_.__bases__)
|
|
3535
4104
|
pws.append(functools.partial(ScopedInjectorProvider, k=key, sc=in_))
|
|
3536
4105
|
if singleton:
|
|
3537
4106
|
pws.append(SingletonInjectorProvider)
|
|
@@ -3732,80 +4301,129 @@ inj = InjectionApi()
|
|
|
3732
4301
|
|
|
3733
4302
|
|
|
3734
4303
|
########################################
|
|
3735
|
-
# ../../../omlish/
|
|
4304
|
+
# ../../../omlish/logs/std/standard.py
|
|
4305
|
+
"""
|
|
4306
|
+
TODO:
|
|
4307
|
+
- structured
|
|
4308
|
+
- prefixed
|
|
4309
|
+
- debug
|
|
4310
|
+
- optional noisy? noisy will never be lite - some kinda configure_standard callback mechanism?
|
|
4311
|
+
"""
|
|
3736
4312
|
|
|
3737
4313
|
|
|
3738
4314
|
##
|
|
3739
4315
|
|
|
3740
4316
|
|
|
3741
|
-
|
|
3742
|
-
|
|
3743
|
-
|
|
4317
|
+
STANDARD_LOG_FORMAT_PARTS = [
|
|
4318
|
+
('asctime', '%(asctime)-15s'),
|
|
4319
|
+
('process', 'pid=%(process)s'),
|
|
4320
|
+
('thread', 'tid=%(thread)x'),
|
|
4321
|
+
('levelname', '%(levelname)s'),
|
|
4322
|
+
('name', '%(name)s'),
|
|
4323
|
+
('separator', '::'),
|
|
4324
|
+
('message', '%(message)s'),
|
|
4325
|
+
]
|
|
3744
4326
|
|
|
3745
4327
|
|
|
3746
|
-
|
|
4328
|
+
class StandardLoggingFormatter(logging.Formatter):
|
|
4329
|
+
@staticmethod
|
|
4330
|
+
def build_log_format(parts: ta.Iterable[ta.Tuple[str, str]]) -> str:
|
|
4331
|
+
return ' '.join(v for k, v in parts)
|
|
3747
4332
|
|
|
4333
|
+
converter = datetime.datetime.fromtimestamp # type: ignore
|
|
3748
4334
|
|
|
3749
|
-
def
|
|
3750
|
-
|
|
3751
|
-
|
|
4335
|
+
def formatTime(self, record, datefmt=None):
|
|
4336
|
+
ct = self.converter(record.created)
|
|
4337
|
+
if datefmt:
|
|
4338
|
+
return ct.strftime(datefmt) # noqa
|
|
4339
|
+
else:
|
|
4340
|
+
t = ct.strftime('%Y-%m-%d %H:%M:%S')
|
|
4341
|
+
return '%s.%03d' % (t, record.msecs) # noqa
|
|
3752
4342
|
|
|
3753
4343
|
|
|
3754
|
-
|
|
3755
|
-
|
|
3756
|
-
|
|
3757
|
-
|
|
3758
|
-
|
|
3759
|
-
|
|
4344
|
+
##
|
|
4345
|
+
|
|
4346
|
+
|
|
4347
|
+
class StandardConfiguredLoggingHandler(ProxyLoggingHandler):
|
|
4348
|
+
def __init_subclass__(cls, **kwargs):
|
|
4349
|
+
raise TypeError('This class serves only as a marker and should not be subclassed.')
|
|
3760
4350
|
|
|
3761
4351
|
|
|
3762
4352
|
##
|
|
3763
4353
|
|
|
3764
4354
|
|
|
3765
|
-
|
|
3766
|
-
|
|
3767
|
-
|
|
3768
|
-
|
|
3769
|
-
|
|
3770
|
-
|
|
3771
|
-
|
|
3772
|
-
|
|
3773
|
-
|
|
3774
|
-
|
|
3775
|
-
|
|
3776
|
-
|
|
3777
|
-
|
|
3778
|
-
|
|
3779
|
-
|
|
3780
|
-
'
|
|
3781
|
-
|
|
3782
|
-
|
|
3783
|
-
|
|
3784
|
-
|
|
3785
|
-
|
|
3786
|
-
|
|
3787
|
-
|
|
4355
|
+
@contextlib.contextmanager
|
|
4356
|
+
def _locking_logging_module_lock() -> ta.Iterator[None]:
|
|
4357
|
+
if hasattr(logging, '_acquireLock'):
|
|
4358
|
+
logging._acquireLock() # noqa
|
|
4359
|
+
try:
|
|
4360
|
+
yield
|
|
4361
|
+
finally:
|
|
4362
|
+
logging._releaseLock() # type: ignore # noqa
|
|
4363
|
+
|
|
4364
|
+
elif hasattr(logging, '_lock'):
|
|
4365
|
+
# https://github.com/python/cpython/commit/74723e11109a320e628898817ab449b3dad9ee96
|
|
4366
|
+
with logging._lock: # noqa
|
|
4367
|
+
yield
|
|
4368
|
+
|
|
4369
|
+
else:
|
|
4370
|
+
raise Exception("Can't find lock in logging module")
|
|
4371
|
+
|
|
4372
|
+
|
|
4373
|
+
def configure_standard_logging(
|
|
4374
|
+
level: ta.Union[int, str] = logging.INFO,
|
|
4375
|
+
*,
|
|
4376
|
+
target: ta.Optional[logging.Logger] = None,
|
|
4377
|
+
|
|
4378
|
+
force: bool = False,
|
|
4379
|
+
|
|
4380
|
+
handler_factory: ta.Optional[ta.Callable[[], logging.Handler]] = None,
|
|
4381
|
+
|
|
4382
|
+
formatter: ta.Optional[logging.Formatter] = None, # noqa
|
|
4383
|
+
json: bool = False,
|
|
4384
|
+
) -> ta.Optional[StandardConfiguredLoggingHandler]:
|
|
4385
|
+
with _locking_logging_module_lock():
|
|
4386
|
+
if target is None:
|
|
4387
|
+
target = logging.root
|
|
4388
|
+
|
|
4389
|
+
#
|
|
4390
|
+
|
|
4391
|
+
if not force:
|
|
4392
|
+
if any(isinstance(h, StandardConfiguredLoggingHandler) for h in list(target.handlers)):
|
|
4393
|
+
return None
|
|
4394
|
+
|
|
4395
|
+
#
|
|
4396
|
+
|
|
4397
|
+
if handler_factory is not None:
|
|
4398
|
+
handler = handler_factory()
|
|
4399
|
+
else:
|
|
4400
|
+
handler = logging.StreamHandler()
|
|
4401
|
+
|
|
4402
|
+
#
|
|
4403
|
+
|
|
4404
|
+
if formatter is None:
|
|
4405
|
+
if json:
|
|
4406
|
+
formatter = JsonLoggingFormatter()
|
|
4407
|
+
else:
|
|
4408
|
+
formatter = StandardLoggingFormatter(StandardLoggingFormatter.build_log_format(STANDARD_LOG_FORMAT_PARTS)) # noqa
|
|
4409
|
+
handler.setFormatter(formatter)
|
|
4410
|
+
|
|
4411
|
+
#
|
|
4412
|
+
|
|
4413
|
+
handler.addFilter(TidLoggingFilter())
|
|
3788
4414
|
|
|
3789
|
-
|
|
3790
|
-
self,
|
|
3791
|
-
*args: ta.Any,
|
|
3792
|
-
json_dumps: ta.Optional[ta.Callable[[ta.Any], str]] = None,
|
|
3793
|
-
**kwargs: ta.Any,
|
|
3794
|
-
) -> None:
|
|
3795
|
-
super().__init__(*args, **kwargs)
|
|
4415
|
+
#
|
|
3796
4416
|
|
|
3797
|
-
|
|
3798
|
-
json_dumps = json_dumps_compact
|
|
3799
|
-
self._json_dumps = json_dumps
|
|
4417
|
+
target.addHandler(handler)
|
|
3800
4418
|
|
|
3801
|
-
|
|
3802
|
-
|
|
3803
|
-
|
|
3804
|
-
|
|
3805
|
-
|
|
3806
|
-
|
|
3807
|
-
|
|
3808
|
-
return
|
|
4419
|
+
#
|
|
4420
|
+
|
|
4421
|
+
if level is not None:
|
|
4422
|
+
target.setLevel(level)
|
|
4423
|
+
|
|
4424
|
+
#
|
|
4425
|
+
|
|
4426
|
+
return StandardConfiguredLoggingHandler(handler)
|
|
3809
4427
|
|
|
3810
4428
|
|
|
3811
4429
|
########################################
|
|
@@ -3924,7 +4542,7 @@ SubprocessRun._FIELD_NAMES = frozenset(fld.name for fld in dc.fields(SubprocessR
|
|
|
3924
4542
|
##
|
|
3925
4543
|
|
|
3926
4544
|
|
|
3927
|
-
class SubprocessRunnable(
|
|
4545
|
+
class SubprocessRunnable(Abstract, ta.Generic[T]):
|
|
3928
4546
|
@abc.abstractmethod
|
|
3929
4547
|
def make_run(self) -> SubprocessRun:
|
|
3930
4548
|
raise NotImplementedError
|
|
@@ -3957,233 +4575,6 @@ class SubprocessRunnable(abc.ABC, ta.Generic[T]):
|
|
|
3957
4575
|
return self.handle_run_output(await self.make_run().maysync_run(maysync_subprocesses, **kwargs))
|
|
3958
4576
|
|
|
3959
4577
|
|
|
3960
|
-
########################################
|
|
3961
|
-
# ../types.py
|
|
3962
|
-
|
|
3963
|
-
|
|
3964
|
-
##
|
|
3965
|
-
|
|
3966
|
-
|
|
3967
|
-
# See https://peps.python.org/pep-3149/
|
|
3968
|
-
INTERP_OPT_GLYPHS_BY_ATTR: ta.Mapping[str, str] = collections.OrderedDict([
|
|
3969
|
-
('debug', 'd'),
|
|
3970
|
-
('threaded', 't'),
|
|
3971
|
-
])
|
|
3972
|
-
|
|
3973
|
-
INTERP_OPT_ATTRS_BY_GLYPH: ta.Mapping[str, str] = collections.OrderedDict(
|
|
3974
|
-
(g, a) for a, g in INTERP_OPT_GLYPHS_BY_ATTR.items()
|
|
3975
|
-
)
|
|
3976
|
-
|
|
3977
|
-
|
|
3978
|
-
@dc.dataclass(frozen=True)
|
|
3979
|
-
class InterpOpts:
|
|
3980
|
-
threaded: bool = False
|
|
3981
|
-
debug: bool = False
|
|
3982
|
-
|
|
3983
|
-
def __str__(self) -> str:
|
|
3984
|
-
return ''.join(g for a, g in INTERP_OPT_GLYPHS_BY_ATTR.items() if getattr(self, a))
|
|
3985
|
-
|
|
3986
|
-
@classmethod
|
|
3987
|
-
def parse(cls, s: str) -> 'InterpOpts':
|
|
3988
|
-
return cls(**{INTERP_OPT_ATTRS_BY_GLYPH[g]: True for g in s})
|
|
3989
|
-
|
|
3990
|
-
@classmethod
|
|
3991
|
-
def parse_suffix(cls, s: str) -> ta.Tuple[str, 'InterpOpts']:
|
|
3992
|
-
kw = {}
|
|
3993
|
-
while s and (a := INTERP_OPT_ATTRS_BY_GLYPH.get(s[-1])):
|
|
3994
|
-
s, kw[a] = s[:-1], True
|
|
3995
|
-
return s, cls(**kw)
|
|
3996
|
-
|
|
3997
|
-
|
|
3998
|
-
##
|
|
3999
|
-
|
|
4000
|
-
|
|
4001
|
-
@dc.dataclass(frozen=True)
|
|
4002
|
-
class InterpVersion:
|
|
4003
|
-
version: Version
|
|
4004
|
-
opts: InterpOpts
|
|
4005
|
-
|
|
4006
|
-
def __str__(self) -> str:
|
|
4007
|
-
return str(self.version) + str(self.opts)
|
|
4008
|
-
|
|
4009
|
-
@classmethod
|
|
4010
|
-
def parse(cls, s: str) -> 'InterpVersion':
|
|
4011
|
-
s, o = InterpOpts.parse_suffix(s)
|
|
4012
|
-
v = Version(s)
|
|
4013
|
-
return cls(
|
|
4014
|
-
version=v,
|
|
4015
|
-
opts=o,
|
|
4016
|
-
)
|
|
4017
|
-
|
|
4018
|
-
@classmethod
|
|
4019
|
-
def try_parse(cls, s: str) -> ta.Optional['InterpVersion']:
|
|
4020
|
-
try:
|
|
4021
|
-
return cls.parse(s)
|
|
4022
|
-
except (KeyError, InvalidVersion):
|
|
4023
|
-
return None
|
|
4024
|
-
|
|
4025
|
-
|
|
4026
|
-
##
|
|
4027
|
-
|
|
4028
|
-
|
|
4029
|
-
@dc.dataclass(frozen=True)
|
|
4030
|
-
class InterpSpecifier:
|
|
4031
|
-
specifier: Specifier
|
|
4032
|
-
opts: InterpOpts
|
|
4033
|
-
|
|
4034
|
-
def __str__(self) -> str:
|
|
4035
|
-
return str(self.specifier) + str(self.opts)
|
|
4036
|
-
|
|
4037
|
-
@classmethod
|
|
4038
|
-
def parse(cls, s: str) -> 'InterpSpecifier':
|
|
4039
|
-
s, o = InterpOpts.parse_suffix(s)
|
|
4040
|
-
if not any(s.startswith(o) for o in Specifier.OPERATORS):
|
|
4041
|
-
s = '~=' + s
|
|
4042
|
-
if s.count('.') < 2:
|
|
4043
|
-
s += '.0'
|
|
4044
|
-
return cls(
|
|
4045
|
-
specifier=Specifier(s),
|
|
4046
|
-
opts=o,
|
|
4047
|
-
)
|
|
4048
|
-
|
|
4049
|
-
def contains(self, iv: InterpVersion) -> bool:
|
|
4050
|
-
return self.specifier.contains(iv.version) and self.opts == iv.opts
|
|
4051
|
-
|
|
4052
|
-
def __contains__(self, iv: InterpVersion) -> bool:
|
|
4053
|
-
return self.contains(iv)
|
|
4054
|
-
|
|
4055
|
-
|
|
4056
|
-
##
|
|
4057
|
-
|
|
4058
|
-
|
|
4059
|
-
@dc.dataclass(frozen=True)
|
|
4060
|
-
class Interp:
|
|
4061
|
-
exe: str
|
|
4062
|
-
version: InterpVersion
|
|
4063
|
-
|
|
4064
|
-
|
|
4065
|
-
########################################
|
|
4066
|
-
# ../../../omlish/logs/standard.py
|
|
4067
|
-
"""
|
|
4068
|
-
TODO:
|
|
4069
|
-
- structured
|
|
4070
|
-
- prefixed
|
|
4071
|
-
- debug
|
|
4072
|
-
- optional noisy? noisy will never be lite - some kinda configure_standard callback mechanism?
|
|
4073
|
-
"""
|
|
4074
|
-
|
|
4075
|
-
|
|
4076
|
-
##
|
|
4077
|
-
|
|
4078
|
-
|
|
4079
|
-
STANDARD_LOG_FORMAT_PARTS = [
|
|
4080
|
-
('asctime', '%(asctime)-15s'),
|
|
4081
|
-
('process', 'pid=%(process)s'),
|
|
4082
|
-
('thread', 'tid=%(thread)x'),
|
|
4083
|
-
('levelname', '%(levelname)s'),
|
|
4084
|
-
('name', '%(name)s'),
|
|
4085
|
-
('separator', '::'),
|
|
4086
|
-
('message', '%(message)s'),
|
|
4087
|
-
]
|
|
4088
|
-
|
|
4089
|
-
|
|
4090
|
-
class StandardLogFormatter(logging.Formatter):
|
|
4091
|
-
@staticmethod
|
|
4092
|
-
def build_log_format(parts: ta.Iterable[ta.Tuple[str, str]]) -> str:
|
|
4093
|
-
return ' '.join(v for k, v in parts)
|
|
4094
|
-
|
|
4095
|
-
converter = datetime.datetime.fromtimestamp # type: ignore
|
|
4096
|
-
|
|
4097
|
-
def formatTime(self, record, datefmt=None):
|
|
4098
|
-
ct = self.converter(record.created)
|
|
4099
|
-
if datefmt:
|
|
4100
|
-
return ct.strftime(datefmt) # noqa
|
|
4101
|
-
else:
|
|
4102
|
-
t = ct.strftime('%Y-%m-%d %H:%M:%S')
|
|
4103
|
-
return '%s.%03d' % (t, record.msecs) # noqa
|
|
4104
|
-
|
|
4105
|
-
|
|
4106
|
-
##
|
|
4107
|
-
|
|
4108
|
-
|
|
4109
|
-
class StandardConfiguredLogHandler(ProxyLogHandler):
|
|
4110
|
-
def __init_subclass__(cls, **kwargs):
|
|
4111
|
-
raise TypeError('This class serves only as a marker and should not be subclassed.')
|
|
4112
|
-
|
|
4113
|
-
|
|
4114
|
-
##
|
|
4115
|
-
|
|
4116
|
-
|
|
4117
|
-
@contextlib.contextmanager
|
|
4118
|
-
def _locking_logging_module_lock() -> ta.Iterator[None]:
|
|
4119
|
-
if hasattr(logging, '_acquireLock'):
|
|
4120
|
-
logging._acquireLock() # noqa
|
|
4121
|
-
try:
|
|
4122
|
-
yield
|
|
4123
|
-
finally:
|
|
4124
|
-
logging._releaseLock() # type: ignore # noqa
|
|
4125
|
-
|
|
4126
|
-
elif hasattr(logging, '_lock'):
|
|
4127
|
-
# https://github.com/python/cpython/commit/74723e11109a320e628898817ab449b3dad9ee96
|
|
4128
|
-
with logging._lock: # noqa
|
|
4129
|
-
yield
|
|
4130
|
-
|
|
4131
|
-
else:
|
|
4132
|
-
raise Exception("Can't find lock in logging module")
|
|
4133
|
-
|
|
4134
|
-
|
|
4135
|
-
def configure_standard_logging(
|
|
4136
|
-
level: ta.Union[int, str] = logging.INFO,
|
|
4137
|
-
*,
|
|
4138
|
-
json: bool = False,
|
|
4139
|
-
target: ta.Optional[logging.Logger] = None,
|
|
4140
|
-
force: bool = False,
|
|
4141
|
-
handler_factory: ta.Optional[ta.Callable[[], logging.Handler]] = None,
|
|
4142
|
-
) -> ta.Optional[StandardConfiguredLogHandler]:
|
|
4143
|
-
with _locking_logging_module_lock():
|
|
4144
|
-
if target is None:
|
|
4145
|
-
target = logging.root
|
|
4146
|
-
|
|
4147
|
-
#
|
|
4148
|
-
|
|
4149
|
-
if not force:
|
|
4150
|
-
if any(isinstance(h, StandardConfiguredLogHandler) for h in list(target.handlers)):
|
|
4151
|
-
return None
|
|
4152
|
-
|
|
4153
|
-
#
|
|
4154
|
-
|
|
4155
|
-
if handler_factory is not None:
|
|
4156
|
-
handler = handler_factory()
|
|
4157
|
-
else:
|
|
4158
|
-
handler = logging.StreamHandler()
|
|
4159
|
-
|
|
4160
|
-
#
|
|
4161
|
-
|
|
4162
|
-
formatter: logging.Formatter
|
|
4163
|
-
if json:
|
|
4164
|
-
formatter = JsonLogFormatter()
|
|
4165
|
-
else:
|
|
4166
|
-
formatter = StandardLogFormatter(StandardLogFormatter.build_log_format(STANDARD_LOG_FORMAT_PARTS))
|
|
4167
|
-
handler.setFormatter(formatter)
|
|
4168
|
-
|
|
4169
|
-
#
|
|
4170
|
-
|
|
4171
|
-
handler.addFilter(TidLogFilter())
|
|
4172
|
-
|
|
4173
|
-
#
|
|
4174
|
-
|
|
4175
|
-
target.addHandler(handler)
|
|
4176
|
-
|
|
4177
|
-
#
|
|
4178
|
-
|
|
4179
|
-
if level is not None:
|
|
4180
|
-
target.setLevel(level)
|
|
4181
|
-
|
|
4182
|
-
#
|
|
4183
|
-
|
|
4184
|
-
return StandardConfiguredLogHandler(handler)
|
|
4185
|
-
|
|
4186
|
-
|
|
4187
4578
|
########################################
|
|
4188
4579
|
# ../../../omlish/subprocesses/wrap.py
|
|
4189
4580
|
"""
|
|
@@ -4225,13 +4616,13 @@ TODO:
|
|
|
4225
4616
|
##
|
|
4226
4617
|
|
|
4227
4618
|
|
|
4228
|
-
class InterpProvider(
|
|
4619
|
+
class InterpProvider(Abstract):
|
|
4229
4620
|
name: ta.ClassVar[str]
|
|
4230
4621
|
|
|
4231
4622
|
def __init_subclass__(cls, **kwargs: ta.Any) -> None:
|
|
4232
4623
|
super().__init_subclass__(**kwargs)
|
|
4233
4624
|
|
|
4234
|
-
if
|
|
4625
|
+
if Abstract not in cls.__bases__ and 'name' not in cls.__dict__:
|
|
4235
4626
|
sfx = 'InterpProvider'
|
|
4236
4627
|
if not cls.__name__.endswith(sfx):
|
|
4237
4628
|
raise NameError(cls)
|
|
@@ -4297,13 +4688,17 @@ class VerboseCalledProcessError(subprocess.CalledProcessError):
|
|
|
4297
4688
|
return msg
|
|
4298
4689
|
|
|
4299
4690
|
|
|
4300
|
-
class BaseSubprocesses(
|
|
4301
|
-
DEFAULT_LOGGER: ta.ClassVar[ta.Optional[
|
|
4691
|
+
class BaseSubprocesses(Abstract):
|
|
4692
|
+
DEFAULT_LOGGER: ta.ClassVar[ta.Optional[LoggerLike]] = None
|
|
4693
|
+
|
|
4694
|
+
PIPE: ta.ClassVar[int] = subprocess.PIPE
|
|
4695
|
+
STDOUT: ta.ClassVar[int] = subprocess.STDOUT
|
|
4696
|
+
DEVNULL: ta.ClassVar[int] = subprocess.DEVNULL
|
|
4302
4697
|
|
|
4303
4698
|
def __init__(
|
|
4304
4699
|
self,
|
|
4305
4700
|
*,
|
|
4306
|
-
log: ta.Optional[
|
|
4701
|
+
log: ta.Optional[LoggerLike] = None,
|
|
4307
4702
|
try_exceptions: ta.Optional[ta.Tuple[ta.Type[Exception], ...]] = None,
|
|
4308
4703
|
) -> None:
|
|
4309
4704
|
super().__init__()
|
|
@@ -4311,7 +4706,7 @@ class BaseSubprocesses(abc.ABC): # noqa
|
|
|
4311
4706
|
self._log = log if log is not None else self.DEFAULT_LOGGER
|
|
4312
4707
|
self._try_exceptions = try_exceptions if try_exceptions is not None else self.DEFAULT_TRY_EXCEPTIONS
|
|
4313
4708
|
|
|
4314
|
-
def set_logger(self, log: ta.Optional[
|
|
4709
|
+
def set_logger(self, log: ta.Optional[LoggerLike]) -> None:
|
|
4315
4710
|
self._log = log
|
|
4316
4711
|
|
|
4317
4712
|
#
|
|
@@ -4562,7 +4957,7 @@ class InterpResolver:
|
|
|
4562
4957
|
##
|
|
4563
4958
|
|
|
4564
4959
|
|
|
4565
|
-
class AbstractAsyncSubprocesses(BaseSubprocesses):
|
|
4960
|
+
class AbstractAsyncSubprocesses(BaseSubprocesses, Abstract):
|
|
4566
4961
|
@abc.abstractmethod
|
|
4567
4962
|
def run_(self, run: SubprocessRun) -> ta.Awaitable[SubprocessRunOutput]:
|
|
4568
4963
|
raise NotImplementedError
|
|
@@ -4669,7 +5064,7 @@ class AsyncioProcessCommunicator:
|
|
|
4669
5064
|
proc: asyncio.subprocess.Process,
|
|
4670
5065
|
loop: ta.Optional[ta.Any] = None,
|
|
4671
5066
|
*,
|
|
4672
|
-
log: ta.Optional[
|
|
5067
|
+
log: ta.Optional[LoggerLike] = None,
|
|
4673
5068
|
) -> None:
|
|
4674
5069
|
super().__init__()
|
|
4675
5070
|
|
|
@@ -4892,7 +5287,7 @@ class InterpInspector:
|
|
|
4892
5287
|
def __init__(
|
|
4893
5288
|
self,
|
|
4894
5289
|
*,
|
|
4895
|
-
log: ta.Optional[
|
|
5290
|
+
log: ta.Optional[LoggerLike] = None,
|
|
4896
5291
|
) -> None:
|
|
4897
5292
|
super().__init__()
|
|
4898
5293
|
|
|
@@ -5056,7 +5451,7 @@ class Uv:
|
|
|
5056
5451
|
self,
|
|
5057
5452
|
config: UvConfig = UvConfig(),
|
|
5058
5453
|
*,
|
|
5059
|
-
log: ta.Optional[
|
|
5454
|
+
log: ta.Optional[LoggerLike] = None,
|
|
5060
5455
|
) -> None:
|
|
5061
5456
|
super().__init__()
|
|
5062
5457
|
|
|
@@ -5148,7 +5543,7 @@ class SystemInterpProvider(InterpProvider):
|
|
|
5148
5543
|
options: Options = Options(),
|
|
5149
5544
|
*,
|
|
5150
5545
|
inspector: ta.Optional[InterpInspector] = None,
|
|
5151
|
-
log: ta.Optional[
|
|
5546
|
+
log: ta.Optional[LoggerLike] = None,
|
|
5152
5547
|
) -> None:
|
|
5153
5548
|
super().__init__()
|
|
5154
5549
|
|
|
@@ -5328,7 +5723,7 @@ THREADED_PYENV_INSTALL_OPTS = PyenvInstallOpts(conf_opts=['--disable-gil'])
|
|
|
5328
5723
|
#
|
|
5329
5724
|
|
|
5330
5725
|
|
|
5331
|
-
class PyenvInstallOptsProvider(
|
|
5726
|
+
class PyenvInstallOptsProvider(Abstract):
|
|
5332
5727
|
@abc.abstractmethod
|
|
5333
5728
|
def opts(self) -> ta.Awaitable[PyenvInstallOpts]:
|
|
5334
5729
|
raise NotImplementedError
|
|
@@ -5519,19 +5914,49 @@ uv run pip
|
|
|
5519
5914
|
uv run --python 3.11.6 pip
|
|
5520
5915
|
uv venv --python 3.11.6 --seed barf
|
|
5521
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
|
|
5522
5919
|
"""
|
|
5523
5920
|
|
|
5524
5921
|
|
|
5525
5922
|
##
|
|
5526
5923
|
|
|
5527
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
|
+
|
|
5528
5953
|
class UvInterpProvider(InterpProvider):
|
|
5529
5954
|
def __init__(
|
|
5530
5955
|
self,
|
|
5531
5956
|
*,
|
|
5532
5957
|
pyenv: Uv,
|
|
5533
5958
|
inspector: InterpInspector,
|
|
5534
|
-
log: ta.Optional[
|
|
5959
|
+
log: ta.Optional[LoggerLike] = None,
|
|
5535
5960
|
) -> None:
|
|
5536
5961
|
super().__init__()
|
|
5537
5962
|
|
|
@@ -5545,6 +5970,12 @@ class UvInterpProvider(InterpProvider):
|
|
|
5545
5970
|
async def get_installed_version(self, version: InterpVersion) -> Interp:
|
|
5546
5971
|
raise NotImplementedError
|
|
5547
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
|
+
|
|
5548
5979
|
|
|
5549
5980
|
########################################
|
|
5550
5981
|
# ../providers/inject.py
|
|
@@ -5588,7 +6019,7 @@ class PyenvInterpProvider(InterpProvider):
|
|
|
5588
6019
|
*,
|
|
5589
6020
|
pyenv: Pyenv,
|
|
5590
6021
|
inspector: InterpInspector,
|
|
5591
|
-
log: ta.Optional[
|
|
6022
|
+
log: ta.Optional[LoggerLike] = None,
|
|
5592
6023
|
) -> None:
|
|
5593
6024
|
super().__init__()
|
|
5594
6025
|
|