omdev 0.0.0.dev224__py3-none-any.whl → 0.0.0.dev226__py3-none-any.whl
Sign up to get free protection for your applications and to get access to all the features.
- omdev/amalg/typing.py +7 -1
- omdev/ci/requirements.py +1 -1
- omdev/git/revisions.py +2 -2
- omdev/git/shallow.py +1 -1
- omdev/git/status.py +1 -1
- omdev/precheck/lite.py +1 -1
- omdev/pyproject/pkg.py +1 -1
- omdev/scripts/ci.py +600 -296
- omdev/scripts/interp.py +501 -343
- omdev/scripts/pyproject.py +603 -299
- {omdev-0.0.0.dev224.dist-info → omdev-0.0.0.dev226.dist-info}/METADATA +2 -2
- {omdev-0.0.0.dev224.dist-info → omdev-0.0.0.dev226.dist-info}/RECORD +16 -16
- {omdev-0.0.0.dev224.dist-info → omdev-0.0.0.dev226.dist-info}/LICENSE +0 -0
- {omdev-0.0.0.dev224.dist-info → omdev-0.0.0.dev226.dist-info}/WHEEL +0 -0
- {omdev-0.0.0.dev224.dist-info → omdev-0.0.0.dev226.dist-info}/entry_points.txt +0 -0
- {omdev-0.0.0.dev224.dist-info → omdev-0.0.0.dev226.dist-info}/top_level.txt +0 -0
omdev/scripts/interp.py
CHANGED
@@ -57,9 +57,6 @@ VersionCmpLocalType = ta.Union['NegativeInfinityVersionType', _VersionCmpLocalTy
|
|
57
57
|
VersionCmpKey = ta.Tuple[int, ta.Tuple[int, ...], VersionCmpPrePostDevType, VersionCmpPrePostDevType, VersionCmpPrePostDevType, VersionCmpLocalType] # noqa
|
58
58
|
VersionComparisonMethod = ta.Callable[[VersionCmpKey, VersionCmpKey], bool]
|
59
59
|
|
60
|
-
# ../../omlish/asyncs/asyncio/timeouts.py
|
61
|
-
AwaitableT = ta.TypeVar('AwaitableT', bound=ta.Awaitable)
|
62
|
-
|
63
60
|
# ../../omlish/lite/cached.py
|
64
61
|
T = ta.TypeVar('T')
|
65
62
|
CallableT = ta.TypeVar('CallableT', bound=ta.Callable)
|
@@ -72,6 +69,9 @@ CheckOnRaiseFn = ta.Callable[[Exception], None] # ta.TypeAlias
|
|
72
69
|
CheckExceptionFactory = ta.Callable[..., Exception] # ta.TypeAlias
|
73
70
|
CheckArgsRenderer = ta.Callable[..., ta.Optional[str]] # ta.TypeAlias
|
74
71
|
|
72
|
+
# ../../omlish/lite/timeouts.py
|
73
|
+
TimeoutLike = ta.Union['Timeout', 'Timeout.Default', ta.Iterable['TimeoutLike'], float] # ta.TypeAlias
|
74
|
+
|
75
75
|
# ../packaging/specifiers.py
|
76
76
|
UnparsedVersion = ta.Union['Version', str]
|
77
77
|
UnparsedVersionVar = ta.TypeVar('UnparsedVersionVar', bound=UnparsedVersion)
|
@@ -80,6 +80,9 @@ CallableVersionOperator = ta.Callable[['Version', str], bool]
|
|
80
80
|
# ../../omlish/argparse/cli.py
|
81
81
|
ArgparseCmdFn = ta.Callable[[], ta.Optional[int]] # ta.TypeAlias
|
82
82
|
|
83
|
+
# ../../omlish/asyncs/asyncio/timeouts.py
|
84
|
+
AwaitableT = ta.TypeVar('AwaitableT', bound=ta.Awaitable)
|
85
|
+
|
83
86
|
# ../../omlish/lite/inject.py
|
84
87
|
U = ta.TypeVar('U')
|
85
88
|
InjectorKeyCls = ta.Union[type, ta.NewType]
|
@@ -87,7 +90,7 @@ InjectorProviderFn = ta.Callable[['Injector'], ta.Any]
|
|
87
90
|
InjectorProviderFnMap = ta.Mapping['InjectorKey', 'InjectorProviderFn']
|
88
91
|
InjectorBindingOrBindings = ta.Union['InjectorBinding', 'InjectorBindings']
|
89
92
|
|
90
|
-
# ../../omlish/subprocesses.py
|
93
|
+
# ../../omlish/subprocesses/base.py
|
91
94
|
SubprocessChannelOption = ta.Literal['pipe', 'stdout', 'devnull'] # ta.TypeAlias
|
92
95
|
|
93
96
|
|
@@ -498,19 +501,6 @@ def canonicalize_version(
|
|
498
501
|
return ''.join(parts)
|
499
502
|
|
500
503
|
|
501
|
-
########################################
|
502
|
-
# ../../../omlish/asyncs/asyncio/timeouts.py
|
503
|
-
|
504
|
-
|
505
|
-
def asyncio_maybe_timeout(
|
506
|
-
fut: AwaitableT,
|
507
|
-
timeout: ta.Optional[float] = None,
|
508
|
-
) -> AwaitableT:
|
509
|
-
if timeout is not None:
|
510
|
-
fut = asyncio.wait_for(fut, timeout) # type: ignore
|
511
|
-
return fut
|
512
|
-
|
513
|
-
|
514
504
|
########################################
|
515
505
|
# ../../../omlish/lite/cached.py
|
516
506
|
|
@@ -1303,6 +1293,205 @@ def format_num_bytes(num_bytes: int) -> str:
|
|
1303
1293
|
return f'{num_bytes / 1024 ** (len(FORMAT_NUM_BYTES_SUFFIXES) - 1):.2f}{FORMAT_NUM_BYTES_SUFFIXES[-1]}'
|
1304
1294
|
|
1305
1295
|
|
1296
|
+
########################################
|
1297
|
+
# ../../../omlish/lite/timeouts.py
|
1298
|
+
"""
|
1299
|
+
TODO:
|
1300
|
+
- Event (/ Predicate)
|
1301
|
+
"""
|
1302
|
+
|
1303
|
+
|
1304
|
+
##
|
1305
|
+
|
1306
|
+
|
1307
|
+
class Timeout(abc.ABC):
|
1308
|
+
@property
|
1309
|
+
@abc.abstractmethod
|
1310
|
+
def can_expire(self) -> bool:
|
1311
|
+
"""Indicates whether or not this timeout will ever expire."""
|
1312
|
+
|
1313
|
+
raise NotImplementedError
|
1314
|
+
|
1315
|
+
@abc.abstractmethod
|
1316
|
+
def expired(self) -> bool:
|
1317
|
+
"""Return whether or not this timeout has expired."""
|
1318
|
+
|
1319
|
+
raise NotImplementedError
|
1320
|
+
|
1321
|
+
@abc.abstractmethod
|
1322
|
+
def remaining(self) -> float:
|
1323
|
+
"""Returns the time (in seconds) remaining until the timeout expires. May be negative and/or infinite."""
|
1324
|
+
|
1325
|
+
raise NotImplementedError
|
1326
|
+
|
1327
|
+
@abc.abstractmethod
|
1328
|
+
def __call__(self) -> float:
|
1329
|
+
"""Returns the time (in seconds) remaining until the timeout expires, or raises if the timeout has expired."""
|
1330
|
+
|
1331
|
+
raise NotImplementedError
|
1332
|
+
|
1333
|
+
@abc.abstractmethod
|
1334
|
+
def or_(self, o: ta.Any) -> ta.Any:
|
1335
|
+
"""Evaluates time remaining via remaining() if this timeout can expire, otherwise returns `o`."""
|
1336
|
+
|
1337
|
+
raise NotImplementedError
|
1338
|
+
|
1339
|
+
#
|
1340
|
+
|
1341
|
+
@classmethod
|
1342
|
+
def _now(cls) -> float:
|
1343
|
+
return time.time()
|
1344
|
+
|
1345
|
+
#
|
1346
|
+
|
1347
|
+
class Default:
|
1348
|
+
def __new__(cls, *args, **kwargs): # noqa
|
1349
|
+
raise TypeError
|
1350
|
+
|
1351
|
+
class _NOT_SPECIFIED: # noqa
|
1352
|
+
def __new__(cls, *args, **kwargs): # noqa
|
1353
|
+
raise TypeError
|
1354
|
+
|
1355
|
+
@classmethod
|
1356
|
+
def of(
|
1357
|
+
cls,
|
1358
|
+
obj: ta.Optional[TimeoutLike],
|
1359
|
+
default: ta.Union[TimeoutLike, ta.Type[_NOT_SPECIFIED]] = _NOT_SPECIFIED,
|
1360
|
+
) -> 'Timeout':
|
1361
|
+
if obj is None:
|
1362
|
+
return InfiniteTimeout()
|
1363
|
+
|
1364
|
+
elif isinstance(obj, Timeout):
|
1365
|
+
return obj
|
1366
|
+
|
1367
|
+
elif isinstance(obj, (float, int)):
|
1368
|
+
return DeadlineTimeout(cls._now() + obj)
|
1369
|
+
|
1370
|
+
elif isinstance(obj, ta.Iterable):
|
1371
|
+
return CompositeTimeout(*[Timeout.of(c) for c in obj])
|
1372
|
+
|
1373
|
+
elif obj is Timeout.Default:
|
1374
|
+
if default is Timeout._NOT_SPECIFIED or default is Timeout.Default:
|
1375
|
+
raise RuntimeError('Must specify a default timeout')
|
1376
|
+
|
1377
|
+
else:
|
1378
|
+
return Timeout.of(default) # type: ignore[arg-type]
|
1379
|
+
|
1380
|
+
else:
|
1381
|
+
raise TypeError(obj)
|
1382
|
+
|
1383
|
+
@classmethod
|
1384
|
+
def of_deadline(cls, deadline: float) -> 'DeadlineTimeout':
|
1385
|
+
return DeadlineTimeout(deadline)
|
1386
|
+
|
1387
|
+
@classmethod
|
1388
|
+
def of_predicate(cls, expired_fn: ta.Callable[[], bool]) -> 'PredicateTimeout':
|
1389
|
+
return PredicateTimeout(expired_fn)
|
1390
|
+
|
1391
|
+
|
1392
|
+
class DeadlineTimeout(Timeout):
|
1393
|
+
def __init__(
|
1394
|
+
self,
|
1395
|
+
deadline: float,
|
1396
|
+
exc: ta.Union[ta.Type[BaseException], BaseException] = TimeoutError,
|
1397
|
+
) -> None:
|
1398
|
+
super().__init__()
|
1399
|
+
|
1400
|
+
self.deadline = deadline
|
1401
|
+
self.exc = exc
|
1402
|
+
|
1403
|
+
@property
|
1404
|
+
def can_expire(self) -> bool:
|
1405
|
+
return True
|
1406
|
+
|
1407
|
+
def expired(self) -> bool:
|
1408
|
+
return not (self.remaining() > 0)
|
1409
|
+
|
1410
|
+
def remaining(self) -> float:
|
1411
|
+
return self.deadline - self._now()
|
1412
|
+
|
1413
|
+
def __call__(self) -> float:
|
1414
|
+
if (rem := self.remaining()) > 0:
|
1415
|
+
return rem
|
1416
|
+
raise self.exc
|
1417
|
+
|
1418
|
+
def or_(self, o: ta.Any) -> ta.Any:
|
1419
|
+
return self()
|
1420
|
+
|
1421
|
+
|
1422
|
+
class InfiniteTimeout(Timeout):
|
1423
|
+
@property
|
1424
|
+
def can_expire(self) -> bool:
|
1425
|
+
return False
|
1426
|
+
|
1427
|
+
def expired(self) -> bool:
|
1428
|
+
return False
|
1429
|
+
|
1430
|
+
def remaining(self) -> float:
|
1431
|
+
return float('inf')
|
1432
|
+
|
1433
|
+
def __call__(self) -> float:
|
1434
|
+
return float('inf')
|
1435
|
+
|
1436
|
+
def or_(self, o: ta.Any) -> ta.Any:
|
1437
|
+
return o
|
1438
|
+
|
1439
|
+
|
1440
|
+
class CompositeTimeout(Timeout):
|
1441
|
+
def __init__(self, *children: Timeout) -> None:
|
1442
|
+
super().__init__()
|
1443
|
+
|
1444
|
+
self.children = children
|
1445
|
+
|
1446
|
+
@property
|
1447
|
+
def can_expire(self) -> bool:
|
1448
|
+
return any(c.can_expire for c in self.children)
|
1449
|
+
|
1450
|
+
def expired(self) -> bool:
|
1451
|
+
return any(c.expired() for c in self.children)
|
1452
|
+
|
1453
|
+
def remaining(self) -> float:
|
1454
|
+
return min(c.remaining() for c in self.children)
|
1455
|
+
|
1456
|
+
def __call__(self) -> float:
|
1457
|
+
return min(c() for c in self.children)
|
1458
|
+
|
1459
|
+
def or_(self, o: ta.Any) -> ta.Any:
|
1460
|
+
if self.can_expire:
|
1461
|
+
return self()
|
1462
|
+
return o
|
1463
|
+
|
1464
|
+
|
1465
|
+
class PredicateTimeout(Timeout):
|
1466
|
+
def __init__(
|
1467
|
+
self,
|
1468
|
+
expired_fn: ta.Callable[[], bool],
|
1469
|
+
exc: ta.Union[ta.Type[BaseException], BaseException] = TimeoutError,
|
1470
|
+
) -> None:
|
1471
|
+
super().__init__()
|
1472
|
+
|
1473
|
+
self.expired_fn = expired_fn
|
1474
|
+
self.exc = exc
|
1475
|
+
|
1476
|
+
@property
|
1477
|
+
def can_expire(self) -> bool:
|
1478
|
+
return True
|
1479
|
+
|
1480
|
+
def expired(self) -> bool:
|
1481
|
+
return self.expired_fn()
|
1482
|
+
|
1483
|
+
def remaining(self) -> float:
|
1484
|
+
return float('inf')
|
1485
|
+
|
1486
|
+
def __call__(self) -> float:
|
1487
|
+
if not self.expired_fn():
|
1488
|
+
return float('inf')
|
1489
|
+
raise self.exc
|
1490
|
+
|
1491
|
+
def or_(self, o: ta.Any) -> ta.Any:
|
1492
|
+
return self()
|
1493
|
+
|
1494
|
+
|
1306
1495
|
########################################
|
1307
1496
|
# ../../../omlish/logs/filters.py
|
1308
1497
|
|
@@ -2224,6 +2413,19 @@ class ArgparseCli:
|
|
2224
2413
|
return fn()
|
2225
2414
|
|
2226
2415
|
|
2416
|
+
########################################
|
2417
|
+
# ../../../omlish/asyncs/asyncio/timeouts.py
|
2418
|
+
|
2419
|
+
|
2420
|
+
def asyncio_maybe_timeout(
|
2421
|
+
fut: AwaitableT,
|
2422
|
+
timeout: ta.Optional[TimeoutLike] = None,
|
2423
|
+
) -> AwaitableT:
|
2424
|
+
if timeout is not None:
|
2425
|
+
fut = asyncio.wait_for(fut, Timeout.of(timeout)()) # type: ignore
|
2426
|
+
return fut
|
2427
|
+
|
2428
|
+
|
2227
2429
|
########################################
|
2228
2430
|
# ../../../omlish/lite/inject.py
|
2229
2431
|
|
@@ -3369,6 +3571,137 @@ class JsonLogFormatter(logging.Formatter):
|
|
3369
3571
|
return self._json_dumps(dct)
|
3370
3572
|
|
3371
3573
|
|
3574
|
+
########################################
|
3575
|
+
# ../../../omlish/subprocesses/run.py
|
3576
|
+
|
3577
|
+
|
3578
|
+
##
|
3579
|
+
|
3580
|
+
|
3581
|
+
@dc.dataclass(frozen=True)
|
3582
|
+
class SubprocessRunOutput(ta.Generic[T]):
|
3583
|
+
proc: T
|
3584
|
+
|
3585
|
+
returncode: int # noqa
|
3586
|
+
|
3587
|
+
stdout: ta.Optional[bytes] = None
|
3588
|
+
stderr: ta.Optional[bytes] = None
|
3589
|
+
|
3590
|
+
|
3591
|
+
##
|
3592
|
+
|
3593
|
+
|
3594
|
+
@dc.dataclass(frozen=True)
|
3595
|
+
class SubprocessRun:
|
3596
|
+
cmd: ta.Sequence[str]
|
3597
|
+
input: ta.Any = None
|
3598
|
+
timeout: ta.Optional[TimeoutLike] = None
|
3599
|
+
check: bool = False
|
3600
|
+
capture_output: ta.Optional[bool] = None
|
3601
|
+
kwargs: ta.Optional[ta.Mapping[str, ta.Any]] = None
|
3602
|
+
|
3603
|
+
#
|
3604
|
+
|
3605
|
+
_FIELD_NAMES: ta.ClassVar[ta.FrozenSet[str]]
|
3606
|
+
|
3607
|
+
def replace(self, **kwargs: ta.Any) -> 'SubprocessRun':
|
3608
|
+
if not kwargs:
|
3609
|
+
return self
|
3610
|
+
|
3611
|
+
field_kws = {}
|
3612
|
+
extra_kws = {}
|
3613
|
+
for k, v in kwargs.items():
|
3614
|
+
if k in self._FIELD_NAMES:
|
3615
|
+
field_kws[k] = v
|
3616
|
+
else:
|
3617
|
+
extra_kws[k] = v
|
3618
|
+
|
3619
|
+
return dc.replace(self, **{
|
3620
|
+
**dict(kwargs={
|
3621
|
+
**(self.kwargs or {}),
|
3622
|
+
**extra_kws,
|
3623
|
+
}),
|
3624
|
+
**field_kws, # passing a kwarg named 'kwargs' intentionally clobbers
|
3625
|
+
})
|
3626
|
+
|
3627
|
+
#
|
3628
|
+
|
3629
|
+
@classmethod
|
3630
|
+
def of(
|
3631
|
+
cls,
|
3632
|
+
*cmd: str,
|
3633
|
+
input: ta.Any = None, # noqa
|
3634
|
+
timeout: ta.Optional[TimeoutLike] = None,
|
3635
|
+
check: bool = False, # noqa
|
3636
|
+
capture_output: ta.Optional[bool] = None,
|
3637
|
+
**kwargs: ta.Any,
|
3638
|
+
) -> 'SubprocessRun':
|
3639
|
+
return cls(
|
3640
|
+
cmd=cmd,
|
3641
|
+
input=input,
|
3642
|
+
timeout=timeout,
|
3643
|
+
check=check,
|
3644
|
+
capture_output=capture_output,
|
3645
|
+
kwargs=kwargs,
|
3646
|
+
)
|
3647
|
+
|
3648
|
+
#
|
3649
|
+
|
3650
|
+
_DEFAULT_SUBPROCESSES: ta.ClassVar[ta.Optional[ta.Any]] = None # AbstractSubprocesses
|
3651
|
+
|
3652
|
+
def run(
|
3653
|
+
self,
|
3654
|
+
subprocesses: ta.Optional[ta.Any] = None, # AbstractSubprocesses
|
3655
|
+
**kwargs: ta.Any,
|
3656
|
+
) -> SubprocessRunOutput:
|
3657
|
+
if subprocesses is None:
|
3658
|
+
subprocesses = self._DEFAULT_SUBPROCESSES
|
3659
|
+
return check.not_none(subprocesses).run_(self.replace(**kwargs)) # type: ignore[attr-defined]
|
3660
|
+
|
3661
|
+
_DEFAULT_ASYNC_SUBPROCESSES: ta.ClassVar[ta.Optional[ta.Any]] = None # AbstractAsyncSubprocesses
|
3662
|
+
|
3663
|
+
async def async_run(
|
3664
|
+
self,
|
3665
|
+
async_subprocesses: ta.Optional[ta.Any] = None, # AbstractAsyncSubprocesses
|
3666
|
+
**kwargs: ta.Any,
|
3667
|
+
) -> SubprocessRunOutput:
|
3668
|
+
if async_subprocesses is None:
|
3669
|
+
async_subprocesses = self._DEFAULT_ASYNC_SUBPROCESSES
|
3670
|
+
return await check.not_none(async_subprocesses).run_(self.replace(**kwargs)) # type: ignore[attr-defined]
|
3671
|
+
|
3672
|
+
|
3673
|
+
SubprocessRun._FIELD_NAMES = frozenset(fld.name for fld in dc.fields(SubprocessRun)) # noqa
|
3674
|
+
|
3675
|
+
|
3676
|
+
##
|
3677
|
+
|
3678
|
+
|
3679
|
+
class SubprocessRunnable(abc.ABC, ta.Generic[T]):
|
3680
|
+
@abc.abstractmethod
|
3681
|
+
def make_run(self) -> SubprocessRun:
|
3682
|
+
raise NotImplementedError
|
3683
|
+
|
3684
|
+
@abc.abstractmethod
|
3685
|
+
def handle_run_output(self, output: SubprocessRunOutput) -> T:
|
3686
|
+
raise NotImplementedError
|
3687
|
+
|
3688
|
+
#
|
3689
|
+
|
3690
|
+
def run(
|
3691
|
+
self,
|
3692
|
+
subprocesses: ta.Optional[ta.Any] = None, # AbstractSubprocesses
|
3693
|
+
**kwargs: ta.Any,
|
3694
|
+
) -> T:
|
3695
|
+
return self.handle_run_output(self.make_run().run(subprocesses, **kwargs))
|
3696
|
+
|
3697
|
+
async def async_run(
|
3698
|
+
self,
|
3699
|
+
async_subprocesses: ta.Optional[ta.Any] = None, # AbstractAsyncSubprocesses
|
3700
|
+
**kwargs: ta.Any,
|
3701
|
+
) -> T:
|
3702
|
+
return self.handle_run_output(await self.make_run().async_run(async_subprocesses, **kwargs))
|
3703
|
+
|
3704
|
+
|
3372
3705
|
########################################
|
3373
3706
|
# ../types.py
|
3374
3707
|
|
@@ -3607,23 +3940,7 @@ def configure_standard_logging(
|
|
3607
3940
|
|
3608
3941
|
|
3609
3942
|
########################################
|
3610
|
-
# ../../../omlish/subprocesses.py
|
3611
|
-
|
3612
|
-
|
3613
|
-
##
|
3614
|
-
|
3615
|
-
|
3616
|
-
# Valid channel type kwarg values:
|
3617
|
-
# - A special flag negative int
|
3618
|
-
# - A positive fd int
|
3619
|
-
# - A file-like object
|
3620
|
-
# - None
|
3621
|
-
|
3622
|
-
SUBPROCESS_CHANNEL_OPTION_VALUES: ta.Mapping[SubprocessChannelOption, int] = {
|
3623
|
-
'pipe': subprocess.PIPE,
|
3624
|
-
'stdout': subprocess.STDOUT,
|
3625
|
-
'devnull': subprocess.DEVNULL,
|
3626
|
-
}
|
3943
|
+
# ../../../omlish/subprocesses/wrap.py
|
3627
3944
|
|
3628
3945
|
|
3629
3946
|
##
|
@@ -3643,28 +3960,74 @@ def subprocess_maybe_shell_wrap_exec(*cmd: str) -> ta.Tuple[str, ...]:
|
|
3643
3960
|
return cmd
|
3644
3961
|
|
3645
3962
|
|
3646
|
-
|
3647
|
-
|
3648
|
-
|
3649
|
-
|
3650
|
-
|
3651
|
-
|
3652
|
-
|
3653
|
-
|
3654
|
-
|
3655
|
-
|
3656
|
-
if proc.stderr:
|
3657
|
-
proc.stderr.close()
|
3658
|
-
if proc.stdin:
|
3659
|
-
proc.stdin.close()
|
3660
|
-
|
3661
|
-
proc.wait(timeout)
|
3963
|
+
########################################
|
3964
|
+
# ../providers/base.py
|
3965
|
+
"""
|
3966
|
+
TODO:
|
3967
|
+
- backends
|
3968
|
+
- local builds
|
3969
|
+
- deadsnakes?
|
3970
|
+
- uv
|
3971
|
+
- loose versions
|
3972
|
+
"""
|
3662
3973
|
|
3663
3974
|
|
3664
3975
|
##
|
3665
3976
|
|
3666
3977
|
|
3667
|
-
class
|
3978
|
+
class InterpProvider(abc.ABC):
|
3979
|
+
name: ta.ClassVar[str]
|
3980
|
+
|
3981
|
+
def __init_subclass__(cls, **kwargs: ta.Any) -> None:
|
3982
|
+
super().__init_subclass__(**kwargs)
|
3983
|
+
if abc.ABC not in cls.__bases__ and 'name' not in cls.__dict__:
|
3984
|
+
sfx = 'InterpProvider'
|
3985
|
+
if not cls.__name__.endswith(sfx):
|
3986
|
+
raise NameError(cls)
|
3987
|
+
setattr(cls, 'name', snake_case(cls.__name__[:-len(sfx)]))
|
3988
|
+
|
3989
|
+
@abc.abstractmethod
|
3990
|
+
def get_installed_versions(self, spec: InterpSpecifier) -> ta.Awaitable[ta.Sequence[InterpVersion]]:
|
3991
|
+
raise NotImplementedError
|
3992
|
+
|
3993
|
+
@abc.abstractmethod
|
3994
|
+
def get_installed_version(self, version: InterpVersion) -> ta.Awaitable[Interp]:
|
3995
|
+
raise NotImplementedError
|
3996
|
+
|
3997
|
+
async def get_installable_versions(self, spec: InterpSpecifier) -> ta.Sequence[InterpVersion]:
|
3998
|
+
return []
|
3999
|
+
|
4000
|
+
async def install_version(self, version: InterpVersion) -> Interp:
|
4001
|
+
raise TypeError
|
4002
|
+
|
4003
|
+
|
4004
|
+
InterpProviders = ta.NewType('InterpProviders', ta.Sequence[InterpProvider])
|
4005
|
+
|
4006
|
+
|
4007
|
+
########################################
|
4008
|
+
# ../../../omlish/subprocesses/base.py
|
4009
|
+
|
4010
|
+
|
4011
|
+
##
|
4012
|
+
|
4013
|
+
|
4014
|
+
# Valid channel type kwarg values:
|
4015
|
+
# - A special flag negative int
|
4016
|
+
# - A positive fd int
|
4017
|
+
# - A file-like object
|
4018
|
+
# - None
|
4019
|
+
|
4020
|
+
SUBPROCESS_CHANNEL_OPTION_VALUES: ta.Mapping[SubprocessChannelOption, int] = {
|
4021
|
+
'pipe': subprocess.PIPE,
|
4022
|
+
'stdout': subprocess.STDOUT,
|
4023
|
+
'devnull': subprocess.DEVNULL,
|
4024
|
+
}
|
4025
|
+
|
4026
|
+
|
4027
|
+
##
|
4028
|
+
|
4029
|
+
|
4030
|
+
class VerboseCalledProcessError(subprocess.CalledProcessError):
|
3668
4031
|
@classmethod
|
3669
4032
|
def from_std(cls, e: subprocess.CalledProcessError) -> 'VerboseCalledProcessError':
|
3670
4033
|
return cls(
|
@@ -3741,6 +4104,11 @@ class BaseSubprocesses(abc.ABC): # noqa
|
|
3741
4104
|
|
3742
4105
|
#
|
3743
4106
|
|
4107
|
+
if 'timeout' in kwargs:
|
4108
|
+
kwargs['timeout'] = Timeout.of(kwargs['timeout']).or_(None)
|
4109
|
+
|
4110
|
+
#
|
4111
|
+
|
3744
4112
|
return cmd, dict(
|
3745
4113
|
env=env,
|
3746
4114
|
shell=shell,
|
@@ -3845,174 +4213,96 @@ class BaseSubprocesses(abc.ABC): # noqa
|
|
3845
4213
|
return e
|
3846
4214
|
|
3847
4215
|
|
3848
|
-
|
3849
|
-
|
3850
|
-
|
3851
|
-
@dc.dataclass(frozen=True)
|
3852
|
-
class SubprocessRun:
|
3853
|
-
cmd: ta.Sequence[str]
|
3854
|
-
input: ta.Any = None
|
3855
|
-
timeout: ta.Optional[float] = None
|
3856
|
-
check: bool = False
|
3857
|
-
capture_output: ta.Optional[bool] = None
|
3858
|
-
kwargs: ta.Optional[ta.Mapping[str, ta.Any]] = None
|
3859
|
-
|
3860
|
-
@classmethod
|
3861
|
-
def of(
|
3862
|
-
cls,
|
3863
|
-
*cmd: str,
|
3864
|
-
input: ta.Any = None, # noqa
|
3865
|
-
timeout: ta.Optional[float] = None,
|
3866
|
-
check: bool = False,
|
3867
|
-
capture_output: ta.Optional[bool] = None,
|
3868
|
-
**kwargs: ta.Any,
|
3869
|
-
) -> 'SubprocessRun':
|
3870
|
-
return cls(
|
3871
|
-
cmd=cmd,
|
3872
|
-
input=input,
|
3873
|
-
timeout=timeout,
|
3874
|
-
check=check,
|
3875
|
-
capture_output=capture_output,
|
3876
|
-
kwargs=kwargs,
|
3877
|
-
)
|
4216
|
+
########################################
|
4217
|
+
# ../resolvers.py
|
3878
4218
|
|
3879
4219
|
|
3880
4220
|
@dc.dataclass(frozen=True)
|
3881
|
-
class
|
3882
|
-
|
3883
|
-
|
3884
|
-
returncode: int # noqa
|
3885
|
-
|
3886
|
-
stdout: ta.Optional[bytes] = None
|
3887
|
-
stderr: ta.Optional[bytes] = None
|
3888
|
-
|
3889
|
-
|
3890
|
-
class AbstractSubprocesses(BaseSubprocesses, abc.ABC):
|
3891
|
-
@abc.abstractmethod
|
3892
|
-
def run_(self, run: SubprocessRun) -> SubprocessRunOutput:
|
3893
|
-
raise NotImplementedError
|
3894
|
-
|
3895
|
-
def run(
|
3896
|
-
self,
|
3897
|
-
*cmd: str,
|
3898
|
-
input: ta.Any = None, # noqa
|
3899
|
-
timeout: ta.Optional[float] = None,
|
3900
|
-
check: bool = False,
|
3901
|
-
capture_output: ta.Optional[bool] = None,
|
3902
|
-
**kwargs: ta.Any,
|
3903
|
-
) -> SubprocessRunOutput:
|
3904
|
-
return self.run_(SubprocessRun(
|
3905
|
-
cmd=cmd,
|
3906
|
-
input=input,
|
3907
|
-
timeout=timeout,
|
3908
|
-
check=check,
|
3909
|
-
capture_output=capture_output,
|
3910
|
-
kwargs=kwargs,
|
3911
|
-
))
|
4221
|
+
class InterpResolverProviders:
|
4222
|
+
providers: ta.Sequence[ta.Tuple[str, InterpProvider]]
|
3912
4223
|
|
3913
|
-
#
|
3914
4224
|
|
3915
|
-
|
3916
|
-
def
|
4225
|
+
class InterpResolver:
|
4226
|
+
def __init__(
|
3917
4227
|
self,
|
3918
|
-
|
3919
|
-
stdout: ta.Any = sys.stderr,
|
3920
|
-
**kwargs: ta.Any,
|
4228
|
+
providers: InterpResolverProviders,
|
3921
4229
|
) -> None:
|
3922
|
-
|
3923
|
-
|
3924
|
-
@abc.abstractmethod
|
3925
|
-
def check_output(
|
3926
|
-
self,
|
3927
|
-
*cmd: str,
|
3928
|
-
**kwargs: ta.Any,
|
3929
|
-
) -> bytes:
|
3930
|
-
raise NotImplementedError
|
4230
|
+
super().__init__()
|
3931
4231
|
|
3932
|
-
|
4232
|
+
self._providers: ta.Mapping[str, InterpProvider] = collections.OrderedDict(providers.providers)
|
3933
4233
|
|
3934
|
-
def
|
3935
|
-
|
3936
|
-
|
3937
|
-
|
3938
|
-
|
3939
|
-
|
4234
|
+
async def _resolve_installed(self, spec: InterpSpecifier) -> ta.Optional[ta.Tuple[InterpProvider, InterpVersion]]:
|
4235
|
+
lst = [
|
4236
|
+
(i, si)
|
4237
|
+
for i, p in enumerate(self._providers.values())
|
4238
|
+
for si in await p.get_installed_versions(spec)
|
4239
|
+
if spec.contains(si)
|
4240
|
+
]
|
3940
4241
|
|
3941
|
-
|
4242
|
+
slst = sorted(lst, key=lambda t: (-t[0], t[1].version))
|
4243
|
+
if not slst:
|
4244
|
+
return None
|
3942
4245
|
|
3943
|
-
|
3944
|
-
|
3945
|
-
|
3946
|
-
**kwargs: ta.Any,
|
3947
|
-
) -> bool:
|
3948
|
-
if isinstance(self.try_fn(self.check_call, *cmd, **kwargs), Exception):
|
3949
|
-
return False
|
3950
|
-
else:
|
3951
|
-
return True
|
4246
|
+
bi, bv = slst[-1]
|
4247
|
+
bp = list(self._providers.values())[bi]
|
4248
|
+
return (bp, bv)
|
3952
4249
|
|
3953
|
-
def
|
4250
|
+
async def resolve(
|
3954
4251
|
self,
|
3955
|
-
|
3956
|
-
|
3957
|
-
|
3958
|
-
|
3959
|
-
|
3960
|
-
|
3961
|
-
|
4252
|
+
spec: InterpSpecifier,
|
4253
|
+
*,
|
4254
|
+
install: bool = False,
|
4255
|
+
) -> ta.Optional[Interp]:
|
4256
|
+
tup = await self._resolve_installed(spec)
|
4257
|
+
if tup is not None:
|
4258
|
+
bp, bv = tup
|
4259
|
+
return await bp.get_installed_version(bv)
|
3962
4260
|
|
3963
|
-
|
3964
|
-
self,
|
3965
|
-
*cmd: str,
|
3966
|
-
**kwargs: ta.Any,
|
3967
|
-
) -> ta.Optional[str]:
|
3968
|
-
if (ret := self.try_output(*cmd, **kwargs)) is None:
|
4261
|
+
if not install:
|
3969
4262
|
return None
|
3970
|
-
else:
|
3971
|
-
return ret.decode().strip()
|
3972
|
-
|
3973
|
-
|
3974
|
-
##
|
3975
4263
|
|
4264
|
+
tp = list(self._providers.values())[0] # noqa
|
3976
4265
|
|
3977
|
-
|
3978
|
-
|
3979
|
-
|
3980
|
-
run.cmd,
|
3981
|
-
input=run.input,
|
3982
|
-
timeout=run.timeout,
|
3983
|
-
check=run.check,
|
3984
|
-
capture_output=run.capture_output or False,
|
3985
|
-
**(run.kwargs or {}),
|
4266
|
+
sv = sorted(
|
4267
|
+
[s for s in await tp.get_installable_versions(spec) if s in spec],
|
4268
|
+
key=lambda s: s.version,
|
3986
4269
|
)
|
4270
|
+
if not sv:
|
4271
|
+
return None
|
3987
4272
|
|
3988
|
-
|
3989
|
-
|
3990
|
-
|
3991
|
-
returncode=proc.returncode,
|
4273
|
+
bv = sv[-1]
|
4274
|
+
return await tp.install_version(bv)
|
3992
4275
|
|
3993
|
-
|
3994
|
-
|
3995
|
-
)
|
4276
|
+
async def list(self, spec: InterpSpecifier) -> None:
|
4277
|
+
print('installed:')
|
4278
|
+
for n, p in self._providers.items():
|
4279
|
+
lst = [
|
4280
|
+
si
|
4281
|
+
for si in await p.get_installed_versions(spec)
|
4282
|
+
if spec.contains(si)
|
4283
|
+
]
|
4284
|
+
if lst:
|
4285
|
+
print(f' {n}')
|
4286
|
+
for si in lst:
|
4287
|
+
print(f' {si}')
|
3996
4288
|
|
3997
|
-
|
3998
|
-
self,
|
3999
|
-
*cmd: str,
|
4000
|
-
stdout: ta.Any = sys.stderr,
|
4001
|
-
**kwargs: ta.Any,
|
4002
|
-
) -> None:
|
4003
|
-
with self.prepare_and_wrap(*cmd, stdout=stdout, **kwargs) as (cmd, kwargs): # noqa
|
4004
|
-
subprocess.check_call(cmd, **kwargs)
|
4289
|
+
print()
|
4005
4290
|
|
4006
|
-
|
4007
|
-
|
4008
|
-
|
4009
|
-
|
4010
|
-
|
4011
|
-
|
4012
|
-
|
4291
|
+
print('installable:')
|
4292
|
+
for n, p in self._providers.items():
|
4293
|
+
lst = [
|
4294
|
+
si
|
4295
|
+
for si in await p.get_installable_versions(spec)
|
4296
|
+
if spec.contains(si)
|
4297
|
+
]
|
4298
|
+
if lst:
|
4299
|
+
print(f' {n}')
|
4300
|
+
for si in lst:
|
4301
|
+
print(f' {si}')
|
4013
4302
|
|
4014
4303
|
|
4015
|
-
|
4304
|
+
########################################
|
4305
|
+
# ../../../omlish/subprocesses/async_.py
|
4016
4306
|
|
4017
4307
|
|
4018
4308
|
##
|
@@ -4027,7 +4317,7 @@ class AbstractAsyncSubprocesses(BaseSubprocesses):
|
|
4027
4317
|
self,
|
4028
4318
|
*cmd: str,
|
4029
4319
|
input: ta.Any = None, # noqa
|
4030
|
-
timeout: ta.Optional[
|
4320
|
+
timeout: ta.Optional[TimeoutLike] = None,
|
4031
4321
|
check: bool = False,
|
4032
4322
|
capture_output: ta.Optional[bool] = None,
|
4033
4323
|
**kwargs: ta.Any,
|
@@ -4102,50 +4392,6 @@ class AbstractAsyncSubprocesses(BaseSubprocesses):
|
|
4102
4392
|
return ret.decode().strip()
|
4103
4393
|
|
4104
4394
|
|
4105
|
-
########################################
|
4106
|
-
# ../providers/base.py
|
4107
|
-
"""
|
4108
|
-
TODO:
|
4109
|
-
- backends
|
4110
|
-
- local builds
|
4111
|
-
- deadsnakes?
|
4112
|
-
- uv
|
4113
|
-
- loose versions
|
4114
|
-
"""
|
4115
|
-
|
4116
|
-
|
4117
|
-
##
|
4118
|
-
|
4119
|
-
|
4120
|
-
class InterpProvider(abc.ABC):
|
4121
|
-
name: ta.ClassVar[str]
|
4122
|
-
|
4123
|
-
def __init_subclass__(cls, **kwargs: ta.Any) -> None:
|
4124
|
-
super().__init_subclass__(**kwargs)
|
4125
|
-
if abc.ABC not in cls.__bases__ and 'name' not in cls.__dict__:
|
4126
|
-
sfx = 'InterpProvider'
|
4127
|
-
if not cls.__name__.endswith(sfx):
|
4128
|
-
raise NameError(cls)
|
4129
|
-
setattr(cls, 'name', snake_case(cls.__name__[:-len(sfx)]))
|
4130
|
-
|
4131
|
-
@abc.abstractmethod
|
4132
|
-
def get_installed_versions(self, spec: InterpSpecifier) -> ta.Awaitable[ta.Sequence[InterpVersion]]:
|
4133
|
-
raise NotImplementedError
|
4134
|
-
|
4135
|
-
@abc.abstractmethod
|
4136
|
-
def get_installed_version(self, version: InterpVersion) -> ta.Awaitable[Interp]:
|
4137
|
-
raise NotImplementedError
|
4138
|
-
|
4139
|
-
async def get_installable_versions(self, spec: InterpSpecifier) -> ta.Sequence[InterpVersion]:
|
4140
|
-
return []
|
4141
|
-
|
4142
|
-
async def install_version(self, version: InterpVersion) -> Interp:
|
4143
|
-
raise TypeError
|
4144
|
-
|
4145
|
-
|
4146
|
-
InterpProviders = ta.NewType('InterpProviders', ta.Sequence[InterpProvider])
|
4147
|
-
|
4148
|
-
|
4149
4395
|
########################################
|
4150
4396
|
# ../../../omlish/asyncs/asyncio/subprocesses.py
|
4151
4397
|
|
@@ -4261,7 +4507,7 @@ class AsyncioProcessCommunicator:
|
|
4261
4507
|
async def communicate(
|
4262
4508
|
self,
|
4263
4509
|
input: ta.Any = None, # noqa
|
4264
|
-
timeout: ta.Optional[
|
4510
|
+
timeout: ta.Optional[TimeoutLike] = None,
|
4265
4511
|
) -> Communication:
|
4266
4512
|
return await asyncio_maybe_timeout(self._communicate(input), timeout)
|
4267
4513
|
|
@@ -4274,7 +4520,7 @@ class AsyncioSubprocesses(AbstractAsyncSubprocesses):
|
|
4274
4520
|
self,
|
4275
4521
|
proc: asyncio.subprocess.Process,
|
4276
4522
|
input: ta.Any = None, # noqa
|
4277
|
-
timeout: ta.Optional[
|
4523
|
+
timeout: ta.Optional[TimeoutLike] = None,
|
4278
4524
|
) -> ta.Tuple[ta.Optional[bytes], ta.Optional[bytes]]:
|
4279
4525
|
return await AsyncioProcessCommunicator(proc).communicate(input, timeout) # noqa
|
4280
4526
|
|
@@ -4285,22 +4531,22 @@ class AsyncioSubprocesses(AbstractAsyncSubprocesses):
|
|
4285
4531
|
self,
|
4286
4532
|
*cmd: str,
|
4287
4533
|
shell: bool = False,
|
4288
|
-
timeout: ta.Optional[
|
4534
|
+
timeout: ta.Optional[TimeoutLike] = None,
|
4289
4535
|
**kwargs: ta.Any,
|
4290
4536
|
) -> ta.AsyncGenerator[asyncio.subprocess.Process, None]:
|
4291
|
-
fac: ta.Any
|
4292
|
-
if shell:
|
4293
|
-
fac = functools.partial(
|
4294
|
-
asyncio.create_subprocess_shell,
|
4295
|
-
check.single(cmd),
|
4296
|
-
)
|
4297
|
-
else:
|
4298
|
-
fac = functools.partial(
|
4299
|
-
asyncio.create_subprocess_exec,
|
4300
|
-
*cmd,
|
4301
|
-
)
|
4302
|
-
|
4303
4537
|
with self.prepare_and_wrap( *cmd, shell=shell, **kwargs) as (cmd, kwargs): # noqa
|
4538
|
+
fac: ta.Any
|
4539
|
+
if shell:
|
4540
|
+
fac = functools.partial(
|
4541
|
+
asyncio.create_subprocess_shell,
|
4542
|
+
check.single(cmd),
|
4543
|
+
)
|
4544
|
+
else:
|
4545
|
+
fac = functools.partial(
|
4546
|
+
asyncio.create_subprocess_exec,
|
4547
|
+
*cmd,
|
4548
|
+
)
|
4549
|
+
|
4304
4550
|
proc: asyncio.subprocess.Process = await fac(**kwargs)
|
4305
4551
|
try:
|
4306
4552
|
yield proc
|
@@ -4541,94 +4787,6 @@ class Pyenv:
|
|
4541
4787
|
return True
|
4542
4788
|
|
4543
4789
|
|
4544
|
-
########################################
|
4545
|
-
# ../resolvers.py
|
4546
|
-
|
4547
|
-
|
4548
|
-
@dc.dataclass(frozen=True)
|
4549
|
-
class InterpResolverProviders:
|
4550
|
-
providers: ta.Sequence[ta.Tuple[str, InterpProvider]]
|
4551
|
-
|
4552
|
-
|
4553
|
-
class InterpResolver:
|
4554
|
-
def __init__(
|
4555
|
-
self,
|
4556
|
-
providers: InterpResolverProviders,
|
4557
|
-
) -> None:
|
4558
|
-
super().__init__()
|
4559
|
-
|
4560
|
-
self._providers: ta.Mapping[str, InterpProvider] = collections.OrderedDict(providers.providers)
|
4561
|
-
|
4562
|
-
async def _resolve_installed(self, spec: InterpSpecifier) -> ta.Optional[ta.Tuple[InterpProvider, InterpVersion]]:
|
4563
|
-
lst = [
|
4564
|
-
(i, si)
|
4565
|
-
for i, p in enumerate(self._providers.values())
|
4566
|
-
for si in await p.get_installed_versions(spec)
|
4567
|
-
if spec.contains(si)
|
4568
|
-
]
|
4569
|
-
|
4570
|
-
slst = sorted(lst, key=lambda t: (-t[0], t[1].version))
|
4571
|
-
if not slst:
|
4572
|
-
return None
|
4573
|
-
|
4574
|
-
bi, bv = slst[-1]
|
4575
|
-
bp = list(self._providers.values())[bi]
|
4576
|
-
return (bp, bv)
|
4577
|
-
|
4578
|
-
async def resolve(
|
4579
|
-
self,
|
4580
|
-
spec: InterpSpecifier,
|
4581
|
-
*,
|
4582
|
-
install: bool = False,
|
4583
|
-
) -> ta.Optional[Interp]:
|
4584
|
-
tup = await self._resolve_installed(spec)
|
4585
|
-
if tup is not None:
|
4586
|
-
bp, bv = tup
|
4587
|
-
return await bp.get_installed_version(bv)
|
4588
|
-
|
4589
|
-
if not install:
|
4590
|
-
return None
|
4591
|
-
|
4592
|
-
tp = list(self._providers.values())[0] # noqa
|
4593
|
-
|
4594
|
-
sv = sorted(
|
4595
|
-
[s for s in await tp.get_installable_versions(spec) if s in spec],
|
4596
|
-
key=lambda s: s.version,
|
4597
|
-
)
|
4598
|
-
if not sv:
|
4599
|
-
return None
|
4600
|
-
|
4601
|
-
bv = sv[-1]
|
4602
|
-
return await tp.install_version(bv)
|
4603
|
-
|
4604
|
-
async def list(self, spec: InterpSpecifier) -> None:
|
4605
|
-
print('installed:')
|
4606
|
-
for n, p in self._providers.items():
|
4607
|
-
lst = [
|
4608
|
-
si
|
4609
|
-
for si in await p.get_installed_versions(spec)
|
4610
|
-
if spec.contains(si)
|
4611
|
-
]
|
4612
|
-
if lst:
|
4613
|
-
print(f' {n}')
|
4614
|
-
for si in lst:
|
4615
|
-
print(f' {si}')
|
4616
|
-
|
4617
|
-
print()
|
4618
|
-
|
4619
|
-
print('installable:')
|
4620
|
-
for n, p in self._providers.items():
|
4621
|
-
lst = [
|
4622
|
-
si
|
4623
|
-
for si in await p.get_installable_versions(spec)
|
4624
|
-
if spec.contains(si)
|
4625
|
-
]
|
4626
|
-
if lst:
|
4627
|
-
print(f' {n}')
|
4628
|
-
for si in lst:
|
4629
|
-
print(f' {si}')
|
4630
|
-
|
4631
|
-
|
4632
4790
|
########################################
|
4633
4791
|
# ../providers/running.py
|
4634
4792
|
|