omdev 0.0.0.dev440__py3-none-any.whl → 0.0.0.dev495__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of omdev might be problematic. Click here for more details.
- omdev/.omlish-manifests.json +18 -30
- omdev/README.md +51 -0
- omdev/__about__.py +11 -7
- omdev/amalg/gen/gen.py +49 -6
- omdev/amalg/gen/imports.py +1 -1
- omdev/amalg/gen/manifests.py +1 -1
- omdev/amalg/gen/resources.py +1 -1
- omdev/amalg/gen/srcfiles.py +13 -3
- omdev/amalg/gen/strip.py +1 -1
- omdev/amalg/gen/types.py +1 -1
- omdev/amalg/gen/typing.py +1 -1
- omdev/amalg/info.py +32 -0
- omdev/cache/data/actions.py +1 -1
- omdev/cache/data/specs.py +1 -1
- omdev/cexts/_boilerplate.cc +2 -3
- omdev/cexts/cmake.py +4 -1
- omdev/ci/cli.py +2 -3
- omdev/cli/clicli.py +37 -7
- omdev/cmdlog/cli.py +1 -2
- omdev/dataclasses/_dumping.py +1960 -0
- omdev/dataclasses/_template.py +22 -0
- omdev/dataclasses/cli.py +7 -2
- omdev/dataclasses/codegen.py +340 -60
- omdev/dataclasses/dumping.py +200 -0
- omdev/interp/cli.py +1 -1
- omdev/interp/types.py +3 -2
- omdev/interp/uv/provider.py +37 -0
- omdev/interp/venvs.py +1 -0
- omdev/irc/messages/base.py +50 -0
- omdev/irc/messages/formats.py +92 -0
- omdev/irc/messages/messages.py +775 -0
- omdev/irc/messages/parsing.py +99 -0
- omdev/irc/numerics/__init__.py +0 -0
- omdev/irc/numerics/formats.py +97 -0
- omdev/irc/numerics/numerics.py +865 -0
- omdev/irc/numerics/types.py +59 -0
- omdev/irc/protocol/LICENSE +11 -0
- omdev/irc/protocol/__init__.py +61 -0
- omdev/irc/protocol/consts.py +6 -0
- omdev/irc/protocol/errors.py +30 -0
- omdev/irc/protocol/message.py +21 -0
- omdev/irc/protocol/nuh.py +55 -0
- omdev/irc/protocol/parsing.py +158 -0
- omdev/irc/protocol/rendering.py +153 -0
- omdev/irc/protocol/tags.py +102 -0
- omdev/irc/protocol/utils.py +30 -0
- omdev/manifests/_dumping.py +125 -25
- omdev/manifests/main.py +1 -1
- omdev/markdown/__init__.py +0 -0
- omdev/markdown/incparse.py +116 -0
- omdev/markdown/tokens.py +51 -0
- omdev/packaging/marshal.py +8 -8
- omdev/packaging/requires.py +6 -6
- omdev/packaging/revisions.py +1 -1
- omdev/packaging/specifiers.py +2 -1
- omdev/packaging/versions.py +4 -4
- omdev/packaging/wheelfile.py +2 -0
- omdev/precheck/blanklines.py +66 -0
- omdev/precheck/caches.py +1 -1
- omdev/precheck/imports.py +14 -1
- omdev/precheck/main.py +4 -3
- omdev/precheck/unicode.py +39 -15
- omdev/py/asts/__init__.py +0 -0
- omdev/py/asts/parents.py +28 -0
- omdev/py/asts/toplevel.py +123 -0
- omdev/py/asts/visitors.py +18 -0
- omdev/py/attrdocs.py +1 -1
- omdev/py/bracepy.py +12 -4
- omdev/py/reprs.py +32 -0
- omdev/py/srcheaders.py +1 -1
- omdev/py/tokens/__init__.py +0 -0
- omdev/py/tools/mkrelimp.py +1 -1
- omdev/py/tools/pipdepup.py +686 -0
- omdev/pyproject/cli.py +1 -1
- omdev/pyproject/pkg.py +190 -45
- omdev/pyproject/reqs.py +31 -9
- omdev/pyproject/tools/__init__.py +0 -0
- omdev/pyproject/tools/aboutdeps.py +60 -0
- omdev/pyproject/venvs.py +8 -1
- omdev/rs/__init__.py +0 -0
- omdev/scripts/ci.py +752 -98
- omdev/scripts/interp.py +232 -39
- omdev/scripts/lib/inject.py +74 -27
- omdev/scripts/lib/logs.py +187 -43
- omdev/scripts/lib/marshal.py +67 -25
- omdev/scripts/pyproject.py +1369 -143
- omdev/tools/git/cli.py +10 -0
- omdev/tools/json/formats.py +2 -0
- omdev/tools/json/processing.py +5 -2
- omdev/tools/jsonview/cli.py +49 -65
- omdev/tools/jsonview/resources/jsonview.html.j2 +43 -0
- omdev/tools/pawk/README.md +195 -0
- omdev/tools/pawk/pawk.py +2 -2
- omdev/tools/pip.py +8 -0
- omdev/tui/__init__.py +0 -0
- omdev/tui/apps/__init__.py +0 -0
- omdev/tui/apps/edit/__init__.py +0 -0
- omdev/tui/apps/edit/main.py +167 -0
- omdev/tui/apps/irc/__init__.py +0 -0
- omdev/tui/apps/irc/__main__.py +4 -0
- omdev/tui/apps/irc/app.py +286 -0
- omdev/tui/apps/irc/client.py +187 -0
- omdev/tui/apps/irc/commands.py +175 -0
- omdev/tui/apps/irc/main.py +26 -0
- omdev/tui/apps/markdown/__init__.py +0 -0
- omdev/tui/apps/markdown/__main__.py +11 -0
- omdev/{ptk → tui/apps}/markdown/cli.py +5 -7
- omdev/tui/rich/__init__.py +46 -0
- omdev/tui/rich/console2.py +20 -0
- omdev/tui/rich/markdown2.py +186 -0
- omdev/tui/textual/__init__.py +265 -0
- omdev/tui/textual/app2.py +16 -0
- omdev/tui/textual/autocomplete/LICENSE +21 -0
- omdev/tui/textual/autocomplete/__init__.py +33 -0
- omdev/tui/textual/autocomplete/matching.py +226 -0
- omdev/tui/textual/autocomplete/paths.py +202 -0
- omdev/tui/textual/autocomplete/widget.py +612 -0
- omdev/tui/textual/debug/__init__.py +10 -0
- omdev/tui/textual/debug/dominfo.py +151 -0
- omdev/tui/textual/debug/screen.py +24 -0
- omdev/tui/textual/devtools.py +187 -0
- omdev/tui/textual/drivers2.py +55 -0
- omdev/tui/textual/logging2.py +20 -0
- omdev/tui/textual/types.py +45 -0
- {omdev-0.0.0.dev440.dist-info → omdev-0.0.0.dev495.dist-info}/METADATA +15 -9
- {omdev-0.0.0.dev440.dist-info → omdev-0.0.0.dev495.dist-info}/RECORD +135 -80
- omdev/ptk/__init__.py +0 -103
- omdev/ptk/apps/ncdu.py +0 -167
- omdev/ptk/confirm.py +0 -60
- omdev/ptk/markdown/LICENSE +0 -22
- omdev/ptk/markdown/__init__.py +0 -10
- omdev/ptk/markdown/__main__.py +0 -11
- omdev/ptk/markdown/border.py +0 -94
- omdev/ptk/markdown/markdown.py +0 -390
- omdev/ptk/markdown/parser.py +0 -42
- omdev/ptk/markdown/styles.py +0 -29
- omdev/ptk/markdown/tags.py +0 -299
- omdev/ptk/markdown/utils.py +0 -366
- omdev/pyproject/cexts.py +0 -110
- /omdev/{ptk/apps → irc}/__init__.py +0 -0
- /omdev/{tokens → irc/messages}/__init__.py +0 -0
- /omdev/{tokens → py/tokens}/all.py +0 -0
- /omdev/{tokens → py/tokens}/tokenizert.py +0 -0
- /omdev/{tokens → py/tokens}/utils.py +0 -0
- {omdev-0.0.0.dev440.dist-info → omdev-0.0.0.dev495.dist-info}/WHEEL +0 -0
- {omdev-0.0.0.dev440.dist-info → omdev-0.0.0.dev495.dist-info}/entry_points.txt +0 -0
- {omdev-0.0.0.dev440.dist-info → omdev-0.0.0.dev495.dist-info}/licenses/LICENSE +0 -0
- {omdev-0.0.0.dev440.dist-info → omdev-0.0.0.dev495.dist-info}/top_level.txt +0 -0
omdev/scripts/ci.py
CHANGED
|
@@ -49,6 +49,7 @@ import io
|
|
|
49
49
|
import itertools
|
|
50
50
|
import json
|
|
51
51
|
import logging
|
|
52
|
+
import operator
|
|
52
53
|
import os
|
|
53
54
|
import os.path
|
|
54
55
|
import re
|
|
@@ -83,6 +84,124 @@ if sys.version_info < (3, 8):
|
|
|
83
84
|
raise OSError(f'Requires python (3, 8), got {sys.version_info} from {sys.executable}') # noqa
|
|
84
85
|
|
|
85
86
|
|
|
87
|
+
def __omlish_amalg__(): # noqa
|
|
88
|
+
return dict(
|
|
89
|
+
src_files=[
|
|
90
|
+
dict(path='consts.py', sha1='ef00d55ab4cdd799b22f2e8b736eacd52ee8a80e'),
|
|
91
|
+
dict(path='github/env.py', sha1='c7a2389048f008f46f59f6bcc11e0d15655f2b1c'),
|
|
92
|
+
dict(path='shell.py', sha1='a59e59b812394d0502837f4c198e1cf604f90227'),
|
|
93
|
+
dict(path='utils.py', sha1='f0f9ef0778db316b1ba83e6eeac79c8fd132d86a'),
|
|
94
|
+
dict(path='../oci/compression.py', sha1='7d165bc51a77db13ff45927daecc42839cfd75ea'),
|
|
95
|
+
dict(path='../../omlish/asyncs/asyncio/utils.py', sha1='34691d4d0e5bab68f14e193a6200df040cfd0136'),
|
|
96
|
+
dict(path='../../omlish/docker/ports.py', sha1='a3202c69b85bc4f1034479df3400fddc86130e5c'),
|
|
97
|
+
dict(path='../../omlish/http/urllib.py', sha1='25431c5bdc7dd5cbecfcb8c0bdffaabf8c1691b9'),
|
|
98
|
+
dict(path='../../omlish/http/versions.py', sha1='197685ffbb62a457a0e8d4047a9df26aebd7dae4'),
|
|
99
|
+
dict(path='../../omlish/lite/abstract.py', sha1='a2fc3f3697fa8de5247761e9d554e70176f37aac'),
|
|
100
|
+
dict(path='../../omlish/lite/asyncs.py', sha1='b3f2251c56617ce548abf9c333ac996b63edb23e'),
|
|
101
|
+
dict(path='../../omlish/lite/cached.py', sha1='0c33cf961ac8f0727284303c7a30c5ea98f714f2'),
|
|
102
|
+
dict(path='../../omlish/lite/check.py', sha1='bb6b6b63333699b84462951a854d99ae83195b94'),
|
|
103
|
+
dict(path='../../omlish/lite/contextmanagers.py', sha1='993f5ed96d3410f739a20363f55670d5e5267fa3'),
|
|
104
|
+
dict(path='../../omlish/lite/dataclasses.py', sha1='73b7f5e5493c7ed12ff0ce36e37b596e5984cb08'),
|
|
105
|
+
dict(path='../../omlish/lite/json.py', sha1='57eeddc4d23a17931e00284ffa5cb6e3ce089486'),
|
|
106
|
+
dict(path='../../omlish/lite/objects.py', sha1='9566bbf3530fd71fcc56321485216b592fae21e9'),
|
|
107
|
+
dict(path='../../omlish/lite/reflect.py', sha1='c4fec44bf144e9d93293c996af06f6c65fc5e63d'),
|
|
108
|
+
dict(path='../../omlish/lite/strings.py', sha1='89831ecbc34ad80e118a865eceb390ed399dc4d6'),
|
|
109
|
+
dict(path='../../omlish/logs/levels.py', sha1='91405563d082a5eba874da82aac89d83ce7b6152'),
|
|
110
|
+
dict(path='../../omlish/logs/std/filters.py', sha1='f36aab646d84d31e295b33aaaaa6f8b67ff38b3d'),
|
|
111
|
+
dict(path='../../omlish/logs/std/proxy.py', sha1='3e7301a2aa351127f9c85f61b2f85dcc3f15aafb'),
|
|
112
|
+
dict(path='../../omlish/logs/warnings.py', sha1='c4eb694b24773351107fcc058f3620f1dbfb6799'),
|
|
113
|
+
dict(path='../../omlish/os/files.py', sha1='32f4fe2e7d32a6b368619081bd300e6f150e312b'),
|
|
114
|
+
dict(path='../../omlish/os/paths.py', sha1='56c40b7c2aa84d1778d60ee4cda498f8c380cc8d'),
|
|
115
|
+
dict(path='../../omlish/secrets/ssl.py', sha1='68af8abad22d64afa1736a8363036aa2121ada78'),
|
|
116
|
+
dict(path='../../omlish/sockets/addresses.py', sha1='26533e88a8073f89646c0f77f1fbe0869282ab0e'),
|
|
117
|
+
dict(path='../../omlish/sockets/io.py', sha1='b6b8a73ac0f29893c7128f9d4f62240efbd917bb'),
|
|
118
|
+
dict(path='docker/utils.py', sha1='082e2b962ca1bc8e6b3f9bbe6ecfcadff310d54f'),
|
|
119
|
+
dict(path='github/api/v1/api.py', sha1='1985c16447f5d245b659936571d361285374c5d9'),
|
|
120
|
+
dict(path='github/api/v2/api.py', sha1='08322895cd895db1cbffceb1e5bfc7b10cac50cc'),
|
|
121
|
+
dict(path='github/bootstrap.py', sha1='9bf24b05603cd1a82db8be8b645bbad3e0d3f22f'),
|
|
122
|
+
dict(path='../oci/datarefs.py', sha1='793ce5f2774e052b28d04b226a5f1eff6eec0a72'),
|
|
123
|
+
dict(path='../oci/pack/unpacking.py', sha1='f43dee9a2eee79cbbb90f0721ed234a2bc35daa7'),
|
|
124
|
+
dict(path='../../omlish/argparse/cli.py', sha1='f4dc3cd353d14386b5da0306768700e396afd2b3'),
|
|
125
|
+
dict(path='../../omlish/http/coro/io.py', sha1='2cdf6529c37a37cc0c1db2e02032157cf906d5d6'),
|
|
126
|
+
dict(path='../../omlish/http/parsing.py', sha1='3fea28dc6341908ba7c8fad42bf7bbe711f21b82'),
|
|
127
|
+
dict(path='../../omlish/lite/marshal.py', sha1='96348f5f2a26dc27d842d33cc3927e9da163436b'),
|
|
128
|
+
dict(path='../../omlish/lite/maybes.py', sha1='bdf5136654ccd14b6a072588cad228925bdfbabd'),
|
|
129
|
+
dict(path='../../omlish/lite/runtime.py', sha1='2e752a27ae2bf89b1bb79b4a2da522a3ec360c70'),
|
|
130
|
+
dict(path='../../omlish/lite/timeouts.py', sha1='a0f673033a6943f242e35848d78a41892b9c62a1'),
|
|
131
|
+
dict(path='../../omlish/logs/infos.py', sha1='4dd104bd468a8c438601dd0bbda619b47d2f1620'),
|
|
132
|
+
dict(path='../../omlish/logs/protocols.py', sha1='05ca4d1d7feb50c4e3b9f22ee371aa7bf4b3dbd1'),
|
|
133
|
+
dict(path='../../omlish/logs/std/json.py', sha1='2a75553131e4d5331bb0cedde42aa183f403fc3b'),
|
|
134
|
+
dict(path='../../omlish/os/temp.py', sha1='fba3470ac095a6c3f893156cc4437bda1b8796cb'),
|
|
135
|
+
dict(path='../../omlish/sockets/bind.py', sha1='d0040d74960fb00c30ae9ece5252c270b59ae3f4'),
|
|
136
|
+
dict(path='../../omlish/sockets/handlers.py', sha1='733a4855d563001ad09df511531d710aa2632770'),
|
|
137
|
+
dict(path='../../omlish/text/mangle.py', sha1='5631de37ca659e064eb1afcf2213d317b626f8bd'),
|
|
138
|
+
dict(path='../dataserver/targets.py', sha1='661fc3e60ad436646c8acff3c547d5b86ceb0bd6'),
|
|
139
|
+
dict(path='../oci/data.py', sha1='9cfc3bb8e23fb4cd746c6e8f0e02624e8f63f234'),
|
|
140
|
+
dict(path='../oci/repositories.py', sha1='bd0ac0fb906f679a660c87124da268370733fcc6'),
|
|
141
|
+
dict(path='../oci/tars.py', sha1='3ed00e97a494bd92c6a6149d22d51469bc0af384'),
|
|
142
|
+
dict(path='../../omlish/asyncs/asyncio/sockets.py', sha1='8d24dae988a30bb73f167a9ab62d4fc9eef4ad06'),
|
|
143
|
+
dict(path='../../omlish/asyncs/asyncio/timeouts.py', sha1='4d31b02b3c39b8f2fa7e94db36552fde6942e36a'),
|
|
144
|
+
dict(path='../../omlish/http/handlers.py', sha1='40629060bac22ea5e94b720b57001861a4ec9031'),
|
|
145
|
+
dict(path='../../omlish/lite/inject.py', sha1='6f097e3170019a34ff6834d36fcc9cbeed3a7ab4'),
|
|
146
|
+
dict(path='../../omlish/logs/contexts.py', sha1='1000a6d5ddfb642865ca532e34b1d50759781cf0'),
|
|
147
|
+
dict(path='../../omlish/logs/std/standard.py', sha1='5c97c1b9f7ead58d6127d047b873398f708f288d'),
|
|
148
|
+
dict(path='../../omlish/logs/utils.py', sha1='39599f5e9d9911a06eac6e0d7e5116fdc69b1263'),
|
|
149
|
+
dict(path='../../omlish/sockets/server/handlers.py', sha1='6f9adca9fa04774a28a488a4e2a11bb4492c71d0'),
|
|
150
|
+
dict(path='../../omlish/subprocesses/run.py', sha1='8200e48f0c49d164df3503cd0143038d0c4d30aa'),
|
|
151
|
+
dict(path='../../omlish/subprocesses/wrap.py', sha1='8a9b7d2255481fae15c05f5624b0cdc0766f4b3f'),
|
|
152
|
+
dict(path='../dataserver/handlers.py', sha1='f624715f2500087226ec3374315cc8a1ea47a29b'),
|
|
153
|
+
dict(path='../dataserver/routes.py', sha1='0186bb2e84ff4d5c05af2a57c61f6fd605eba790'),
|
|
154
|
+
dict(path='../oci/media.py', sha1='a20324c5b0661c9a9a7679406d019ab3ba4acd98'),
|
|
155
|
+
dict(path='../oci/pack/packing.py', sha1='7585c3dea6b8a62b6ca63fe78968497db915ea57'),
|
|
156
|
+
dict(path='../../omlish/http/coro/server/server.py', sha1='c0a980afa8346dbc20570acddb2b3b579bfc1ce0'),
|
|
157
|
+
dict(path='../../omlish/logs/base.py', sha1='8d06faee05fead6b1dd98c9035a5b042af4aebb1'),
|
|
158
|
+
dict(path='../../omlish/logs/std/records.py', sha1='8bbf6ef9eccb3a012c6ca416ddf3969450fd8fc9'),
|
|
159
|
+
dict(path='../../omlish/secrets/tempssl.py', sha1='360d4cd98483357bcf013e156dafd92fd37ed220'),
|
|
160
|
+
dict(path='../../omlish/sockets/server/server.py', sha1='a93a74f6beb38d69e0fb9047c932f2a95aa37eca'),
|
|
161
|
+
dict(path='../../omlish/sockets/server/ssl.py', sha1='790dfd208f4d267c826d491d4eb5deeda5ebdddc'),
|
|
162
|
+
dict(path='../../omlish/sockets/server/threading.py', sha1='0ba3c7a3d15781326610b12feef94e53903d0ce9'),
|
|
163
|
+
dict(path='../../omlish/subprocesses/base.py', sha1='cb9f668be5422fecb27222caabb67daac6c1bab9'),
|
|
164
|
+
dict(path='docker/cacheserved/manifests.py', sha1='80a65d08319d152f0bc6f893351e23368b3de93b'),
|
|
165
|
+
dict(path='../dataserver/server.py', sha1='e1ba8ca6f85458a64ede4ca07836aa103246132a'),
|
|
166
|
+
dict(path='../oci/building.py', sha1='b4fea06c03ba02d3ecfc6d10d955dc76f263846a'),
|
|
167
|
+
dict(path='../oci/loading.py', sha1='64d806ffad8d24087ccc29f759f672e6d795bee2'),
|
|
168
|
+
dict(path='../../omlish/http/coro/server/sockets.py', sha1='40ef4aa43f94f1a1a2a431a012cb961f25905ff4'),
|
|
169
|
+
dict(path='../../omlish/logs/asyncs.py', sha1='ab11b70033d9f2e9a4e70254185aa1c6130c6077'),
|
|
170
|
+
dict(path='../../omlish/logs/std/loggers.py', sha1='a569179445d6a8a942b5dcfad1d1f77702868803'),
|
|
171
|
+
dict(path='../../omlish/subprocesses/asyncs.py', sha1='bba44d524c24c6ac73168aee6343488414e5bf48'),
|
|
172
|
+
dict(path='../../omlish/subprocesses/sync.py', sha1='8434919eba4da67825773d56918fdc0cb2f1883b'),
|
|
173
|
+
dict(path='requirements.py', sha1='c370a65958a00412e00608a0e1f12795e276aee1'),
|
|
174
|
+
dict(path='../dataserver/http.py', sha1='f85ca91015bac434281326ef7885babd9d6d834c'),
|
|
175
|
+
dict(path='../oci/dataserver.py', sha1='dd147b56282b054cef264556a0ff3b3d1719bcee'),
|
|
176
|
+
dict(path='../../omlish/asyncs/asyncio/subprocesses.py', sha1='b6b5f9ae3fd0b9c83593bad2e04a08f726e5904d'),
|
|
177
|
+
dict(path='../../omlish/http/coro/server/simple.py', sha1='2332079fe29993123c68d7dbc266b47cd44cd6a6'),
|
|
178
|
+
dict(path='../../omlish/logs/modules.py', sha1='dd7d5f8e63fe8829dfb49460f3929ab64b68ee14'),
|
|
179
|
+
dict(path='cache.py', sha1='9353e5c3b73bed47258680fd15ac49417113f0ca'),
|
|
180
|
+
dict(path='compose.py', sha1='d2bec1385701979c7ff9913456b72d8c7b31f70b'),
|
|
181
|
+
dict(path='docker/cmds.py', sha1='5528c384f68f9003732bfaf6be302e84747909dd'),
|
|
182
|
+
dict(path='docker/dataserver.py', sha1='949e561ab756846425a39c05964c0fb256ae61db'),
|
|
183
|
+
dict(path='../../omlish/lite/timing.py', sha1='af5022f5a508939f1b433ed0514ede340fd0d672'),
|
|
184
|
+
dict(path='docker/cache.py', sha1='07a9e3d00bdd60f1a0a9b55aca12430fa1b4e3d9'),
|
|
185
|
+
dict(path='docker/repositories.py', sha1='e4bfc0e91c3bf20259895ce7c95a1eb3f6507518'),
|
|
186
|
+
dict(path='github/api/clients.py', sha1='8ddc0f5ccf718f1b530f4a965f0cc56b68a6a2a8'),
|
|
187
|
+
dict(path='github/api/v2/azure.py', sha1='19052e8e2babb8b2953ec10e6b9dcee97c21419a'),
|
|
188
|
+
dict(path='../oci/pack/repositories.py', sha1='e9bf6fa8bdaae2031dd0967d07a56c93a2e099b6'),
|
|
189
|
+
dict(path='docker/buildcaching.py', sha1='7b2633d5b8dac6aab01dd459e273cb370c5b11c8'),
|
|
190
|
+
dict(path='docker/cacheserved/cache.py', sha1='69732c658dba7ccf260e784132ff0c60192e3c69'),
|
|
191
|
+
dict(path='docker/imagepulling.py', sha1='d6b1ca1ecb9aa5c593a25e6deb78e942c75ebcb4'),
|
|
192
|
+
dict(path='github/api/v1/client.py', sha1='6ddd600cd8a7ff72a6a3408ded14240bafab6944'),
|
|
193
|
+
dict(path='github/api/v2/client.py', sha1='e28f27c07011487d5a3f4ae32fdfa1a857d02459'),
|
|
194
|
+
dict(path='ci.py', sha1='87b82e2bd86aa886764f1e0067251b056e359650'),
|
|
195
|
+
dict(path='docker/inject.py', sha1='69acac65fae413cb58c1f9aa739d2cc1c3ffa09d'),
|
|
196
|
+
dict(path='github/cache.py', sha1='d91f9c87d167574e94c99817e6c3a0f75925dfb9'),
|
|
197
|
+
dict(path='github/cli.py', sha1='6d14b0eb4ca5f606ad2821b63b9707ce57f50406'),
|
|
198
|
+
dict(path='github/inject.py', sha1='99c0dd7c55767e7c49f70b7edac25da67f718b2e'),
|
|
199
|
+
dict(path='inject.py', sha1='e86b16d79a113a4f387e68ed0db1d067bcada93a'),
|
|
200
|
+
dict(path='cli.py', sha1='92948cf3ec76fd9ceb25762aadbf497354adce6d'),
|
|
201
|
+
],
|
|
202
|
+
)
|
|
203
|
+
|
|
204
|
+
|
|
86
205
|
########################################
|
|
87
206
|
|
|
88
207
|
|
|
@@ -345,6 +464,8 @@ async def asyncio_wait_concurrent(
|
|
|
345
464
|
if isinstance(concurrency, asyncio.Semaphore):
|
|
346
465
|
semaphore = concurrency
|
|
347
466
|
elif isinstance(concurrency, int):
|
|
467
|
+
if concurrency < 1:
|
|
468
|
+
raise ValueError(f'Concurrency must be >= 1, got {concurrency}')
|
|
348
469
|
semaphore = asyncio.Semaphore(concurrency)
|
|
349
470
|
else:
|
|
350
471
|
raise TypeError(concurrency)
|
|
@@ -508,25 +629,49 @@ def is_abstract_method(obj: ta.Any) -> bool:
|
|
|
508
629
|
return bool(getattr(obj, _IS_ABSTRACT_METHOD_ATTR, False))
|
|
509
630
|
|
|
510
631
|
|
|
511
|
-
def
|
|
632
|
+
def compute_abstract_methods(cls: type) -> ta.FrozenSet[str]:
|
|
633
|
+
# ~> https://github.com/python/cpython/blob/f3476c6507381ca860eec0989f53647b13517423/Modules/_abc.c#L358
|
|
634
|
+
|
|
635
|
+
# Stage 1: direct abstract methods
|
|
636
|
+
|
|
637
|
+
abstracts = {
|
|
638
|
+
a
|
|
639
|
+
# Get items as a list to avoid mutation issues during iteration
|
|
640
|
+
for a, v in list(cls.__dict__.items())
|
|
641
|
+
if is_abstract_method(v)
|
|
642
|
+
}
|
|
643
|
+
|
|
644
|
+
# Stage 2: inherited abstract methods
|
|
645
|
+
|
|
646
|
+
for base in cls.__bases__:
|
|
647
|
+
# Get __abstractmethods__ from base if it exists
|
|
648
|
+
if (base_abstracts := getattr(base, _ABSTRACT_METHODS_ATTR, None)) is None:
|
|
649
|
+
continue
|
|
650
|
+
|
|
651
|
+
# Iterate over abstract methods in base
|
|
652
|
+
for key in base_abstracts:
|
|
653
|
+
# Check if this class has an attribute with this name
|
|
654
|
+
try:
|
|
655
|
+
value = getattr(cls, key)
|
|
656
|
+
except AttributeError:
|
|
657
|
+
# Attribute not found in this class, skip
|
|
658
|
+
continue
|
|
659
|
+
|
|
660
|
+
# Check if it's still abstract
|
|
661
|
+
if is_abstract_method(value):
|
|
662
|
+
abstracts.add(key)
|
|
663
|
+
|
|
664
|
+
return frozenset(abstracts)
|
|
665
|
+
|
|
666
|
+
|
|
667
|
+
def update_abstracts(cls: ta.Type[T], *, force: bool = False) -> ta.Type[T]:
|
|
512
668
|
if not force and not hasattr(cls, _ABSTRACT_METHODS_ATTR):
|
|
513
669
|
# Per stdlib: We check for __abstractmethods__ here because cls might by a C implementation or a python
|
|
514
670
|
# implementation (especially during testing), and we want to handle both cases.
|
|
515
671
|
return cls
|
|
516
672
|
|
|
517
|
-
abstracts
|
|
518
|
-
|
|
519
|
-
for scls in cls.__bases__:
|
|
520
|
-
for name in getattr(scls, _ABSTRACT_METHODS_ATTR, ()):
|
|
521
|
-
value = getattr(cls, name, None)
|
|
522
|
-
if getattr(value, _IS_ABSTRACT_METHOD_ATTR, False):
|
|
523
|
-
abstracts.add(name)
|
|
524
|
-
|
|
525
|
-
for name, value in cls.__dict__.items():
|
|
526
|
-
if getattr(value, _IS_ABSTRACT_METHOD_ATTR, False):
|
|
527
|
-
abstracts.add(name)
|
|
528
|
-
|
|
529
|
-
setattr(cls, _ABSTRACT_METHODS_ATTR, frozenset(abstracts))
|
|
673
|
+
abstracts = compute_abstract_methods(cls)
|
|
674
|
+
setattr(cls, _ABSTRACT_METHODS_ATTR, abstracts)
|
|
530
675
|
return cls
|
|
531
676
|
|
|
532
677
|
|
|
@@ -580,23 +725,26 @@ class Abstract:
|
|
|
580
725
|
super().__init_subclass__(**kwargs)
|
|
581
726
|
|
|
582
727
|
if not (Abstract in cls.__bases__ or abc.ABC in cls.__bases__):
|
|
583
|
-
ams
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
728
|
+
if ams := compute_abstract_methods(cls):
|
|
729
|
+
amd = {
|
|
730
|
+
a: mcls
|
|
731
|
+
for mcls in cls.__mro__[::-1]
|
|
732
|
+
for a in ams
|
|
733
|
+
if a in mcls.__dict__
|
|
734
|
+
}
|
|
589
735
|
|
|
590
|
-
if ams:
|
|
591
736
|
raise AbstractTypeError(
|
|
592
737
|
f'Cannot subclass abstract class {cls.__name__} with abstract methods: ' +
|
|
593
738
|
', '.join(sorted([
|
|
594
739
|
'.'.join([
|
|
595
|
-
*([
|
|
596
|
-
|
|
740
|
+
*([
|
|
741
|
+
*([m] if (m := getattr(c, '__module__')) else []),
|
|
742
|
+
getattr(c, '__qualname__', getattr(c, '__name__')),
|
|
743
|
+
] if c is not None else '?'),
|
|
597
744
|
a,
|
|
598
745
|
])
|
|
599
|
-
for a
|
|
746
|
+
for a in ams
|
|
747
|
+
for c in [amd.get(a)]
|
|
600
748
|
])),
|
|
601
749
|
)
|
|
602
750
|
|
|
@@ -613,6 +761,150 @@ class Abstract:
|
|
|
613
761
|
update_abstracts(cls, force=True)
|
|
614
762
|
|
|
615
763
|
|
|
764
|
+
########################################
|
|
765
|
+
# ../../../omlish/lite/asyncs.py
|
|
766
|
+
|
|
767
|
+
|
|
768
|
+
##
|
|
769
|
+
|
|
770
|
+
|
|
771
|
+
async def opt_await(aw: ta.Optional[ta.Awaitable[T]]) -> ta.Optional[T]:
|
|
772
|
+
return (await aw if aw is not None else None)
|
|
773
|
+
|
|
774
|
+
|
|
775
|
+
async def async_list(ai: ta.AsyncIterable[T]) -> ta.List[T]:
|
|
776
|
+
return [v async for v in ai]
|
|
777
|
+
|
|
778
|
+
|
|
779
|
+
async def async_enumerate(ai: ta.AsyncIterable[T]) -> ta.AsyncIterable[ta.Tuple[int, T]]:
|
|
780
|
+
i = 0
|
|
781
|
+
async for e in ai:
|
|
782
|
+
yield (i, e)
|
|
783
|
+
i += 1
|
|
784
|
+
|
|
785
|
+
|
|
786
|
+
##
|
|
787
|
+
|
|
788
|
+
|
|
789
|
+
def as_async(fn: ta.Callable[..., T], *, wrap: bool = False) -> ta.Callable[..., ta.Awaitable[T]]:
|
|
790
|
+
async def inner(*args, **kwargs):
|
|
791
|
+
return fn(*args, **kwargs)
|
|
792
|
+
|
|
793
|
+
return functools.wraps(fn)(inner) if wrap else inner
|
|
794
|
+
|
|
795
|
+
|
|
796
|
+
##
|
|
797
|
+
|
|
798
|
+
|
|
799
|
+
class SyncAwaitCoroutineNotTerminatedError(Exception):
|
|
800
|
+
pass
|
|
801
|
+
|
|
802
|
+
|
|
803
|
+
def sync_await(aw: ta.Awaitable[T]) -> T:
|
|
804
|
+
"""
|
|
805
|
+
Allows for the synchronous execution of async functions which will never actually *externally* await anything. These
|
|
806
|
+
functions are allowed to await any number of other functions - including contextmanagers and generators - so long as
|
|
807
|
+
nothing ever actually 'leaks' out of the function, presumably to an event loop.
|
|
808
|
+
"""
|
|
809
|
+
|
|
810
|
+
ret = missing = object()
|
|
811
|
+
|
|
812
|
+
async def thunk():
|
|
813
|
+
nonlocal ret
|
|
814
|
+
|
|
815
|
+
ret = await aw
|
|
816
|
+
|
|
817
|
+
cr = thunk()
|
|
818
|
+
try:
|
|
819
|
+
try:
|
|
820
|
+
cr.send(None)
|
|
821
|
+
except StopIteration:
|
|
822
|
+
pass
|
|
823
|
+
|
|
824
|
+
if ret is missing or cr.cr_await is not None or cr.cr_running:
|
|
825
|
+
raise SyncAwaitCoroutineNotTerminatedError('Not terminated')
|
|
826
|
+
|
|
827
|
+
finally:
|
|
828
|
+
cr.close()
|
|
829
|
+
|
|
830
|
+
return ta.cast(T, ret)
|
|
831
|
+
|
|
832
|
+
|
|
833
|
+
#
|
|
834
|
+
|
|
835
|
+
|
|
836
|
+
def sync_aiter(ai: ta.AsyncIterator[T]) -> ta.Iterator[T]:
|
|
837
|
+
while True:
|
|
838
|
+
try:
|
|
839
|
+
o = sync_await(ai.__anext__())
|
|
840
|
+
except StopAsyncIteration:
|
|
841
|
+
break
|
|
842
|
+
yield o
|
|
843
|
+
|
|
844
|
+
|
|
845
|
+
def sync_async_list(ai: ta.AsyncIterable[T]) -> ta.List[T]:
|
|
846
|
+
"""
|
|
847
|
+
Uses `sync_await` to synchronously read the full contents of a function call returning an async iterator, given that
|
|
848
|
+
the function never externally awaits anything.
|
|
849
|
+
"""
|
|
850
|
+
|
|
851
|
+
lst: ta.Optional[ta.List[T]] = None
|
|
852
|
+
|
|
853
|
+
async def inner():
|
|
854
|
+
nonlocal lst
|
|
855
|
+
|
|
856
|
+
lst = [v async for v in ai]
|
|
857
|
+
|
|
858
|
+
sync_await(inner())
|
|
859
|
+
|
|
860
|
+
if not isinstance(lst, list):
|
|
861
|
+
raise TypeError(lst)
|
|
862
|
+
|
|
863
|
+
return lst
|
|
864
|
+
|
|
865
|
+
|
|
866
|
+
#
|
|
867
|
+
|
|
868
|
+
|
|
869
|
+
@ta.final
|
|
870
|
+
class SyncAwaitContextManager(ta.Generic[T]):
|
|
871
|
+
def __init__(self, acm: ta.AsyncContextManager[T]) -> None:
|
|
872
|
+
self._acm = acm
|
|
873
|
+
|
|
874
|
+
def __repr__(self) -> str:
|
|
875
|
+
return f'{self.__class__.__name__}({self._acm!r})'
|
|
876
|
+
|
|
877
|
+
def __enter__(self) -> T:
|
|
878
|
+
return sync_await(self._acm.__aenter__())
|
|
879
|
+
|
|
880
|
+
def __exit__(self, exc_type, exc_val, exc_tb):
|
|
881
|
+
return sync_await(self._acm.__aexit__(exc_type, exc_val, exc_tb))
|
|
882
|
+
|
|
883
|
+
|
|
884
|
+
sync_async_with = SyncAwaitContextManager
|
|
885
|
+
|
|
886
|
+
|
|
887
|
+
##
|
|
888
|
+
|
|
889
|
+
|
|
890
|
+
@ta.final
|
|
891
|
+
class SyncToAsyncContextManager(ta.Generic[T]):
|
|
892
|
+
def __init__(self, cm: ta.ContextManager[T]) -> None:
|
|
893
|
+
self._cm = cm
|
|
894
|
+
|
|
895
|
+
def __repr__(self) -> str:
|
|
896
|
+
return f'{self.__class__.__name__}({self._cm!r})'
|
|
897
|
+
|
|
898
|
+
async def __aenter__(self) -> T:
|
|
899
|
+
return self._cm.__enter__()
|
|
900
|
+
|
|
901
|
+
async def __aexit__(self, exc_type, exc_value, traceback, /):
|
|
902
|
+
return self._cm.__exit__(exc_type, exc_value, traceback)
|
|
903
|
+
|
|
904
|
+
|
|
905
|
+
as_async_context_manager = SyncToAsyncContextManager
|
|
906
|
+
|
|
907
|
+
|
|
616
908
|
########################################
|
|
617
909
|
# ../../../omlish/lite/cached.py
|
|
618
910
|
|
|
@@ -670,6 +962,62 @@ def async_cached_nullary(fn): # ta.Callable[..., T]) -> ta.Callable[..., T]:
|
|
|
670
962
|
return _AsyncCachedNullary(fn)
|
|
671
963
|
|
|
672
964
|
|
|
965
|
+
##
|
|
966
|
+
|
|
967
|
+
|
|
968
|
+
cached_property = functools.cached_property
|
|
969
|
+
|
|
970
|
+
|
|
971
|
+
class _cached_property: # noqa
|
|
972
|
+
"""Backported to pick up https://github.com/python/cpython/commit/056dfc71dce15f81887f0bd6da09d6099d71f979 ."""
|
|
973
|
+
|
|
974
|
+
def __init__(self, func):
|
|
975
|
+
self.func = func
|
|
976
|
+
self.attrname = None # noqa
|
|
977
|
+
self.__doc__ = func.__doc__
|
|
978
|
+
self.__module__ = func.__module__
|
|
979
|
+
|
|
980
|
+
_NOT_FOUND = object()
|
|
981
|
+
|
|
982
|
+
def __set_name__(self, owner, name):
|
|
983
|
+
if self.attrname is None:
|
|
984
|
+
self.attrname = name # noqa
|
|
985
|
+
elif name != self.attrname:
|
|
986
|
+
raise TypeError(
|
|
987
|
+
f'Cannot assign the same cached_property to two different names ({self.attrname!r} and {name!r}).',
|
|
988
|
+
)
|
|
989
|
+
|
|
990
|
+
def __get__(self, instance, owner=None):
|
|
991
|
+
if instance is None:
|
|
992
|
+
return self
|
|
993
|
+
if self.attrname is None:
|
|
994
|
+
raise TypeError('Cannot use cached_property instance without calling __set_name__ on it.')
|
|
995
|
+
|
|
996
|
+
try:
|
|
997
|
+
cache = instance.__dict__
|
|
998
|
+
except AttributeError: # not all objects have __dict__ (e.g. class defines slots)
|
|
999
|
+
raise TypeError(
|
|
1000
|
+
f"No '__dict__' attribute on {type(instance).__name__!r} instance to cache {self.attrname!r} property.",
|
|
1001
|
+
) from None
|
|
1002
|
+
|
|
1003
|
+
val = cache.get(self.attrname, self._NOT_FOUND)
|
|
1004
|
+
|
|
1005
|
+
if val is self._NOT_FOUND:
|
|
1006
|
+
val = self.func(instance)
|
|
1007
|
+
try:
|
|
1008
|
+
cache[self.attrname] = val
|
|
1009
|
+
except TypeError:
|
|
1010
|
+
raise TypeError(
|
|
1011
|
+
f"The '__dict__' attribute on {type(instance).__name__!r} instance does not support item "
|
|
1012
|
+
f"assignment for caching {self.attrname!r} property.",
|
|
1013
|
+
) from None
|
|
1014
|
+
|
|
1015
|
+
return val
|
|
1016
|
+
|
|
1017
|
+
|
|
1018
|
+
globals()['cached_property'] = _cached_property
|
|
1019
|
+
|
|
1020
|
+
|
|
673
1021
|
########################################
|
|
674
1022
|
# ../../../omlish/lite/check.py
|
|
675
1023
|
"""
|
|
@@ -1209,7 +1557,7 @@ class ExitStacked:
|
|
|
1209
1557
|
es.__enter__()
|
|
1210
1558
|
try:
|
|
1211
1559
|
self._enter_contexts()
|
|
1212
|
-
except
|
|
1560
|
+
except BaseException: # noqa
|
|
1213
1561
|
es.__exit__(*sys.exc_info())
|
|
1214
1562
|
raise
|
|
1215
1563
|
return self
|
|
@@ -1220,7 +1568,7 @@ class ExitStacked:
|
|
|
1220
1568
|
return None
|
|
1221
1569
|
try:
|
|
1222
1570
|
self._exit_contexts()
|
|
1223
|
-
except
|
|
1571
|
+
except BaseException: # noqa
|
|
1224
1572
|
es.__exit__(*sys.exc_info())
|
|
1225
1573
|
raise
|
|
1226
1574
|
return es.__exit__(exc_type, exc_val, exc_tb)
|
|
@@ -1268,7 +1616,7 @@ class AsyncExitStacked:
|
|
|
1268
1616
|
await es.__aenter__()
|
|
1269
1617
|
try:
|
|
1270
1618
|
await self._async_enter_contexts()
|
|
1271
|
-
except
|
|
1619
|
+
except BaseException: # noqa
|
|
1272
1620
|
await es.__aexit__(*sys.exc_info())
|
|
1273
1621
|
raise
|
|
1274
1622
|
return self
|
|
@@ -1279,7 +1627,7 @@ class AsyncExitStacked:
|
|
|
1279
1627
|
return None
|
|
1280
1628
|
try:
|
|
1281
1629
|
await self._async_exit_contexts()
|
|
1282
|
-
except
|
|
1630
|
+
except BaseException: # noqa
|
|
1283
1631
|
await es.__aexit__(*sys.exc_info())
|
|
1284
1632
|
raise
|
|
1285
1633
|
return await es.__aexit__(exc_type, exc_val, exc_tb)
|
|
@@ -1366,6 +1714,17 @@ aclosing = AsyncClosingManager
|
|
|
1366
1714
|
##
|
|
1367
1715
|
|
|
1368
1716
|
|
|
1717
|
+
def dataclass_shallow_astuple(o: ta.Any) -> ta.Tuple[ta.Any, ...]:
|
|
1718
|
+
return tuple(getattr(o, f.name) for f in dc.fields(o))
|
|
1719
|
+
|
|
1720
|
+
|
|
1721
|
+
def dataclass_shallow_asdict(o: ta.Any) -> ta.Dict[str, ta.Any]:
|
|
1722
|
+
return {f.name: getattr(o, f.name) for f in dc.fields(o)}
|
|
1723
|
+
|
|
1724
|
+
|
|
1725
|
+
##
|
|
1726
|
+
|
|
1727
|
+
|
|
1369
1728
|
def is_immediate_dataclass(cls: type) -> bool:
|
|
1370
1729
|
if not isinstance(cls, type):
|
|
1371
1730
|
raise TypeError(cls)
|
|
@@ -1448,6 +1807,36 @@ def dataclass_repr_omit_falsey(obj: ta.Any) -> str:
|
|
|
1448
1807
|
##
|
|
1449
1808
|
|
|
1450
1809
|
|
|
1810
|
+
def dataclass_descriptor_method(*bind_attrs: str, bind_owner: bool = False) -> ta.Callable:
|
|
1811
|
+
if not bind_attrs:
|
|
1812
|
+
def __get__(self, instance, owner=None): # noqa
|
|
1813
|
+
return self
|
|
1814
|
+
|
|
1815
|
+
elif bind_owner:
|
|
1816
|
+
def __get__(self, instance, owner=None): # noqa
|
|
1817
|
+
# Guaranteed to return a new instance even with no attrs
|
|
1818
|
+
return dc.replace(self, **{
|
|
1819
|
+
a: v.__get__(instance, owner) if (v := getattr(self, a)) is not None else None
|
|
1820
|
+
for a in bind_attrs
|
|
1821
|
+
})
|
|
1822
|
+
|
|
1823
|
+
else:
|
|
1824
|
+
def __get__(self, instance, owner=None): # noqa
|
|
1825
|
+
if instance is None:
|
|
1826
|
+
return self
|
|
1827
|
+
|
|
1828
|
+
# Guaranteed to return a new instance even with no attrs
|
|
1829
|
+
return dc.replace(self, **{
|
|
1830
|
+
a: v.__get__(instance, owner) if (v := getattr(self, a)) is not None else None
|
|
1831
|
+
for a in bind_attrs
|
|
1832
|
+
})
|
|
1833
|
+
|
|
1834
|
+
return __get__
|
|
1835
|
+
|
|
1836
|
+
|
|
1837
|
+
##
|
|
1838
|
+
|
|
1839
|
+
|
|
1451
1840
|
def dataclass_kw_only_init():
|
|
1452
1841
|
def inner(cls):
|
|
1453
1842
|
if not isinstance(cls, type) and dc.is_dataclass(cls):
|
|
@@ -1511,6 +1900,20 @@ def dataclass_kw_only_init():
|
|
|
1511
1900
|
return inner
|
|
1512
1901
|
|
|
1513
1902
|
|
|
1903
|
+
##
|
|
1904
|
+
|
|
1905
|
+
|
|
1906
|
+
@dc.dataclass()
|
|
1907
|
+
class DataclassFieldRequiredError(Exception):
|
|
1908
|
+
name: str
|
|
1909
|
+
|
|
1910
|
+
|
|
1911
|
+
def dataclass_field_required(name: str) -> ta.Callable[[], ta.Any]:
|
|
1912
|
+
def inner() -> ta.NoReturn:
|
|
1913
|
+
raise DataclassFieldRequiredError(name)
|
|
1914
|
+
return inner
|
|
1915
|
+
|
|
1916
|
+
|
|
1514
1917
|
########################################
|
|
1515
1918
|
# ../../../omlish/lite/json.py
|
|
1516
1919
|
|
|
@@ -2968,6 +3371,7 @@ TODO:
|
|
|
2968
3371
|
- pre-run, post-run hooks
|
|
2969
3372
|
- exitstack?
|
|
2970
3373
|
- suggestion - difflib.get_close_matches
|
|
3374
|
+
- add_argument_group - group kw on ArgparseKwarg?
|
|
2971
3375
|
"""
|
|
2972
3376
|
|
|
2973
3377
|
|
|
@@ -2978,6 +3382,7 @@ TODO:
|
|
|
2978
3382
|
class ArgparseArg:
|
|
2979
3383
|
args: ta.Sequence[ta.Any]
|
|
2980
3384
|
kwargs: ta.Mapping[str, ta.Any]
|
|
3385
|
+
group: ta.Optional[str] = None
|
|
2981
3386
|
dest: ta.Optional[str] = None
|
|
2982
3387
|
|
|
2983
3388
|
def __get__(self, instance, owner=None):
|
|
@@ -2987,7 +3392,11 @@ class ArgparseArg:
|
|
|
2987
3392
|
|
|
2988
3393
|
|
|
2989
3394
|
def argparse_arg(*args, **kwargs) -> ArgparseArg:
|
|
2990
|
-
return ArgparseArg(
|
|
3395
|
+
return ArgparseArg(
|
|
3396
|
+
args=args,
|
|
3397
|
+
group=kwargs.pop('group', None),
|
|
3398
|
+
kwargs=kwargs,
|
|
3399
|
+
)
|
|
2991
3400
|
|
|
2992
3401
|
|
|
2993
3402
|
def argparse_arg_(*args, **kwargs) -> ta.Any:
|
|
@@ -3157,6 +3566,10 @@ class ArgparseCli:
|
|
|
3157
3566
|
subparser.set_defaults(_cmd=obj)
|
|
3158
3567
|
|
|
3159
3568
|
elif isinstance(obj, ArgparseArg):
|
|
3569
|
+
if obj.group is not None:
|
|
3570
|
+
# FIXME: add_argument_group
|
|
3571
|
+
raise NotImplementedError
|
|
3572
|
+
|
|
3160
3573
|
if att in anns:
|
|
3161
3574
|
ann_kwargs = _get_argparse_arg_ann_kwargs(anns[att])
|
|
3162
3575
|
obj.kwargs = {**ann_kwargs, **obj.kwargs}
|
|
@@ -3202,7 +3615,7 @@ class ArgparseCli:
|
|
|
3202
3615
|
|
|
3203
3616
|
if self._unknown_args and not (cmd is not None and cmd.accepts_unknown):
|
|
3204
3617
|
msg = f'unrecognized arguments: {" ".join(self._unknown_args)}'
|
|
3205
|
-
if (parser := self.get_parser()).exit_on_error:
|
|
3618
|
+
if (parser := self.get_parser()).exit_on_error: # noqa
|
|
3206
3619
|
parser.error(msg)
|
|
3207
3620
|
else:
|
|
3208
3621
|
raise argparse.ArgumentError(None, msg)
|
|
@@ -3222,7 +3635,10 @@ class ArgparseCli:
|
|
|
3222
3635
|
return fn()
|
|
3223
3636
|
|
|
3224
3637
|
def cli_run_and_exit(self) -> ta.NoReturn:
|
|
3225
|
-
|
|
3638
|
+
rc = self.cli_run()
|
|
3639
|
+
if not isinstance(rc, int):
|
|
3640
|
+
rc = 0
|
|
3641
|
+
raise SystemExit(rc)
|
|
3226
3642
|
|
|
3227
3643
|
def __call__(self, *, exit: bool = False) -> ta.Optional[int]: # noqa
|
|
3228
3644
|
if exit:
|
|
@@ -3254,6 +3670,72 @@ class ArgparseCli:
|
|
|
3254
3670
|
return fn()
|
|
3255
3671
|
|
|
3256
3672
|
|
|
3673
|
+
########################################
|
|
3674
|
+
# ../../../omlish/http/coro/io.py
|
|
3675
|
+
|
|
3676
|
+
|
|
3677
|
+
##
|
|
3678
|
+
|
|
3679
|
+
|
|
3680
|
+
class CoroHttpIo:
|
|
3681
|
+
def __new__(cls, *args, **kwargs): # noqa
|
|
3682
|
+
raise TypeError
|
|
3683
|
+
|
|
3684
|
+
def __init_subclass__(cls, **kwargs): # noqa
|
|
3685
|
+
raise TypeError
|
|
3686
|
+
|
|
3687
|
+
#
|
|
3688
|
+
|
|
3689
|
+
MAX_LINE: ta.ClassVar[int] = 65536
|
|
3690
|
+
|
|
3691
|
+
#
|
|
3692
|
+
|
|
3693
|
+
class Io(Abstract):
|
|
3694
|
+
pass
|
|
3695
|
+
|
|
3696
|
+
#
|
|
3697
|
+
|
|
3698
|
+
class AnyLogIo(Io, Abstract):
|
|
3699
|
+
pass
|
|
3700
|
+
|
|
3701
|
+
#
|
|
3702
|
+
|
|
3703
|
+
@dc.dataclass(frozen=True)
|
|
3704
|
+
class ConnectIo(Io):
|
|
3705
|
+
args: ta.Tuple[ta.Any, ...]
|
|
3706
|
+
kwargs: ta.Optional[ta.Dict[str, ta.Any]] = None
|
|
3707
|
+
|
|
3708
|
+
server_hostname: ta.Optional[str] = None
|
|
3709
|
+
|
|
3710
|
+
#
|
|
3711
|
+
|
|
3712
|
+
class CloseIo(Io):
|
|
3713
|
+
pass
|
|
3714
|
+
|
|
3715
|
+
#
|
|
3716
|
+
|
|
3717
|
+
class AnyReadIo(Io): # noqa
|
|
3718
|
+
pass
|
|
3719
|
+
|
|
3720
|
+
@dc.dataclass(frozen=True)
|
|
3721
|
+
class ReadIo(AnyReadIo):
|
|
3722
|
+
sz: ta.Optional[int]
|
|
3723
|
+
|
|
3724
|
+
@dc.dataclass(frozen=True)
|
|
3725
|
+
class ReadLineIo(AnyReadIo):
|
|
3726
|
+
sz: int
|
|
3727
|
+
|
|
3728
|
+
@dc.dataclass(frozen=True)
|
|
3729
|
+
class PeekIo(AnyReadIo):
|
|
3730
|
+
sz: int
|
|
3731
|
+
|
|
3732
|
+
#
|
|
3733
|
+
|
|
3734
|
+
@dc.dataclass(frozen=True)
|
|
3735
|
+
class WriteIo(Io):
|
|
3736
|
+
data: bytes
|
|
3737
|
+
|
|
3738
|
+
|
|
3257
3739
|
########################################
|
|
3258
3740
|
# ../../../omlish/http/parsing.py
|
|
3259
3741
|
# PYTHON SOFTWARE FOUNDATION LICENSE VERSION 2
|
|
@@ -4587,8 +5069,6 @@ class _JustMaybe(_Maybe[T]):
|
|
|
4587
5069
|
__slots__ = ('_v', '_hash')
|
|
4588
5070
|
|
|
4589
5071
|
def __init__(self, v: T) -> None:
|
|
4590
|
-
super().__init__()
|
|
4591
|
-
|
|
4592
5072
|
self._v = v
|
|
4593
5073
|
|
|
4594
5074
|
@property
|
|
@@ -4646,6 +5126,13 @@ class _EmptyMaybe(_Maybe[T]):
|
|
|
4646
5126
|
Maybe._empty = _EmptyMaybe() # noqa
|
|
4647
5127
|
|
|
4648
5128
|
|
|
5129
|
+
##
|
|
5130
|
+
|
|
5131
|
+
|
|
5132
|
+
setattr(Maybe, 'just', _JustMaybe) # noqa
|
|
5133
|
+
setattr(Maybe, 'empty', functools.partial(operator.attrgetter('_empty'), Maybe))
|
|
5134
|
+
|
|
5135
|
+
|
|
4649
5136
|
########################################
|
|
4650
5137
|
# ../../../omlish/lite/runtime.py
|
|
4651
5138
|
|
|
@@ -7740,6 +8227,9 @@ class CaptureLoggingContextImpl(CaptureLoggingContext):
|
|
|
7740
8227
|
self._infos[type(info)] = info
|
|
7741
8228
|
return self
|
|
7742
8229
|
|
|
8230
|
+
def get_infos(self) -> ta.Mapping[ta.Type[LoggingContextInfo], LoggingContextInfo]:
|
|
8231
|
+
return self._infos
|
|
8232
|
+
|
|
7743
8233
|
def get_info(self, ty: ta.Type[LoggingContextInfoT]) -> ta.Optional[LoggingContextInfoT]:
|
|
7744
8234
|
return self._infos.get(ty)
|
|
7745
8235
|
|
|
@@ -7762,7 +8252,7 @@ class CaptureLoggingContextImpl(CaptureLoggingContext):
|
|
|
7762
8252
|
_stack_offset: int
|
|
7763
8253
|
_stack_info: bool
|
|
7764
8254
|
|
|
7765
|
-
def inc_stack_offset(self, ofs: int = 1) -> '
|
|
8255
|
+
def inc_stack_offset(self, ofs: int = 1) -> 'CaptureLoggingContextImpl':
|
|
7766
8256
|
if hasattr(self, '_stack_offset'):
|
|
7767
8257
|
self._stack_offset += ofs
|
|
7768
8258
|
return self
|
|
@@ -7794,10 +8284,9 @@ class CaptureLoggingContextImpl(CaptureLoggingContext):
|
|
|
7794
8284
|
|
|
7795
8285
|
|
|
7796
8286
|
########################################
|
|
7797
|
-
# ../../../omlish/logs/standard.py
|
|
8287
|
+
# ../../../omlish/logs/std/standard.py
|
|
7798
8288
|
"""
|
|
7799
8289
|
TODO:
|
|
7800
|
-
- !! move to std !!
|
|
7801
8290
|
- structured
|
|
7802
8291
|
- prefixed
|
|
7803
8292
|
- debug
|
|
@@ -7927,13 +8416,13 @@ def configure_standard_logging(
|
|
|
7927
8416
|
##
|
|
7928
8417
|
|
|
7929
8418
|
|
|
7930
|
-
def
|
|
8419
|
+
def exception_logging(log): # noqa
|
|
7931
8420
|
def outer(fn):
|
|
7932
8421
|
@functools.wraps(fn)
|
|
7933
8422
|
def inner(*args, **kwargs):
|
|
7934
8423
|
try:
|
|
7935
8424
|
return fn(*args, **kwargs)
|
|
7936
|
-
except Exception:
|
|
8425
|
+
except Exception as e: # noqa
|
|
7937
8426
|
log.exception('Error in %r', fn)
|
|
7938
8427
|
raise
|
|
7939
8428
|
|
|
@@ -7942,6 +8431,21 @@ def error_logging(log): # noqa
|
|
|
7942
8431
|
return outer
|
|
7943
8432
|
|
|
7944
8433
|
|
|
8434
|
+
def async_exception_logging(alog): # noqa
|
|
8435
|
+
def outer(fn):
|
|
8436
|
+
@functools.wraps(fn)
|
|
8437
|
+
async def inner(*args, **kwargs):
|
|
8438
|
+
try:
|
|
8439
|
+
return await fn(*args, **kwargs)
|
|
8440
|
+
except Exception as e: # noqa
|
|
8441
|
+
await alog.exception('Error in %r', fn)
|
|
8442
|
+
raise
|
|
8443
|
+
|
|
8444
|
+
return inner
|
|
8445
|
+
|
|
8446
|
+
return outer
|
|
8447
|
+
|
|
8448
|
+
|
|
7945
8449
|
##
|
|
7946
8450
|
|
|
7947
8451
|
|
|
@@ -9247,48 +9751,21 @@ class CoroHttpServer:
|
|
|
9247
9751
|
|
|
9248
9752
|
#
|
|
9249
9753
|
|
|
9250
|
-
class Io(Abstract):
|
|
9251
|
-
pass
|
|
9252
|
-
|
|
9253
|
-
#
|
|
9254
|
-
|
|
9255
|
-
class AnyLogIo(Io):
|
|
9256
|
-
pass
|
|
9257
|
-
|
|
9258
9754
|
@dc.dataclass(frozen=True)
|
|
9259
|
-
class ParsedRequestLogIo(AnyLogIo):
|
|
9755
|
+
class ParsedRequestLogIo(CoroHttpIo.AnyLogIo):
|
|
9260
9756
|
request: ParsedHttpRequest
|
|
9261
9757
|
|
|
9262
9758
|
@dc.dataclass(frozen=True)
|
|
9263
|
-
class ErrorLogIo(AnyLogIo):
|
|
9759
|
+
class ErrorLogIo(CoroHttpIo.AnyLogIo):
|
|
9264
9760
|
error: 'CoroHttpServer.Error'
|
|
9265
9761
|
|
|
9266
9762
|
#
|
|
9267
9763
|
|
|
9268
|
-
class AnyReadIo(Io): # noqa
|
|
9269
|
-
pass
|
|
9270
|
-
|
|
9271
|
-
@dc.dataclass(frozen=True)
|
|
9272
|
-
class ReadIo(AnyReadIo):
|
|
9273
|
-
sz: int
|
|
9274
|
-
|
|
9275
|
-
@dc.dataclass(frozen=True)
|
|
9276
|
-
class ReadLineIo(AnyReadIo):
|
|
9277
|
-
sz: int
|
|
9278
|
-
|
|
9279
|
-
#
|
|
9280
|
-
|
|
9281
|
-
@dc.dataclass(frozen=True)
|
|
9282
|
-
class WriteIo(Io):
|
|
9283
|
-
data: bytes
|
|
9284
|
-
|
|
9285
|
-
#
|
|
9286
|
-
|
|
9287
9764
|
@dc.dataclass(frozen=True)
|
|
9288
9765
|
class CoroHandleResult:
|
|
9289
9766
|
close_reason: ta.Literal['response', 'internal', None] = None
|
|
9290
9767
|
|
|
9291
|
-
def coro_handle(self) -> ta.Generator[Io, ta.Optional[bytes], CoroHandleResult]:
|
|
9768
|
+
def coro_handle(self) -> ta.Generator[CoroHttpIo.Io, ta.Optional[bytes], CoroHandleResult]:
|
|
9292
9769
|
return self._coro_run_handler(self._coro_handle_one())
|
|
9293
9770
|
|
|
9294
9771
|
class Close(Exception): # noqa
|
|
@@ -9297,20 +9774,20 @@ class CoroHttpServer:
|
|
|
9297
9774
|
def _coro_run_handler(
|
|
9298
9775
|
self,
|
|
9299
9776
|
gen: ta.Generator[
|
|
9300
|
-
ta.Union[AnyLogIo, AnyReadIo, _Response],
|
|
9777
|
+
ta.Union[CoroHttpIo.AnyLogIo, CoroHttpIo.AnyReadIo, _Response],
|
|
9301
9778
|
ta.Optional[bytes],
|
|
9302
9779
|
None,
|
|
9303
9780
|
],
|
|
9304
|
-
) -> ta.Generator[Io, ta.Optional[bytes], CoroHandleResult]:
|
|
9781
|
+
) -> ta.Generator[CoroHttpIo.Io, ta.Optional[bytes], CoroHandleResult]:
|
|
9305
9782
|
i: ta.Optional[bytes]
|
|
9306
9783
|
o: ta.Any = next(gen)
|
|
9307
9784
|
while True:
|
|
9308
9785
|
try:
|
|
9309
|
-
if isinstance(o,
|
|
9786
|
+
if isinstance(o, CoroHttpIo.AnyLogIo):
|
|
9310
9787
|
i = None
|
|
9311
9788
|
yield o
|
|
9312
9789
|
|
|
9313
|
-
elif isinstance(o,
|
|
9790
|
+
elif isinstance(o, CoroHttpIo.AnyReadIo):
|
|
9314
9791
|
i = check.isinstance((yield o), bytes)
|
|
9315
9792
|
|
|
9316
9793
|
elif isinstance(o, self._Response):
|
|
@@ -9318,10 +9795,10 @@ class CoroHttpServer:
|
|
|
9318
9795
|
|
|
9319
9796
|
r = self._preprocess_response(o)
|
|
9320
9797
|
hb = self._build_response_head_bytes(r)
|
|
9321
|
-
check.none((yield
|
|
9798
|
+
check.none((yield CoroHttpIo.WriteIo(hb)))
|
|
9322
9799
|
|
|
9323
9800
|
for b in self._yield_response_data(r):
|
|
9324
|
-
yield
|
|
9801
|
+
yield CoroHttpIo.WriteIo(b)
|
|
9325
9802
|
|
|
9326
9803
|
o.close()
|
|
9327
9804
|
if o.close_connection:
|
|
@@ -9349,7 +9826,7 @@ class CoroHttpServer:
|
|
|
9349
9826
|
raise
|
|
9350
9827
|
|
|
9351
9828
|
def _coro_handle_one(self) -> ta.Generator[
|
|
9352
|
-
ta.Union[AnyLogIo, AnyReadIo, _Response],
|
|
9829
|
+
ta.Union[CoroHttpIo.AnyLogIo, CoroHttpIo.AnyReadIo, _Response],
|
|
9353
9830
|
ta.Optional[bytes],
|
|
9354
9831
|
None,
|
|
9355
9832
|
]:
|
|
@@ -9359,7 +9836,7 @@ class CoroHttpServer:
|
|
|
9359
9836
|
sz = next(gen)
|
|
9360
9837
|
while True:
|
|
9361
9838
|
try:
|
|
9362
|
-
line = check.isinstance((yield
|
|
9839
|
+
line = check.isinstance((yield CoroHttpIo.ReadLineIo(sz)), bytes)
|
|
9363
9840
|
sz = gen.send(line)
|
|
9364
9841
|
except StopIteration as e:
|
|
9365
9842
|
parsed = e.value
|
|
@@ -9398,7 +9875,7 @@ class CoroHttpServer:
|
|
|
9398
9875
|
|
|
9399
9876
|
request_data: ta.Optional[bytes]
|
|
9400
9877
|
if (cl := parsed.headers.get('Content-Length')) is not None:
|
|
9401
|
-
request_data = check.isinstance((yield
|
|
9878
|
+
request_data = check.isinstance((yield CoroHttpIo.ReadIo(int(cl))), bytes)
|
|
9402
9879
|
else:
|
|
9403
9880
|
request_data = None
|
|
9404
9881
|
|
|
@@ -9485,6 +9962,11 @@ class AnyLogger(Abstract, ta.Generic[T]):
|
|
|
9485
9962
|
|
|
9486
9963
|
##
|
|
9487
9964
|
|
|
9965
|
+
# This will be 1 for [Sync]Logger and 0 for AsyncLogger - in sync loggers these methods remain present on the stack,
|
|
9966
|
+
# in async loggers they return a coroutine to be awaited and thus aren't actually present when said coroutine is
|
|
9967
|
+
# awaited.
|
|
9968
|
+
_level_proxy_method_stack_offset: int
|
|
9969
|
+
|
|
9488
9970
|
@ta.overload
|
|
9489
9971
|
def log(self, level: LogLevel, msg: str, *args: ta.Any, **kwargs: ta.Any) -> T:
|
|
9490
9972
|
...
|
|
@@ -9499,7 +9981,14 @@ class AnyLogger(Abstract, ta.Generic[T]):
|
|
|
9499
9981
|
|
|
9500
9982
|
@ta.final
|
|
9501
9983
|
def log(self, level: LogLevel, *args, **kwargs):
|
|
9502
|
-
return self._log(
|
|
9984
|
+
return self._log(
|
|
9985
|
+
CaptureLoggingContextImpl(
|
|
9986
|
+
level,
|
|
9987
|
+
stack_offset=self._level_proxy_method_stack_offset,
|
|
9988
|
+
),
|
|
9989
|
+
*args,
|
|
9990
|
+
**kwargs,
|
|
9991
|
+
)
|
|
9503
9992
|
|
|
9504
9993
|
#
|
|
9505
9994
|
|
|
@@ -9517,7 +10006,14 @@ class AnyLogger(Abstract, ta.Generic[T]):
|
|
|
9517
10006
|
|
|
9518
10007
|
@ta.final
|
|
9519
10008
|
def debug(self, *args, **kwargs):
|
|
9520
|
-
return self._log(
|
|
10009
|
+
return self._log(
|
|
10010
|
+
CaptureLoggingContextImpl(
|
|
10011
|
+
NamedLogLevel.DEBUG,
|
|
10012
|
+
stack_offset=self._level_proxy_method_stack_offset,
|
|
10013
|
+
),
|
|
10014
|
+
*args,
|
|
10015
|
+
**kwargs,
|
|
10016
|
+
)
|
|
9521
10017
|
|
|
9522
10018
|
#
|
|
9523
10019
|
|
|
@@ -9535,7 +10031,14 @@ class AnyLogger(Abstract, ta.Generic[T]):
|
|
|
9535
10031
|
|
|
9536
10032
|
@ta.final
|
|
9537
10033
|
def info(self, *args, **kwargs):
|
|
9538
|
-
return self._log(
|
|
10034
|
+
return self._log(
|
|
10035
|
+
CaptureLoggingContextImpl(
|
|
10036
|
+
NamedLogLevel.INFO,
|
|
10037
|
+
stack_offset=self._level_proxy_method_stack_offset,
|
|
10038
|
+
),
|
|
10039
|
+
*args,
|
|
10040
|
+
**kwargs,
|
|
10041
|
+
)
|
|
9539
10042
|
|
|
9540
10043
|
#
|
|
9541
10044
|
|
|
@@ -9553,7 +10056,14 @@ class AnyLogger(Abstract, ta.Generic[T]):
|
|
|
9553
10056
|
|
|
9554
10057
|
@ta.final
|
|
9555
10058
|
def warning(self, *args, **kwargs):
|
|
9556
|
-
return self._log(
|
|
10059
|
+
return self._log(
|
|
10060
|
+
CaptureLoggingContextImpl(
|
|
10061
|
+
NamedLogLevel.WARNING,
|
|
10062
|
+
stack_offset=self._level_proxy_method_stack_offset,
|
|
10063
|
+
),
|
|
10064
|
+
*args,
|
|
10065
|
+
**kwargs,
|
|
10066
|
+
)
|
|
9557
10067
|
|
|
9558
10068
|
#
|
|
9559
10069
|
|
|
@@ -9571,7 +10081,14 @@ class AnyLogger(Abstract, ta.Generic[T]):
|
|
|
9571
10081
|
|
|
9572
10082
|
@ta.final
|
|
9573
10083
|
def error(self, *args, **kwargs):
|
|
9574
|
-
return self._log(
|
|
10084
|
+
return self._log(
|
|
10085
|
+
CaptureLoggingContextImpl(
|
|
10086
|
+
NamedLogLevel.ERROR,
|
|
10087
|
+
stack_offset=self._level_proxy_method_stack_offset,
|
|
10088
|
+
),
|
|
10089
|
+
*args,
|
|
10090
|
+
**kwargs,
|
|
10091
|
+
)
|
|
9575
10092
|
|
|
9576
10093
|
#
|
|
9577
10094
|
|
|
@@ -9589,7 +10106,15 @@ class AnyLogger(Abstract, ta.Generic[T]):
|
|
|
9589
10106
|
|
|
9590
10107
|
@ta.final
|
|
9591
10108
|
def exception(self, *args, exc_info: LoggingExcInfoArg = True, **kwargs):
|
|
9592
|
-
return self._log(
|
|
10109
|
+
return self._log(
|
|
10110
|
+
CaptureLoggingContextImpl(
|
|
10111
|
+
NamedLogLevel.ERROR,
|
|
10112
|
+
exc_info=exc_info,
|
|
10113
|
+
stack_offset=self._level_proxy_method_stack_offset,
|
|
10114
|
+
),
|
|
10115
|
+
*args,
|
|
10116
|
+
**kwargs,
|
|
10117
|
+
)
|
|
9593
10118
|
|
|
9594
10119
|
#
|
|
9595
10120
|
|
|
@@ -9607,24 +10132,53 @@ class AnyLogger(Abstract, ta.Generic[T]):
|
|
|
9607
10132
|
|
|
9608
10133
|
@ta.final
|
|
9609
10134
|
def critical(self, *args, **kwargs):
|
|
9610
|
-
return self._log(
|
|
10135
|
+
return self._log(
|
|
10136
|
+
CaptureLoggingContextImpl(
|
|
10137
|
+
NamedLogLevel.CRITICAL,
|
|
10138
|
+
stack_offset=self._level_proxy_method_stack_offset,
|
|
10139
|
+
),
|
|
10140
|
+
*args,
|
|
10141
|
+
**kwargs,
|
|
10142
|
+
)
|
|
9611
10143
|
|
|
9612
10144
|
##
|
|
9613
10145
|
|
|
9614
10146
|
@abc.abstractmethod
|
|
9615
|
-
def _log(
|
|
10147
|
+
def _log(
|
|
10148
|
+
self,
|
|
10149
|
+
ctx: CaptureLoggingContext,
|
|
10150
|
+
msg: ta.Union[str, tuple, LoggingMsgFn],
|
|
10151
|
+
*args: ta.Any,
|
|
10152
|
+
**kwargs: ta.Any,
|
|
10153
|
+
) -> T:
|
|
9616
10154
|
raise NotImplementedError
|
|
9617
10155
|
|
|
9618
10156
|
|
|
9619
10157
|
class Logger(AnyLogger[None], Abstract):
|
|
10158
|
+
_level_proxy_method_stack_offset: int = 1
|
|
10159
|
+
|
|
9620
10160
|
@abc.abstractmethod
|
|
9621
|
-
def _log(
|
|
10161
|
+
def _log(
|
|
10162
|
+
self,
|
|
10163
|
+
ctx: CaptureLoggingContext,
|
|
10164
|
+
msg: ta.Union[str, tuple, LoggingMsgFn],
|
|
10165
|
+
*args: ta.Any,
|
|
10166
|
+
**kwargs: ta.Any,
|
|
10167
|
+
) -> None:
|
|
9622
10168
|
raise NotImplementedError
|
|
9623
10169
|
|
|
9624
10170
|
|
|
9625
10171
|
class AsyncLogger(AnyLogger[ta.Awaitable[None]], Abstract):
|
|
10172
|
+
_level_proxy_method_stack_offset: int = 0
|
|
10173
|
+
|
|
9626
10174
|
@abc.abstractmethod
|
|
9627
|
-
def _log(
|
|
10175
|
+
def _log(
|
|
10176
|
+
self,
|
|
10177
|
+
ctx: CaptureLoggingContext,
|
|
10178
|
+
msg: ta.Union[str, tuple, LoggingMsgFn],
|
|
10179
|
+
*args: ta.Any,
|
|
10180
|
+
**kwargs: ta.Any,
|
|
10181
|
+
) -> ta.Awaitable[None]:
|
|
9628
10182
|
raise NotImplementedError
|
|
9629
10183
|
|
|
9630
10184
|
|
|
@@ -9639,13 +10193,25 @@ class AnyNopLogger(AnyLogger[T], Abstract):
|
|
|
9639
10193
|
|
|
9640
10194
|
@ta.final
|
|
9641
10195
|
class NopLogger(AnyNopLogger[None], Logger):
|
|
9642
|
-
def _log(
|
|
10196
|
+
def _log(
|
|
10197
|
+
self,
|
|
10198
|
+
ctx: CaptureLoggingContext,
|
|
10199
|
+
msg: ta.Union[str, tuple, LoggingMsgFn],
|
|
10200
|
+
*args: ta.Any,
|
|
10201
|
+
**kwargs: ta.Any,
|
|
10202
|
+
) -> None:
|
|
9643
10203
|
pass
|
|
9644
10204
|
|
|
9645
10205
|
|
|
9646
10206
|
@ta.final
|
|
9647
10207
|
class AsyncNopLogger(AnyNopLogger[ta.Awaitable[None]], AsyncLogger):
|
|
9648
|
-
async def _log(
|
|
10208
|
+
async def _log(
|
|
10209
|
+
self,
|
|
10210
|
+
ctx: CaptureLoggingContext,
|
|
10211
|
+
msg: ta.Union[str, tuple, LoggingMsgFn],
|
|
10212
|
+
*args: ta.Any,
|
|
10213
|
+
**kwargs: ta.Any,
|
|
10214
|
+
) -> None:
|
|
9649
10215
|
pass
|
|
9650
10216
|
|
|
9651
10217
|
|
|
@@ -10753,6 +11319,10 @@ class VerboseCalledProcessError(subprocess.CalledProcessError):
|
|
|
10753
11319
|
class BaseSubprocesses(Abstract):
|
|
10754
11320
|
DEFAULT_LOGGER: ta.ClassVar[ta.Optional[LoggerLike]] = None
|
|
10755
11321
|
|
|
11322
|
+
PIPE: ta.ClassVar[int] = subprocess.PIPE
|
|
11323
|
+
STDOUT: ta.ClassVar[int] = subprocess.STDOUT
|
|
11324
|
+
DEVNULL: ta.ClassVar[int] = subprocess.DEVNULL
|
|
11325
|
+
|
|
10756
11326
|
def __init__(
|
|
10757
11327
|
self,
|
|
10758
11328
|
*,
|
|
@@ -11443,7 +12013,7 @@ class CoroHttpServerSocketHandler(SocketHandler_):
|
|
|
11443
12013
|
server_factory: CoroHttpServerFactory,
|
|
11444
12014
|
*,
|
|
11445
12015
|
keep_alive: bool = False,
|
|
11446
|
-
log_handler: ta.Optional[ta.Callable[[CoroHttpServer,
|
|
12016
|
+
log_handler: ta.Optional[ta.Callable[[CoroHttpServer, CoroHttpIo.AnyLogIo], None]] = None,
|
|
11447
12017
|
) -> None:
|
|
11448
12018
|
super().__init__()
|
|
11449
12019
|
|
|
@@ -11472,18 +12042,18 @@ class CoroHttpServerSocketHandler(SocketHandler_):
|
|
|
11472
12042
|
|
|
11473
12043
|
o = next(gen)
|
|
11474
12044
|
while True:
|
|
11475
|
-
if isinstance(o,
|
|
12045
|
+
if isinstance(o, CoroHttpIo.AnyLogIo):
|
|
11476
12046
|
i = None
|
|
11477
12047
|
if self._log_handler is not None:
|
|
11478
12048
|
self._log_handler(server, o)
|
|
11479
12049
|
|
|
11480
|
-
elif isinstance(o,
|
|
11481
|
-
i = fp.r.read(o.sz)
|
|
12050
|
+
elif isinstance(o, CoroHttpIo.ReadIo):
|
|
12051
|
+
i = fp.r.read(check.not_none(o.sz))
|
|
11482
12052
|
|
|
11483
|
-
elif isinstance(o,
|
|
12053
|
+
elif isinstance(o, CoroHttpIo.ReadLineIo):
|
|
11484
12054
|
i = fp.r.readline(o.sz)
|
|
11485
12055
|
|
|
11486
|
-
elif isinstance(o,
|
|
12056
|
+
elif isinstance(o, CoroHttpIo.WriteIo):
|
|
11487
12057
|
i = None
|
|
11488
12058
|
fp.w.write(o.data)
|
|
11489
12059
|
fp.w.flush()
|
|
@@ -11500,6 +12070,70 @@ class CoroHttpServerSocketHandler(SocketHandler_):
|
|
|
11500
12070
|
return check.isinstance(e.value, CoroHttpServer.CoroHandleResult)
|
|
11501
12071
|
|
|
11502
12072
|
|
|
12073
|
+
########################################
|
|
12074
|
+
# ../../../omlish/logs/asyncs.py
|
|
12075
|
+
|
|
12076
|
+
|
|
12077
|
+
##
|
|
12078
|
+
|
|
12079
|
+
|
|
12080
|
+
class AsyncLoggerToLogger(Logger):
|
|
12081
|
+
def __init__(self, u: AsyncLogger) -> None:
|
|
12082
|
+
super().__init__()
|
|
12083
|
+
|
|
12084
|
+
self._u = u
|
|
12085
|
+
|
|
12086
|
+
def get_effective_level(self) -> LogLevel:
|
|
12087
|
+
return self._u.get_effective_level()
|
|
12088
|
+
|
|
12089
|
+
def _log(
|
|
12090
|
+
self,
|
|
12091
|
+
ctx: CaptureLoggingContext,
|
|
12092
|
+
msg: ta.Union[str, tuple, LoggingMsgFn],
|
|
12093
|
+
*args: ta.Any,
|
|
12094
|
+
**kwargs: ta.Any,
|
|
12095
|
+
) -> None:
|
|
12096
|
+
# Nope out early to avoid sync_await if possible - don't bother in the LoggerToAsyncLogger.
|
|
12097
|
+
if not self.is_enabled_for(ctx.must_get_info(LoggingContextInfos.Level).level):
|
|
12098
|
+
return
|
|
12099
|
+
|
|
12100
|
+
# Note: we hardcode the stack offset of sync_await (which is 2 - sync_await + sync_await.thunk). In non-lite
|
|
12101
|
+
# code, lang.sync_await uses a cext if present to avoid being on the py stack, which would obviously complicate
|
|
12102
|
+
# this, but this is lite code so we will always have the non-c version.
|
|
12103
|
+
sync_await(
|
|
12104
|
+
self._u._log( # noqa
|
|
12105
|
+
check.isinstance(ctx, CaptureLoggingContextImpl).inc_stack_offset(3),
|
|
12106
|
+
msg,
|
|
12107
|
+
*args,
|
|
12108
|
+
**kwargs,
|
|
12109
|
+
),
|
|
12110
|
+
)
|
|
12111
|
+
|
|
12112
|
+
|
|
12113
|
+
class LoggerToAsyncLogger(AsyncLogger):
|
|
12114
|
+
def __init__(self, u: Logger) -> None:
|
|
12115
|
+
super().__init__()
|
|
12116
|
+
|
|
12117
|
+
self._u = u
|
|
12118
|
+
|
|
12119
|
+
def get_effective_level(self) -> LogLevel:
|
|
12120
|
+
return self._u.get_effective_level()
|
|
12121
|
+
|
|
12122
|
+
async def _log(
|
|
12123
|
+
self,
|
|
12124
|
+
ctx: CaptureLoggingContext,
|
|
12125
|
+
msg: ta.Union[str, tuple, LoggingMsgFn],
|
|
12126
|
+
*args: ta.Any,
|
|
12127
|
+
**kwargs: ta.Any,
|
|
12128
|
+
) -> None:
|
|
12129
|
+
return self._u._log( # noqa
|
|
12130
|
+
check.isinstance(ctx, CaptureLoggingContextImpl).inc_stack_offset(),
|
|
12131
|
+
msg,
|
|
12132
|
+
*args,
|
|
12133
|
+
**kwargs,
|
|
12134
|
+
)
|
|
12135
|
+
|
|
12136
|
+
|
|
11503
12137
|
########################################
|
|
11504
12138
|
# ../../../omlish/logs/std/loggers.py
|
|
11505
12139
|
|
|
@@ -11523,7 +12157,12 @@ class StdLogger(Logger):
|
|
|
11523
12157
|
def get_effective_level(self) -> LogLevel:
|
|
11524
12158
|
return self._std.getEffectiveLevel()
|
|
11525
12159
|
|
|
11526
|
-
def _log(
|
|
12160
|
+
def _log(
|
|
12161
|
+
self,
|
|
12162
|
+
ctx: CaptureLoggingContext,
|
|
12163
|
+
msg: ta.Union[str, tuple, LoggingMsgFn],
|
|
12164
|
+
*args: ta.Any,
|
|
12165
|
+
) -> None:
|
|
11527
12166
|
if not self.is_enabled_for(ctx.must_get_info(LoggingContextInfos.Level).level):
|
|
11528
12167
|
return
|
|
11529
12168
|
|
|
@@ -12274,8 +12913,23 @@ def make_simple_http_server(
|
|
|
12274
12913
|
##
|
|
12275
12914
|
|
|
12276
12915
|
|
|
12916
|
+
def _get_module_std_logger(mod_globals: ta.Mapping[str, ta.Any]) -> logging.Logger:
|
|
12917
|
+
return logging.getLogger(mod_globals.get('__name__'))
|
|
12918
|
+
|
|
12919
|
+
|
|
12277
12920
|
def get_module_logger(mod_globals: ta.Mapping[str, ta.Any]) -> Logger:
|
|
12278
|
-
return StdLogger(
|
|
12921
|
+
return StdLogger(_get_module_std_logger(mod_globals))
|
|
12922
|
+
|
|
12923
|
+
|
|
12924
|
+
def get_module_async_logger(mod_globals: ta.Mapping[str, ta.Any]) -> AsyncLogger:
|
|
12925
|
+
return LoggerToAsyncLogger(get_module_logger(mod_globals))
|
|
12926
|
+
|
|
12927
|
+
|
|
12928
|
+
def get_module_loggers(mod_globals: ta.Mapping[str, ta.Any]) -> ta.Tuple[Logger, AsyncLogger]:
|
|
12929
|
+
return (
|
|
12930
|
+
log := get_module_logger(mod_globals),
|
|
12931
|
+
LoggerToAsyncLogger(log),
|
|
12932
|
+
)
|
|
12279
12933
|
|
|
12280
12934
|
|
|
12281
12935
|
########################################
|
|
@@ -15376,7 +16030,7 @@ async def _async_main() -> ta.Optional[int]:
|
|
|
15376
16030
|
def _main() -> None:
|
|
15377
16031
|
configure_standard_logging('DEBUG')
|
|
15378
16032
|
|
|
15379
|
-
|
|
16033
|
+
raise SystemExit(rc if isinstance(rc := asyncio.run(_async_main()), int) else 0)
|
|
15380
16034
|
|
|
15381
16035
|
|
|
15382
16036
|
if __name__ == '__main__':
|