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/pyproject.py
CHANGED
|
@@ -27,6 +27,7 @@ See:
|
|
|
27
27
|
"""
|
|
28
28
|
import abc
|
|
29
29
|
import argparse
|
|
30
|
+
import ast
|
|
30
31
|
import asyncio
|
|
31
32
|
import asyncio.base_subprocess
|
|
32
33
|
import asyncio.subprocess
|
|
@@ -52,6 +53,7 @@ import itertools
|
|
|
52
53
|
import json
|
|
53
54
|
import logging
|
|
54
55
|
import multiprocessing as mp
|
|
56
|
+
import operator
|
|
55
57
|
import os
|
|
56
58
|
import os.path
|
|
57
59
|
import re
|
|
@@ -63,6 +65,7 @@ import subprocess
|
|
|
63
65
|
import sys
|
|
64
66
|
import tarfile
|
|
65
67
|
import tempfile
|
|
68
|
+
import textwrap
|
|
66
69
|
import threading
|
|
67
70
|
import time
|
|
68
71
|
import traceback
|
|
@@ -80,6 +83,84 @@ if sys.version_info < (3, 8):
|
|
|
80
83
|
raise OSError(f'Requires python (3, 8), got {sys.version_info} from {sys.executable}') # noqa
|
|
81
84
|
|
|
82
85
|
|
|
86
|
+
def __omlish_amalg__(): # noqa
|
|
87
|
+
return dict(
|
|
88
|
+
src_files=[
|
|
89
|
+
dict(path='../magic/magic.py', sha1='16a7598eac927e7994d78b9f851dd6cd1fce34c9'),
|
|
90
|
+
dict(path='../magic/prepare.py', sha1='a9b6bd7408d86a52fab7aae2c522032fb251cb8e'),
|
|
91
|
+
dict(path='../magic/styles.py', sha1='60fc56d089669eaad72c5c134b91bc69d4bc107e'),
|
|
92
|
+
dict(path='../packaging/versions.py', sha1='71627ad600b3529b829b0e227b0952f2c63c7271'),
|
|
93
|
+
dict(path='../packaging/wheelfile.py', sha1='2e1113819aa85ed00e1fe25c71a2b3dbc0a383f5'),
|
|
94
|
+
dict(path='../../omlish/formats/toml/parser.py', sha1='73dac82289350ab951c4bcdbfe61167fa221f26f'),
|
|
95
|
+
dict(path='../../omlish/formats/toml/writer.py', sha1='6ea41d7e724bb1dcf6bd84b88993ff4e8798e021'),
|
|
96
|
+
dict(path='../../omlish/lite/abstract.py', sha1='a2fc3f3697fa8de5247761e9d554e70176f37aac'),
|
|
97
|
+
dict(path='../../omlish/lite/asyncs.py', sha1='b3f2251c56617ce548abf9c333ac996b63edb23e'),
|
|
98
|
+
dict(path='../../omlish/lite/cached.py', sha1='0c33cf961ac8f0727284303c7a30c5ea98f714f2'),
|
|
99
|
+
dict(path='../../omlish/lite/check.py', sha1='bb6b6b63333699b84462951a854d99ae83195b94'),
|
|
100
|
+
dict(path='../../omlish/lite/json.py', sha1='57eeddc4d23a17931e00284ffa5cb6e3ce089486'),
|
|
101
|
+
dict(path='../../omlish/lite/objects.py', sha1='9566bbf3530fd71fcc56321485216b592fae21e9'),
|
|
102
|
+
dict(path='../../omlish/lite/reflect.py', sha1='c4fec44bf144e9d93293c996af06f6c65fc5e63d'),
|
|
103
|
+
dict(path='../../omlish/lite/strings.py', sha1='89831ecbc34ad80e118a865eceb390ed399dc4d6'),
|
|
104
|
+
dict(path='../../omlish/lite/typing.py', sha1='c501ff8f9ed08202e8016eaa098526d4deede834'),
|
|
105
|
+
dict(path='../../omlish/logs/levels.py', sha1='91405563d082a5eba874da82aac89d83ce7b6152'),
|
|
106
|
+
dict(path='../../omlish/logs/std/filters.py', sha1='f36aab646d84d31e295b33aaaaa6f8b67ff38b3d'),
|
|
107
|
+
dict(path='../../omlish/logs/std/proxy.py', sha1='3e7301a2aa351127f9c85f61b2f85dcc3f15aafb'),
|
|
108
|
+
dict(path='../../omlish/logs/warnings.py', sha1='c4eb694b24773351107fcc058f3620f1dbfb6799'),
|
|
109
|
+
dict(path='../cexts/magic.py', sha1='4e5ce6732454f75c9dd27352959708d8fa7b1666'),
|
|
110
|
+
dict(path='../magic/find.py', sha1='436228a9cf1d8bab6b9234d09f72913b0960382f'),
|
|
111
|
+
dict(path='../packaging/specifiers.py', sha1='a56ab4e8c9b174adb523921f6280ac41e0fce749'),
|
|
112
|
+
dict(path='../../omlish/argparse/cli.py', sha1='f4dc3cd353d14386b5da0306768700e396afd2b3'),
|
|
113
|
+
dict(path='../../omlish/lite/marshal.py', sha1='96348f5f2a26dc27d842d33cc3927e9da163436b'),
|
|
114
|
+
dict(path='../../omlish/lite/maybes.py', sha1='bdf5136654ccd14b6a072588cad228925bdfbabd'),
|
|
115
|
+
dict(path='../../omlish/lite/runtime.py', sha1='2e752a27ae2bf89b1bb79b4a2da522a3ec360c70'),
|
|
116
|
+
dict(path='../../omlish/lite/timeouts.py', sha1='a0f673033a6943f242e35848d78a41892b9c62a1'),
|
|
117
|
+
dict(path='../../omlish/logs/infos.py', sha1='4dd104bd468a8c438601dd0bbda619b47d2f1620'),
|
|
118
|
+
dict(path='../../omlish/logs/protocols.py', sha1='05ca4d1d7feb50c4e3b9f22ee371aa7bf4b3dbd1'),
|
|
119
|
+
dict(path='../../omlish/logs/std/json.py', sha1='2a75553131e4d5331bb0cedde42aa183f403fc3b'),
|
|
120
|
+
dict(path='../interp/types.py', sha1='caf068a6e81fb6e221d777b341ac5777d92b8091'),
|
|
121
|
+
dict(path='../packaging/requires.py', sha1='5818353abd45135e0e638e28fa6247b24122231b'),
|
|
122
|
+
dict(path='../../omlish/asyncs/asyncio/timeouts.py', sha1='4d31b02b3c39b8f2fa7e94db36552fde6942e36a'),
|
|
123
|
+
dict(path='../../omlish/lite/inject.py', sha1='6f097e3170019a34ff6834d36fcc9cbeed3a7ab4'),
|
|
124
|
+
dict(path='../../omlish/logs/contexts.py', sha1='1000a6d5ddfb642865ca532e34b1d50759781cf0'),
|
|
125
|
+
dict(path='../../omlish/logs/std/standard.py', sha1='5c97c1b9f7ead58d6127d047b873398f708f288d'),
|
|
126
|
+
dict(path='../../omlish/subprocesses/run.py', sha1='8200e48f0c49d164df3503cd0143038d0c4d30aa'),
|
|
127
|
+
dict(path='../../omlish/subprocesses/wrap.py', sha1='8a9b7d2255481fae15c05f5624b0cdc0766f4b3f'),
|
|
128
|
+
dict(path='../interp/providers/base.py', sha1='f5d068c21f230d742e9015b033cd6320f4c68898'),
|
|
129
|
+
dict(path='../../omlish/logs/base.py', sha1='8d06faee05fead6b1dd98c9035a5b042af4aebb1'),
|
|
130
|
+
dict(path='../../omlish/logs/std/records.py', sha1='8bbf6ef9eccb3a012c6ca416ddf3969450fd8fc9'),
|
|
131
|
+
dict(path='../../omlish/subprocesses/base.py', sha1='cb9f668be5422fecb27222caabb67daac6c1bab9'),
|
|
132
|
+
dict(path='../interp/resolvers.py', sha1='817b8e76401cd7a19eb43ca54d65272e4c8a4b0e'),
|
|
133
|
+
dict(path='../../omlish/logs/asyncs.py', sha1='ab11b70033d9f2e9a4e70254185aa1c6130c6077'),
|
|
134
|
+
dict(path='../../omlish/logs/std/loggers.py', sha1='a569179445d6a8a942b5dcfad1d1f77702868803'),
|
|
135
|
+
dict(path='../../omlish/subprocesses/asyncs.py', sha1='bba44d524c24c6ac73168aee6343488414e5bf48'),
|
|
136
|
+
dict(path='../../omlish/subprocesses/sync.py', sha1='8434919eba4da67825773d56918fdc0cb2f1883b'),
|
|
137
|
+
dict(path='../git/revisions.py', sha1='a26b5afa568313e034b6b2d3a5d2dd0b065979d4'),
|
|
138
|
+
dict(path='../../omlish/asyncs/asyncio/subprocesses.py', sha1='b6b5f9ae3fd0b9c83593bad2e04a08f726e5904d'),
|
|
139
|
+
dict(path='../../omlish/logs/modules.py', sha1='dd7d5f8e63fe8829dfb49460f3929ab64b68ee14'),
|
|
140
|
+
dict(path='../interp/inspect.py', sha1='736287b4ec8d14a8c30afa0ba23996fdc0662caa'),
|
|
141
|
+
dict(path='../interp/pyenv/pyenv.py', sha1='d1f6e657c671c1b1a5b0e627284df656fe2d10d3'),
|
|
142
|
+
dict(path='../interp/uv/uv.py', sha1='8c6515cd6755efab3972da92a285e94ccb255515'),
|
|
143
|
+
dict(path='../packaging/revisions.py', sha1='9ba90e4a93b1bfcc93f6ca65dbaaf38f79929677'),
|
|
144
|
+
dict(path='reqs.py', sha1='822e265b0d2e6d9548ee24d3ac60c81066e40ee8'),
|
|
145
|
+
dict(path='../interp/providers/running.py', sha1='85c9cc69ff6fbd6c8cf78ed6262619a30856c2f1'),
|
|
146
|
+
dict(path='../interp/providers/system.py', sha1='9638a154475ca98775159d27739563ac7fb2eb16'),
|
|
147
|
+
dict(path='../interp/pyenv/install.py', sha1='4a10a19717364b4ba9f3b8bf1d12621cf21ba8b8'),
|
|
148
|
+
dict(path='../interp/uv/provider.py', sha1='3c3980878ad2b9fd2cd02172f9424954759c7f06'),
|
|
149
|
+
dict(path='pkg.py', sha1='a7b64fcf267ba385442393b90c9711af08ba9ac3'),
|
|
150
|
+
dict(path='../interp/providers/inject.py', sha1='7cc9ebf58cf2ec09545321456bd9da9f9a3a79fb'),
|
|
151
|
+
dict(path='../interp/pyenv/provider.py', sha1='377542ce01a35849e2a5b4a4dbafedc26882f983'),
|
|
152
|
+
dict(path='../interp/uv/inject.py', sha1='e95d058c2340baa5a3155ec3440f311d1daa10a8'),
|
|
153
|
+
dict(path='../interp/pyenv/inject.py', sha1='b8fb68f5a7cae86c70fe1bad6c29a8b2dfc985c3'),
|
|
154
|
+
dict(path='../interp/inject.py', sha1='b039abbadf0b096d2724182af2e0ebda2a230852'),
|
|
155
|
+
dict(path='../interp/default.py', sha1='a799969a0d3f4b57538587b13ceb08f6334ebc16'),
|
|
156
|
+
dict(path='../interp/venvs.py', sha1='9ba8f2c3131d7d519d5cf36ca69b75f9c6fe2b27'),
|
|
157
|
+
dict(path='configs.py', sha1='7b1c1ed034ecb728d67ff15e3bb2b21a218773c9'),
|
|
158
|
+
dict(path='venvs.py', sha1='9f1935171017aeb802da56e14d7f41d632a7aa25'),
|
|
159
|
+
dict(path='cli.py', sha1='77efd5e792baa941a79adef6b363751dbd6a0d3e'),
|
|
160
|
+
],
|
|
161
|
+
)
|
|
162
|
+
|
|
163
|
+
|
|
83
164
|
########################################
|
|
84
165
|
|
|
85
166
|
|
|
@@ -96,8 +177,10 @@ TomlParseFloat = ta.Callable[[str], ta.Any] # ta.TypeAlias
|
|
|
96
177
|
TomlKey = ta.Tuple[str, ...] # ta.TypeAlias
|
|
97
178
|
TomlPos = int # ta.TypeAlias
|
|
98
179
|
|
|
99
|
-
# ../../omlish/lite/
|
|
180
|
+
# ../../omlish/lite/abstract.py
|
|
100
181
|
T = ta.TypeVar('T')
|
|
182
|
+
|
|
183
|
+
# ../../omlish/lite/cached.py
|
|
101
184
|
CallableT = ta.TypeVar('CallableT', bound=ta.Callable)
|
|
102
185
|
|
|
103
186
|
# ../../omlish/lite/check.py
|
|
@@ -137,6 +220,11 @@ LoggingExcInfo = ta.Union[BaseException, LoggingExcInfoTuple] # ta.TypeAlias
|
|
|
137
220
|
LoggingExcInfoArg = ta.Union[LoggingExcInfo, bool, None] # ta.TypeAlias
|
|
138
221
|
LoggingContextInfo = ta.Any # ta.TypeAlias
|
|
139
222
|
|
|
223
|
+
# ../packaging/requires.py
|
|
224
|
+
RequiresMarkerVar = ta.Union['RequiresVariable', 'RequiresValue'] # ta.TypeAlias
|
|
225
|
+
RequiresMarkerAtom = ta.Union['RequiresMarkerItem', ta.Sequence['RequiresMarkerAtom']] # ta.TypeAlias
|
|
226
|
+
RequiresMarkerList = ta.Sequence[ta.Union['RequiresMarkerList', 'RequiresMarkerAtom', str]] # ta.TypeAlias
|
|
227
|
+
|
|
140
228
|
# ../../omlish/asyncs/asyncio/timeouts.py
|
|
141
229
|
AwaitableT = ta.TypeVar('AwaitableT', bound=ta.Awaitable)
|
|
142
230
|
|
|
@@ -361,12 +449,12 @@ class _BaseVersion:
|
|
|
361
449
|
|
|
362
450
|
def __lt__(self, other: '_BaseVersion') -> bool:
|
|
363
451
|
if not isinstance(other, _BaseVersion):
|
|
364
|
-
return NotImplemented
|
|
452
|
+
return NotImplemented
|
|
365
453
|
return self._key < other._key
|
|
366
454
|
|
|
367
455
|
def __le__(self, other: '_BaseVersion') -> bool:
|
|
368
456
|
if not isinstance(other, _BaseVersion):
|
|
369
|
-
return NotImplemented
|
|
457
|
+
return NotImplemented
|
|
370
458
|
return self._key <= other._key
|
|
371
459
|
|
|
372
460
|
def __eq__(self, other: object) -> bool:
|
|
@@ -376,12 +464,12 @@ class _BaseVersion:
|
|
|
376
464
|
|
|
377
465
|
def __ge__(self, other: '_BaseVersion') -> bool:
|
|
378
466
|
if not isinstance(other, _BaseVersion):
|
|
379
|
-
return NotImplemented
|
|
467
|
+
return NotImplemented
|
|
380
468
|
return self._key >= other._key
|
|
381
469
|
|
|
382
470
|
def __gt__(self, other: '_BaseVersion') -> bool:
|
|
383
471
|
if not isinstance(other, _BaseVersion):
|
|
384
|
-
return NotImplemented
|
|
472
|
+
return NotImplemented
|
|
385
473
|
return self._key > other._key
|
|
386
474
|
|
|
387
475
|
def __ne__(self, other: object) -> bool:
|
|
@@ -765,11 +853,13 @@ class WheelFile(zipfile.ZipFile):
|
|
|
765
853
|
@staticmethod
|
|
766
854
|
def _urlsafe_b64encode(data: bytes) -> bytes:
|
|
767
855
|
"""urlsafe_b64encode without padding"""
|
|
856
|
+
|
|
768
857
|
return base64.urlsafe_b64encode(data).rstrip(b'=')
|
|
769
858
|
|
|
770
859
|
@staticmethod
|
|
771
860
|
def _urlsafe_b64decode(data: bytes) -> bytes:
|
|
772
861
|
"""urlsafe_b64decode without padding"""
|
|
862
|
+
|
|
773
863
|
pad = b'=' * (4 - (len(data) & 3))
|
|
774
864
|
return base64.urlsafe_b64decode(data + pad)
|
|
775
865
|
|
|
@@ -1959,25 +2049,49 @@ def is_abstract_method(obj: ta.Any) -> bool:
|
|
|
1959
2049
|
return bool(getattr(obj, _IS_ABSTRACT_METHOD_ATTR, False))
|
|
1960
2050
|
|
|
1961
2051
|
|
|
1962
|
-
def
|
|
2052
|
+
def compute_abstract_methods(cls: type) -> ta.FrozenSet[str]:
|
|
2053
|
+
# ~> https://github.com/python/cpython/blob/f3476c6507381ca860eec0989f53647b13517423/Modules/_abc.c#L358
|
|
2054
|
+
|
|
2055
|
+
# Stage 1: direct abstract methods
|
|
2056
|
+
|
|
2057
|
+
abstracts = {
|
|
2058
|
+
a
|
|
2059
|
+
# Get items as a list to avoid mutation issues during iteration
|
|
2060
|
+
for a, v in list(cls.__dict__.items())
|
|
2061
|
+
if is_abstract_method(v)
|
|
2062
|
+
}
|
|
2063
|
+
|
|
2064
|
+
# Stage 2: inherited abstract methods
|
|
2065
|
+
|
|
2066
|
+
for base in cls.__bases__:
|
|
2067
|
+
# Get __abstractmethods__ from base if it exists
|
|
2068
|
+
if (base_abstracts := getattr(base, _ABSTRACT_METHODS_ATTR, None)) is None:
|
|
2069
|
+
continue
|
|
2070
|
+
|
|
2071
|
+
# Iterate over abstract methods in base
|
|
2072
|
+
for key in base_abstracts:
|
|
2073
|
+
# Check if this class has an attribute with this name
|
|
2074
|
+
try:
|
|
2075
|
+
value = getattr(cls, key)
|
|
2076
|
+
except AttributeError:
|
|
2077
|
+
# Attribute not found in this class, skip
|
|
2078
|
+
continue
|
|
2079
|
+
|
|
2080
|
+
# Check if it's still abstract
|
|
2081
|
+
if is_abstract_method(value):
|
|
2082
|
+
abstracts.add(key)
|
|
2083
|
+
|
|
2084
|
+
return frozenset(abstracts)
|
|
2085
|
+
|
|
2086
|
+
|
|
2087
|
+
def update_abstracts(cls: ta.Type[T], *, force: bool = False) -> ta.Type[T]:
|
|
1963
2088
|
if not force and not hasattr(cls, _ABSTRACT_METHODS_ATTR):
|
|
1964
2089
|
# Per stdlib: We check for __abstractmethods__ here because cls might by a C implementation or a python
|
|
1965
2090
|
# implementation (especially during testing), and we want to handle both cases.
|
|
1966
2091
|
return cls
|
|
1967
2092
|
|
|
1968
|
-
abstracts
|
|
1969
|
-
|
|
1970
|
-
for scls in cls.__bases__:
|
|
1971
|
-
for name in getattr(scls, _ABSTRACT_METHODS_ATTR, ()):
|
|
1972
|
-
value = getattr(cls, name, None)
|
|
1973
|
-
if getattr(value, _IS_ABSTRACT_METHOD_ATTR, False):
|
|
1974
|
-
abstracts.add(name)
|
|
1975
|
-
|
|
1976
|
-
for name, value in cls.__dict__.items():
|
|
1977
|
-
if getattr(value, _IS_ABSTRACT_METHOD_ATTR, False):
|
|
1978
|
-
abstracts.add(name)
|
|
1979
|
-
|
|
1980
|
-
setattr(cls, _ABSTRACT_METHODS_ATTR, frozenset(abstracts))
|
|
2093
|
+
abstracts = compute_abstract_methods(cls)
|
|
2094
|
+
setattr(cls, _ABSTRACT_METHODS_ATTR, abstracts)
|
|
1981
2095
|
return cls
|
|
1982
2096
|
|
|
1983
2097
|
|
|
@@ -2031,23 +2145,26 @@ class Abstract:
|
|
|
2031
2145
|
super().__init_subclass__(**kwargs)
|
|
2032
2146
|
|
|
2033
2147
|
if not (Abstract in cls.__bases__ or abc.ABC in cls.__bases__):
|
|
2034
|
-
ams
|
|
2148
|
+
if ams := compute_abstract_methods(cls):
|
|
2149
|
+
amd = {
|
|
2150
|
+
a: mcls
|
|
2151
|
+
for mcls in cls.__mro__[::-1]
|
|
2152
|
+
for a in ams
|
|
2153
|
+
if a in mcls.__dict__
|
|
2154
|
+
}
|
|
2035
2155
|
|
|
2036
|
-
seen = set(cls.__dict__)
|
|
2037
|
-
for b in cls.__bases__:
|
|
2038
|
-
ams.update({a: b for a in set(getattr(b, _ABSTRACT_METHODS_ATTR, [])) - seen}) # noqa
|
|
2039
|
-
seen.update(dir(b))
|
|
2040
|
-
|
|
2041
|
-
if ams:
|
|
2042
2156
|
raise AbstractTypeError(
|
|
2043
2157
|
f'Cannot subclass abstract class {cls.__name__} with abstract methods: ' +
|
|
2044
2158
|
', '.join(sorted([
|
|
2045
2159
|
'.'.join([
|
|
2046
|
-
*([
|
|
2047
|
-
|
|
2160
|
+
*([
|
|
2161
|
+
*([m] if (m := getattr(c, '__module__')) else []),
|
|
2162
|
+
getattr(c, '__qualname__', getattr(c, '__name__')),
|
|
2163
|
+
] if c is not None else '?'),
|
|
2048
2164
|
a,
|
|
2049
2165
|
])
|
|
2050
|
-
for a
|
|
2166
|
+
for a in ams
|
|
2167
|
+
for c in [amd.get(a)]
|
|
2051
2168
|
])),
|
|
2052
2169
|
)
|
|
2053
2170
|
|
|
@@ -2064,6 +2181,150 @@ class Abstract:
|
|
|
2064
2181
|
update_abstracts(cls, force=True)
|
|
2065
2182
|
|
|
2066
2183
|
|
|
2184
|
+
########################################
|
|
2185
|
+
# ../../../omlish/lite/asyncs.py
|
|
2186
|
+
|
|
2187
|
+
|
|
2188
|
+
##
|
|
2189
|
+
|
|
2190
|
+
|
|
2191
|
+
async def opt_await(aw: ta.Optional[ta.Awaitable[T]]) -> ta.Optional[T]:
|
|
2192
|
+
return (await aw if aw is not None else None)
|
|
2193
|
+
|
|
2194
|
+
|
|
2195
|
+
async def async_list(ai: ta.AsyncIterable[T]) -> ta.List[T]:
|
|
2196
|
+
return [v async for v in ai]
|
|
2197
|
+
|
|
2198
|
+
|
|
2199
|
+
async def async_enumerate(ai: ta.AsyncIterable[T]) -> ta.AsyncIterable[ta.Tuple[int, T]]:
|
|
2200
|
+
i = 0
|
|
2201
|
+
async for e in ai:
|
|
2202
|
+
yield (i, e)
|
|
2203
|
+
i += 1
|
|
2204
|
+
|
|
2205
|
+
|
|
2206
|
+
##
|
|
2207
|
+
|
|
2208
|
+
|
|
2209
|
+
def as_async(fn: ta.Callable[..., T], *, wrap: bool = False) -> ta.Callable[..., ta.Awaitable[T]]:
|
|
2210
|
+
async def inner(*args, **kwargs):
|
|
2211
|
+
return fn(*args, **kwargs)
|
|
2212
|
+
|
|
2213
|
+
return functools.wraps(fn)(inner) if wrap else inner
|
|
2214
|
+
|
|
2215
|
+
|
|
2216
|
+
##
|
|
2217
|
+
|
|
2218
|
+
|
|
2219
|
+
class SyncAwaitCoroutineNotTerminatedError(Exception):
|
|
2220
|
+
pass
|
|
2221
|
+
|
|
2222
|
+
|
|
2223
|
+
def sync_await(aw: ta.Awaitable[T]) -> T:
|
|
2224
|
+
"""
|
|
2225
|
+
Allows for the synchronous execution of async functions which will never actually *externally* await anything. These
|
|
2226
|
+
functions are allowed to await any number of other functions - including contextmanagers and generators - so long as
|
|
2227
|
+
nothing ever actually 'leaks' out of the function, presumably to an event loop.
|
|
2228
|
+
"""
|
|
2229
|
+
|
|
2230
|
+
ret = missing = object()
|
|
2231
|
+
|
|
2232
|
+
async def thunk():
|
|
2233
|
+
nonlocal ret
|
|
2234
|
+
|
|
2235
|
+
ret = await aw
|
|
2236
|
+
|
|
2237
|
+
cr = thunk()
|
|
2238
|
+
try:
|
|
2239
|
+
try:
|
|
2240
|
+
cr.send(None)
|
|
2241
|
+
except StopIteration:
|
|
2242
|
+
pass
|
|
2243
|
+
|
|
2244
|
+
if ret is missing or cr.cr_await is not None or cr.cr_running:
|
|
2245
|
+
raise SyncAwaitCoroutineNotTerminatedError('Not terminated')
|
|
2246
|
+
|
|
2247
|
+
finally:
|
|
2248
|
+
cr.close()
|
|
2249
|
+
|
|
2250
|
+
return ta.cast(T, ret)
|
|
2251
|
+
|
|
2252
|
+
|
|
2253
|
+
#
|
|
2254
|
+
|
|
2255
|
+
|
|
2256
|
+
def sync_aiter(ai: ta.AsyncIterator[T]) -> ta.Iterator[T]:
|
|
2257
|
+
while True:
|
|
2258
|
+
try:
|
|
2259
|
+
o = sync_await(ai.__anext__())
|
|
2260
|
+
except StopAsyncIteration:
|
|
2261
|
+
break
|
|
2262
|
+
yield o
|
|
2263
|
+
|
|
2264
|
+
|
|
2265
|
+
def sync_async_list(ai: ta.AsyncIterable[T]) -> ta.List[T]:
|
|
2266
|
+
"""
|
|
2267
|
+
Uses `sync_await` to synchronously read the full contents of a function call returning an async iterator, given that
|
|
2268
|
+
the function never externally awaits anything.
|
|
2269
|
+
"""
|
|
2270
|
+
|
|
2271
|
+
lst: ta.Optional[ta.List[T]] = None
|
|
2272
|
+
|
|
2273
|
+
async def inner():
|
|
2274
|
+
nonlocal lst
|
|
2275
|
+
|
|
2276
|
+
lst = [v async for v in ai]
|
|
2277
|
+
|
|
2278
|
+
sync_await(inner())
|
|
2279
|
+
|
|
2280
|
+
if not isinstance(lst, list):
|
|
2281
|
+
raise TypeError(lst)
|
|
2282
|
+
|
|
2283
|
+
return lst
|
|
2284
|
+
|
|
2285
|
+
|
|
2286
|
+
#
|
|
2287
|
+
|
|
2288
|
+
|
|
2289
|
+
@ta.final
|
|
2290
|
+
class SyncAwaitContextManager(ta.Generic[T]):
|
|
2291
|
+
def __init__(self, acm: ta.AsyncContextManager[T]) -> None:
|
|
2292
|
+
self._acm = acm
|
|
2293
|
+
|
|
2294
|
+
def __repr__(self) -> str:
|
|
2295
|
+
return f'{self.__class__.__name__}({self._acm!r})'
|
|
2296
|
+
|
|
2297
|
+
def __enter__(self) -> T:
|
|
2298
|
+
return sync_await(self._acm.__aenter__())
|
|
2299
|
+
|
|
2300
|
+
def __exit__(self, exc_type, exc_val, exc_tb):
|
|
2301
|
+
return sync_await(self._acm.__aexit__(exc_type, exc_val, exc_tb))
|
|
2302
|
+
|
|
2303
|
+
|
|
2304
|
+
sync_async_with = SyncAwaitContextManager
|
|
2305
|
+
|
|
2306
|
+
|
|
2307
|
+
##
|
|
2308
|
+
|
|
2309
|
+
|
|
2310
|
+
@ta.final
|
|
2311
|
+
class SyncToAsyncContextManager(ta.Generic[T]):
|
|
2312
|
+
def __init__(self, cm: ta.ContextManager[T]) -> None:
|
|
2313
|
+
self._cm = cm
|
|
2314
|
+
|
|
2315
|
+
def __repr__(self) -> str:
|
|
2316
|
+
return f'{self.__class__.__name__}({self._cm!r})'
|
|
2317
|
+
|
|
2318
|
+
async def __aenter__(self) -> T:
|
|
2319
|
+
return self._cm.__enter__()
|
|
2320
|
+
|
|
2321
|
+
async def __aexit__(self, exc_type, exc_value, traceback, /):
|
|
2322
|
+
return self._cm.__exit__(exc_type, exc_value, traceback)
|
|
2323
|
+
|
|
2324
|
+
|
|
2325
|
+
as_async_context_manager = SyncToAsyncContextManager
|
|
2326
|
+
|
|
2327
|
+
|
|
2067
2328
|
########################################
|
|
2068
2329
|
# ../../../omlish/lite/cached.py
|
|
2069
2330
|
|
|
@@ -2121,6 +2382,62 @@ def async_cached_nullary(fn): # ta.Callable[..., T]) -> ta.Callable[..., T]:
|
|
|
2121
2382
|
return _AsyncCachedNullary(fn)
|
|
2122
2383
|
|
|
2123
2384
|
|
|
2385
|
+
##
|
|
2386
|
+
|
|
2387
|
+
|
|
2388
|
+
cached_property = functools.cached_property
|
|
2389
|
+
|
|
2390
|
+
|
|
2391
|
+
class _cached_property: # noqa
|
|
2392
|
+
"""Backported to pick up https://github.com/python/cpython/commit/056dfc71dce15f81887f0bd6da09d6099d71f979 ."""
|
|
2393
|
+
|
|
2394
|
+
def __init__(self, func):
|
|
2395
|
+
self.func = func
|
|
2396
|
+
self.attrname = None # noqa
|
|
2397
|
+
self.__doc__ = func.__doc__
|
|
2398
|
+
self.__module__ = func.__module__
|
|
2399
|
+
|
|
2400
|
+
_NOT_FOUND = object()
|
|
2401
|
+
|
|
2402
|
+
def __set_name__(self, owner, name):
|
|
2403
|
+
if self.attrname is None:
|
|
2404
|
+
self.attrname = name # noqa
|
|
2405
|
+
elif name != self.attrname:
|
|
2406
|
+
raise TypeError(
|
|
2407
|
+
f'Cannot assign the same cached_property to two different names ({self.attrname!r} and {name!r}).',
|
|
2408
|
+
)
|
|
2409
|
+
|
|
2410
|
+
def __get__(self, instance, owner=None):
|
|
2411
|
+
if instance is None:
|
|
2412
|
+
return self
|
|
2413
|
+
if self.attrname is None:
|
|
2414
|
+
raise TypeError('Cannot use cached_property instance without calling __set_name__ on it.')
|
|
2415
|
+
|
|
2416
|
+
try:
|
|
2417
|
+
cache = instance.__dict__
|
|
2418
|
+
except AttributeError: # not all objects have __dict__ (e.g. class defines slots)
|
|
2419
|
+
raise TypeError(
|
|
2420
|
+
f"No '__dict__' attribute on {type(instance).__name__!r} instance to cache {self.attrname!r} property.",
|
|
2421
|
+
) from None
|
|
2422
|
+
|
|
2423
|
+
val = cache.get(self.attrname, self._NOT_FOUND)
|
|
2424
|
+
|
|
2425
|
+
if val is self._NOT_FOUND:
|
|
2426
|
+
val = self.func(instance)
|
|
2427
|
+
try:
|
|
2428
|
+
cache[self.attrname] = val
|
|
2429
|
+
except TypeError:
|
|
2430
|
+
raise TypeError(
|
|
2431
|
+
f"The '__dict__' attribute on {type(instance).__name__!r} instance does not support item "
|
|
2432
|
+
f"assignment for caching {self.attrname!r} property.",
|
|
2433
|
+
) from None
|
|
2434
|
+
|
|
2435
|
+
return val
|
|
2436
|
+
|
|
2437
|
+
|
|
2438
|
+
globals()['cached_property'] = _cached_property
|
|
2439
|
+
|
|
2440
|
+
|
|
2124
2441
|
########################################
|
|
2125
2442
|
# ../../../omlish/lite/check.py
|
|
2126
2443
|
"""
|
|
@@ -2909,6 +3226,12 @@ def format_num_bytes(num_bytes: int) -> str:
|
|
|
2909
3226
|
|
|
2910
3227
|
##
|
|
2911
3228
|
# A workaround for typing deficiencies (like `Argument 2 to NewType(...) must be subclassable`).
|
|
3229
|
+
#
|
|
3230
|
+
# Note that this problem doesn't happen at runtime - it happens in mypy:
|
|
3231
|
+
#
|
|
3232
|
+
# mypy <(echo "import typing as ta; MyCallback = ta.NewType('MyCallback', ta.Callable[[], None])")
|
|
3233
|
+
# /dev/fd/11:1:22: error: Argument 2 to NewType(...) must be subclassable (got "Callable[[], None]") [valid-newtype]
|
|
3234
|
+
#
|
|
2912
3235
|
|
|
2913
3236
|
|
|
2914
3237
|
@dc.dataclass(frozen=True)
|
|
@@ -2954,6 +3277,24 @@ class Func3(ta.Generic[A0, A1, A2, T]):
|
|
|
2954
3277
|
##
|
|
2955
3278
|
|
|
2956
3279
|
|
|
3280
|
+
@dc.dataclass(frozen=True)
|
|
3281
|
+
class CachedFunc0(ta.Generic[T]):
|
|
3282
|
+
fn: ta.Callable[[], T]
|
|
3283
|
+
|
|
3284
|
+
def __call__(self) -> T:
|
|
3285
|
+
try:
|
|
3286
|
+
return object.__getattribute__(self, '_value')
|
|
3287
|
+
except AttributeError:
|
|
3288
|
+
pass
|
|
3289
|
+
|
|
3290
|
+
value = self.fn()
|
|
3291
|
+
object.__setattr__(self, '_value', value)
|
|
3292
|
+
return value
|
|
3293
|
+
|
|
3294
|
+
|
|
3295
|
+
##
|
|
3296
|
+
|
|
3297
|
+
|
|
2957
3298
|
_TYPING_ANNOTATIONS_ATTR = '__annotate__' if sys.version_info >= (3, 14) else '__annotations__'
|
|
2958
3299
|
|
|
2959
3300
|
|
|
@@ -3868,7 +4209,7 @@ class SpecifierSet(BaseSpecifier):
|
|
|
3868
4209
|
if isinstance(other, str):
|
|
3869
4210
|
other = SpecifierSet(other)
|
|
3870
4211
|
elif not isinstance(other, SpecifierSet):
|
|
3871
|
-
return NotImplemented
|
|
4212
|
+
return NotImplemented
|
|
3872
4213
|
|
|
3873
4214
|
specifier = SpecifierSet()
|
|
3874
4215
|
specifier._specs = frozenset(self._specs | other._specs)
|
|
@@ -3888,6 +4229,7 @@ class SpecifierSet(BaseSpecifier):
|
|
|
3888
4229
|
if isinstance(other, (str, Specifier)):
|
|
3889
4230
|
other = SpecifierSet(str(other))
|
|
3890
4231
|
elif not isinstance(other, SpecifierSet):
|
|
4232
|
+
|
|
3891
4233
|
return NotImplemented
|
|
3892
4234
|
|
|
3893
4235
|
return self._specs == other._specs
|
|
@@ -3959,6 +4301,7 @@ TODO:
|
|
|
3959
4301
|
- pre-run, post-run hooks
|
|
3960
4302
|
- exitstack?
|
|
3961
4303
|
- suggestion - difflib.get_close_matches
|
|
4304
|
+
- add_argument_group - group kw on ArgparseKwarg?
|
|
3962
4305
|
"""
|
|
3963
4306
|
|
|
3964
4307
|
|
|
@@ -3969,6 +4312,7 @@ TODO:
|
|
|
3969
4312
|
class ArgparseArg:
|
|
3970
4313
|
args: ta.Sequence[ta.Any]
|
|
3971
4314
|
kwargs: ta.Mapping[str, ta.Any]
|
|
4315
|
+
group: ta.Optional[str] = None
|
|
3972
4316
|
dest: ta.Optional[str] = None
|
|
3973
4317
|
|
|
3974
4318
|
def __get__(self, instance, owner=None):
|
|
@@ -3978,7 +4322,11 @@ class ArgparseArg:
|
|
|
3978
4322
|
|
|
3979
4323
|
|
|
3980
4324
|
def argparse_arg(*args, **kwargs) -> ArgparseArg:
|
|
3981
|
-
return ArgparseArg(
|
|
4325
|
+
return ArgparseArg(
|
|
4326
|
+
args=args,
|
|
4327
|
+
group=kwargs.pop('group', None),
|
|
4328
|
+
kwargs=kwargs,
|
|
4329
|
+
)
|
|
3982
4330
|
|
|
3983
4331
|
|
|
3984
4332
|
def argparse_arg_(*args, **kwargs) -> ta.Any:
|
|
@@ -4148,6 +4496,10 @@ class ArgparseCli:
|
|
|
4148
4496
|
subparser.set_defaults(_cmd=obj)
|
|
4149
4497
|
|
|
4150
4498
|
elif isinstance(obj, ArgparseArg):
|
|
4499
|
+
if obj.group is not None:
|
|
4500
|
+
# FIXME: add_argument_group
|
|
4501
|
+
raise NotImplementedError
|
|
4502
|
+
|
|
4151
4503
|
if att in anns:
|
|
4152
4504
|
ann_kwargs = _get_argparse_arg_ann_kwargs(anns[att])
|
|
4153
4505
|
obj.kwargs = {**ann_kwargs, **obj.kwargs}
|
|
@@ -4193,7 +4545,7 @@ class ArgparseCli:
|
|
|
4193
4545
|
|
|
4194
4546
|
if self._unknown_args and not (cmd is not None and cmd.accepts_unknown):
|
|
4195
4547
|
msg = f'unrecognized arguments: {" ".join(self._unknown_args)}'
|
|
4196
|
-
if (parser := self.get_parser()).exit_on_error:
|
|
4548
|
+
if (parser := self.get_parser()).exit_on_error: # noqa
|
|
4197
4549
|
parser.error(msg)
|
|
4198
4550
|
else:
|
|
4199
4551
|
raise argparse.ArgumentError(None, msg)
|
|
@@ -4213,7 +4565,10 @@ class ArgparseCli:
|
|
|
4213
4565
|
return fn()
|
|
4214
4566
|
|
|
4215
4567
|
def cli_run_and_exit(self) -> ta.NoReturn:
|
|
4216
|
-
|
|
4568
|
+
rc = self.cli_run()
|
|
4569
|
+
if not isinstance(rc, int):
|
|
4570
|
+
rc = 0
|
|
4571
|
+
raise SystemExit(rc)
|
|
4217
4572
|
|
|
4218
4573
|
def __call__(self, *, exit: bool = False) -> ta.Optional[int]: # noqa
|
|
4219
4574
|
if exit:
|
|
@@ -5165,8 +5520,6 @@ class _JustMaybe(_Maybe[T]):
|
|
|
5165
5520
|
__slots__ = ('_v', '_hash')
|
|
5166
5521
|
|
|
5167
5522
|
def __init__(self, v: T) -> None:
|
|
5168
|
-
super().__init__()
|
|
5169
|
-
|
|
5170
5523
|
self._v = v
|
|
5171
5524
|
|
|
5172
5525
|
@property
|
|
@@ -5224,6 +5577,13 @@ class _EmptyMaybe(_Maybe[T]):
|
|
|
5224
5577
|
Maybe._empty = _EmptyMaybe() # noqa
|
|
5225
5578
|
|
|
5226
5579
|
|
|
5580
|
+
##
|
|
5581
|
+
|
|
5582
|
+
|
|
5583
|
+
setattr(Maybe, 'just', _JustMaybe) # noqa
|
|
5584
|
+
setattr(Maybe, 'empty', functools.partial(operator.attrgetter('_empty'), Maybe))
|
|
5585
|
+
|
|
5586
|
+
|
|
5227
5587
|
########################################
|
|
5228
5588
|
# ../../../omlish/lite/runtime.py
|
|
5229
5589
|
|
|
@@ -5970,9 +6330,10 @@ class InterpSpecifier:
|
|
|
5970
6330
|
def parse(cls, s: str) -> 'InterpSpecifier':
|
|
5971
6331
|
s, o = InterpOpts.parse_suffix(s)
|
|
5972
6332
|
if not any(s.startswith(o) for o in Specifier.OPERATORS):
|
|
5973
|
-
s = '~=' + s
|
|
5974
6333
|
if s.count('.') < 2:
|
|
5975
|
-
s
|
|
6334
|
+
s = '~=' + s + '.0'
|
|
6335
|
+
else:
|
|
6336
|
+
s = '==' + s
|
|
5976
6337
|
return cls(
|
|
5977
6338
|
specifier=Specifier(s),
|
|
5978
6339
|
opts=o,
|
|
@@ -5995,62 +6356,544 @@ class Interp:
|
|
|
5995
6356
|
|
|
5996
6357
|
|
|
5997
6358
|
########################################
|
|
5998
|
-
#
|
|
6359
|
+
# ../../packaging/requires.py
|
|
6360
|
+
# Copyright (c) Donald Stufft and individual contributors.
|
|
6361
|
+
# All rights reserved.
|
|
6362
|
+
#
|
|
6363
|
+
# Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
|
|
6364
|
+
# following conditions are met:
|
|
6365
|
+
#
|
|
6366
|
+
# 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the
|
|
6367
|
+
# following disclaimer.
|
|
6368
|
+
#
|
|
6369
|
+
# 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
|
|
6370
|
+
# following disclaimer in the documentation and/or other materials provided with the distribution.
|
|
6371
|
+
#
|
|
6372
|
+
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
|
6373
|
+
# INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
6374
|
+
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
|
6375
|
+
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
|
6376
|
+
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
|
6377
|
+
# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
6378
|
+
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. This file is dual licensed under the terms of the
|
|
6379
|
+
# Apache License, Version 2.0, and the BSD License. See the LICENSE file in the root of this repository for complete
|
|
6380
|
+
# details.
|
|
6381
|
+
# https://github.com/pypa/packaging/blob/cf2cbe2aec28f87c6228a6fb136c27931c9af407/src/packaging/_parser.py#L65
|
|
5999
6382
|
|
|
6000
6383
|
|
|
6001
6384
|
##
|
|
6002
6385
|
|
|
6003
6386
|
|
|
6004
|
-
|
|
6005
|
-
|
|
6006
|
-
|
|
6007
|
-
|
|
6008
|
-
|
|
6009
|
-
fut = asyncio.wait_for(fut, Timeout.of(timeout)()) # type: ignore
|
|
6010
|
-
return fut
|
|
6387
|
+
@dc.dataclass()
|
|
6388
|
+
class RequiresToken:
|
|
6389
|
+
name: str
|
|
6390
|
+
text: str
|
|
6391
|
+
position: int
|
|
6011
6392
|
|
|
6012
6393
|
|
|
6013
|
-
|
|
6014
|
-
|
|
6394
|
+
class RequiresParserSyntaxError(Exception):
|
|
6395
|
+
def __init__(
|
|
6396
|
+
self,
|
|
6397
|
+
message: str,
|
|
6398
|
+
*,
|
|
6399
|
+
source: str,
|
|
6400
|
+
span: ta.Tuple[int, int],
|
|
6401
|
+
) -> None:
|
|
6402
|
+
self.span = span
|
|
6403
|
+
self.message = message
|
|
6404
|
+
self.source = source
|
|
6015
6405
|
|
|
6406
|
+
super().__init__()
|
|
6016
6407
|
|
|
6017
|
-
|
|
6018
|
-
|
|
6408
|
+
def __str__(self) -> str:
|
|
6409
|
+
marker = ' ' * self.span[0] + '~' * (self.span[1] - self.span[0]) + '^'
|
|
6410
|
+
return '\n '.join([self.message, self.source, marker])
|
|
6411
|
+
|
|
6412
|
+
|
|
6413
|
+
REQUIRES_DEFAULT_RULES: ta.Dict[str, ta.Union[str, ta.Pattern[str]]] = {
|
|
6414
|
+
'LEFT_PARENTHESIS': r'\(',
|
|
6415
|
+
'RIGHT_PARENTHESIS': r'\)',
|
|
6416
|
+
'LEFT_BRACKET': r'\[',
|
|
6417
|
+
'RIGHT_BRACKET': r'\]',
|
|
6418
|
+
'SEMICOLON': r';',
|
|
6419
|
+
'COMMA': r',',
|
|
6420
|
+
'QUOTED_STRING': re.compile(
|
|
6421
|
+
r"""
|
|
6422
|
+
(
|
|
6423
|
+
('[^']*')
|
|
6424
|
+
|
|
|
6425
|
+
("[^"]*")
|
|
6426
|
+
)
|
|
6427
|
+
""",
|
|
6428
|
+
re.VERBOSE,
|
|
6429
|
+
),
|
|
6430
|
+
'OP': r'(===|==|~=|!=|<=|>=|<|>)',
|
|
6431
|
+
'BOOLOP': r'\b(or|and)\b',
|
|
6432
|
+
'IN': r'\bin\b',
|
|
6433
|
+
'NOT': r'\bnot\b',
|
|
6434
|
+
'VARIABLE': re.compile(
|
|
6435
|
+
r"""
|
|
6436
|
+
\b(
|
|
6437
|
+
python_version
|
|
6438
|
+
|python_full_version
|
|
6439
|
+
|os[._]name
|
|
6440
|
+
|sys[._]platform
|
|
6441
|
+
|platform_(release|system)
|
|
6442
|
+
|platform[._](version|machine|python_implementation)
|
|
6443
|
+
|python_implementation
|
|
6444
|
+
|implementation_(name|version)
|
|
6445
|
+
|extra
|
|
6446
|
+
)\b
|
|
6447
|
+
""",
|
|
6448
|
+
re.VERBOSE,
|
|
6449
|
+
),
|
|
6450
|
+
'SPECIFIER': re.compile(
|
|
6451
|
+
Specifier._operator_regex_str + Specifier._version_regex_str, # noqa
|
|
6452
|
+
re.VERBOSE | re.IGNORECASE,
|
|
6453
|
+
),
|
|
6454
|
+
'AT': r'\@',
|
|
6455
|
+
'URL': r'[^ \t]+',
|
|
6456
|
+
'IDENTIFIER': r'\b[a-zA-Z0-9][a-zA-Z0-9._-]*\b',
|
|
6457
|
+
'VERSION_PREFIX_TRAIL': r'\.\*',
|
|
6458
|
+
'VERSION_LOCAL_LABEL_TRAIL': r'\+[a-z0-9]+(?:[-_\.][a-z0-9]+)*',
|
|
6459
|
+
'WS': r'[ \t]+',
|
|
6460
|
+
'END': r'$',
|
|
6461
|
+
}
|
|
6019
6462
|
|
|
6020
6463
|
|
|
6021
|
-
|
|
6022
|
-
|
|
6023
|
-
|
|
6024
|
-
|
|
6025
|
-
|
|
6026
|
-
|
|
6027
|
-
|
|
6028
|
-
|
|
6464
|
+
class RequiresTokenizer:
|
|
6465
|
+
def __init__(
|
|
6466
|
+
self,
|
|
6467
|
+
source: str,
|
|
6468
|
+
*,
|
|
6469
|
+
rules: ta.Dict[str, ta.Union[str, ta.Pattern[str]]],
|
|
6470
|
+
) -> None:
|
|
6471
|
+
super().__init__()
|
|
6029
6472
|
|
|
6030
|
-
|
|
6031
|
-
|
|
6473
|
+
self.source = source
|
|
6474
|
+
self.rules: ta.Dict[str, ta.Pattern[str]] = {name: re.compile(pattern) for name, pattern in rules.items()}
|
|
6475
|
+
self.next_token: ta.Optional[RequiresToken] = None
|
|
6476
|
+
self.position = 0
|
|
6032
6477
|
|
|
6478
|
+
def consume(self, name: str) -> None:
|
|
6479
|
+
if self.check(name):
|
|
6480
|
+
self.read()
|
|
6033
6481
|
|
|
6034
|
-
def
|
|
6035
|
-
|
|
6482
|
+
def check(self, name: str, *, peek: bool = False) -> bool:
|
|
6483
|
+
check.state(self.next_token is None, f'Cannot check for {name!r}, already have {self.next_token!r}')
|
|
6484
|
+
check.state(name in self.rules, f'Unknown token name: {name!r}')
|
|
6036
6485
|
|
|
6486
|
+
expression = self.rules[name]
|
|
6037
6487
|
|
|
6038
|
-
|
|
6039
|
-
|
|
6040
|
-
|
|
6041
|
-
|
|
6488
|
+
match = expression.match(self.source, self.position)
|
|
6489
|
+
if match is None:
|
|
6490
|
+
return False
|
|
6491
|
+
if not peek:
|
|
6492
|
+
self.next_token = RequiresToken(name, match[0], self.position)
|
|
6493
|
+
return True
|
|
6042
6494
|
|
|
6495
|
+
def expect(self, name: str, *, expected: str) -> RequiresToken:
|
|
6496
|
+
if not self.check(name):
|
|
6497
|
+
raise self.raise_syntax_error(f'Expected {expected}')
|
|
6498
|
+
return self.read()
|
|
6043
6499
|
|
|
6044
|
-
|
|
6500
|
+
def read(self) -> RequiresToken:
|
|
6501
|
+
token = self.next_token
|
|
6502
|
+
check.state(token is not None)
|
|
6045
6503
|
|
|
6504
|
+
self.position += len(check.not_none(token).text)
|
|
6505
|
+
self.next_token = None
|
|
6046
6506
|
|
|
6047
|
-
|
|
6048
|
-
@abc.abstractmethod
|
|
6049
|
-
def provider_fn(self) -> InjectorProviderFn:
|
|
6050
|
-
raise NotImplementedError
|
|
6507
|
+
return check.not_none(token)
|
|
6051
6508
|
|
|
6509
|
+
def raise_syntax_error(
|
|
6510
|
+
self,
|
|
6511
|
+
message: str,
|
|
6512
|
+
*,
|
|
6513
|
+
span_start: ta.Optional[int] = None,
|
|
6514
|
+
span_end: ta.Optional[int] = None,
|
|
6515
|
+
) -> ta.NoReturn:
|
|
6516
|
+
span = (
|
|
6517
|
+
self.position if span_start is None else span_start,
|
|
6518
|
+
self.position if span_end is None else span_end,
|
|
6519
|
+
)
|
|
6520
|
+
raise RequiresParserSyntaxError(
|
|
6521
|
+
message,
|
|
6522
|
+
source=self.source,
|
|
6523
|
+
span=span,
|
|
6524
|
+
)
|
|
6052
6525
|
|
|
6053
|
-
|
|
6526
|
+
@contextlib.contextmanager
|
|
6527
|
+
def enclosing_tokens(self, open_token: str, close_token: str, *, around: str) -> ta.Iterator[None]:
|
|
6528
|
+
if self.check(open_token):
|
|
6529
|
+
open_position = self.position
|
|
6530
|
+
self.read()
|
|
6531
|
+
else:
|
|
6532
|
+
open_position = None
|
|
6533
|
+
|
|
6534
|
+
yield
|
|
6535
|
+
|
|
6536
|
+
if open_position is None:
|
|
6537
|
+
return
|
|
6538
|
+
|
|
6539
|
+
if not self.check(close_token):
|
|
6540
|
+
self.raise_syntax_error(
|
|
6541
|
+
f'Expected matching {close_token} for {open_token}, after {around}',
|
|
6542
|
+
span_start=open_position,
|
|
6543
|
+
)
|
|
6544
|
+
|
|
6545
|
+
self.read()
|
|
6546
|
+
|
|
6547
|
+
|
|
6548
|
+
@dc.dataclass(frozen=True)
|
|
6549
|
+
class RequiresNode:
|
|
6550
|
+
value: str
|
|
6551
|
+
|
|
6552
|
+
def __str__(self) -> str:
|
|
6553
|
+
return self.value
|
|
6554
|
+
|
|
6555
|
+
def __repr__(self) -> str:
|
|
6556
|
+
return f"<{self.__class__.__name__}('{self}')>"
|
|
6557
|
+
|
|
6558
|
+
def serialize(self) -> str:
|
|
6559
|
+
raise NotImplementedError
|
|
6560
|
+
|
|
6561
|
+
|
|
6562
|
+
@dc.dataclass(frozen=True)
|
|
6563
|
+
class RequiresVariable(RequiresNode):
|
|
6564
|
+
def serialize(self) -> str:
|
|
6565
|
+
return str(self)
|
|
6566
|
+
|
|
6567
|
+
|
|
6568
|
+
@dc.dataclass(frozen=True)
|
|
6569
|
+
class RequiresValue(RequiresNode):
|
|
6570
|
+
def serialize(self) -> str:
|
|
6571
|
+
return f'"{self}"'
|
|
6572
|
+
|
|
6573
|
+
|
|
6574
|
+
@dc.dataclass(frozen=True)
|
|
6575
|
+
class RequiresOp(RequiresNode):
|
|
6576
|
+
def serialize(self) -> str:
|
|
6577
|
+
return str(self)
|
|
6578
|
+
|
|
6579
|
+
|
|
6580
|
+
class RequiresMarkerItem(ta.NamedTuple):
|
|
6581
|
+
l: ta.Union[RequiresVariable, RequiresValue]
|
|
6582
|
+
op: RequiresOp
|
|
6583
|
+
r: ta.Union[RequiresVariable, RequiresValue]
|
|
6584
|
+
|
|
6585
|
+
|
|
6586
|
+
class ParsedRequirement(ta.NamedTuple):
|
|
6587
|
+
name: str
|
|
6588
|
+
url: str
|
|
6589
|
+
extras: ta.List[str]
|
|
6590
|
+
specifier: str
|
|
6591
|
+
marker: ta.Optional[RequiresMarkerList]
|
|
6592
|
+
|
|
6593
|
+
|
|
6594
|
+
def parse_requirement(source: str) -> ParsedRequirement:
|
|
6595
|
+
return _parse_requirement(RequiresTokenizer(source, rules=REQUIRES_DEFAULT_RULES))
|
|
6596
|
+
|
|
6597
|
+
|
|
6598
|
+
def _parse_requirement(tokenizer: RequiresTokenizer) -> ParsedRequirement:
|
|
6599
|
+
tokenizer.consume('WS')
|
|
6600
|
+
|
|
6601
|
+
name_token = tokenizer.expect('IDENTIFIER', expected='package name at the start of dependency specifier')
|
|
6602
|
+
name = name_token.text
|
|
6603
|
+
tokenizer.consume('WS')
|
|
6604
|
+
|
|
6605
|
+
extras = _parse_requires_extras(tokenizer)
|
|
6606
|
+
tokenizer.consume('WS')
|
|
6607
|
+
|
|
6608
|
+
url, specifier, marker = _parse_requirement_details(tokenizer)
|
|
6609
|
+
tokenizer.expect('END', expected='end of dependency specifier')
|
|
6610
|
+
|
|
6611
|
+
return ParsedRequirement(name, url, extras, specifier, marker)
|
|
6612
|
+
|
|
6613
|
+
|
|
6614
|
+
def _parse_requirement_details(tokenizer: RequiresTokenizer) -> ta.Tuple[str, str, ta.Optional[RequiresMarkerList]]:
|
|
6615
|
+
specifier = ''
|
|
6616
|
+
url = ''
|
|
6617
|
+
marker = None
|
|
6618
|
+
|
|
6619
|
+
if tokenizer.check('AT'):
|
|
6620
|
+
tokenizer.read()
|
|
6621
|
+
tokenizer.consume('WS')
|
|
6622
|
+
|
|
6623
|
+
url_start = tokenizer.position
|
|
6624
|
+
url = tokenizer.expect('URL', expected='URL after @').text
|
|
6625
|
+
if tokenizer.check('END', peek=True):
|
|
6626
|
+
return (url, specifier, marker)
|
|
6627
|
+
|
|
6628
|
+
tokenizer.expect('WS', expected='whitespace after URL')
|
|
6629
|
+
|
|
6630
|
+
# The input might end after whitespace.
|
|
6631
|
+
if tokenizer.check('END', peek=True):
|
|
6632
|
+
return (url, specifier, marker)
|
|
6633
|
+
|
|
6634
|
+
marker = _parse_requirement_marker(
|
|
6635
|
+
tokenizer, span_start=url_start, after='URL and whitespace',
|
|
6636
|
+
)
|
|
6637
|
+
else:
|
|
6638
|
+
specifier_start = tokenizer.position
|
|
6639
|
+
specifier = _parse_requires_specifier(tokenizer)
|
|
6640
|
+
tokenizer.consume('WS')
|
|
6641
|
+
|
|
6642
|
+
if tokenizer.check('END', peek=True):
|
|
6643
|
+
return (url, specifier, marker)
|
|
6644
|
+
|
|
6645
|
+
marker = _parse_requirement_marker(
|
|
6646
|
+
tokenizer,
|
|
6647
|
+
span_start=specifier_start,
|
|
6648
|
+
after=(
|
|
6649
|
+
'version specifier'
|
|
6650
|
+
if specifier
|
|
6651
|
+
else 'name and no valid version specifier'
|
|
6652
|
+
),
|
|
6653
|
+
)
|
|
6654
|
+
|
|
6655
|
+
return (url, specifier, marker)
|
|
6656
|
+
|
|
6657
|
+
|
|
6658
|
+
def _parse_requirement_marker(
|
|
6659
|
+
tokenizer: RequiresTokenizer, *, span_start: int, after: str,
|
|
6660
|
+
) -> RequiresMarkerList:
|
|
6661
|
+
if not tokenizer.check('SEMICOLON'):
|
|
6662
|
+
tokenizer.raise_syntax_error(
|
|
6663
|
+
f'Expected end or semicolon (after {after})',
|
|
6664
|
+
span_start=span_start,
|
|
6665
|
+
)
|
|
6666
|
+
tokenizer.read()
|
|
6667
|
+
|
|
6668
|
+
marker = _parse_requires_marker(tokenizer)
|
|
6669
|
+
tokenizer.consume('WS')
|
|
6670
|
+
|
|
6671
|
+
return marker
|
|
6672
|
+
|
|
6673
|
+
|
|
6674
|
+
def _parse_requires_extras(tokenizer: RequiresTokenizer) -> ta.List[str]:
|
|
6675
|
+
if not tokenizer.check('LEFT_BRACKET', peek=True):
|
|
6676
|
+
return []
|
|
6677
|
+
|
|
6678
|
+
with tokenizer.enclosing_tokens(
|
|
6679
|
+
'LEFT_BRACKET',
|
|
6680
|
+
'RIGHT_BRACKET',
|
|
6681
|
+
around='extras',
|
|
6682
|
+
):
|
|
6683
|
+
tokenizer.consume('WS')
|
|
6684
|
+
extras = _parse_requires_extras_list(tokenizer)
|
|
6685
|
+
tokenizer.consume('WS')
|
|
6686
|
+
|
|
6687
|
+
return extras
|
|
6688
|
+
|
|
6689
|
+
|
|
6690
|
+
def _parse_requires_extras_list(tokenizer: RequiresTokenizer) -> ta.List[str]:
|
|
6691
|
+
extras: ta.List[str] = []
|
|
6692
|
+
|
|
6693
|
+
if not tokenizer.check('IDENTIFIER'):
|
|
6694
|
+
return extras
|
|
6695
|
+
|
|
6696
|
+
extras.append(tokenizer.read().text)
|
|
6697
|
+
|
|
6698
|
+
while True:
|
|
6699
|
+
tokenizer.consume('WS')
|
|
6700
|
+
if tokenizer.check('IDENTIFIER', peek=True):
|
|
6701
|
+
tokenizer.raise_syntax_error('Expected comma between extra names')
|
|
6702
|
+
elif not tokenizer.check('COMMA'):
|
|
6703
|
+
break
|
|
6704
|
+
|
|
6705
|
+
tokenizer.read()
|
|
6706
|
+
tokenizer.consume('WS')
|
|
6707
|
+
|
|
6708
|
+
extra_token = tokenizer.expect('IDENTIFIER', expected='extra name after comma')
|
|
6709
|
+
extras.append(extra_token.text)
|
|
6710
|
+
|
|
6711
|
+
return extras
|
|
6712
|
+
|
|
6713
|
+
|
|
6714
|
+
def _parse_requires_specifier(tokenizer: RequiresTokenizer) -> str:
|
|
6715
|
+
with tokenizer.enclosing_tokens(
|
|
6716
|
+
'LEFT_PARENTHESIS',
|
|
6717
|
+
'RIGHT_PARENTHESIS',
|
|
6718
|
+
around='version specifier',
|
|
6719
|
+
):
|
|
6720
|
+
tokenizer.consume('WS')
|
|
6721
|
+
parsed_specifiers = _parse_requires_version_many(tokenizer)
|
|
6722
|
+
tokenizer.consume('WS')
|
|
6723
|
+
|
|
6724
|
+
return parsed_specifiers
|
|
6725
|
+
|
|
6726
|
+
|
|
6727
|
+
def _parse_requires_version_many(tokenizer: RequiresTokenizer) -> str:
|
|
6728
|
+
parsed_specifiers = ''
|
|
6729
|
+
while tokenizer.check('SPECIFIER'):
|
|
6730
|
+
span_start = tokenizer.position
|
|
6731
|
+
parsed_specifiers += tokenizer.read().text
|
|
6732
|
+
if tokenizer.check('VERSION_PREFIX_TRAIL', peek=True):
|
|
6733
|
+
tokenizer.raise_syntax_error(
|
|
6734
|
+
'.* suffix can only be used with `==` or `!=` operators',
|
|
6735
|
+
span_start=span_start,
|
|
6736
|
+
span_end=tokenizer.position + 1,
|
|
6737
|
+
)
|
|
6738
|
+
if tokenizer.check('VERSION_LOCAL_LABEL_TRAIL', peek=True):
|
|
6739
|
+
tokenizer.raise_syntax_error(
|
|
6740
|
+
'Local version label can only be used with `==` or `!=` operators',
|
|
6741
|
+
span_start=span_start,
|
|
6742
|
+
span_end=tokenizer.position,
|
|
6743
|
+
)
|
|
6744
|
+
tokenizer.consume('WS')
|
|
6745
|
+
if not tokenizer.check('COMMA'):
|
|
6746
|
+
break
|
|
6747
|
+
parsed_specifiers += tokenizer.read().text
|
|
6748
|
+
tokenizer.consume('WS')
|
|
6749
|
+
|
|
6750
|
+
return parsed_specifiers
|
|
6751
|
+
|
|
6752
|
+
|
|
6753
|
+
def parse_requires_marker(source: str) -> RequiresMarkerList:
|
|
6754
|
+
return _parse_requires_full_marker(RequiresTokenizer(source, rules=REQUIRES_DEFAULT_RULES))
|
|
6755
|
+
|
|
6756
|
+
|
|
6757
|
+
def _parse_requires_full_marker(tokenizer: RequiresTokenizer) -> RequiresMarkerList:
|
|
6758
|
+
retval = _parse_requires_marker(tokenizer)
|
|
6759
|
+
tokenizer.expect('END', expected='end of marker expression')
|
|
6760
|
+
return retval
|
|
6761
|
+
|
|
6762
|
+
|
|
6763
|
+
def _parse_requires_marker(tokenizer: RequiresTokenizer) -> RequiresMarkerList:
|
|
6764
|
+
expression = [_parse_requires_marker_atom(tokenizer)]
|
|
6765
|
+
while tokenizer.check('BOOLOP'):
|
|
6766
|
+
token = tokenizer.read()
|
|
6767
|
+
expr_right = _parse_requires_marker_atom(tokenizer)
|
|
6768
|
+
expression.extend((token.text, expr_right))
|
|
6769
|
+
return expression
|
|
6770
|
+
|
|
6771
|
+
|
|
6772
|
+
def _parse_requires_marker_atom(tokenizer: RequiresTokenizer) -> RequiresMarkerAtom:
|
|
6773
|
+
tokenizer.consume('WS')
|
|
6774
|
+
if tokenizer.check('LEFT_PARENTHESIS', peek=True):
|
|
6775
|
+
with tokenizer.enclosing_tokens(
|
|
6776
|
+
'LEFT_PARENTHESIS',
|
|
6777
|
+
'RIGHT_PARENTHESIS',
|
|
6778
|
+
around='marker expression',
|
|
6779
|
+
):
|
|
6780
|
+
tokenizer.consume('WS')
|
|
6781
|
+
marker: RequiresMarkerAtom = _parse_requires_marker(tokenizer)
|
|
6782
|
+
tokenizer.consume('WS')
|
|
6783
|
+
else:
|
|
6784
|
+
marker = _parse_requires_marker_item(tokenizer)
|
|
6785
|
+
tokenizer.consume('WS')
|
|
6786
|
+
return marker
|
|
6787
|
+
|
|
6788
|
+
|
|
6789
|
+
def _parse_requires_marker_item(tokenizer: RequiresTokenizer) -> RequiresMarkerItem:
|
|
6790
|
+
tokenizer.consume('WS')
|
|
6791
|
+
marker_var_left = _parse_requires_marker_var(tokenizer)
|
|
6792
|
+
tokenizer.consume('WS')
|
|
6793
|
+
marker_op = _parse_requires_marker_op(tokenizer)
|
|
6794
|
+
tokenizer.consume('WS')
|
|
6795
|
+
marker_var_right = _parse_requires_marker_var(tokenizer)
|
|
6796
|
+
tokenizer.consume('WS')
|
|
6797
|
+
return RequiresMarkerItem(marker_var_left, marker_op, marker_var_right)
|
|
6798
|
+
|
|
6799
|
+
|
|
6800
|
+
def _parse_requires_marker_var(tokenizer: RequiresTokenizer) -> RequiresMarkerVar:
|
|
6801
|
+
if tokenizer.check('VARIABLE'):
|
|
6802
|
+
return process_requires_env_var(tokenizer.read().text.replace('.', '_'))
|
|
6803
|
+
elif tokenizer.check('QUOTED_STRING'):
|
|
6804
|
+
return process_requires_python_str(tokenizer.read().text)
|
|
6805
|
+
else:
|
|
6806
|
+
tokenizer.raise_syntax_error(message='Expected a marker variable or quoted string')
|
|
6807
|
+
raise RuntimeError # noqa
|
|
6808
|
+
|
|
6809
|
+
|
|
6810
|
+
def process_requires_env_var(env_var: str) -> RequiresVariable:
|
|
6811
|
+
if env_var in ('platform_python_implementation', 'python_implementation'):
|
|
6812
|
+
return RequiresVariable('platform_python_implementation')
|
|
6813
|
+
else:
|
|
6814
|
+
return RequiresVariable(env_var)
|
|
6815
|
+
|
|
6816
|
+
|
|
6817
|
+
def process_requires_python_str(python_str: str) -> RequiresValue:
|
|
6818
|
+
value = ast.literal_eval(python_str)
|
|
6819
|
+
return RequiresValue(str(value))
|
|
6820
|
+
|
|
6821
|
+
|
|
6822
|
+
def _parse_requires_marker_op(tokenizer: RequiresTokenizer) -> RequiresOp:
|
|
6823
|
+
if tokenizer.check('IN'):
|
|
6824
|
+
tokenizer.read()
|
|
6825
|
+
return RequiresOp('in')
|
|
6826
|
+
elif tokenizer.check('NOT'):
|
|
6827
|
+
tokenizer.read()
|
|
6828
|
+
tokenizer.expect('WS', expected="whitespace after 'not'")
|
|
6829
|
+
tokenizer.expect('IN', expected="'in' after 'not'")
|
|
6830
|
+
return RequiresOp('not in')
|
|
6831
|
+
elif tokenizer.check('OP'):
|
|
6832
|
+
return RequiresOp(tokenizer.read().text)
|
|
6833
|
+
else:
|
|
6834
|
+
return tokenizer.raise_syntax_error(
|
|
6835
|
+
'Expected marker operator, one of '
|
|
6836
|
+
'<=, <, !=, ==, >=, >, ~=, ===, in, not in',
|
|
6837
|
+
)
|
|
6838
|
+
|
|
6839
|
+
|
|
6840
|
+
########################################
|
|
6841
|
+
# ../../../omlish/asyncs/asyncio/timeouts.py
|
|
6842
|
+
|
|
6843
|
+
|
|
6844
|
+
##
|
|
6845
|
+
|
|
6846
|
+
|
|
6847
|
+
def asyncio_maybe_timeout(
|
|
6848
|
+
fut: AwaitableT,
|
|
6849
|
+
timeout: TimeoutLike = None,
|
|
6850
|
+
) -> AwaitableT:
|
|
6851
|
+
if timeout is not None:
|
|
6852
|
+
fut = asyncio.wait_for(fut, Timeout.of(timeout)()) # type: ignore
|
|
6853
|
+
return fut
|
|
6854
|
+
|
|
6855
|
+
|
|
6856
|
+
########################################
|
|
6857
|
+
# ../../../omlish/lite/inject.py
|
|
6858
|
+
|
|
6859
|
+
|
|
6860
|
+
###
|
|
6861
|
+
# types
|
|
6862
|
+
|
|
6863
|
+
|
|
6864
|
+
@dc.dataclass(frozen=True)
|
|
6865
|
+
class InjectorKey(ta.Generic[T]):
|
|
6866
|
+
# Before PEP-560 typing.Generic was a metaclass with a __new__ that takes a 'cls' arg, so instantiating a dataclass
|
|
6867
|
+
# with kwargs (such as through dc.replace) causes `TypeError: __new__() got multiple values for argument 'cls'`.
|
|
6868
|
+
# See:
|
|
6869
|
+
# - https://github.com/python/cpython/commit/d911e40e788fb679723d78b6ea11cabf46caed5a
|
|
6870
|
+
# - https://gist.github.com/wrmsr/4468b86efe9f373b6b114bfe85b98fd3
|
|
6871
|
+
cls_: InjectorKeyCls
|
|
6872
|
+
|
|
6873
|
+
tag: ta.Any = None
|
|
6874
|
+
array: bool = False
|
|
6875
|
+
|
|
6876
|
+
|
|
6877
|
+
def is_valid_injector_key_cls(cls: ta.Any) -> bool:
|
|
6878
|
+
return isinstance(cls, type) or is_new_type(cls)
|
|
6879
|
+
|
|
6880
|
+
|
|
6881
|
+
def check_valid_injector_key_cls(cls: T) -> T:
|
|
6882
|
+
if not is_valid_injector_key_cls(cls):
|
|
6883
|
+
raise TypeError(cls)
|
|
6884
|
+
return cls
|
|
6885
|
+
|
|
6886
|
+
|
|
6887
|
+
##
|
|
6888
|
+
|
|
6889
|
+
|
|
6890
|
+
class InjectorProvider(Abstract):
|
|
6891
|
+
@abc.abstractmethod
|
|
6892
|
+
def provider_fn(self) -> InjectorProviderFn:
|
|
6893
|
+
raise NotImplementedError
|
|
6894
|
+
|
|
6895
|
+
|
|
6896
|
+
##
|
|
6054
6897
|
|
|
6055
6898
|
|
|
6056
6899
|
@dc.dataclass(frozen=True)
|
|
@@ -7201,6 +8044,9 @@ class CaptureLoggingContextImpl(CaptureLoggingContext):
|
|
|
7201
8044
|
self._infos[type(info)] = info
|
|
7202
8045
|
return self
|
|
7203
8046
|
|
|
8047
|
+
def get_infos(self) -> ta.Mapping[ta.Type[LoggingContextInfo], LoggingContextInfo]:
|
|
8048
|
+
return self._infos
|
|
8049
|
+
|
|
7204
8050
|
def get_info(self, ty: ta.Type[LoggingContextInfoT]) -> ta.Optional[LoggingContextInfoT]:
|
|
7205
8051
|
return self._infos.get(ty)
|
|
7206
8052
|
|
|
@@ -7223,7 +8069,7 @@ class CaptureLoggingContextImpl(CaptureLoggingContext):
|
|
|
7223
8069
|
_stack_offset: int
|
|
7224
8070
|
_stack_info: bool
|
|
7225
8071
|
|
|
7226
|
-
def inc_stack_offset(self, ofs: int = 1) -> '
|
|
8072
|
+
def inc_stack_offset(self, ofs: int = 1) -> 'CaptureLoggingContextImpl':
|
|
7227
8073
|
if hasattr(self, '_stack_offset'):
|
|
7228
8074
|
self._stack_offset += ofs
|
|
7229
8075
|
return self
|
|
@@ -7255,10 +8101,9 @@ class CaptureLoggingContextImpl(CaptureLoggingContext):
|
|
|
7255
8101
|
|
|
7256
8102
|
|
|
7257
8103
|
########################################
|
|
7258
|
-
# ../../../omlish/logs/standard.py
|
|
8104
|
+
# ../../../omlish/logs/std/standard.py
|
|
7259
8105
|
"""
|
|
7260
8106
|
TODO:
|
|
7261
|
-
- !! move to std !!
|
|
7262
8107
|
- structured
|
|
7263
8108
|
- prefixed
|
|
7264
8109
|
- debug
|
|
@@ -7628,6 +8473,11 @@ class AnyLogger(Abstract, ta.Generic[T]):
|
|
|
7628
8473
|
|
|
7629
8474
|
##
|
|
7630
8475
|
|
|
8476
|
+
# This will be 1 for [Sync]Logger and 0 for AsyncLogger - in sync loggers these methods remain present on the stack,
|
|
8477
|
+
# in async loggers they return a coroutine to be awaited and thus aren't actually present when said coroutine is
|
|
8478
|
+
# awaited.
|
|
8479
|
+
_level_proxy_method_stack_offset: int
|
|
8480
|
+
|
|
7631
8481
|
@ta.overload
|
|
7632
8482
|
def log(self, level: LogLevel, msg: str, *args: ta.Any, **kwargs: ta.Any) -> T:
|
|
7633
8483
|
...
|
|
@@ -7642,7 +8492,14 @@ class AnyLogger(Abstract, ta.Generic[T]):
|
|
|
7642
8492
|
|
|
7643
8493
|
@ta.final
|
|
7644
8494
|
def log(self, level: LogLevel, *args, **kwargs):
|
|
7645
|
-
return self._log(
|
|
8495
|
+
return self._log(
|
|
8496
|
+
CaptureLoggingContextImpl(
|
|
8497
|
+
level,
|
|
8498
|
+
stack_offset=self._level_proxy_method_stack_offset,
|
|
8499
|
+
),
|
|
8500
|
+
*args,
|
|
8501
|
+
**kwargs,
|
|
8502
|
+
)
|
|
7646
8503
|
|
|
7647
8504
|
#
|
|
7648
8505
|
|
|
@@ -7660,7 +8517,14 @@ class AnyLogger(Abstract, ta.Generic[T]):
|
|
|
7660
8517
|
|
|
7661
8518
|
@ta.final
|
|
7662
8519
|
def debug(self, *args, **kwargs):
|
|
7663
|
-
return self._log(
|
|
8520
|
+
return self._log(
|
|
8521
|
+
CaptureLoggingContextImpl(
|
|
8522
|
+
NamedLogLevel.DEBUG,
|
|
8523
|
+
stack_offset=self._level_proxy_method_stack_offset,
|
|
8524
|
+
),
|
|
8525
|
+
*args,
|
|
8526
|
+
**kwargs,
|
|
8527
|
+
)
|
|
7664
8528
|
|
|
7665
8529
|
#
|
|
7666
8530
|
|
|
@@ -7678,7 +8542,14 @@ class AnyLogger(Abstract, ta.Generic[T]):
|
|
|
7678
8542
|
|
|
7679
8543
|
@ta.final
|
|
7680
8544
|
def info(self, *args, **kwargs):
|
|
7681
|
-
return self._log(
|
|
8545
|
+
return self._log(
|
|
8546
|
+
CaptureLoggingContextImpl(
|
|
8547
|
+
NamedLogLevel.INFO,
|
|
8548
|
+
stack_offset=self._level_proxy_method_stack_offset,
|
|
8549
|
+
),
|
|
8550
|
+
*args,
|
|
8551
|
+
**kwargs,
|
|
8552
|
+
)
|
|
7682
8553
|
|
|
7683
8554
|
#
|
|
7684
8555
|
|
|
@@ -7696,7 +8567,14 @@ class AnyLogger(Abstract, ta.Generic[T]):
|
|
|
7696
8567
|
|
|
7697
8568
|
@ta.final
|
|
7698
8569
|
def warning(self, *args, **kwargs):
|
|
7699
|
-
return self._log(
|
|
8570
|
+
return self._log(
|
|
8571
|
+
CaptureLoggingContextImpl(
|
|
8572
|
+
NamedLogLevel.WARNING,
|
|
8573
|
+
stack_offset=self._level_proxy_method_stack_offset,
|
|
8574
|
+
),
|
|
8575
|
+
*args,
|
|
8576
|
+
**kwargs,
|
|
8577
|
+
)
|
|
7700
8578
|
|
|
7701
8579
|
#
|
|
7702
8580
|
|
|
@@ -7714,7 +8592,14 @@ class AnyLogger(Abstract, ta.Generic[T]):
|
|
|
7714
8592
|
|
|
7715
8593
|
@ta.final
|
|
7716
8594
|
def error(self, *args, **kwargs):
|
|
7717
|
-
return self._log(
|
|
8595
|
+
return self._log(
|
|
8596
|
+
CaptureLoggingContextImpl(
|
|
8597
|
+
NamedLogLevel.ERROR,
|
|
8598
|
+
stack_offset=self._level_proxy_method_stack_offset,
|
|
8599
|
+
),
|
|
8600
|
+
*args,
|
|
8601
|
+
**kwargs,
|
|
8602
|
+
)
|
|
7718
8603
|
|
|
7719
8604
|
#
|
|
7720
8605
|
|
|
@@ -7732,7 +8617,15 @@ class AnyLogger(Abstract, ta.Generic[T]):
|
|
|
7732
8617
|
|
|
7733
8618
|
@ta.final
|
|
7734
8619
|
def exception(self, *args, exc_info: LoggingExcInfoArg = True, **kwargs):
|
|
7735
|
-
return self._log(
|
|
8620
|
+
return self._log(
|
|
8621
|
+
CaptureLoggingContextImpl(
|
|
8622
|
+
NamedLogLevel.ERROR,
|
|
8623
|
+
exc_info=exc_info,
|
|
8624
|
+
stack_offset=self._level_proxy_method_stack_offset,
|
|
8625
|
+
),
|
|
8626
|
+
*args,
|
|
8627
|
+
**kwargs,
|
|
8628
|
+
)
|
|
7736
8629
|
|
|
7737
8630
|
#
|
|
7738
8631
|
|
|
@@ -7750,24 +8643,53 @@ class AnyLogger(Abstract, ta.Generic[T]):
|
|
|
7750
8643
|
|
|
7751
8644
|
@ta.final
|
|
7752
8645
|
def critical(self, *args, **kwargs):
|
|
7753
|
-
return self._log(
|
|
8646
|
+
return self._log(
|
|
8647
|
+
CaptureLoggingContextImpl(
|
|
8648
|
+
NamedLogLevel.CRITICAL,
|
|
8649
|
+
stack_offset=self._level_proxy_method_stack_offset,
|
|
8650
|
+
),
|
|
8651
|
+
*args,
|
|
8652
|
+
**kwargs,
|
|
8653
|
+
)
|
|
7754
8654
|
|
|
7755
8655
|
##
|
|
7756
8656
|
|
|
7757
8657
|
@abc.abstractmethod
|
|
7758
|
-
def _log(
|
|
8658
|
+
def _log(
|
|
8659
|
+
self,
|
|
8660
|
+
ctx: CaptureLoggingContext,
|
|
8661
|
+
msg: ta.Union[str, tuple, LoggingMsgFn],
|
|
8662
|
+
*args: ta.Any,
|
|
8663
|
+
**kwargs: ta.Any,
|
|
8664
|
+
) -> T:
|
|
7759
8665
|
raise NotImplementedError
|
|
7760
8666
|
|
|
7761
8667
|
|
|
7762
8668
|
class Logger(AnyLogger[None], Abstract):
|
|
8669
|
+
_level_proxy_method_stack_offset: int = 1
|
|
8670
|
+
|
|
7763
8671
|
@abc.abstractmethod
|
|
7764
|
-
def _log(
|
|
8672
|
+
def _log(
|
|
8673
|
+
self,
|
|
8674
|
+
ctx: CaptureLoggingContext,
|
|
8675
|
+
msg: ta.Union[str, tuple, LoggingMsgFn],
|
|
8676
|
+
*args: ta.Any,
|
|
8677
|
+
**kwargs: ta.Any,
|
|
8678
|
+
) -> None:
|
|
7765
8679
|
raise NotImplementedError
|
|
7766
8680
|
|
|
7767
8681
|
|
|
7768
8682
|
class AsyncLogger(AnyLogger[ta.Awaitable[None]], Abstract):
|
|
8683
|
+
_level_proxy_method_stack_offset: int = 0
|
|
8684
|
+
|
|
7769
8685
|
@abc.abstractmethod
|
|
7770
|
-
def _log(
|
|
8686
|
+
def _log(
|
|
8687
|
+
self,
|
|
8688
|
+
ctx: CaptureLoggingContext,
|
|
8689
|
+
msg: ta.Union[str, tuple, LoggingMsgFn],
|
|
8690
|
+
*args: ta.Any,
|
|
8691
|
+
**kwargs: ta.Any,
|
|
8692
|
+
) -> ta.Awaitable[None]:
|
|
7771
8693
|
raise NotImplementedError
|
|
7772
8694
|
|
|
7773
8695
|
|
|
@@ -7782,13 +8704,25 @@ class AnyNopLogger(AnyLogger[T], Abstract):
|
|
|
7782
8704
|
|
|
7783
8705
|
@ta.final
|
|
7784
8706
|
class NopLogger(AnyNopLogger[None], Logger):
|
|
7785
|
-
def _log(
|
|
8707
|
+
def _log(
|
|
8708
|
+
self,
|
|
8709
|
+
ctx: CaptureLoggingContext,
|
|
8710
|
+
msg: ta.Union[str, tuple, LoggingMsgFn],
|
|
8711
|
+
*args: ta.Any,
|
|
8712
|
+
**kwargs: ta.Any,
|
|
8713
|
+
) -> None:
|
|
7786
8714
|
pass
|
|
7787
8715
|
|
|
7788
8716
|
|
|
7789
8717
|
@ta.final
|
|
7790
8718
|
class AsyncNopLogger(AnyNopLogger[ta.Awaitable[None]], AsyncLogger):
|
|
7791
|
-
async def _log(
|
|
8719
|
+
async def _log(
|
|
8720
|
+
self,
|
|
8721
|
+
ctx: CaptureLoggingContext,
|
|
8722
|
+
msg: ta.Union[str, tuple, LoggingMsgFn],
|
|
8723
|
+
*args: ta.Any,
|
|
8724
|
+
**kwargs: ta.Any,
|
|
8725
|
+
) -> None:
|
|
7792
8726
|
pass
|
|
7793
8727
|
|
|
7794
8728
|
|
|
@@ -8495,6 +9429,10 @@ class VerboseCalledProcessError(subprocess.CalledProcessError):
|
|
|
8495
9429
|
class BaseSubprocesses(Abstract):
|
|
8496
9430
|
DEFAULT_LOGGER: ta.ClassVar[ta.Optional[LoggerLike]] = None
|
|
8497
9431
|
|
|
9432
|
+
PIPE: ta.ClassVar[int] = subprocess.PIPE
|
|
9433
|
+
STDOUT: ta.ClassVar[int] = subprocess.STDOUT
|
|
9434
|
+
DEVNULL: ta.ClassVar[int] = subprocess.DEVNULL
|
|
9435
|
+
|
|
8498
9436
|
def __init__(
|
|
8499
9437
|
self,
|
|
8500
9438
|
*,
|
|
@@ -8750,6 +9688,70 @@ class InterpResolver:
|
|
|
8750
9688
|
print(f' {si}')
|
|
8751
9689
|
|
|
8752
9690
|
|
|
9691
|
+
########################################
|
|
9692
|
+
# ../../../omlish/logs/asyncs.py
|
|
9693
|
+
|
|
9694
|
+
|
|
9695
|
+
##
|
|
9696
|
+
|
|
9697
|
+
|
|
9698
|
+
class AsyncLoggerToLogger(Logger):
|
|
9699
|
+
def __init__(self, u: AsyncLogger) -> None:
|
|
9700
|
+
super().__init__()
|
|
9701
|
+
|
|
9702
|
+
self._u = u
|
|
9703
|
+
|
|
9704
|
+
def get_effective_level(self) -> LogLevel:
|
|
9705
|
+
return self._u.get_effective_level()
|
|
9706
|
+
|
|
9707
|
+
def _log(
|
|
9708
|
+
self,
|
|
9709
|
+
ctx: CaptureLoggingContext,
|
|
9710
|
+
msg: ta.Union[str, tuple, LoggingMsgFn],
|
|
9711
|
+
*args: ta.Any,
|
|
9712
|
+
**kwargs: ta.Any,
|
|
9713
|
+
) -> None:
|
|
9714
|
+
# Nope out early to avoid sync_await if possible - don't bother in the LoggerToAsyncLogger.
|
|
9715
|
+
if not self.is_enabled_for(ctx.must_get_info(LoggingContextInfos.Level).level):
|
|
9716
|
+
return
|
|
9717
|
+
|
|
9718
|
+
# Note: we hardcode the stack offset of sync_await (which is 2 - sync_await + sync_await.thunk). In non-lite
|
|
9719
|
+
# code, lang.sync_await uses a cext if present to avoid being on the py stack, which would obviously complicate
|
|
9720
|
+
# this, but this is lite code so we will always have the non-c version.
|
|
9721
|
+
sync_await(
|
|
9722
|
+
self._u._log( # noqa
|
|
9723
|
+
check.isinstance(ctx, CaptureLoggingContextImpl).inc_stack_offset(3),
|
|
9724
|
+
msg,
|
|
9725
|
+
*args,
|
|
9726
|
+
**kwargs,
|
|
9727
|
+
),
|
|
9728
|
+
)
|
|
9729
|
+
|
|
9730
|
+
|
|
9731
|
+
class LoggerToAsyncLogger(AsyncLogger):
|
|
9732
|
+
def __init__(self, u: Logger) -> None:
|
|
9733
|
+
super().__init__()
|
|
9734
|
+
|
|
9735
|
+
self._u = u
|
|
9736
|
+
|
|
9737
|
+
def get_effective_level(self) -> LogLevel:
|
|
9738
|
+
return self._u.get_effective_level()
|
|
9739
|
+
|
|
9740
|
+
async def _log(
|
|
9741
|
+
self,
|
|
9742
|
+
ctx: CaptureLoggingContext,
|
|
9743
|
+
msg: ta.Union[str, tuple, LoggingMsgFn],
|
|
9744
|
+
*args: ta.Any,
|
|
9745
|
+
**kwargs: ta.Any,
|
|
9746
|
+
) -> None:
|
|
9747
|
+
return self._u._log( # noqa
|
|
9748
|
+
check.isinstance(ctx, CaptureLoggingContextImpl).inc_stack_offset(),
|
|
9749
|
+
msg,
|
|
9750
|
+
*args,
|
|
9751
|
+
**kwargs,
|
|
9752
|
+
)
|
|
9753
|
+
|
|
9754
|
+
|
|
8753
9755
|
########################################
|
|
8754
9756
|
# ../../../omlish/logs/std/loggers.py
|
|
8755
9757
|
|
|
@@ -8773,7 +9775,12 @@ class StdLogger(Logger):
|
|
|
8773
9775
|
def get_effective_level(self) -> LogLevel:
|
|
8774
9776
|
return self._std.getEffectiveLevel()
|
|
8775
9777
|
|
|
8776
|
-
def _log(
|
|
9778
|
+
def _log(
|
|
9779
|
+
self,
|
|
9780
|
+
ctx: CaptureLoggingContext,
|
|
9781
|
+
msg: ta.Union[str, tuple, LoggingMsgFn],
|
|
9782
|
+
*args: ta.Any,
|
|
9783
|
+
) -> None:
|
|
8777
9784
|
if not self.is_enabled_for(ctx.must_get_info(LoggingContextInfos.Level).level):
|
|
8778
9785
|
return
|
|
8779
9786
|
|
|
@@ -9292,8 +10299,23 @@ asyncio_subprocesses = AsyncioSubprocesses()
|
|
|
9292
10299
|
##
|
|
9293
10300
|
|
|
9294
10301
|
|
|
10302
|
+
def _get_module_std_logger(mod_globals: ta.Mapping[str, ta.Any]) -> logging.Logger:
|
|
10303
|
+
return logging.getLogger(mod_globals.get('__name__'))
|
|
10304
|
+
|
|
10305
|
+
|
|
9295
10306
|
def get_module_logger(mod_globals: ta.Mapping[str, ta.Any]) -> Logger:
|
|
9296
|
-
return StdLogger(
|
|
10307
|
+
return StdLogger(_get_module_std_logger(mod_globals))
|
|
10308
|
+
|
|
10309
|
+
|
|
10310
|
+
def get_module_async_logger(mod_globals: ta.Mapping[str, ta.Any]) -> AsyncLogger:
|
|
10311
|
+
return LoggerToAsyncLogger(get_module_logger(mod_globals))
|
|
10312
|
+
|
|
10313
|
+
|
|
10314
|
+
def get_module_loggers(mod_globals: ta.Mapping[str, ta.Any]) -> ta.Tuple[Logger, AsyncLogger]:
|
|
10315
|
+
return (
|
|
10316
|
+
log := get_module_logger(mod_globals),
|
|
10317
|
+
LoggerToAsyncLogger(log),
|
|
10318
|
+
)
|
|
9297
10319
|
|
|
9298
10320
|
|
|
9299
10321
|
########################################
|
|
@@ -9684,11 +10706,14 @@ log = get_module_logger(globals()) # noqa
|
|
|
9684
10706
|
class RequirementsRewriter:
|
|
9685
10707
|
def __init__(
|
|
9686
10708
|
self,
|
|
10709
|
+
*,
|
|
9687
10710
|
venv: ta.Optional[str] = None,
|
|
10711
|
+
only_pats: ta.Optional[ta.Sequence[re.Pattern]] = None,
|
|
9688
10712
|
) -> None:
|
|
9689
10713
|
super().__init__()
|
|
9690
10714
|
|
|
9691
10715
|
self._venv = venv
|
|
10716
|
+
self._only_pats = only_pats
|
|
9692
10717
|
|
|
9693
10718
|
@cached_nullary
|
|
9694
10719
|
def _tmp_dir(self) -> str:
|
|
@@ -9704,17 +10729,32 @@ class RequirementsRewriter:
|
|
|
9704
10729
|
out_lines = []
|
|
9705
10730
|
|
|
9706
10731
|
for l in in_lines:
|
|
9707
|
-
if
|
|
9708
|
-
lp, _, rp = l.partition(self.VENV_MAGIC)
|
|
9709
|
-
rp = rp.partition('#')[0]
|
|
10732
|
+
if l.split('#')[0].strip():
|
|
9710
10733
|
omit = False
|
|
9711
|
-
|
|
9712
|
-
|
|
9713
|
-
|
|
9714
|
-
|
|
9715
|
-
|
|
10734
|
+
|
|
10735
|
+
if self.VENV_MAGIC in l:
|
|
10736
|
+
lp, _, rp = l.partition(self.VENV_MAGIC)
|
|
10737
|
+
rp = rp.partition('#')[0]
|
|
10738
|
+
for v in rp.split():
|
|
10739
|
+
if v[0] == '!':
|
|
10740
|
+
if self._venv is not None and self._venv == v[1:]:
|
|
10741
|
+
omit = True
|
|
10742
|
+
break
|
|
10743
|
+
else:
|
|
10744
|
+
raise NotImplementedError
|
|
10745
|
+
|
|
10746
|
+
if (
|
|
10747
|
+
not omit and
|
|
10748
|
+
(ops := self._only_pats) is not None and
|
|
10749
|
+
not l.strip().startswith('-')
|
|
10750
|
+
):
|
|
10751
|
+
try:
|
|
10752
|
+
pr = parse_requirement(l.split('#')[0].strip())
|
|
10753
|
+
except RequiresParserSyntaxError:
|
|
10754
|
+
pass
|
|
9716
10755
|
else:
|
|
9717
|
-
|
|
10756
|
+
if not any(op.fullmatch(pr.name) for op in ops):
|
|
10757
|
+
omit = True
|
|
9718
10758
|
|
|
9719
10759
|
if omit:
|
|
9720
10760
|
out_lines.append('# OMITTED: ' + l)
|
|
@@ -10171,12 +11211,42 @@ uv run pip
|
|
|
10171
11211
|
uv run --python 3.11.6 pip
|
|
10172
11212
|
uv venv --python 3.11.6 --seed barf
|
|
10173
11213
|
python3 -m venv barf && barf/bin/pip install uv && barf/bin/uv venv --python 3.11.6 --seed barf2
|
|
11214
|
+
uv python find '3.13.10'
|
|
11215
|
+
uv python list --output-format=json
|
|
10174
11216
|
"""
|
|
10175
11217
|
|
|
10176
11218
|
|
|
10177
11219
|
##
|
|
10178
11220
|
|
|
10179
11221
|
|
|
11222
|
+
@dc.dataclass(frozen=True)
|
|
11223
|
+
class UvPythonListOutput:
|
|
11224
|
+
key: str
|
|
11225
|
+
version: str
|
|
11226
|
+
|
|
11227
|
+
@dc.dataclass(frozen=True)
|
|
11228
|
+
class VersionParts:
|
|
11229
|
+
major: int
|
|
11230
|
+
minor: int
|
|
11231
|
+
patch: int
|
|
11232
|
+
|
|
11233
|
+
version_parts: VersionParts
|
|
11234
|
+
|
|
11235
|
+
path: ta.Optional[str]
|
|
11236
|
+
symlink: ta.Optional[str]
|
|
11237
|
+
|
|
11238
|
+
url: str
|
|
11239
|
+
|
|
11240
|
+
os: str # emscripten linux macos
|
|
11241
|
+
variant: str # default freethreaded
|
|
11242
|
+
implementation: str # cpython graalpy pyodide pypy
|
|
11243
|
+
arch: str # aarch64 wasm32 x86_64
|
|
11244
|
+
libc: str # gnu musl none
|
|
11245
|
+
|
|
11246
|
+
|
|
11247
|
+
##
|
|
11248
|
+
|
|
11249
|
+
|
|
10180
11250
|
class UvInterpProvider(InterpProvider):
|
|
10181
11251
|
def __init__(
|
|
10182
11252
|
self,
|
|
@@ -10197,6 +11267,12 @@ class UvInterpProvider(InterpProvider):
|
|
|
10197
11267
|
async def get_installed_version(self, version: InterpVersion) -> Interp:
|
|
10198
11268
|
raise NotImplementedError
|
|
10199
11269
|
|
|
11270
|
+
# async def get_installable_versions(self, spec: InterpSpecifier) -> ta.Sequence[InterpVersion]:
|
|
11271
|
+
# return []
|
|
11272
|
+
|
|
11273
|
+
# async def install_version(self, version: InterpVersion) -> Interp:
|
|
11274
|
+
# raise TypeError
|
|
11275
|
+
|
|
10200
11276
|
|
|
10201
11277
|
########################################
|
|
10202
11278
|
# ../pkg.py
|
|
@@ -10273,7 +11349,7 @@ class BasePyprojectPackageGenerator(Abstract):
|
|
|
10273
11349
|
|
|
10274
11350
|
def _write_git_ignore(self) -> None:
|
|
10275
11351
|
with open(os.path.join(self._pkg_dir(), '.gitignore'), 'w') as f:
|
|
10276
|
-
f.write('\n'.join(self._GIT_IGNORE))
|
|
11352
|
+
f.write('\n'.join([*self._GIT_IGNORE, '']))
|
|
10277
11353
|
|
|
10278
11354
|
#
|
|
10279
11355
|
|
|
@@ -10442,6 +11518,7 @@ class BasePyprojectPackageGenerator(Abstract):
|
|
|
10442
11518
|
)
|
|
10443
11519
|
|
|
10444
11520
|
if output_dir is not None:
|
|
11521
|
+
log.info(lambda: f'Copying {dist_dir} to {output_dir}')
|
|
10445
11522
|
for fn in os.listdir(dist_dir):
|
|
10446
11523
|
shutil.copyfile(os.path.join(dist_dir, fn), os.path.join(output_dir, fn))
|
|
10447
11524
|
|
|
@@ -10497,7 +11574,11 @@ class PyprojectPackageGenerator(BasePyprojectPackageGenerator):
|
|
|
10497
11574
|
st = dict(specs.setuptools)
|
|
10498
11575
|
pyp_dct['tool.setuptools'] = st
|
|
10499
11576
|
|
|
10500
|
-
|
|
11577
|
+
for k in [
|
|
11578
|
+
'cext',
|
|
11579
|
+
'rs',
|
|
11580
|
+
]:
|
|
11581
|
+
st.pop(k, None)
|
|
10501
11582
|
|
|
10502
11583
|
#
|
|
10503
11584
|
|
|
@@ -10570,13 +11651,20 @@ class PyprojectPackageGenerator(BasePyprojectPackageGenerator):
|
|
|
10570
11651
|
def children(self) -> ta.Sequence[BasePyprojectPackageGenerator]:
|
|
10571
11652
|
out: ta.List[BasePyprojectPackageGenerator] = []
|
|
10572
11653
|
|
|
10573
|
-
if self.build_specs().setuptools.get('
|
|
11654
|
+
if self.build_specs().setuptools.get('cext'):
|
|
10574
11655
|
out.append(_PyprojectCextPackageGenerator(
|
|
10575
11656
|
self._dir_name,
|
|
10576
11657
|
self._pkgs_root,
|
|
10577
11658
|
pkg_suffix='-cext',
|
|
10578
11659
|
))
|
|
10579
11660
|
|
|
11661
|
+
if self.build_specs().setuptools.get('rs'):
|
|
11662
|
+
out.append(_PyprojectRsPackageGenerator(
|
|
11663
|
+
self._dir_name,
|
|
11664
|
+
self._pkgs_root,
|
|
11665
|
+
pkg_suffix='-rs',
|
|
11666
|
+
))
|
|
11667
|
+
|
|
10580
11668
|
if self.build_specs().pyproject.get('cli_scripts'):
|
|
10581
11669
|
out.append(_PyprojectCliPackageGenerator(
|
|
10582
11670
|
self._dir_name,
|
|
@@ -10587,10 +11675,67 @@ class PyprojectPackageGenerator(BasePyprojectPackageGenerator):
|
|
|
10587
11675
|
return out
|
|
10588
11676
|
|
|
10589
11677
|
|
|
10590
|
-
|
|
11678
|
+
##
|
|
11679
|
+
|
|
11680
|
+
|
|
11681
|
+
class _PyprojectExtensionPackageGenerator(BasePyprojectPackageGenerator, Abstract):
|
|
11682
|
+
#
|
|
11683
|
+
|
|
11684
|
+
def _build_project_dict(self) -> ta.Dict[str, ta.Any]:
|
|
11685
|
+
prj = dict(self.build_specs().pyproject)
|
|
11686
|
+
|
|
11687
|
+
prj['dependencies'] = [f'{prj["name"]} == {prj["version"]}']
|
|
11688
|
+
prj['name'] += self._pkg_suffix
|
|
11689
|
+
|
|
11690
|
+
for k in [
|
|
11691
|
+
'optional_dependencies',
|
|
11692
|
+
'entry_points',
|
|
11693
|
+
'scripts',
|
|
11694
|
+
'cli_scripts',
|
|
11695
|
+
]:
|
|
11696
|
+
prj.pop(k, None)
|
|
11697
|
+
|
|
11698
|
+
return prj
|
|
11699
|
+
|
|
11700
|
+
def _build_setuptools_dict(self) -> ta.Dict[str, ta.Any]:
|
|
11701
|
+
st = dict(self.build_specs().setuptools)
|
|
11702
|
+
|
|
11703
|
+
for k in [
|
|
11704
|
+
'cext',
|
|
11705
|
+
'rs',
|
|
11706
|
+
|
|
11707
|
+
'find_packages',
|
|
11708
|
+
'package_data',
|
|
11709
|
+
'manifest_in',
|
|
11710
|
+
]:
|
|
11711
|
+
st.pop(k, None)
|
|
11712
|
+
|
|
11713
|
+
return st
|
|
11714
|
+
|
|
11715
|
+
#
|
|
11716
|
+
|
|
11717
|
+
@dc.dataclass(frozen=True)
|
|
11718
|
+
class FileContents:
|
|
11719
|
+
pyproject_dct: ta.Mapping[str, ta.Any]
|
|
11720
|
+
setup_py: str
|
|
11721
|
+
|
|
11722
|
+
@abc.abstractmethod
|
|
11723
|
+
def file_contents(self) -> FileContents:
|
|
11724
|
+
raise NotImplementedError
|
|
11725
|
+
|
|
11726
|
+
#
|
|
10591
11727
|
|
|
11728
|
+
def _write_file_contents(self) -> None:
|
|
11729
|
+
fc = self.file_contents()
|
|
10592
11730
|
|
|
10593
|
-
|
|
11731
|
+
with open(os.path.join(self._pkg_dir(), 'pyproject.toml'), 'w') as f:
|
|
11732
|
+
TomlWriter(f).write_root(fc.pyproject_dct)
|
|
11733
|
+
|
|
11734
|
+
with open(os.path.join(self._pkg_dir(), 'setup.py'), 'w') as f:
|
|
11735
|
+
f.write(fc.setup_py)
|
|
11736
|
+
|
|
11737
|
+
|
|
11738
|
+
class _PyprojectCextPackageGenerator(_PyprojectExtensionPackageGenerator):
|
|
10594
11739
|
@cached_nullary
|
|
10595
11740
|
def find_cext_srcs(self) -> ta.Sequence[str]:
|
|
10596
11741
|
return sorted(find_magic_files(
|
|
@@ -10601,14 +11746,10 @@ class _PyprojectCextPackageGenerator(BasePyprojectPackageGenerator):
|
|
|
10601
11746
|
|
|
10602
11747
|
#
|
|
10603
11748
|
|
|
10604
|
-
@dc.dataclass(frozen=True)
|
|
10605
|
-
class FileContents:
|
|
10606
|
-
pyproject_dct: ta.Mapping[str, ta.Any]
|
|
10607
|
-
setup_py: str
|
|
10608
|
-
|
|
10609
11749
|
@cached_nullary
|
|
10610
|
-
def file_contents(self) -> FileContents:
|
|
10611
|
-
|
|
11750
|
+
def file_contents(self) -> _PyprojectExtensionPackageGenerator.FileContents:
|
|
11751
|
+
prj = self._build_project_dict()
|
|
11752
|
+
st = self._build_setuptools_dict()
|
|
10612
11753
|
|
|
10613
11754
|
#
|
|
10614
11755
|
|
|
@@ -10619,33 +11760,9 @@ class _PyprojectCextPackageGenerator(BasePyprojectPackageGenerator):
|
|
|
10619
11760
|
'build-backend': 'setuptools.build_meta',
|
|
10620
11761
|
}
|
|
10621
11762
|
|
|
10622
|
-
prj = specs.pyproject
|
|
10623
|
-
prj['dependencies'] = [f'{prj["name"]} == {prj["version"]}']
|
|
10624
|
-
prj['name'] += self._pkg_suffix
|
|
10625
|
-
for k in [
|
|
10626
|
-
'optional_dependencies',
|
|
10627
|
-
'entry_points',
|
|
10628
|
-
'scripts',
|
|
10629
|
-
'cli_scripts',
|
|
10630
|
-
]:
|
|
10631
|
-
prj.pop(k, None)
|
|
10632
|
-
|
|
10633
11763
|
pyp_dct['project'] = prj
|
|
10634
|
-
|
|
10635
|
-
#
|
|
10636
|
-
|
|
10637
|
-
st = dict(specs.setuptools)
|
|
10638
11764
|
pyp_dct['tool.setuptools'] = st
|
|
10639
11765
|
|
|
10640
|
-
for k in [
|
|
10641
|
-
'cexts',
|
|
10642
|
-
|
|
10643
|
-
'find_packages',
|
|
10644
|
-
'package_data',
|
|
10645
|
-
'manifest_in',
|
|
10646
|
-
]:
|
|
10647
|
-
st.pop(k, None)
|
|
10648
|
-
|
|
10649
11766
|
pyp_dct['tool.setuptools.packages.find'] = {
|
|
10650
11767
|
'include': [],
|
|
10651
11768
|
}
|
|
@@ -10655,12 +11772,17 @@ class _PyprojectCextPackageGenerator(BasePyprojectPackageGenerator):
|
|
|
10655
11772
|
ext_lines = []
|
|
10656
11773
|
|
|
10657
11774
|
for ext_src in self.find_cext_srcs():
|
|
11775
|
+
ext_lang = ext_src.rpartition('.')[2]
|
|
11776
|
+
compile_args = {
|
|
11777
|
+
'c': ['-std=c11'],
|
|
11778
|
+
'cc': ['-std=c++20'],
|
|
11779
|
+
}.get(ext_lang, [])
|
|
10658
11780
|
ext_name = ext_src.rpartition('.')[0].replace(os.sep, '.')
|
|
10659
11781
|
ext_lines.extend([
|
|
10660
11782
|
'st.Extension(',
|
|
10661
11783
|
f" name='{ext_name}',",
|
|
10662
11784
|
f" sources=['{ext_src}'],",
|
|
10663
|
-
|
|
11785
|
+
f' extra_compile_args={compile_args!r},',
|
|
10664
11786
|
'),',
|
|
10665
11787
|
])
|
|
10666
11788
|
|
|
@@ -10671,7 +11793,7 @@ class _PyprojectCextPackageGenerator(BasePyprojectPackageGenerator):
|
|
|
10671
11793
|
'st.setup(',
|
|
10672
11794
|
' ext_modules=[',
|
|
10673
11795
|
*[' ' + l for l in ext_lines],
|
|
10674
|
-
' ]',
|
|
11796
|
+
' ],',
|
|
10675
11797
|
')',
|
|
10676
11798
|
'',
|
|
10677
11799
|
])
|
|
@@ -10683,14 +11805,110 @@ class _PyprojectCextPackageGenerator(BasePyprojectPackageGenerator):
|
|
|
10683
11805
|
src,
|
|
10684
11806
|
)
|
|
10685
11807
|
|
|
10686
|
-
def _write_file_contents(self) -> None:
|
|
10687
|
-
fc = self.file_contents()
|
|
10688
11808
|
|
|
10689
|
-
|
|
10690
|
-
|
|
11809
|
+
class _PyprojectRsPackageGenerator(_PyprojectExtensionPackageGenerator):
|
|
11810
|
+
@cached_nullary
|
|
11811
|
+
def find_rs_dirs(self) -> ta.Sequence[str]:
|
|
11812
|
+
return sorted(
|
|
11813
|
+
dp
|
|
11814
|
+
for dp, dns, fns in os.walk(self._dir_name)
|
|
11815
|
+
for fn in fns
|
|
11816
|
+
if fn == '.omlish-rs-ext'
|
|
11817
|
+
)
|
|
10691
11818
|
|
|
10692
|
-
|
|
10693
|
-
|
|
11819
|
+
#
|
|
11820
|
+
|
|
11821
|
+
@staticmethod
|
|
11822
|
+
def _sdist_patch_body() -> None:
|
|
11823
|
+
def _patch_sdist():
|
|
11824
|
+
def _sdist_add_defaults(old, self):
|
|
11825
|
+
import os.path
|
|
11826
|
+
|
|
11827
|
+
old(self)
|
|
11828
|
+
|
|
11829
|
+
if self.distribution.rust_extensions and len(self.distribution.rust_extensions) > 0:
|
|
11830
|
+
build_rust = self.get_finalized_command('build_rust') # noqa
|
|
11831
|
+
for ext in build_rust.extensions:
|
|
11832
|
+
ext_dir = os.path.dirname(ext.path)
|
|
11833
|
+
for n in os.listdir(ext_dir):
|
|
11834
|
+
if n.startswith('.') or n == 'target':
|
|
11835
|
+
continue
|
|
11836
|
+
p = os.path.join(ext_dir, n)
|
|
11837
|
+
if os.path.isfile(p):
|
|
11838
|
+
self.filelist.append(p)
|
|
11839
|
+
elif os.path.isdir(p):
|
|
11840
|
+
self.filelist.extend(os.path.join(dp, f) for dp, dn, fn in os.walk(p) for f in fn)
|
|
11841
|
+
|
|
11842
|
+
# Sadly, we can't just subclass sdist and override it via cmdclass because manifest_maker calls
|
|
11843
|
+
# `sdist.add_defaults` as an unbound function, not a bound method:
|
|
11844
|
+
# https://github.com/pypa/setuptools/blob/9c4d383631d3951fcae0afd73b5d08ff5a262976/setuptools/command/egg_info.py#L581
|
|
11845
|
+
from setuptools.command.sdist import sdist # noqa
|
|
11846
|
+
sdist.add_defaults = (lambda old: lambda sdist: _sdist_add_defaults(old, sdist))(sdist.add_defaults) # noqa
|
|
11847
|
+
|
|
11848
|
+
_patch_sdist()
|
|
11849
|
+
|
|
11850
|
+
@cached_nullary
|
|
11851
|
+
def sdist_patch_code(self) -> str:
|
|
11852
|
+
return textwrap.dedent(''.join(inspect.getsource(self._sdist_patch_body).splitlines(keepends=True)[2:])).strip()
|
|
11853
|
+
|
|
11854
|
+
#
|
|
11855
|
+
|
|
11856
|
+
@cached_nullary
|
|
11857
|
+
def file_contents(self) -> _PyprojectExtensionPackageGenerator.FileContents:
|
|
11858
|
+
prj = self._build_project_dict()
|
|
11859
|
+
st = self._build_setuptools_dict()
|
|
11860
|
+
|
|
11861
|
+
#
|
|
11862
|
+
|
|
11863
|
+
pyp_dct = {}
|
|
11864
|
+
|
|
11865
|
+
pyp_dct['build-system'] = {
|
|
11866
|
+
'requires': ['setuptools', 'setuptools-rust'],
|
|
11867
|
+
'build-backend': 'setuptools.build_meta',
|
|
11868
|
+
}
|
|
11869
|
+
|
|
11870
|
+
pyp_dct['project'] = prj
|
|
11871
|
+
pyp_dct['tool.setuptools'] = st
|
|
11872
|
+
|
|
11873
|
+
pyp_dct['tool.setuptools.packages.find'] = {
|
|
11874
|
+
'include': [],
|
|
11875
|
+
}
|
|
11876
|
+
|
|
11877
|
+
#
|
|
11878
|
+
|
|
11879
|
+
ext_lines: list = []
|
|
11880
|
+
|
|
11881
|
+
for ext_dir in self.find_rs_dirs(): # noqa
|
|
11882
|
+
ext_name = ext_dir.replace(os.sep, '.')
|
|
11883
|
+
ext_lines.extend([
|
|
11884
|
+
'st_rs.RustExtension(',
|
|
11885
|
+
f" '{ext_name}',",
|
|
11886
|
+
f" path='{ext_dir}/Cargo.toml',",
|
|
11887
|
+
'),',
|
|
11888
|
+
])
|
|
11889
|
+
|
|
11890
|
+
src = '\n'.join([
|
|
11891
|
+
'import setuptools as st',
|
|
11892
|
+
'import setuptools_rust as st_rs',
|
|
11893
|
+
'',
|
|
11894
|
+
'',
|
|
11895
|
+
self.sdist_patch_code(),
|
|
11896
|
+
'',
|
|
11897
|
+
'',
|
|
11898
|
+
'st.setup(',
|
|
11899
|
+
' rust_extensions=[',
|
|
11900
|
+
*[' ' + l for l in ext_lines],
|
|
11901
|
+
' ],',
|
|
11902
|
+
')',
|
|
11903
|
+
'',
|
|
11904
|
+
])
|
|
11905
|
+
|
|
11906
|
+
#
|
|
11907
|
+
|
|
11908
|
+
return self.FileContents(
|
|
11909
|
+
pyp_dct,
|
|
11910
|
+
src,
|
|
11911
|
+
)
|
|
10694
11912
|
|
|
10695
11913
|
|
|
10696
11914
|
##
|
|
@@ -10735,7 +11953,8 @@ class _PyprojectCliPackageGenerator(BasePyprojectPackageGenerator):
|
|
|
10735
11953
|
pyp_dct['tool.setuptools'] = st
|
|
10736
11954
|
|
|
10737
11955
|
for k in [
|
|
10738
|
-
'
|
|
11956
|
+
'cext',
|
|
11957
|
+
'rs',
|
|
10739
11958
|
|
|
10740
11959
|
'find_packages',
|
|
10741
11960
|
'package_data',
|
|
@@ -11020,6 +12239,7 @@ def get_default_interp_resolver() -> InterpResolver:
|
|
|
11020
12239
|
class InterpVenvConfig:
|
|
11021
12240
|
interp: ta.Optional[str] = None
|
|
11022
12241
|
requires: ta.Optional[ta.Sequence[str]] = None
|
|
12242
|
+
requires_pats: ta.Optional[ta.Sequence[str]] = None
|
|
11023
12243
|
use_uv: ta.Optional[bool] = None
|
|
11024
12244
|
|
|
11025
12245
|
|
|
@@ -11244,7 +12464,13 @@ class Venv:
|
|
|
11244
12464
|
|
|
11245
12465
|
@cached_nullary
|
|
11246
12466
|
def _iv(self) -> InterpVenv:
|
|
11247
|
-
rr = RequirementsRewriter(
|
|
12467
|
+
rr = RequirementsRewriter(
|
|
12468
|
+
venv=self._name,
|
|
12469
|
+
only_pats=(
|
|
12470
|
+
[re.compile(p) for p in self._cfg.requires_pats]
|
|
12471
|
+
if self._cfg.requires_pats is not None else None
|
|
12472
|
+
),
|
|
12473
|
+
)
|
|
11248
12474
|
|
|
11249
12475
|
return InterpVenv(
|
|
11250
12476
|
self.dir_name,
|