omdev 0.0.0.dev440__py3-none-any.whl → 0.0.0.dev442__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.
- omdev/interp/venvs.py +1 -0
- omdev/manifests/_dumping.py +56 -0
- omdev/packaging/requires.py +6 -6
- omdev/pyproject/reqs.py +31 -9
- omdev/pyproject/venvs.py +8 -1
- omdev/scripts/ci.py +149 -47
- omdev/scripts/interp.py +56 -2
- omdev/scripts/lib/inject.py +0 -2
- omdev/scripts/pyproject.py +579 -12
- {omdev-0.0.0.dev440.dist-info → omdev-0.0.0.dev442.dist-info}/METADATA +2 -2
- {omdev-0.0.0.dev440.dist-info → omdev-0.0.0.dev442.dist-info}/RECORD +15 -15
- {omdev-0.0.0.dev440.dist-info → omdev-0.0.0.dev442.dist-info}/WHEEL +0 -0
- {omdev-0.0.0.dev440.dist-info → omdev-0.0.0.dev442.dist-info}/entry_points.txt +0 -0
- {omdev-0.0.0.dev440.dist-info → omdev-0.0.0.dev442.dist-info}/licenses/LICENSE +0 -0
- {omdev-0.0.0.dev440.dist-info → omdev-0.0.0.dev442.dist-info}/top_level.txt +0 -0
omdev/interp/venvs.py
CHANGED
omdev/manifests/_dumping.py
CHANGED
@@ -227,6 +227,62 @@ def async_cached_nullary(fn): # ta.Callable[..., T]) -> ta.Callable[..., T]:
|
|
227
227
|
return _AsyncCachedNullary(fn)
|
228
228
|
|
229
229
|
|
230
|
+
##
|
231
|
+
|
232
|
+
|
233
|
+
cached_property = functools.cached_property
|
234
|
+
|
235
|
+
|
236
|
+
class _cached_property: # noqa
|
237
|
+
"""Backported to pick up https://github.com/python/cpython/commit/056dfc71dce15f81887f0bd6da09d6099d71f979 ."""
|
238
|
+
|
239
|
+
def __init__(self, func):
|
240
|
+
self.func = func
|
241
|
+
self.attrname = None # noqa
|
242
|
+
self.__doc__ = func.__doc__
|
243
|
+
self.__module__ = func.__module__
|
244
|
+
|
245
|
+
_NOT_FOUND = object()
|
246
|
+
|
247
|
+
def __set_name__(self, owner, name):
|
248
|
+
if self.attrname is None:
|
249
|
+
self.attrname = name # noqa
|
250
|
+
elif name != self.attrname:
|
251
|
+
raise TypeError(
|
252
|
+
f'Cannot assign the same cached_property to two different names ({self.attrname!r} and {name!r}).',
|
253
|
+
)
|
254
|
+
|
255
|
+
def __get__(self, instance, owner=None):
|
256
|
+
if instance is None:
|
257
|
+
return self
|
258
|
+
if self.attrname is None:
|
259
|
+
raise TypeError('Cannot use cached_property instance without calling __set_name__ on it.')
|
260
|
+
|
261
|
+
try:
|
262
|
+
cache = instance.__dict__
|
263
|
+
except AttributeError: # not all objects have __dict__ (e.g. class defines slots)
|
264
|
+
raise TypeError(
|
265
|
+
f"No '__dict__' attribute on {type(instance).__name__!r} instance to cache {self.attrname!r} property.",
|
266
|
+
) from None
|
267
|
+
|
268
|
+
val = cache.get(self.attrname, self._NOT_FOUND)
|
269
|
+
|
270
|
+
if val is self._NOT_FOUND:
|
271
|
+
val = self.func(instance)
|
272
|
+
try:
|
273
|
+
cache[self.attrname] = val
|
274
|
+
except TypeError:
|
275
|
+
raise TypeError(
|
276
|
+
f"The '__dict__' attribute on {type(instance).__name__!r} instance does not support item "
|
277
|
+
f"assignment for caching {self.attrname!r} property.",
|
278
|
+
) from None
|
279
|
+
|
280
|
+
return val
|
281
|
+
|
282
|
+
|
283
|
+
globals()['cached_property'] = _cached_property
|
284
|
+
|
285
|
+
|
230
286
|
########################################
|
231
287
|
# ../../../omlish/lite/check.py
|
232
288
|
"""
|
omdev/packaging/requires.py
CHANGED
@@ -33,6 +33,12 @@ from omlish.lite.check import check
|
|
33
33
|
from .specifiers import Specifier
|
34
34
|
|
35
35
|
|
36
|
+
RequiresMarkerVar = ta.Union['RequiresVariable', 'RequiresValue'] # ta.TypeAlias
|
37
|
+
|
38
|
+
RequiresMarkerAtom = ta.Union['RequiresMarkerItem', ta.Sequence['RequiresMarkerAtom']] # ta.TypeAlias
|
39
|
+
RequiresMarkerList = ta.Sequence[ta.Union['RequiresMarkerList', 'RequiresMarkerAtom', str]] # ta.TypeAlias
|
40
|
+
|
41
|
+
|
36
42
|
##
|
37
43
|
|
38
44
|
|
@@ -229,12 +235,6 @@ class RequiresOp(RequiresNode):
|
|
229
235
|
return str(self)
|
230
236
|
|
231
237
|
|
232
|
-
RequiresMarkerVar = ta.Union['RequiresVariable', 'RequiresValue']
|
233
|
-
|
234
|
-
RequiresMarkerAtom = ta.Union['RequiresMarkerItem', ta.Sequence['RequiresMarkerAtom']]
|
235
|
-
RequiresMarkerList = ta.Sequence[ta.Union['RequiresMarkerList', 'RequiresMarkerAtom', str]]
|
236
|
-
|
237
|
-
|
238
238
|
class RequiresMarkerItem(ta.NamedTuple):
|
239
239
|
l: ta.Union[RequiresVariable, RequiresValue]
|
240
240
|
op: RequiresOp
|
omdev/pyproject/reqs.py
CHANGED
@@ -4,12 +4,16 @@ TODO:
|
|
4
4
|
"""
|
5
5
|
# ruff: noqa: UP007 UP045
|
6
6
|
import os.path
|
7
|
+
import re
|
7
8
|
import tempfile
|
8
9
|
import typing as ta
|
9
10
|
|
10
11
|
from omlish.lite.cached import cached_nullary
|
11
12
|
from omlish.logs.modules import get_module_logger
|
12
13
|
|
14
|
+
from ..packaging.requires import RequiresParserSyntaxError
|
15
|
+
from ..packaging.requires import parse_requirement
|
16
|
+
|
13
17
|
|
14
18
|
log = get_module_logger(globals()) # noqa
|
15
19
|
|
@@ -20,11 +24,14 @@ log = get_module_logger(globals()) # noqa
|
|
20
24
|
class RequirementsRewriter:
|
21
25
|
def __init__(
|
22
26
|
self,
|
27
|
+
*,
|
23
28
|
venv: ta.Optional[str] = None,
|
29
|
+
only_pats: ta.Optional[ta.Sequence[re.Pattern]] = None,
|
24
30
|
) -> None:
|
25
31
|
super().__init__()
|
26
32
|
|
27
33
|
self._venv = venv
|
34
|
+
self._only_pats = only_pats
|
28
35
|
|
29
36
|
@cached_nullary
|
30
37
|
def _tmp_dir(self) -> str:
|
@@ -40,17 +47,32 @@ class RequirementsRewriter:
|
|
40
47
|
out_lines = []
|
41
48
|
|
42
49
|
for l in in_lines:
|
43
|
-
if
|
44
|
-
lp, _, rp = l.partition(self.VENV_MAGIC)
|
45
|
-
rp = rp.partition('#')[0]
|
50
|
+
if l.split('#')[0].strip():
|
46
51
|
omit = False
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
+
|
53
|
+
if self.VENV_MAGIC in l:
|
54
|
+
lp, _, rp = l.partition(self.VENV_MAGIC)
|
55
|
+
rp = rp.partition('#')[0]
|
56
|
+
for v in rp.split():
|
57
|
+
if v[0] == '!':
|
58
|
+
if self._venv is not None and self._venv == v[1:]:
|
59
|
+
omit = True
|
60
|
+
break
|
61
|
+
else:
|
62
|
+
raise NotImplementedError
|
63
|
+
|
64
|
+
if (
|
65
|
+
not omit and
|
66
|
+
(ops := self._only_pats) is not None and
|
67
|
+
not l.strip().startswith('-')
|
68
|
+
):
|
69
|
+
try:
|
70
|
+
pr = parse_requirement(l.split('#')[0].strip())
|
71
|
+
except RequiresParserSyntaxError:
|
72
|
+
pass
|
52
73
|
else:
|
53
|
-
|
74
|
+
if not any(op.fullmatch(pr.name) for op in ops):
|
75
|
+
omit = True
|
54
76
|
|
55
77
|
if omit:
|
56
78
|
out_lines.append('# OMITTED: ' + l)
|
omdev/pyproject/venvs.py
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
# ruff: noqa: UP006 UP007 UP045
|
2
2
|
import glob
|
3
3
|
import os.path
|
4
|
+
import re
|
4
5
|
import typing as ta
|
5
6
|
|
6
7
|
from omlish.lite.cached import async_cached_nullary
|
@@ -42,7 +43,13 @@ class Venv:
|
|
42
43
|
|
43
44
|
@cached_nullary
|
44
45
|
def _iv(self) -> InterpVenv:
|
45
|
-
rr = RequirementsRewriter(
|
46
|
+
rr = RequirementsRewriter(
|
47
|
+
venv=self._name,
|
48
|
+
only_pats=(
|
49
|
+
[re.compile(p) for p in self._cfg.requires_pats]
|
50
|
+
if self._cfg.requires_pats is not None else None
|
51
|
+
),
|
52
|
+
)
|
46
53
|
|
47
54
|
return InterpVenv(
|
48
55
|
self.dir_name,
|
omdev/scripts/ci.py
CHANGED
@@ -670,6 +670,62 @@ def async_cached_nullary(fn): # ta.Callable[..., T]) -> ta.Callable[..., T]:
|
|
670
670
|
return _AsyncCachedNullary(fn)
|
671
671
|
|
672
672
|
|
673
|
+
##
|
674
|
+
|
675
|
+
|
676
|
+
cached_property = functools.cached_property
|
677
|
+
|
678
|
+
|
679
|
+
class _cached_property: # noqa
|
680
|
+
"""Backported to pick up https://github.com/python/cpython/commit/056dfc71dce15f81887f0bd6da09d6099d71f979 ."""
|
681
|
+
|
682
|
+
def __init__(self, func):
|
683
|
+
self.func = func
|
684
|
+
self.attrname = None # noqa
|
685
|
+
self.__doc__ = func.__doc__
|
686
|
+
self.__module__ = func.__module__
|
687
|
+
|
688
|
+
_NOT_FOUND = object()
|
689
|
+
|
690
|
+
def __set_name__(self, owner, name):
|
691
|
+
if self.attrname is None:
|
692
|
+
self.attrname = name # noqa
|
693
|
+
elif name != self.attrname:
|
694
|
+
raise TypeError(
|
695
|
+
f'Cannot assign the same cached_property to two different names ({self.attrname!r} and {name!r}).',
|
696
|
+
)
|
697
|
+
|
698
|
+
def __get__(self, instance, owner=None):
|
699
|
+
if instance is None:
|
700
|
+
return self
|
701
|
+
if self.attrname is None:
|
702
|
+
raise TypeError('Cannot use cached_property instance without calling __set_name__ on it.')
|
703
|
+
|
704
|
+
try:
|
705
|
+
cache = instance.__dict__
|
706
|
+
except AttributeError: # not all objects have __dict__ (e.g. class defines slots)
|
707
|
+
raise TypeError(
|
708
|
+
f"No '__dict__' attribute on {type(instance).__name__!r} instance to cache {self.attrname!r} property.",
|
709
|
+
) from None
|
710
|
+
|
711
|
+
val = cache.get(self.attrname, self._NOT_FOUND)
|
712
|
+
|
713
|
+
if val is self._NOT_FOUND:
|
714
|
+
val = self.func(instance)
|
715
|
+
try:
|
716
|
+
cache[self.attrname] = val
|
717
|
+
except TypeError:
|
718
|
+
raise TypeError(
|
719
|
+
f"The '__dict__' attribute on {type(instance).__name__!r} instance does not support item "
|
720
|
+
f"assignment for caching {self.attrname!r} property.",
|
721
|
+
) from None
|
722
|
+
|
723
|
+
return val
|
724
|
+
|
725
|
+
|
726
|
+
globals()['cached_property'] = _cached_property
|
727
|
+
|
728
|
+
|
673
729
|
########################################
|
674
730
|
# ../../../omlish/lite/check.py
|
675
731
|
"""
|
@@ -1366,6 +1422,17 @@ aclosing = AsyncClosingManager
|
|
1366
1422
|
##
|
1367
1423
|
|
1368
1424
|
|
1425
|
+
def dataclass_shallow_astuple(o: ta.Any) -> ta.Tuple[ta.Any, ...]:
|
1426
|
+
return tuple(getattr(o, f.name) for f in dc.fields(o))
|
1427
|
+
|
1428
|
+
|
1429
|
+
def dataclass_shallow_asdict(o: ta.Any) -> ta.Dict[str, ta.Any]:
|
1430
|
+
return {f.name: getattr(o, f.name) for f in dc.fields(o)}
|
1431
|
+
|
1432
|
+
|
1433
|
+
##
|
1434
|
+
|
1435
|
+
|
1369
1436
|
def is_immediate_dataclass(cls: type) -> bool:
|
1370
1437
|
if not isinstance(cls, type):
|
1371
1438
|
raise TypeError(cls)
|
@@ -3254,6 +3321,70 @@ class ArgparseCli:
|
|
3254
3321
|
return fn()
|
3255
3322
|
|
3256
3323
|
|
3324
|
+
########################################
|
3325
|
+
# ../../../omlish/http/coro/io.py
|
3326
|
+
|
3327
|
+
|
3328
|
+
##
|
3329
|
+
|
3330
|
+
|
3331
|
+
class CoroHttpIo:
|
3332
|
+
def __new__(cls, *args, **kwargs): # noqa
|
3333
|
+
raise TypeError
|
3334
|
+
|
3335
|
+
def __init_subclass__(cls, **kwargs): # noqa
|
3336
|
+
raise TypeError
|
3337
|
+
|
3338
|
+
#
|
3339
|
+
|
3340
|
+
MAX_LINE: ta.ClassVar[int] = 65536
|
3341
|
+
|
3342
|
+
#
|
3343
|
+
|
3344
|
+
class Io(Abstract):
|
3345
|
+
pass
|
3346
|
+
|
3347
|
+
#
|
3348
|
+
|
3349
|
+
class AnyLogIo(Io, Abstract):
|
3350
|
+
pass
|
3351
|
+
|
3352
|
+
#
|
3353
|
+
|
3354
|
+
@dc.dataclass(frozen=True)
|
3355
|
+
class ConnectIo(Io):
|
3356
|
+
args: ta.Tuple[ta.Any, ...]
|
3357
|
+
kwargs: ta.Optional[ta.Dict[str, ta.Any]] = None
|
3358
|
+
|
3359
|
+
#
|
3360
|
+
|
3361
|
+
class CloseIo(Io):
|
3362
|
+
pass
|
3363
|
+
|
3364
|
+
#
|
3365
|
+
|
3366
|
+
class AnyReadIo(Io): # noqa
|
3367
|
+
pass
|
3368
|
+
|
3369
|
+
@dc.dataclass(frozen=True)
|
3370
|
+
class ReadIo(AnyReadIo):
|
3371
|
+
sz: ta.Optional[int]
|
3372
|
+
|
3373
|
+
@dc.dataclass(frozen=True)
|
3374
|
+
class ReadLineIo(AnyReadIo):
|
3375
|
+
sz: int
|
3376
|
+
|
3377
|
+
@dc.dataclass(frozen=True)
|
3378
|
+
class PeekIo(AnyReadIo):
|
3379
|
+
sz: int
|
3380
|
+
|
3381
|
+
#
|
3382
|
+
|
3383
|
+
@dc.dataclass(frozen=True)
|
3384
|
+
class WriteIo(Io):
|
3385
|
+
data: bytes
|
3386
|
+
|
3387
|
+
|
3257
3388
|
########################################
|
3258
3389
|
# ../../../omlish/http/parsing.py
|
3259
3390
|
# PYTHON SOFTWARE FOUNDATION LICENSE VERSION 2
|
@@ -4587,8 +4718,6 @@ class _JustMaybe(_Maybe[T]):
|
|
4587
4718
|
__slots__ = ('_v', '_hash')
|
4588
4719
|
|
4589
4720
|
def __init__(self, v: T) -> None:
|
4590
|
-
super().__init__()
|
4591
|
-
|
4592
4721
|
self._v = v
|
4593
4722
|
|
4594
4723
|
@property
|
@@ -9247,48 +9376,21 @@ class CoroHttpServer:
|
|
9247
9376
|
|
9248
9377
|
#
|
9249
9378
|
|
9250
|
-
class Io(Abstract):
|
9251
|
-
pass
|
9252
|
-
|
9253
|
-
#
|
9254
|
-
|
9255
|
-
class AnyLogIo(Io):
|
9256
|
-
pass
|
9257
|
-
|
9258
9379
|
@dc.dataclass(frozen=True)
|
9259
|
-
class ParsedRequestLogIo(AnyLogIo):
|
9380
|
+
class ParsedRequestLogIo(CoroHttpIo.AnyLogIo):
|
9260
9381
|
request: ParsedHttpRequest
|
9261
9382
|
|
9262
9383
|
@dc.dataclass(frozen=True)
|
9263
|
-
class ErrorLogIo(AnyLogIo):
|
9384
|
+
class ErrorLogIo(CoroHttpIo.AnyLogIo):
|
9264
9385
|
error: 'CoroHttpServer.Error'
|
9265
9386
|
|
9266
9387
|
#
|
9267
9388
|
|
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
9389
|
@dc.dataclass(frozen=True)
|
9288
9390
|
class CoroHandleResult:
|
9289
9391
|
close_reason: ta.Literal['response', 'internal', None] = None
|
9290
9392
|
|
9291
|
-
def coro_handle(self) -> ta.Generator[Io, ta.Optional[bytes], CoroHandleResult]:
|
9393
|
+
def coro_handle(self) -> ta.Generator[CoroHttpIo.Io, ta.Optional[bytes], CoroHandleResult]:
|
9292
9394
|
return self._coro_run_handler(self._coro_handle_one())
|
9293
9395
|
|
9294
9396
|
class Close(Exception): # noqa
|
@@ -9297,20 +9399,20 @@ class CoroHttpServer:
|
|
9297
9399
|
def _coro_run_handler(
|
9298
9400
|
self,
|
9299
9401
|
gen: ta.Generator[
|
9300
|
-
ta.Union[AnyLogIo, AnyReadIo, _Response],
|
9402
|
+
ta.Union[CoroHttpIo.AnyLogIo, CoroHttpIo.AnyReadIo, _Response],
|
9301
9403
|
ta.Optional[bytes],
|
9302
9404
|
None,
|
9303
9405
|
],
|
9304
|
-
) -> ta.Generator[Io, ta.Optional[bytes], CoroHandleResult]:
|
9406
|
+
) -> ta.Generator[CoroHttpIo.Io, ta.Optional[bytes], CoroHandleResult]:
|
9305
9407
|
i: ta.Optional[bytes]
|
9306
9408
|
o: ta.Any = next(gen)
|
9307
9409
|
while True:
|
9308
9410
|
try:
|
9309
|
-
if isinstance(o,
|
9411
|
+
if isinstance(o, CoroHttpIo.AnyLogIo):
|
9310
9412
|
i = None
|
9311
9413
|
yield o
|
9312
9414
|
|
9313
|
-
elif isinstance(o,
|
9415
|
+
elif isinstance(o, CoroHttpIo.AnyReadIo):
|
9314
9416
|
i = check.isinstance((yield o), bytes)
|
9315
9417
|
|
9316
9418
|
elif isinstance(o, self._Response):
|
@@ -9318,10 +9420,10 @@ class CoroHttpServer:
|
|
9318
9420
|
|
9319
9421
|
r = self._preprocess_response(o)
|
9320
9422
|
hb = self._build_response_head_bytes(r)
|
9321
|
-
check.none((yield
|
9423
|
+
check.none((yield CoroHttpIo.WriteIo(hb)))
|
9322
9424
|
|
9323
9425
|
for b in self._yield_response_data(r):
|
9324
|
-
yield
|
9426
|
+
yield CoroHttpIo.WriteIo(b)
|
9325
9427
|
|
9326
9428
|
o.close()
|
9327
9429
|
if o.close_connection:
|
@@ -9349,7 +9451,7 @@ class CoroHttpServer:
|
|
9349
9451
|
raise
|
9350
9452
|
|
9351
9453
|
def _coro_handle_one(self) -> ta.Generator[
|
9352
|
-
ta.Union[AnyLogIo, AnyReadIo, _Response],
|
9454
|
+
ta.Union[CoroHttpIo.AnyLogIo, CoroHttpIo.AnyReadIo, _Response],
|
9353
9455
|
ta.Optional[bytes],
|
9354
9456
|
None,
|
9355
9457
|
]:
|
@@ -9359,7 +9461,7 @@ class CoroHttpServer:
|
|
9359
9461
|
sz = next(gen)
|
9360
9462
|
while True:
|
9361
9463
|
try:
|
9362
|
-
line = check.isinstance((yield
|
9464
|
+
line = check.isinstance((yield CoroHttpIo.ReadLineIo(sz)), bytes)
|
9363
9465
|
sz = gen.send(line)
|
9364
9466
|
except StopIteration as e:
|
9365
9467
|
parsed = e.value
|
@@ -9398,7 +9500,7 @@ class CoroHttpServer:
|
|
9398
9500
|
|
9399
9501
|
request_data: ta.Optional[bytes]
|
9400
9502
|
if (cl := parsed.headers.get('Content-Length')) is not None:
|
9401
|
-
request_data = check.isinstance((yield
|
9503
|
+
request_data = check.isinstance((yield CoroHttpIo.ReadIo(int(cl))), bytes)
|
9402
9504
|
else:
|
9403
9505
|
request_data = None
|
9404
9506
|
|
@@ -11443,7 +11545,7 @@ class CoroHttpServerSocketHandler(SocketHandler_):
|
|
11443
11545
|
server_factory: CoroHttpServerFactory,
|
11444
11546
|
*,
|
11445
11547
|
keep_alive: bool = False,
|
11446
|
-
log_handler: ta.Optional[ta.Callable[[CoroHttpServer,
|
11548
|
+
log_handler: ta.Optional[ta.Callable[[CoroHttpServer, CoroHttpIo.AnyLogIo], None]] = None,
|
11447
11549
|
) -> None:
|
11448
11550
|
super().__init__()
|
11449
11551
|
|
@@ -11472,18 +11574,18 @@ class CoroHttpServerSocketHandler(SocketHandler_):
|
|
11472
11574
|
|
11473
11575
|
o = next(gen)
|
11474
11576
|
while True:
|
11475
|
-
if isinstance(o,
|
11577
|
+
if isinstance(o, CoroHttpIo.AnyLogIo):
|
11476
11578
|
i = None
|
11477
11579
|
if self._log_handler is not None:
|
11478
11580
|
self._log_handler(server, o)
|
11479
11581
|
|
11480
|
-
elif isinstance(o,
|
11481
|
-
i = fp.r.read(o.sz)
|
11582
|
+
elif isinstance(o, CoroHttpIo.ReadIo):
|
11583
|
+
i = fp.r.read(check.not_none(o.sz))
|
11482
11584
|
|
11483
|
-
elif isinstance(o,
|
11585
|
+
elif isinstance(o, CoroHttpIo.ReadLineIo):
|
11484
11586
|
i = fp.r.readline(o.sz)
|
11485
11587
|
|
11486
|
-
elif isinstance(o,
|
11588
|
+
elif isinstance(o, CoroHttpIo.WriteIo):
|
11487
11589
|
i = None
|
11488
11590
|
fp.w.write(o.data)
|
11489
11591
|
fp.w.flush()
|
omdev/scripts/interp.py
CHANGED
@@ -686,6 +686,62 @@ def async_cached_nullary(fn): # ta.Callable[..., T]) -> ta.Callable[..., T]:
|
|
686
686
|
return _AsyncCachedNullary(fn)
|
687
687
|
|
688
688
|
|
689
|
+
##
|
690
|
+
|
691
|
+
|
692
|
+
cached_property = functools.cached_property
|
693
|
+
|
694
|
+
|
695
|
+
class _cached_property: # noqa
|
696
|
+
"""Backported to pick up https://github.com/python/cpython/commit/056dfc71dce15f81887f0bd6da09d6099d71f979 ."""
|
697
|
+
|
698
|
+
def __init__(self, func):
|
699
|
+
self.func = func
|
700
|
+
self.attrname = None # noqa
|
701
|
+
self.__doc__ = func.__doc__
|
702
|
+
self.__module__ = func.__module__
|
703
|
+
|
704
|
+
_NOT_FOUND = object()
|
705
|
+
|
706
|
+
def __set_name__(self, owner, name):
|
707
|
+
if self.attrname is None:
|
708
|
+
self.attrname = name # noqa
|
709
|
+
elif name != self.attrname:
|
710
|
+
raise TypeError(
|
711
|
+
f'Cannot assign the same cached_property to two different names ({self.attrname!r} and {name!r}).',
|
712
|
+
)
|
713
|
+
|
714
|
+
def __get__(self, instance, owner=None):
|
715
|
+
if instance is None:
|
716
|
+
return self
|
717
|
+
if self.attrname is None:
|
718
|
+
raise TypeError('Cannot use cached_property instance without calling __set_name__ on it.')
|
719
|
+
|
720
|
+
try:
|
721
|
+
cache = instance.__dict__
|
722
|
+
except AttributeError: # not all objects have __dict__ (e.g. class defines slots)
|
723
|
+
raise TypeError(
|
724
|
+
f"No '__dict__' attribute on {type(instance).__name__!r} instance to cache {self.attrname!r} property.",
|
725
|
+
) from None
|
726
|
+
|
727
|
+
val = cache.get(self.attrname, self._NOT_FOUND)
|
728
|
+
|
729
|
+
if val is self._NOT_FOUND:
|
730
|
+
val = self.func(instance)
|
731
|
+
try:
|
732
|
+
cache[self.attrname] = val
|
733
|
+
except TypeError:
|
734
|
+
raise TypeError(
|
735
|
+
f"The '__dict__' attribute on {type(instance).__name__!r} instance does not support item "
|
736
|
+
f"assignment for caching {self.attrname!r} property.",
|
737
|
+
) from None
|
738
|
+
|
739
|
+
return val
|
740
|
+
|
741
|
+
|
742
|
+
globals()['cached_property'] = _cached_property
|
743
|
+
|
744
|
+
|
689
745
|
########################################
|
690
746
|
# ../../../omlish/lite/check.py
|
691
747
|
"""
|
@@ -2574,8 +2630,6 @@ class _JustMaybe(_Maybe[T]):
|
|
2574
2630
|
__slots__ = ('_v', '_hash')
|
2575
2631
|
|
2576
2632
|
def __init__(self, v: T) -> None:
|
2577
|
-
super().__init__()
|
2578
|
-
|
2579
2633
|
self._v = v
|
2580
2634
|
|
2581
2635
|
@property
|
omdev/scripts/lib/inject.py
CHANGED
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
|
@@ -137,6 +138,11 @@ LoggingExcInfo = ta.Union[BaseException, LoggingExcInfoTuple] # ta.TypeAlias
|
|
137
138
|
LoggingExcInfoArg = ta.Union[LoggingExcInfo, bool, None] # ta.TypeAlias
|
138
139
|
LoggingContextInfo = ta.Any # ta.TypeAlias
|
139
140
|
|
141
|
+
# ../packaging/requires.py
|
142
|
+
RequiresMarkerVar = ta.Union['RequiresVariable', 'RequiresValue'] # ta.TypeAlias
|
143
|
+
RequiresMarkerAtom = ta.Union['RequiresMarkerItem', ta.Sequence['RequiresMarkerAtom']] # ta.TypeAlias
|
144
|
+
RequiresMarkerList = ta.Sequence[ta.Union['RequiresMarkerList', 'RequiresMarkerAtom', str]] # ta.TypeAlias
|
145
|
+
|
140
146
|
# ../../omlish/asyncs/asyncio/timeouts.py
|
141
147
|
AwaitableT = ta.TypeVar('AwaitableT', bound=ta.Awaitable)
|
142
148
|
|
@@ -2121,6 +2127,62 @@ def async_cached_nullary(fn): # ta.Callable[..., T]) -> ta.Callable[..., T]:
|
|
2121
2127
|
return _AsyncCachedNullary(fn)
|
2122
2128
|
|
2123
2129
|
|
2130
|
+
##
|
2131
|
+
|
2132
|
+
|
2133
|
+
cached_property = functools.cached_property
|
2134
|
+
|
2135
|
+
|
2136
|
+
class _cached_property: # noqa
|
2137
|
+
"""Backported to pick up https://github.com/python/cpython/commit/056dfc71dce15f81887f0bd6da09d6099d71f979 ."""
|
2138
|
+
|
2139
|
+
def __init__(self, func):
|
2140
|
+
self.func = func
|
2141
|
+
self.attrname = None # noqa
|
2142
|
+
self.__doc__ = func.__doc__
|
2143
|
+
self.__module__ = func.__module__
|
2144
|
+
|
2145
|
+
_NOT_FOUND = object()
|
2146
|
+
|
2147
|
+
def __set_name__(self, owner, name):
|
2148
|
+
if self.attrname is None:
|
2149
|
+
self.attrname = name # noqa
|
2150
|
+
elif name != self.attrname:
|
2151
|
+
raise TypeError(
|
2152
|
+
f'Cannot assign the same cached_property to two different names ({self.attrname!r} and {name!r}).',
|
2153
|
+
)
|
2154
|
+
|
2155
|
+
def __get__(self, instance, owner=None):
|
2156
|
+
if instance is None:
|
2157
|
+
return self
|
2158
|
+
if self.attrname is None:
|
2159
|
+
raise TypeError('Cannot use cached_property instance without calling __set_name__ on it.')
|
2160
|
+
|
2161
|
+
try:
|
2162
|
+
cache = instance.__dict__
|
2163
|
+
except AttributeError: # not all objects have __dict__ (e.g. class defines slots)
|
2164
|
+
raise TypeError(
|
2165
|
+
f"No '__dict__' attribute on {type(instance).__name__!r} instance to cache {self.attrname!r} property.",
|
2166
|
+
) from None
|
2167
|
+
|
2168
|
+
val = cache.get(self.attrname, self._NOT_FOUND)
|
2169
|
+
|
2170
|
+
if val is self._NOT_FOUND:
|
2171
|
+
val = self.func(instance)
|
2172
|
+
try:
|
2173
|
+
cache[self.attrname] = val
|
2174
|
+
except TypeError:
|
2175
|
+
raise TypeError(
|
2176
|
+
f"The '__dict__' attribute on {type(instance).__name__!r} instance does not support item "
|
2177
|
+
f"assignment for caching {self.attrname!r} property.",
|
2178
|
+
) from None
|
2179
|
+
|
2180
|
+
return val
|
2181
|
+
|
2182
|
+
|
2183
|
+
globals()['cached_property'] = _cached_property
|
2184
|
+
|
2185
|
+
|
2124
2186
|
########################################
|
2125
2187
|
# ../../../omlish/lite/check.py
|
2126
2188
|
"""
|
@@ -5165,8 +5227,6 @@ class _JustMaybe(_Maybe[T]):
|
|
5165
5227
|
__slots__ = ('_v', '_hash')
|
5166
5228
|
|
5167
5229
|
def __init__(self, v: T) -> None:
|
5168
|
-
super().__init__()
|
5169
|
-
|
5170
5230
|
self._v = v
|
5171
5231
|
|
5172
5232
|
@property
|
@@ -5994,6 +6054,488 @@ class Interp:
|
|
5994
6054
|
version: InterpVersion
|
5995
6055
|
|
5996
6056
|
|
6057
|
+
########################################
|
6058
|
+
# ../../packaging/requires.py
|
6059
|
+
# Copyright (c) Donald Stufft and individual contributors.
|
6060
|
+
# All rights reserved.
|
6061
|
+
#
|
6062
|
+
# Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
|
6063
|
+
# following conditions are met:
|
6064
|
+
#
|
6065
|
+
# 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the
|
6066
|
+
# following disclaimer.
|
6067
|
+
#
|
6068
|
+
# 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
|
6069
|
+
# following disclaimer in the documentation and/or other materials provided with the distribution.
|
6070
|
+
#
|
6071
|
+
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
6072
|
+
# INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
6073
|
+
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
6074
|
+
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
6075
|
+
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
6076
|
+
# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
6077
|
+
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. This file is dual licensed under the terms of the
|
6078
|
+
# Apache License, Version 2.0, and the BSD License. See the LICENSE file in the root of this repository for complete
|
6079
|
+
# details.
|
6080
|
+
# https://github.com/pypa/packaging/blob/cf2cbe2aec28f87c6228a6fb136c27931c9af407/src/packaging/_parser.py#L65
|
6081
|
+
|
6082
|
+
|
6083
|
+
##
|
6084
|
+
|
6085
|
+
|
6086
|
+
@dc.dataclass()
|
6087
|
+
class RequiresToken:
|
6088
|
+
name: str
|
6089
|
+
text: str
|
6090
|
+
position: int
|
6091
|
+
|
6092
|
+
|
6093
|
+
class RequiresParserSyntaxError(Exception):
|
6094
|
+
def __init__(
|
6095
|
+
self,
|
6096
|
+
message: str,
|
6097
|
+
*,
|
6098
|
+
source: str,
|
6099
|
+
span: ta.Tuple[int, int],
|
6100
|
+
) -> None:
|
6101
|
+
self.span = span
|
6102
|
+
self.message = message
|
6103
|
+
self.source = source
|
6104
|
+
|
6105
|
+
super().__init__()
|
6106
|
+
|
6107
|
+
def __str__(self) -> str:
|
6108
|
+
marker = ' ' * self.span[0] + '~' * (self.span[1] - self.span[0]) + '^'
|
6109
|
+
return '\n '.join([self.message, self.source, marker])
|
6110
|
+
|
6111
|
+
|
6112
|
+
REQUIRES_DEFAULT_RULES: ta.Dict[str, ta.Union[str, ta.Pattern[str]]] = {
|
6113
|
+
'LEFT_PARENTHESIS': r'\(',
|
6114
|
+
'RIGHT_PARENTHESIS': r'\)',
|
6115
|
+
'LEFT_BRACKET': r'\[',
|
6116
|
+
'RIGHT_BRACKET': r'\]',
|
6117
|
+
'SEMICOLON': r';',
|
6118
|
+
'COMMA': r',',
|
6119
|
+
'QUOTED_STRING': re.compile(
|
6120
|
+
r"""
|
6121
|
+
(
|
6122
|
+
('[^']*')
|
6123
|
+
|
|
6124
|
+
("[^"]*")
|
6125
|
+
)
|
6126
|
+
""",
|
6127
|
+
re.VERBOSE,
|
6128
|
+
),
|
6129
|
+
'OP': r'(===|==|~=|!=|<=|>=|<|>)',
|
6130
|
+
'BOOLOP': r'\b(or|and)\b',
|
6131
|
+
'IN': r'\bin\b',
|
6132
|
+
'NOT': r'\bnot\b',
|
6133
|
+
'VARIABLE': re.compile(
|
6134
|
+
r"""
|
6135
|
+
\b(
|
6136
|
+
python_version
|
6137
|
+
|python_full_version
|
6138
|
+
|os[._]name
|
6139
|
+
|sys[._]platform
|
6140
|
+
|platform_(release|system)
|
6141
|
+
|platform[._](version|machine|python_implementation)
|
6142
|
+
|python_implementation
|
6143
|
+
|implementation_(name|version)
|
6144
|
+
|extra
|
6145
|
+
)\b
|
6146
|
+
""",
|
6147
|
+
re.VERBOSE,
|
6148
|
+
),
|
6149
|
+
'SPECIFIER': re.compile(
|
6150
|
+
Specifier._operator_regex_str + Specifier._version_regex_str, # noqa
|
6151
|
+
re.VERBOSE | re.IGNORECASE,
|
6152
|
+
),
|
6153
|
+
'AT': r'\@',
|
6154
|
+
'URL': r'[^ \t]+',
|
6155
|
+
'IDENTIFIER': r'\b[a-zA-Z0-9][a-zA-Z0-9._-]*\b',
|
6156
|
+
'VERSION_PREFIX_TRAIL': r'\.\*',
|
6157
|
+
'VERSION_LOCAL_LABEL_TRAIL': r'\+[a-z0-9]+(?:[-_\.][a-z0-9]+)*',
|
6158
|
+
'WS': r'[ \t]+',
|
6159
|
+
'END': r'$',
|
6160
|
+
}
|
6161
|
+
|
6162
|
+
|
6163
|
+
class RequiresTokenizer:
|
6164
|
+
def __init__(
|
6165
|
+
self,
|
6166
|
+
source: str,
|
6167
|
+
*,
|
6168
|
+
rules: ta.Dict[str, ta.Union[str, ta.Pattern[str]]],
|
6169
|
+
) -> None:
|
6170
|
+
super().__init__()
|
6171
|
+
|
6172
|
+
self.source = source
|
6173
|
+
self.rules: ta.Dict[str, ta.Pattern[str]] = {name: re.compile(pattern) for name, pattern in rules.items()}
|
6174
|
+
self.next_token: ta.Optional[RequiresToken] = None
|
6175
|
+
self.position = 0
|
6176
|
+
|
6177
|
+
def consume(self, name: str) -> None:
|
6178
|
+
if self.check(name):
|
6179
|
+
self.read()
|
6180
|
+
|
6181
|
+
def check(self, name: str, *, peek: bool = False) -> bool:
|
6182
|
+
check.state(self.next_token is None, f'Cannot check for {name!r}, already have {self.next_token!r}')
|
6183
|
+
check.state(name in self.rules, f'Unknown token name: {name!r}')
|
6184
|
+
|
6185
|
+
expression = self.rules[name]
|
6186
|
+
|
6187
|
+
match = expression.match(self.source, self.position)
|
6188
|
+
if match is None:
|
6189
|
+
return False
|
6190
|
+
if not peek:
|
6191
|
+
self.next_token = RequiresToken(name, match[0], self.position)
|
6192
|
+
return True
|
6193
|
+
|
6194
|
+
def expect(self, name: str, *, expected: str) -> RequiresToken:
|
6195
|
+
if not self.check(name):
|
6196
|
+
raise self.raise_syntax_error(f'Expected {expected}')
|
6197
|
+
return self.read()
|
6198
|
+
|
6199
|
+
def read(self) -> RequiresToken:
|
6200
|
+
token = self.next_token
|
6201
|
+
check.state(token is not None)
|
6202
|
+
|
6203
|
+
self.position += len(check.not_none(token).text)
|
6204
|
+
self.next_token = None
|
6205
|
+
|
6206
|
+
return check.not_none(token)
|
6207
|
+
|
6208
|
+
def raise_syntax_error(
|
6209
|
+
self,
|
6210
|
+
message: str,
|
6211
|
+
*,
|
6212
|
+
span_start: ta.Optional[int] = None,
|
6213
|
+
span_end: ta.Optional[int] = None,
|
6214
|
+
) -> ta.NoReturn:
|
6215
|
+
span = (
|
6216
|
+
self.position if span_start is None else span_start,
|
6217
|
+
self.position if span_end is None else span_end,
|
6218
|
+
)
|
6219
|
+
raise RequiresParserSyntaxError(
|
6220
|
+
message,
|
6221
|
+
source=self.source,
|
6222
|
+
span=span,
|
6223
|
+
)
|
6224
|
+
|
6225
|
+
@contextlib.contextmanager
|
6226
|
+
def enclosing_tokens(self, open_token: str, close_token: str, *, around: str) -> ta.Iterator[None]:
|
6227
|
+
if self.check(open_token):
|
6228
|
+
open_position = self.position
|
6229
|
+
self.read()
|
6230
|
+
else:
|
6231
|
+
open_position = None
|
6232
|
+
|
6233
|
+
yield
|
6234
|
+
|
6235
|
+
if open_position is None:
|
6236
|
+
return
|
6237
|
+
|
6238
|
+
if not self.check(close_token):
|
6239
|
+
self.raise_syntax_error(
|
6240
|
+
f'Expected matching {close_token} for {open_token}, after {around}',
|
6241
|
+
span_start=open_position,
|
6242
|
+
)
|
6243
|
+
|
6244
|
+
self.read()
|
6245
|
+
|
6246
|
+
|
6247
|
+
@dc.dataclass(frozen=True)
|
6248
|
+
class RequiresNode:
|
6249
|
+
value: str
|
6250
|
+
|
6251
|
+
def __str__(self) -> str:
|
6252
|
+
return self.value
|
6253
|
+
|
6254
|
+
def __repr__(self) -> str:
|
6255
|
+
return f"<{self.__class__.__name__}('{self}')>"
|
6256
|
+
|
6257
|
+
def serialize(self) -> str:
|
6258
|
+
raise NotImplementedError
|
6259
|
+
|
6260
|
+
|
6261
|
+
@dc.dataclass(frozen=True)
|
6262
|
+
class RequiresVariable(RequiresNode):
|
6263
|
+
def serialize(self) -> str:
|
6264
|
+
return str(self)
|
6265
|
+
|
6266
|
+
|
6267
|
+
@dc.dataclass(frozen=True)
|
6268
|
+
class RequiresValue(RequiresNode):
|
6269
|
+
def serialize(self) -> str:
|
6270
|
+
return f'"{self}"'
|
6271
|
+
|
6272
|
+
|
6273
|
+
@dc.dataclass(frozen=True)
|
6274
|
+
class RequiresOp(RequiresNode):
|
6275
|
+
def serialize(self) -> str:
|
6276
|
+
return str(self)
|
6277
|
+
|
6278
|
+
|
6279
|
+
class RequiresMarkerItem(ta.NamedTuple):
|
6280
|
+
l: ta.Union[RequiresVariable, RequiresValue]
|
6281
|
+
op: RequiresOp
|
6282
|
+
r: ta.Union[RequiresVariable, RequiresValue]
|
6283
|
+
|
6284
|
+
|
6285
|
+
class ParsedRequirement(ta.NamedTuple):
|
6286
|
+
name: str
|
6287
|
+
url: str
|
6288
|
+
extras: ta.List[str]
|
6289
|
+
specifier: str
|
6290
|
+
marker: ta.Optional[RequiresMarkerList]
|
6291
|
+
|
6292
|
+
|
6293
|
+
def parse_requirement(source: str) -> ParsedRequirement:
|
6294
|
+
return _parse_requirement(RequiresTokenizer(source, rules=REQUIRES_DEFAULT_RULES))
|
6295
|
+
|
6296
|
+
|
6297
|
+
def _parse_requirement(tokenizer: RequiresTokenizer) -> ParsedRequirement:
|
6298
|
+
tokenizer.consume('WS')
|
6299
|
+
|
6300
|
+
name_token = tokenizer.expect('IDENTIFIER', expected='package name at the start of dependency specifier')
|
6301
|
+
name = name_token.text
|
6302
|
+
tokenizer.consume('WS')
|
6303
|
+
|
6304
|
+
extras = _parse_requires_extras(tokenizer)
|
6305
|
+
tokenizer.consume('WS')
|
6306
|
+
|
6307
|
+
url, specifier, marker = _parse_requirement_details(tokenizer)
|
6308
|
+
tokenizer.expect('END', expected='end of dependency specifier')
|
6309
|
+
|
6310
|
+
return ParsedRequirement(name, url, extras, specifier, marker)
|
6311
|
+
|
6312
|
+
|
6313
|
+
def _parse_requirement_details(tokenizer: RequiresTokenizer) -> ta.Tuple[str, str, ta.Optional[RequiresMarkerList]]:
|
6314
|
+
specifier = ''
|
6315
|
+
url = ''
|
6316
|
+
marker = None
|
6317
|
+
|
6318
|
+
if tokenizer.check('AT'):
|
6319
|
+
tokenizer.read()
|
6320
|
+
tokenizer.consume('WS')
|
6321
|
+
|
6322
|
+
url_start = tokenizer.position
|
6323
|
+
url = tokenizer.expect('URL', expected='URL after @').text
|
6324
|
+
if tokenizer.check('END', peek=True):
|
6325
|
+
return (url, specifier, marker)
|
6326
|
+
|
6327
|
+
tokenizer.expect('WS', expected='whitespace after URL')
|
6328
|
+
|
6329
|
+
# The input might end after whitespace.
|
6330
|
+
if tokenizer.check('END', peek=True):
|
6331
|
+
return (url, specifier, marker)
|
6332
|
+
|
6333
|
+
marker = _parse_requirement_marker(
|
6334
|
+
tokenizer, span_start=url_start, after='URL and whitespace',
|
6335
|
+
)
|
6336
|
+
else:
|
6337
|
+
specifier_start = tokenizer.position
|
6338
|
+
specifier = _parse_requires_specifier(tokenizer)
|
6339
|
+
tokenizer.consume('WS')
|
6340
|
+
|
6341
|
+
if tokenizer.check('END', peek=True):
|
6342
|
+
return (url, specifier, marker)
|
6343
|
+
|
6344
|
+
marker = _parse_requirement_marker(
|
6345
|
+
tokenizer,
|
6346
|
+
span_start=specifier_start,
|
6347
|
+
after=(
|
6348
|
+
'version specifier'
|
6349
|
+
if specifier
|
6350
|
+
else 'name and no valid version specifier'
|
6351
|
+
),
|
6352
|
+
)
|
6353
|
+
|
6354
|
+
return (url, specifier, marker)
|
6355
|
+
|
6356
|
+
|
6357
|
+
def _parse_requirement_marker(
|
6358
|
+
tokenizer: RequiresTokenizer, *, span_start: int, after: str,
|
6359
|
+
) -> RequiresMarkerList:
|
6360
|
+
if not tokenizer.check('SEMICOLON'):
|
6361
|
+
tokenizer.raise_syntax_error(
|
6362
|
+
f'Expected end or semicolon (after {after})',
|
6363
|
+
span_start=span_start,
|
6364
|
+
)
|
6365
|
+
tokenizer.read()
|
6366
|
+
|
6367
|
+
marker = _parse_requires_marker(tokenizer)
|
6368
|
+
tokenizer.consume('WS')
|
6369
|
+
|
6370
|
+
return marker
|
6371
|
+
|
6372
|
+
|
6373
|
+
def _parse_requires_extras(tokenizer: RequiresTokenizer) -> ta.List[str]:
|
6374
|
+
if not tokenizer.check('LEFT_BRACKET', peek=True):
|
6375
|
+
return []
|
6376
|
+
|
6377
|
+
with tokenizer.enclosing_tokens(
|
6378
|
+
'LEFT_BRACKET',
|
6379
|
+
'RIGHT_BRACKET',
|
6380
|
+
around='extras',
|
6381
|
+
):
|
6382
|
+
tokenizer.consume('WS')
|
6383
|
+
extras = _parse_requires_extras_list(tokenizer)
|
6384
|
+
tokenizer.consume('WS')
|
6385
|
+
|
6386
|
+
return extras
|
6387
|
+
|
6388
|
+
|
6389
|
+
def _parse_requires_extras_list(tokenizer: RequiresTokenizer) -> ta.List[str]:
|
6390
|
+
extras: ta.List[str] = []
|
6391
|
+
|
6392
|
+
if not tokenizer.check('IDENTIFIER'):
|
6393
|
+
return extras
|
6394
|
+
|
6395
|
+
extras.append(tokenizer.read().text)
|
6396
|
+
|
6397
|
+
while True:
|
6398
|
+
tokenizer.consume('WS')
|
6399
|
+
if tokenizer.check('IDENTIFIER', peek=True):
|
6400
|
+
tokenizer.raise_syntax_error('Expected comma between extra names')
|
6401
|
+
elif not tokenizer.check('COMMA'):
|
6402
|
+
break
|
6403
|
+
|
6404
|
+
tokenizer.read()
|
6405
|
+
tokenizer.consume('WS')
|
6406
|
+
|
6407
|
+
extra_token = tokenizer.expect('IDENTIFIER', expected='extra name after comma')
|
6408
|
+
extras.append(extra_token.text)
|
6409
|
+
|
6410
|
+
return extras
|
6411
|
+
|
6412
|
+
|
6413
|
+
def _parse_requires_specifier(tokenizer: RequiresTokenizer) -> str:
|
6414
|
+
with tokenizer.enclosing_tokens(
|
6415
|
+
'LEFT_PARENTHESIS',
|
6416
|
+
'RIGHT_PARENTHESIS',
|
6417
|
+
around='version specifier',
|
6418
|
+
):
|
6419
|
+
tokenizer.consume('WS')
|
6420
|
+
parsed_specifiers = _parse_requires_version_many(tokenizer)
|
6421
|
+
tokenizer.consume('WS')
|
6422
|
+
|
6423
|
+
return parsed_specifiers
|
6424
|
+
|
6425
|
+
|
6426
|
+
def _parse_requires_version_many(tokenizer: RequiresTokenizer) -> str:
|
6427
|
+
parsed_specifiers = ''
|
6428
|
+
while tokenizer.check('SPECIFIER'):
|
6429
|
+
span_start = tokenizer.position
|
6430
|
+
parsed_specifiers += tokenizer.read().text
|
6431
|
+
if tokenizer.check('VERSION_PREFIX_TRAIL', peek=True):
|
6432
|
+
tokenizer.raise_syntax_error(
|
6433
|
+
'.* suffix can only be used with `==` or `!=` operators',
|
6434
|
+
span_start=span_start,
|
6435
|
+
span_end=tokenizer.position + 1,
|
6436
|
+
)
|
6437
|
+
if tokenizer.check('VERSION_LOCAL_LABEL_TRAIL', peek=True):
|
6438
|
+
tokenizer.raise_syntax_error(
|
6439
|
+
'Local version label can only be used with `==` or `!=` operators',
|
6440
|
+
span_start=span_start,
|
6441
|
+
span_end=tokenizer.position,
|
6442
|
+
)
|
6443
|
+
tokenizer.consume('WS')
|
6444
|
+
if not tokenizer.check('COMMA'):
|
6445
|
+
break
|
6446
|
+
parsed_specifiers += tokenizer.read().text
|
6447
|
+
tokenizer.consume('WS')
|
6448
|
+
|
6449
|
+
return parsed_specifiers
|
6450
|
+
|
6451
|
+
|
6452
|
+
def parse_requires_marker(source: str) -> RequiresMarkerList:
|
6453
|
+
return _parse_requires_full_marker(RequiresTokenizer(source, rules=REQUIRES_DEFAULT_RULES))
|
6454
|
+
|
6455
|
+
|
6456
|
+
def _parse_requires_full_marker(tokenizer: RequiresTokenizer) -> RequiresMarkerList:
|
6457
|
+
retval = _parse_requires_marker(tokenizer)
|
6458
|
+
tokenizer.expect('END', expected='end of marker expression')
|
6459
|
+
return retval
|
6460
|
+
|
6461
|
+
|
6462
|
+
def _parse_requires_marker(tokenizer: RequiresTokenizer) -> RequiresMarkerList:
|
6463
|
+
expression = [_parse_requires_marker_atom(tokenizer)]
|
6464
|
+
while tokenizer.check('BOOLOP'):
|
6465
|
+
token = tokenizer.read()
|
6466
|
+
expr_right = _parse_requires_marker_atom(tokenizer)
|
6467
|
+
expression.extend((token.text, expr_right))
|
6468
|
+
return expression
|
6469
|
+
|
6470
|
+
|
6471
|
+
def _parse_requires_marker_atom(tokenizer: RequiresTokenizer) -> RequiresMarkerAtom:
|
6472
|
+
tokenizer.consume('WS')
|
6473
|
+
if tokenizer.check('LEFT_PARENTHESIS', peek=True):
|
6474
|
+
with tokenizer.enclosing_tokens(
|
6475
|
+
'LEFT_PARENTHESIS',
|
6476
|
+
'RIGHT_PARENTHESIS',
|
6477
|
+
around='marker expression',
|
6478
|
+
):
|
6479
|
+
tokenizer.consume('WS')
|
6480
|
+
marker: RequiresMarkerAtom = _parse_requires_marker(tokenizer)
|
6481
|
+
tokenizer.consume('WS')
|
6482
|
+
else:
|
6483
|
+
marker = _parse_requires_marker_item(tokenizer)
|
6484
|
+
tokenizer.consume('WS')
|
6485
|
+
return marker
|
6486
|
+
|
6487
|
+
|
6488
|
+
def _parse_requires_marker_item(tokenizer: RequiresTokenizer) -> RequiresMarkerItem:
|
6489
|
+
tokenizer.consume('WS')
|
6490
|
+
marker_var_left = _parse_requires_marker_var(tokenizer)
|
6491
|
+
tokenizer.consume('WS')
|
6492
|
+
marker_op = _parse_requires_marker_op(tokenizer)
|
6493
|
+
tokenizer.consume('WS')
|
6494
|
+
marker_var_right = _parse_requires_marker_var(tokenizer)
|
6495
|
+
tokenizer.consume('WS')
|
6496
|
+
return RequiresMarkerItem(marker_var_left, marker_op, marker_var_right)
|
6497
|
+
|
6498
|
+
|
6499
|
+
def _parse_requires_marker_var(tokenizer: RequiresTokenizer) -> RequiresMarkerVar:
|
6500
|
+
if tokenizer.check('VARIABLE'):
|
6501
|
+
return process_requires_env_var(tokenizer.read().text.replace('.', '_'))
|
6502
|
+
elif tokenizer.check('QUOTED_STRING'):
|
6503
|
+
return process_requires_python_str(tokenizer.read().text)
|
6504
|
+
else:
|
6505
|
+
tokenizer.raise_syntax_error(message='Expected a marker variable or quoted string')
|
6506
|
+
raise RuntimeError # noqa
|
6507
|
+
|
6508
|
+
|
6509
|
+
def process_requires_env_var(env_var: str) -> RequiresVariable:
|
6510
|
+
if env_var in ('platform_python_implementation', 'python_implementation'):
|
6511
|
+
return RequiresVariable('platform_python_implementation')
|
6512
|
+
else:
|
6513
|
+
return RequiresVariable(env_var)
|
6514
|
+
|
6515
|
+
|
6516
|
+
def process_requires_python_str(python_str: str) -> RequiresValue:
|
6517
|
+
value = ast.literal_eval(python_str)
|
6518
|
+
return RequiresValue(str(value))
|
6519
|
+
|
6520
|
+
|
6521
|
+
def _parse_requires_marker_op(tokenizer: RequiresTokenizer) -> RequiresOp:
|
6522
|
+
if tokenizer.check('IN'):
|
6523
|
+
tokenizer.read()
|
6524
|
+
return RequiresOp('in')
|
6525
|
+
elif tokenizer.check('NOT'):
|
6526
|
+
tokenizer.read()
|
6527
|
+
tokenizer.expect('WS', expected="whitespace after 'not'")
|
6528
|
+
tokenizer.expect('IN', expected="'in' after 'not'")
|
6529
|
+
return RequiresOp('not in')
|
6530
|
+
elif tokenizer.check('OP'):
|
6531
|
+
return RequiresOp(tokenizer.read().text)
|
6532
|
+
else:
|
6533
|
+
return tokenizer.raise_syntax_error(
|
6534
|
+
'Expected marker operator, one of '
|
6535
|
+
'<=, <, !=, ==, >=, >, ~=, ===, in, not in',
|
6536
|
+
)
|
6537
|
+
|
6538
|
+
|
5997
6539
|
########################################
|
5998
6540
|
# ../../../omlish/asyncs/asyncio/timeouts.py
|
5999
6541
|
|
@@ -9684,11 +10226,14 @@ log = get_module_logger(globals()) # noqa
|
|
9684
10226
|
class RequirementsRewriter:
|
9685
10227
|
def __init__(
|
9686
10228
|
self,
|
10229
|
+
*,
|
9687
10230
|
venv: ta.Optional[str] = None,
|
10231
|
+
only_pats: ta.Optional[ta.Sequence[re.Pattern]] = None,
|
9688
10232
|
) -> None:
|
9689
10233
|
super().__init__()
|
9690
10234
|
|
9691
10235
|
self._venv = venv
|
10236
|
+
self._only_pats = only_pats
|
9692
10237
|
|
9693
10238
|
@cached_nullary
|
9694
10239
|
def _tmp_dir(self) -> str:
|
@@ -9704,17 +10249,32 @@ class RequirementsRewriter:
|
|
9704
10249
|
out_lines = []
|
9705
10250
|
|
9706
10251
|
for l in in_lines:
|
9707
|
-
if
|
9708
|
-
lp, _, rp = l.partition(self.VENV_MAGIC)
|
9709
|
-
rp = rp.partition('#')[0]
|
10252
|
+
if l.split('#')[0].strip():
|
9710
10253
|
omit = False
|
9711
|
-
|
9712
|
-
|
9713
|
-
|
9714
|
-
|
9715
|
-
|
10254
|
+
|
10255
|
+
if self.VENV_MAGIC in l:
|
10256
|
+
lp, _, rp = l.partition(self.VENV_MAGIC)
|
10257
|
+
rp = rp.partition('#')[0]
|
10258
|
+
for v in rp.split():
|
10259
|
+
if v[0] == '!':
|
10260
|
+
if self._venv is not None and self._venv == v[1:]:
|
10261
|
+
omit = True
|
10262
|
+
break
|
10263
|
+
else:
|
10264
|
+
raise NotImplementedError
|
10265
|
+
|
10266
|
+
if (
|
10267
|
+
not omit and
|
10268
|
+
(ops := self._only_pats) is not None and
|
10269
|
+
not l.strip().startswith('-')
|
10270
|
+
):
|
10271
|
+
try:
|
10272
|
+
pr = parse_requirement(l.split('#')[0].strip())
|
10273
|
+
except RequiresParserSyntaxError:
|
10274
|
+
pass
|
9716
10275
|
else:
|
9717
|
-
|
10276
|
+
if not any(op.fullmatch(pr.name) for op in ops):
|
10277
|
+
omit = True
|
9718
10278
|
|
9719
10279
|
if omit:
|
9720
10280
|
out_lines.append('# OMITTED: ' + l)
|
@@ -11020,6 +11580,7 @@ def get_default_interp_resolver() -> InterpResolver:
|
|
11020
11580
|
class InterpVenvConfig:
|
11021
11581
|
interp: ta.Optional[str] = None
|
11022
11582
|
requires: ta.Optional[ta.Sequence[str]] = None
|
11583
|
+
requires_pats: ta.Optional[ta.Sequence[str]] = None
|
11023
11584
|
use_uv: ta.Optional[bool] = None
|
11024
11585
|
|
11025
11586
|
|
@@ -11244,7 +11805,13 @@ class Venv:
|
|
11244
11805
|
|
11245
11806
|
@cached_nullary
|
11246
11807
|
def _iv(self) -> InterpVenv:
|
11247
|
-
rr = RequirementsRewriter(
|
11808
|
+
rr = RequirementsRewriter(
|
11809
|
+
venv=self._name,
|
11810
|
+
only_pats=(
|
11811
|
+
[re.compile(p) for p in self._cfg.requires_pats]
|
11812
|
+
if self._cfg.requires_pats is not None else None
|
11813
|
+
),
|
11814
|
+
)
|
11248
11815
|
|
11249
11816
|
return InterpVenv(
|
11250
11817
|
self.dir_name,
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: omdev
|
3
|
-
Version: 0.0.0.
|
3
|
+
Version: 0.0.0.dev442
|
4
4
|
Summary: omdev
|
5
5
|
Author: wrmsr
|
6
6
|
License-Expression: BSD-3-Clause
|
@@ -14,7 +14,7 @@ Classifier: Programming Language :: Python :: 3.13
|
|
14
14
|
Requires-Python: >=3.13
|
15
15
|
Description-Content-Type: text/markdown
|
16
16
|
License-File: LICENSE
|
17
|
-
Requires-Dist: omlish==0.0.0.
|
17
|
+
Requires-Dist: omlish==0.0.0.dev442
|
18
18
|
Provides-Extra: all
|
19
19
|
Requires-Dist: black~=25.1; extra == "all"
|
20
20
|
Requires-Dist: pycparser~=2.23; extra == "all"
|
@@ -159,7 +159,7 @@ omdev/interp/inject.py,sha256=MOppFILGFCp2f4-2uwmH5fN-7erHI3RyMQJaG0kw0Gc,1569
|
|
159
159
|
omdev/interp/inspect.py,sha256=GLjqRkmNr3H0CZsiFqizM_2yfUL7hSD-BGYysNcVi_Q,3018
|
160
160
|
omdev/interp/resolvers.py,sha256=9ExwP0wcQ4mzyTLNurSG4Dg1AQ_IqLfR2ZyqR4VRANE,2590
|
161
161
|
omdev/interp/types.py,sha256=Pr0wrVpNasoCw-ThEvKC5LG30Civ7YJ4EONwrwBLpy0,2516
|
162
|
-
omdev/interp/venvs.py,sha256=
|
162
|
+
omdev/interp/venvs.py,sha256=KAnkHGP8jV8KmiarRl2wuMbya-CEgyN6hEM68irGOxs,3362
|
163
163
|
omdev/interp/providers/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
164
164
|
omdev/interp/providers/base.py,sha256=zMtzMJIDvaI0q1gtsZTCvFiTc7qdhGbUcXRs6LCBmgo,1333
|
165
165
|
omdev/interp/providers/inject.py,sha256=NSDFBQVD3ZR9Mf162XB9_VvTUAXGCRhPcrjVlYcFDJk,857
|
@@ -184,7 +184,7 @@ omdev/magic/prepare.py,sha256=SEOK-bl4zDxq0aphYXsEI-hCjbkV908VNnJt-dk0kL4,594
|
|
184
184
|
omdev/magic/styles.py,sha256=6LAL7XR3fkkH2rh-8nwUvdCYVHBkQxCfP0oEuPuw1Bg,670
|
185
185
|
omdev/manifests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
186
186
|
omdev/manifests/__main__.py,sha256=JqyVDyV7_jo-NZ3wSs5clDU_xCMlxzJv-XFohoZWQ7E,174
|
187
|
-
omdev/manifests/_dumping.py,sha256=
|
187
|
+
omdev/manifests/_dumping.py,sha256=Y2zGFyRUwqqMHAvPpOsrHJhvlAz3oRl3Y7uqIT5J_Cg,54355
|
188
188
|
omdev/manifests/building.py,sha256=M3IHQljk0ca0J32-xNTOcFVvW07s_7fHQ7sGsCJeurU,13908
|
189
189
|
omdev/manifests/dumping.py,sha256=WUIZDvOyO25AhnCPn5Nxj2OkMcZa1LRjGuCnpyx8AL8,4506
|
190
190
|
omdev/manifests/main.py,sha256=mYb8iM5bdwaO8jSd9_hIBSoYLf2h7e0iLb9aCCbgJ6c,2175
|
@@ -208,7 +208,7 @@ omdev/oci/pack/unpacking.py,sha256=tVYw8REKuYd4ciGXwMmXxlp4CRLHdET_gB9ShYh1d_M,6
|
|
208
208
|
omdev/packaging/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
209
209
|
omdev/packaging/marshal.py,sha256=nr7wN-Pi3FGAuh3HaladzDgOgyQl1-vtmxJ_AUOo4d8,2355
|
210
210
|
omdev/packaging/names.py,sha256=-orp16m20gSFeKRiGkRNyqFVV4S1y_Djvjdq_5hNwpY,2533
|
211
|
-
omdev/packaging/requires.py,sha256=
|
211
|
+
omdev/packaging/requires.py,sha256=nn4ff8mlgfsdZooKzQjhASFS7mMVUCCmcb-150F0Lcg,15739
|
212
212
|
omdev/packaging/revisions.py,sha256=tLNDVtPiygB8mSxwp-kDxeEHhpBzD0jayndjsgUOfkM,5055
|
213
213
|
omdev/packaging/specifiers.py,sha256=t6UhvSlmwHmSvqqPb4XnCq9H41HiqeAqRvCUy2DF_P8,17487
|
214
214
|
omdev/packaging/versions.py,sha256=SBh4LYfBYVi8SXMoWcOWY-Y3llOF-6cxayVaIM1NXMs,12371
|
@@ -267,19 +267,19 @@ omdev/pyproject/cli.py,sha256=Umsu2bcJUYeeVXICaZFhKckUBT6VWuYDL4htgCGGQIs,8749
|
|
267
267
|
omdev/pyproject/configs.py,sha256=baNRwHtUW8S8DKCxuKlMbV3Gduujd1PyNURxQ48Nnxk,2813
|
268
268
|
omdev/pyproject/inject.py,sha256=Von8_8ofkITLoCEwDHNRAwY0AEdFQg7r2ILS8kcTMuY,325
|
269
269
|
omdev/pyproject/pkg.py,sha256=CcWBhsOgim8MYe5ryKDGB8ClRIyiCX6YmYUHRbQ5q_Y,14964
|
270
|
-
omdev/pyproject/reqs.py,sha256=
|
271
|
-
omdev/pyproject/venvs.py,sha256=
|
270
|
+
omdev/pyproject/reqs.py,sha256=DU7NBNpFTjU06VgqRYZj5jZRQxpIWbzL9q9Vm13_o0o,3317
|
271
|
+
omdev/pyproject/venvs.py,sha256=PNgfVrGlw9NFKJgUyzyWH5H5nAIzUDPTHRVUNBM0bKs,2187
|
272
272
|
omdev/pyproject/resources/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
273
273
|
omdev/pyproject/resources/docker-dev.sh,sha256=DHkz5D18jok_oDolfg2mqrvGRWFoCe9GQo04dR1czcc,838
|
274
274
|
omdev/pyproject/resources/python.sh,sha256=rFaN4SiJ9hdLDXXsDTwugI6zsw6EPkgYMmtacZeTbvw,749
|
275
275
|
omdev/scripts/__init__.py,sha256=MKCvUAEQwsIvwLixwtPlpBqmkMXLCnjjXyAXvVpDwVk,91
|
276
|
-
omdev/scripts/ci.py,sha256=
|
277
|
-
omdev/scripts/interp.py,sha256
|
278
|
-
omdev/scripts/pyproject.py,sha256=
|
276
|
+
omdev/scripts/ci.py,sha256=0mb5CkL2y6_ZkMM5xXLEoVkPlh-c5_mb-Ezk45xYdCI,426377
|
277
|
+
omdev/scripts/interp.py,sha256=EaKZtDiopNF0i8Wf_DSYyM8c10aAGL41_1FUxCpSjxE,168417
|
278
|
+
omdev/scripts/pyproject.py,sha256=8V1bQYXcFRidO2y2adAiyX8VZyG4RMuFzW9DzSqOrgU,349087
|
279
279
|
omdev/scripts/slowcat.py,sha256=PwdT-pg62imEEb6kcOozl9_YUi-4KopvjvzWT1OmGb0,2717
|
280
280
|
omdev/scripts/tmpexec.py,sha256=t0nErDRALjTk7H0X8ADjZUIDFjlPNzOOokmjCjBHdzs,1431
|
281
281
|
omdev/scripts/lib/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
282
|
-
omdev/scripts/lib/inject.py,sha256=
|
282
|
+
omdev/scripts/lib/inject.py,sha256=dregGw2IK_yBHR8rUKamV-sRx4YW_NUZAy-xrnfyie0,53675
|
283
283
|
omdev/scripts/lib/logs.py,sha256=zRZYc-P9B0-uSETpIXNkNmb874jVvTfKtmUSJ47yZFw,63073
|
284
284
|
omdev/scripts/lib/marshal.py,sha256=DOsUKJ1U3mwsNN1Et20cqJUBlzZZcmAv1m-zxMKHYEQ,46835
|
285
285
|
omdev/tokens/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
@@ -323,9 +323,9 @@ omdev/tools/jsonview/resources/jsonview.js,sha256=faDvXDOXKvEvjOuIlz4D3F2ReQXb_b
|
|
323
323
|
omdev/tools/pawk/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
324
324
|
omdev/tools/pawk/__main__.py,sha256=VCqeRVnqT1RPEoIrqHFSu4PXVMg4YEgF4qCQm90-eRI,66
|
325
325
|
omdev/tools/pawk/pawk.py,sha256=ao5mdrpiSU4AZ8mBozoEaV3UVlmVTnRG9wD9XP70MZE,11429
|
326
|
-
omdev-0.0.0.
|
327
|
-
omdev-0.0.0.
|
328
|
-
omdev-0.0.0.
|
329
|
-
omdev-0.0.0.
|
330
|
-
omdev-0.0.0.
|
331
|
-
omdev-0.0.0.
|
326
|
+
omdev-0.0.0.dev442.dist-info/licenses/LICENSE,sha256=B_hVtavaA8zCYDW99DYdcpDLKz1n3BBRjZrcbv8uG8c,1451
|
327
|
+
omdev-0.0.0.dev442.dist-info/METADATA,sha256=4k0ARrn_Yw1duxD03gcbzVeFcT6qrTO3ncUSCkVNpvc,5100
|
328
|
+
omdev-0.0.0.dev442.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
329
|
+
omdev-0.0.0.dev442.dist-info/entry_points.txt,sha256=dHLXFmq5D9B8qUyhRtFqTGWGxlbx3t5ejedjrnXNYLU,33
|
330
|
+
omdev-0.0.0.dev442.dist-info/top_level.txt,sha256=1nr7j30fEWgLYHW3lGR9pkdHkb7knv1U1ES1XRNVQ6k,6
|
331
|
+
omdev-0.0.0.dev442.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|