omdev 0.0.0.dev225__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/scripts/ci.py +280 -29
- omdev/scripts/interp.py +274 -28
- omdev/scripts/pyproject.py +280 -29
- {omdev-0.0.0.dev225.dist-info → omdev-0.0.0.dev226.dist-info}/METADATA +2 -2
- {omdev-0.0.0.dev225.dist-info → omdev-0.0.0.dev226.dist-info}/RECORD +9 -9
- {omdev-0.0.0.dev225.dist-info → omdev-0.0.0.dev226.dist-info}/LICENSE +0 -0
- {omdev-0.0.0.dev225.dist-info → omdev-0.0.0.dev226.dist-info}/WHEEL +0 -0
- {omdev-0.0.0.dev225.dist-info → omdev-0.0.0.dev226.dist-info}/entry_points.txt +0 -0
- {omdev-0.0.0.dev225.dist-info → omdev-0.0.0.dev226.dist-info}/top_level.txt +0 -0
omdev/scripts/ci.py
CHANGED
@@ -64,9 +64,6 @@ T = ta.TypeVar('T')
|
|
64
64
|
# ../../omlish/asyncs/asyncio/asyncio.py
|
65
65
|
CallableT = ta.TypeVar('CallableT', bound=ta.Callable)
|
66
66
|
|
67
|
-
# ../../omlish/asyncs/asyncio/timeouts.py
|
68
|
-
AwaitableT = ta.TypeVar('AwaitableT', bound=ta.Awaitable)
|
69
|
-
|
70
67
|
# ../../omlish/lite/check.py
|
71
68
|
SizedT = ta.TypeVar('SizedT', bound=ta.Sized)
|
72
69
|
CheckMessage = ta.Union[str, ta.Callable[..., ta.Optional[str]], None] # ta.TypeAlias
|
@@ -75,9 +72,15 @@ CheckOnRaiseFn = ta.Callable[[Exception], None] # ta.TypeAlias
|
|
75
72
|
CheckExceptionFactory = ta.Callable[..., Exception] # ta.TypeAlias
|
76
73
|
CheckArgsRenderer = ta.Callable[..., ta.Optional[str]] # ta.TypeAlias
|
77
74
|
|
75
|
+
# ../../omlish/lite/timeouts.py
|
76
|
+
TimeoutLike = ta.Union['Timeout', 'Timeout.Default', ta.Iterable['TimeoutLike'], float] # ta.TypeAlias
|
77
|
+
|
78
78
|
# ../../omlish/argparse/cli.py
|
79
79
|
ArgparseCmdFn = ta.Callable[[], ta.Optional[int]] # ta.TypeAlias
|
80
80
|
|
81
|
+
# ../../omlish/asyncs/asyncio/timeouts.py
|
82
|
+
AwaitableT = ta.TypeVar('AwaitableT', bound=ta.Awaitable)
|
83
|
+
|
81
84
|
# ../../omlish/lite/contextmanagers.py
|
82
85
|
ExitStackedT = ta.TypeVar('ExitStackedT', bound='ExitStacked')
|
83
86
|
AsyncExitStackedT = ta.TypeVar('AsyncExitStackedT', bound='AsyncExitStacked')
|
@@ -245,19 +248,6 @@ async def asyncio_wait_concurrent(
|
|
245
248
|
return [task.result() for task in done]
|
246
249
|
|
247
250
|
|
248
|
-
########################################
|
249
|
-
# ../../../omlish/asyncs/asyncio/timeouts.py
|
250
|
-
|
251
|
-
|
252
|
-
def asyncio_maybe_timeout(
|
253
|
-
fut: AwaitableT,
|
254
|
-
timeout: ta.Optional[float] = None,
|
255
|
-
) -> AwaitableT:
|
256
|
-
if timeout is not None:
|
257
|
-
fut = asyncio.wait_for(fut, timeout) # type: ignore
|
258
|
-
return fut
|
259
|
-
|
260
|
-
|
261
251
|
########################################
|
262
252
|
# ../../../omlish/lite/cached.py
|
263
253
|
|
@@ -1057,6 +1047,205 @@ def format_num_bytes(num_bytes: int) -> str:
|
|
1057
1047
|
return f'{num_bytes / 1024 ** (len(FORMAT_NUM_BYTES_SUFFIXES) - 1):.2f}{FORMAT_NUM_BYTES_SUFFIXES[-1]}'
|
1058
1048
|
|
1059
1049
|
|
1050
|
+
########################################
|
1051
|
+
# ../../../omlish/lite/timeouts.py
|
1052
|
+
"""
|
1053
|
+
TODO:
|
1054
|
+
- Event (/ Predicate)
|
1055
|
+
"""
|
1056
|
+
|
1057
|
+
|
1058
|
+
##
|
1059
|
+
|
1060
|
+
|
1061
|
+
class Timeout(abc.ABC):
|
1062
|
+
@property
|
1063
|
+
@abc.abstractmethod
|
1064
|
+
def can_expire(self) -> bool:
|
1065
|
+
"""Indicates whether or not this timeout will ever expire."""
|
1066
|
+
|
1067
|
+
raise NotImplementedError
|
1068
|
+
|
1069
|
+
@abc.abstractmethod
|
1070
|
+
def expired(self) -> bool:
|
1071
|
+
"""Return whether or not this timeout has expired."""
|
1072
|
+
|
1073
|
+
raise NotImplementedError
|
1074
|
+
|
1075
|
+
@abc.abstractmethod
|
1076
|
+
def remaining(self) -> float:
|
1077
|
+
"""Returns the time (in seconds) remaining until the timeout expires. May be negative and/or infinite."""
|
1078
|
+
|
1079
|
+
raise NotImplementedError
|
1080
|
+
|
1081
|
+
@abc.abstractmethod
|
1082
|
+
def __call__(self) -> float:
|
1083
|
+
"""Returns the time (in seconds) remaining until the timeout expires, or raises if the timeout has expired."""
|
1084
|
+
|
1085
|
+
raise NotImplementedError
|
1086
|
+
|
1087
|
+
@abc.abstractmethod
|
1088
|
+
def or_(self, o: ta.Any) -> ta.Any:
|
1089
|
+
"""Evaluates time remaining via remaining() if this timeout can expire, otherwise returns `o`."""
|
1090
|
+
|
1091
|
+
raise NotImplementedError
|
1092
|
+
|
1093
|
+
#
|
1094
|
+
|
1095
|
+
@classmethod
|
1096
|
+
def _now(cls) -> float:
|
1097
|
+
return time.time()
|
1098
|
+
|
1099
|
+
#
|
1100
|
+
|
1101
|
+
class Default:
|
1102
|
+
def __new__(cls, *args, **kwargs): # noqa
|
1103
|
+
raise TypeError
|
1104
|
+
|
1105
|
+
class _NOT_SPECIFIED: # noqa
|
1106
|
+
def __new__(cls, *args, **kwargs): # noqa
|
1107
|
+
raise TypeError
|
1108
|
+
|
1109
|
+
@classmethod
|
1110
|
+
def of(
|
1111
|
+
cls,
|
1112
|
+
obj: ta.Optional[TimeoutLike],
|
1113
|
+
default: ta.Union[TimeoutLike, ta.Type[_NOT_SPECIFIED]] = _NOT_SPECIFIED,
|
1114
|
+
) -> 'Timeout':
|
1115
|
+
if obj is None:
|
1116
|
+
return InfiniteTimeout()
|
1117
|
+
|
1118
|
+
elif isinstance(obj, Timeout):
|
1119
|
+
return obj
|
1120
|
+
|
1121
|
+
elif isinstance(obj, (float, int)):
|
1122
|
+
return DeadlineTimeout(cls._now() + obj)
|
1123
|
+
|
1124
|
+
elif isinstance(obj, ta.Iterable):
|
1125
|
+
return CompositeTimeout(*[Timeout.of(c) for c in obj])
|
1126
|
+
|
1127
|
+
elif obj is Timeout.Default:
|
1128
|
+
if default is Timeout._NOT_SPECIFIED or default is Timeout.Default:
|
1129
|
+
raise RuntimeError('Must specify a default timeout')
|
1130
|
+
|
1131
|
+
else:
|
1132
|
+
return Timeout.of(default) # type: ignore[arg-type]
|
1133
|
+
|
1134
|
+
else:
|
1135
|
+
raise TypeError(obj)
|
1136
|
+
|
1137
|
+
@classmethod
|
1138
|
+
def of_deadline(cls, deadline: float) -> 'DeadlineTimeout':
|
1139
|
+
return DeadlineTimeout(deadline)
|
1140
|
+
|
1141
|
+
@classmethod
|
1142
|
+
def of_predicate(cls, expired_fn: ta.Callable[[], bool]) -> 'PredicateTimeout':
|
1143
|
+
return PredicateTimeout(expired_fn)
|
1144
|
+
|
1145
|
+
|
1146
|
+
class DeadlineTimeout(Timeout):
|
1147
|
+
def __init__(
|
1148
|
+
self,
|
1149
|
+
deadline: float,
|
1150
|
+
exc: ta.Union[ta.Type[BaseException], BaseException] = TimeoutError,
|
1151
|
+
) -> None:
|
1152
|
+
super().__init__()
|
1153
|
+
|
1154
|
+
self.deadline = deadline
|
1155
|
+
self.exc = exc
|
1156
|
+
|
1157
|
+
@property
|
1158
|
+
def can_expire(self) -> bool:
|
1159
|
+
return True
|
1160
|
+
|
1161
|
+
def expired(self) -> bool:
|
1162
|
+
return not (self.remaining() > 0)
|
1163
|
+
|
1164
|
+
def remaining(self) -> float:
|
1165
|
+
return self.deadline - self._now()
|
1166
|
+
|
1167
|
+
def __call__(self) -> float:
|
1168
|
+
if (rem := self.remaining()) > 0:
|
1169
|
+
return rem
|
1170
|
+
raise self.exc
|
1171
|
+
|
1172
|
+
def or_(self, o: ta.Any) -> ta.Any:
|
1173
|
+
return self()
|
1174
|
+
|
1175
|
+
|
1176
|
+
class InfiniteTimeout(Timeout):
|
1177
|
+
@property
|
1178
|
+
def can_expire(self) -> bool:
|
1179
|
+
return False
|
1180
|
+
|
1181
|
+
def expired(self) -> bool:
|
1182
|
+
return False
|
1183
|
+
|
1184
|
+
def remaining(self) -> float:
|
1185
|
+
return float('inf')
|
1186
|
+
|
1187
|
+
def __call__(self) -> float:
|
1188
|
+
return float('inf')
|
1189
|
+
|
1190
|
+
def or_(self, o: ta.Any) -> ta.Any:
|
1191
|
+
return o
|
1192
|
+
|
1193
|
+
|
1194
|
+
class CompositeTimeout(Timeout):
|
1195
|
+
def __init__(self, *children: Timeout) -> None:
|
1196
|
+
super().__init__()
|
1197
|
+
|
1198
|
+
self.children = children
|
1199
|
+
|
1200
|
+
@property
|
1201
|
+
def can_expire(self) -> bool:
|
1202
|
+
return any(c.can_expire for c in self.children)
|
1203
|
+
|
1204
|
+
def expired(self) -> bool:
|
1205
|
+
return any(c.expired() for c in self.children)
|
1206
|
+
|
1207
|
+
def remaining(self) -> float:
|
1208
|
+
return min(c.remaining() for c in self.children)
|
1209
|
+
|
1210
|
+
def __call__(self) -> float:
|
1211
|
+
return min(c() for c in self.children)
|
1212
|
+
|
1213
|
+
def or_(self, o: ta.Any) -> ta.Any:
|
1214
|
+
if self.can_expire:
|
1215
|
+
return self()
|
1216
|
+
return o
|
1217
|
+
|
1218
|
+
|
1219
|
+
class PredicateTimeout(Timeout):
|
1220
|
+
def __init__(
|
1221
|
+
self,
|
1222
|
+
expired_fn: ta.Callable[[], bool],
|
1223
|
+
exc: ta.Union[ta.Type[BaseException], BaseException] = TimeoutError,
|
1224
|
+
) -> None:
|
1225
|
+
super().__init__()
|
1226
|
+
|
1227
|
+
self.expired_fn = expired_fn
|
1228
|
+
self.exc = exc
|
1229
|
+
|
1230
|
+
@property
|
1231
|
+
def can_expire(self) -> bool:
|
1232
|
+
return True
|
1233
|
+
|
1234
|
+
def expired(self) -> bool:
|
1235
|
+
return self.expired_fn()
|
1236
|
+
|
1237
|
+
def remaining(self) -> float:
|
1238
|
+
return float('inf')
|
1239
|
+
|
1240
|
+
def __call__(self) -> float:
|
1241
|
+
if not self.expired_fn():
|
1242
|
+
return float('inf')
|
1243
|
+
raise self.exc
|
1244
|
+
|
1245
|
+
def or_(self, o: ta.Any) -> ta.Any:
|
1246
|
+
return self()
|
1247
|
+
|
1248
|
+
|
1060
1249
|
########################################
|
1061
1250
|
# ../../../omlish/logs/filters.py
|
1062
1251
|
|
@@ -1814,6 +2003,19 @@ class ArgparseCli:
|
|
1814
2003
|
return fn()
|
1815
2004
|
|
1816
2005
|
|
2006
|
+
########################################
|
2007
|
+
# ../../../omlish/asyncs/asyncio/timeouts.py
|
2008
|
+
|
2009
|
+
|
2010
|
+
def asyncio_maybe_timeout(
|
2011
|
+
fut: AwaitableT,
|
2012
|
+
timeout: ta.Optional[TimeoutLike] = None,
|
2013
|
+
) -> AwaitableT:
|
2014
|
+
if timeout is not None:
|
2015
|
+
fut = asyncio.wait_for(fut, Timeout.of(timeout)()) # type: ignore
|
2016
|
+
return fut
|
2017
|
+
|
2018
|
+
|
1817
2019
|
########################################
|
1818
2020
|
# ../../../omlish/lite/contextmanagers.py
|
1819
2021
|
|
@@ -3147,17 +3349,43 @@ class SubprocessRunOutput(ta.Generic[T]):
|
|
3147
3349
|
class SubprocessRun:
|
3148
3350
|
cmd: ta.Sequence[str]
|
3149
3351
|
input: ta.Any = None
|
3150
|
-
timeout: ta.Optional[
|
3352
|
+
timeout: ta.Optional[TimeoutLike] = None
|
3151
3353
|
check: bool = False
|
3152
3354
|
capture_output: ta.Optional[bool] = None
|
3153
3355
|
kwargs: ta.Optional[ta.Mapping[str, ta.Any]] = None
|
3154
3356
|
|
3357
|
+
#
|
3358
|
+
|
3359
|
+
_FIELD_NAMES: ta.ClassVar[ta.FrozenSet[str]]
|
3360
|
+
|
3361
|
+
def replace(self, **kwargs: ta.Any) -> 'SubprocessRun':
|
3362
|
+
if not kwargs:
|
3363
|
+
return self
|
3364
|
+
|
3365
|
+
field_kws = {}
|
3366
|
+
extra_kws = {}
|
3367
|
+
for k, v in kwargs.items():
|
3368
|
+
if k in self._FIELD_NAMES:
|
3369
|
+
field_kws[k] = v
|
3370
|
+
else:
|
3371
|
+
extra_kws[k] = v
|
3372
|
+
|
3373
|
+
return dc.replace(self, **{
|
3374
|
+
**dict(kwargs={
|
3375
|
+
**(self.kwargs or {}),
|
3376
|
+
**extra_kws,
|
3377
|
+
}),
|
3378
|
+
**field_kws, # passing a kwarg named 'kwargs' intentionally clobbers
|
3379
|
+
})
|
3380
|
+
|
3381
|
+
#
|
3382
|
+
|
3155
3383
|
@classmethod
|
3156
3384
|
def of(
|
3157
3385
|
cls,
|
3158
3386
|
*cmd: str,
|
3159
3387
|
input: ta.Any = None, # noqa
|
3160
|
-
timeout: ta.Optional[
|
3388
|
+
timeout: ta.Optional[TimeoutLike] = None,
|
3161
3389
|
check: bool = False, # noqa
|
3162
3390
|
capture_output: ta.Optional[bool] = None,
|
3163
3391
|
**kwargs: ta.Any,
|
@@ -3178,20 +3406,25 @@ class SubprocessRun:
|
|
3178
3406
|
def run(
|
3179
3407
|
self,
|
3180
3408
|
subprocesses: ta.Optional[ta.Any] = None, # AbstractSubprocesses
|
3409
|
+
**kwargs: ta.Any,
|
3181
3410
|
) -> SubprocessRunOutput:
|
3182
3411
|
if subprocesses is None:
|
3183
3412
|
subprocesses = self._DEFAULT_SUBPROCESSES
|
3184
|
-
return check.not_none(subprocesses).run_(self) # type: ignore[attr-defined]
|
3413
|
+
return check.not_none(subprocesses).run_(self.replace(**kwargs)) # type: ignore[attr-defined]
|
3185
3414
|
|
3186
3415
|
_DEFAULT_ASYNC_SUBPROCESSES: ta.ClassVar[ta.Optional[ta.Any]] = None # AbstractAsyncSubprocesses
|
3187
3416
|
|
3188
3417
|
async def async_run(
|
3189
3418
|
self,
|
3190
3419
|
async_subprocesses: ta.Optional[ta.Any] = None, # AbstractAsyncSubprocesses
|
3420
|
+
**kwargs: ta.Any,
|
3191
3421
|
) -> SubprocessRunOutput:
|
3192
3422
|
if async_subprocesses is None:
|
3193
3423
|
async_subprocesses = self._DEFAULT_ASYNC_SUBPROCESSES
|
3194
|
-
return await check.not_none(async_subprocesses).run_(self) # type: ignore[attr-defined]
|
3424
|
+
return await check.not_none(async_subprocesses).run_(self.replace(**kwargs)) # type: ignore[attr-defined]
|
3425
|
+
|
3426
|
+
|
3427
|
+
SubprocessRun._FIELD_NAMES = frozenset(fld.name for fld in dc.fields(SubprocessRun)) # noqa
|
3195
3428
|
|
3196
3429
|
|
3197
3430
|
##
|
@@ -3208,11 +3441,19 @@ class SubprocessRunnable(abc.ABC, ta.Generic[T]):
|
|
3208
3441
|
|
3209
3442
|
#
|
3210
3443
|
|
3211
|
-
def run(
|
3212
|
-
|
3444
|
+
def run(
|
3445
|
+
self,
|
3446
|
+
subprocesses: ta.Optional[ta.Any] = None, # AbstractSubprocesses
|
3447
|
+
**kwargs: ta.Any,
|
3448
|
+
) -> T:
|
3449
|
+
return self.handle_run_output(self.make_run().run(subprocesses, **kwargs))
|
3213
3450
|
|
3214
|
-
async def async_run(
|
3215
|
-
|
3451
|
+
async def async_run(
|
3452
|
+
self,
|
3453
|
+
async_subprocesses: ta.Optional[ta.Any] = None, # AbstractAsyncSubprocesses
|
3454
|
+
**kwargs: ta.Any,
|
3455
|
+
) -> T:
|
3456
|
+
return self.handle_run_output(await self.make_run().async_run(async_subprocesses, **kwargs))
|
3216
3457
|
|
3217
3458
|
|
3218
3459
|
########################################
|
@@ -4320,6 +4561,11 @@ class BaseSubprocesses(abc.ABC): # noqa
|
|
4320
4561
|
|
4321
4562
|
#
|
4322
4563
|
|
4564
|
+
if 'timeout' in kwargs:
|
4565
|
+
kwargs['timeout'] = Timeout.of(kwargs['timeout']).or_(None)
|
4566
|
+
|
4567
|
+
#
|
4568
|
+
|
4323
4569
|
return cmd, dict(
|
4324
4570
|
env=env,
|
4325
4571
|
shell=shell,
|
@@ -4465,7 +4711,7 @@ class AbstractAsyncSubprocesses(BaseSubprocesses):
|
|
4465
4711
|
self,
|
4466
4712
|
*cmd: str,
|
4467
4713
|
input: ta.Any = None, # noqa
|
4468
|
-
timeout: ta.Optional[
|
4714
|
+
timeout: ta.Optional[TimeoutLike] = None,
|
4469
4715
|
check: bool = False,
|
4470
4716
|
capture_output: ta.Optional[bool] = None,
|
4471
4717
|
**kwargs: ta.Any,
|
@@ -4542,6 +4788,11 @@ class AbstractAsyncSubprocesses(BaseSubprocesses):
|
|
4542
4788
|
|
4543
4789
|
########################################
|
4544
4790
|
# ../../../omlish/subprocesses/sync.py
|
4791
|
+
"""
|
4792
|
+
TODO:
|
4793
|
+
- popen
|
4794
|
+
- route check_calls through run_?
|
4795
|
+
"""
|
4545
4796
|
|
4546
4797
|
|
4547
4798
|
##
|
@@ -4556,7 +4807,7 @@ class AbstractSubprocesses(BaseSubprocesses, abc.ABC):
|
|
4556
4807
|
self,
|
4557
4808
|
*cmd: str,
|
4558
4809
|
input: ta.Any = None, # noqa
|
4559
|
-
timeout: ta.Optional[
|
4810
|
+
timeout: ta.Optional[TimeoutLike] = None,
|
4560
4811
|
check: bool = False,
|
4561
4812
|
capture_output: ta.Optional[bool] = None,
|
4562
4813
|
**kwargs: ta.Any,
|
@@ -4867,7 +5118,7 @@ class AsyncioProcessCommunicator:
|
|
4867
5118
|
async def communicate(
|
4868
5119
|
self,
|
4869
5120
|
input: ta.Any = None, # noqa
|
4870
|
-
timeout: ta.Optional[
|
5121
|
+
timeout: ta.Optional[TimeoutLike] = None,
|
4871
5122
|
) -> Communication:
|
4872
5123
|
return await asyncio_maybe_timeout(self._communicate(input), timeout)
|
4873
5124
|
|
@@ -4880,7 +5131,7 @@ class AsyncioSubprocesses(AbstractAsyncSubprocesses):
|
|
4880
5131
|
self,
|
4881
5132
|
proc: asyncio.subprocess.Process,
|
4882
5133
|
input: ta.Any = None, # noqa
|
4883
|
-
timeout: ta.Optional[
|
5134
|
+
timeout: ta.Optional[TimeoutLike] = None,
|
4884
5135
|
) -> ta.Tuple[ta.Optional[bytes], ta.Optional[bytes]]:
|
4885
5136
|
return await AsyncioProcessCommunicator(proc).communicate(input, timeout) # noqa
|
4886
5137
|
|
@@ -4891,7 +5142,7 @@ class AsyncioSubprocesses(AbstractAsyncSubprocesses):
|
|
4891
5142
|
self,
|
4892
5143
|
*cmd: str,
|
4893
5144
|
shell: bool = False,
|
4894
|
-
timeout: ta.Optional[
|
5145
|
+
timeout: ta.Optional[TimeoutLike] = None,
|
4895
5146
|
**kwargs: ta.Any,
|
4896
5147
|
) -> ta.AsyncGenerator[asyncio.subprocess.Process, None]:
|
4897
5148
|
with self.prepare_and_wrap( *cmd, shell=shell, **kwargs) as (cmd, kwargs): # noqa
|
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]
|
@@ -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
|
|
@@ -3393,17 +3595,43 @@ class SubprocessRunOutput(ta.Generic[T]):
|
|
3393
3595
|
class SubprocessRun:
|
3394
3596
|
cmd: ta.Sequence[str]
|
3395
3597
|
input: ta.Any = None
|
3396
|
-
timeout: ta.Optional[
|
3598
|
+
timeout: ta.Optional[TimeoutLike] = None
|
3397
3599
|
check: bool = False
|
3398
3600
|
capture_output: ta.Optional[bool] = None
|
3399
3601
|
kwargs: ta.Optional[ta.Mapping[str, ta.Any]] = None
|
3400
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
|
+
|
3401
3629
|
@classmethod
|
3402
3630
|
def of(
|
3403
3631
|
cls,
|
3404
3632
|
*cmd: str,
|
3405
3633
|
input: ta.Any = None, # noqa
|
3406
|
-
timeout: ta.Optional[
|
3634
|
+
timeout: ta.Optional[TimeoutLike] = None,
|
3407
3635
|
check: bool = False, # noqa
|
3408
3636
|
capture_output: ta.Optional[bool] = None,
|
3409
3637
|
**kwargs: ta.Any,
|
@@ -3424,20 +3652,25 @@ class SubprocessRun:
|
|
3424
3652
|
def run(
|
3425
3653
|
self,
|
3426
3654
|
subprocesses: ta.Optional[ta.Any] = None, # AbstractSubprocesses
|
3655
|
+
**kwargs: ta.Any,
|
3427
3656
|
) -> SubprocessRunOutput:
|
3428
3657
|
if subprocesses is None:
|
3429
3658
|
subprocesses = self._DEFAULT_SUBPROCESSES
|
3430
|
-
return check.not_none(subprocesses).run_(self) # type: ignore[attr-defined]
|
3659
|
+
return check.not_none(subprocesses).run_(self.replace(**kwargs)) # type: ignore[attr-defined]
|
3431
3660
|
|
3432
3661
|
_DEFAULT_ASYNC_SUBPROCESSES: ta.ClassVar[ta.Optional[ta.Any]] = None # AbstractAsyncSubprocesses
|
3433
3662
|
|
3434
3663
|
async def async_run(
|
3435
3664
|
self,
|
3436
3665
|
async_subprocesses: ta.Optional[ta.Any] = None, # AbstractAsyncSubprocesses
|
3666
|
+
**kwargs: ta.Any,
|
3437
3667
|
) -> SubprocessRunOutput:
|
3438
3668
|
if async_subprocesses is None:
|
3439
3669
|
async_subprocesses = self._DEFAULT_ASYNC_SUBPROCESSES
|
3440
|
-
return await check.not_none(async_subprocesses).run_(self) # type: ignore[attr-defined]
|
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
|
3441
3674
|
|
3442
3675
|
|
3443
3676
|
##
|
@@ -3454,11 +3687,19 @@ class SubprocessRunnable(abc.ABC, ta.Generic[T]):
|
|
3454
3687
|
|
3455
3688
|
#
|
3456
3689
|
|
3457
|
-
def run(
|
3458
|
-
|
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))
|
3459
3696
|
|
3460
|
-
async def async_run(
|
3461
|
-
|
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))
|
3462
3703
|
|
3463
3704
|
|
3464
3705
|
########################################
|
@@ -3863,6 +4104,11 @@ class BaseSubprocesses(abc.ABC): # noqa
|
|
3863
4104
|
|
3864
4105
|
#
|
3865
4106
|
|
4107
|
+
if 'timeout' in kwargs:
|
4108
|
+
kwargs['timeout'] = Timeout.of(kwargs['timeout']).or_(None)
|
4109
|
+
|
4110
|
+
#
|
4111
|
+
|
3866
4112
|
return cmd, dict(
|
3867
4113
|
env=env,
|
3868
4114
|
shell=shell,
|
@@ -4071,7 +4317,7 @@ class AbstractAsyncSubprocesses(BaseSubprocesses):
|
|
4071
4317
|
self,
|
4072
4318
|
*cmd: str,
|
4073
4319
|
input: ta.Any = None, # noqa
|
4074
|
-
timeout: ta.Optional[
|
4320
|
+
timeout: ta.Optional[TimeoutLike] = None,
|
4075
4321
|
check: bool = False,
|
4076
4322
|
capture_output: ta.Optional[bool] = None,
|
4077
4323
|
**kwargs: ta.Any,
|
@@ -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,7 +4531,7 @@ 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
4537
|
with self.prepare_and_wrap( *cmd, shell=shell, **kwargs) as (cmd, kwargs): # noqa
|
omdev/scripts/pyproject.py
CHANGED
@@ -88,9 +88,6 @@ VersionCmpLocalType = ta.Union['NegativeInfinityVersionType', _VersionCmpLocalTy
|
|
88
88
|
VersionCmpKey = ta.Tuple[int, ta.Tuple[int, ...], VersionCmpPrePostDevType, VersionCmpPrePostDevType, VersionCmpPrePostDevType, VersionCmpLocalType] # noqa
|
89
89
|
VersionComparisonMethod = ta.Callable[[VersionCmpKey, VersionCmpKey], bool]
|
90
90
|
|
91
|
-
# ../../omlish/asyncs/asyncio/timeouts.py
|
92
|
-
AwaitableT = ta.TypeVar('AwaitableT', bound=ta.Awaitable)
|
93
|
-
|
94
91
|
# ../../omlish/formats/toml/parser.py
|
95
92
|
TomlParseFloat = ta.Callable[[str], ta.Any]
|
96
93
|
TomlKey = ta.Tuple[str, ...]
|
@@ -108,6 +105,9 @@ CheckOnRaiseFn = ta.Callable[[Exception], None] # ta.TypeAlias
|
|
108
105
|
CheckExceptionFactory = ta.Callable[..., Exception] # ta.TypeAlias
|
109
106
|
CheckArgsRenderer = ta.Callable[..., ta.Optional[str]] # ta.TypeAlias
|
110
107
|
|
108
|
+
# ../../omlish/lite/timeouts.py
|
109
|
+
TimeoutLike = ta.Union['Timeout', 'Timeout.Default', ta.Iterable['TimeoutLike'], float] # ta.TypeAlias
|
110
|
+
|
111
111
|
# ../../omlish/lite/typing.py
|
112
112
|
A0 = ta.TypeVar('A0')
|
113
113
|
A1 = ta.TypeVar('A1')
|
@@ -121,6 +121,9 @@ CallableVersionOperator = ta.Callable[['Version', str], bool]
|
|
121
121
|
# ../../omlish/argparse/cli.py
|
122
122
|
ArgparseCmdFn = ta.Callable[[], ta.Optional[int]] # ta.TypeAlias
|
123
123
|
|
124
|
+
# ../../omlish/asyncs/asyncio/timeouts.py
|
125
|
+
AwaitableT = ta.TypeVar('AwaitableT', bound=ta.Awaitable)
|
126
|
+
|
124
127
|
# ../../omlish/lite/inject.py
|
125
128
|
U = ta.TypeVar('U')
|
126
129
|
InjectorKeyCls = ta.Union[type, ta.NewType]
|
@@ -858,19 +861,6 @@ class WheelFile(zipfile.ZipFile):
|
|
858
861
|
super().close()
|
859
862
|
|
860
863
|
|
861
|
-
########################################
|
862
|
-
# ../../../omlish/asyncs/asyncio/timeouts.py
|
863
|
-
|
864
|
-
|
865
|
-
def asyncio_maybe_timeout(
|
866
|
-
fut: AwaitableT,
|
867
|
-
timeout: ta.Optional[float] = None,
|
868
|
-
) -> AwaitableT:
|
869
|
-
if timeout is not None:
|
870
|
-
fut = asyncio.wait_for(fut, timeout) # type: ignore
|
871
|
-
return fut
|
872
|
-
|
873
|
-
|
874
864
|
########################################
|
875
865
|
# ../../../omlish/formats/toml/parser.py
|
876
866
|
# SPDX-License-Identifier: MIT
|
@@ -2611,6 +2601,205 @@ def format_num_bytes(num_bytes: int) -> str:
|
|
2611
2601
|
return f'{num_bytes / 1024 ** (len(FORMAT_NUM_BYTES_SUFFIXES) - 1):.2f}{FORMAT_NUM_BYTES_SUFFIXES[-1]}'
|
2612
2602
|
|
2613
2603
|
|
2604
|
+
########################################
|
2605
|
+
# ../../../omlish/lite/timeouts.py
|
2606
|
+
"""
|
2607
|
+
TODO:
|
2608
|
+
- Event (/ Predicate)
|
2609
|
+
"""
|
2610
|
+
|
2611
|
+
|
2612
|
+
##
|
2613
|
+
|
2614
|
+
|
2615
|
+
class Timeout(abc.ABC):
|
2616
|
+
@property
|
2617
|
+
@abc.abstractmethod
|
2618
|
+
def can_expire(self) -> bool:
|
2619
|
+
"""Indicates whether or not this timeout will ever expire."""
|
2620
|
+
|
2621
|
+
raise NotImplementedError
|
2622
|
+
|
2623
|
+
@abc.abstractmethod
|
2624
|
+
def expired(self) -> bool:
|
2625
|
+
"""Return whether or not this timeout has expired."""
|
2626
|
+
|
2627
|
+
raise NotImplementedError
|
2628
|
+
|
2629
|
+
@abc.abstractmethod
|
2630
|
+
def remaining(self) -> float:
|
2631
|
+
"""Returns the time (in seconds) remaining until the timeout expires. May be negative and/or infinite."""
|
2632
|
+
|
2633
|
+
raise NotImplementedError
|
2634
|
+
|
2635
|
+
@abc.abstractmethod
|
2636
|
+
def __call__(self) -> float:
|
2637
|
+
"""Returns the time (in seconds) remaining until the timeout expires, or raises if the timeout has expired."""
|
2638
|
+
|
2639
|
+
raise NotImplementedError
|
2640
|
+
|
2641
|
+
@abc.abstractmethod
|
2642
|
+
def or_(self, o: ta.Any) -> ta.Any:
|
2643
|
+
"""Evaluates time remaining via remaining() if this timeout can expire, otherwise returns `o`."""
|
2644
|
+
|
2645
|
+
raise NotImplementedError
|
2646
|
+
|
2647
|
+
#
|
2648
|
+
|
2649
|
+
@classmethod
|
2650
|
+
def _now(cls) -> float:
|
2651
|
+
return time.time()
|
2652
|
+
|
2653
|
+
#
|
2654
|
+
|
2655
|
+
class Default:
|
2656
|
+
def __new__(cls, *args, **kwargs): # noqa
|
2657
|
+
raise TypeError
|
2658
|
+
|
2659
|
+
class _NOT_SPECIFIED: # noqa
|
2660
|
+
def __new__(cls, *args, **kwargs): # noqa
|
2661
|
+
raise TypeError
|
2662
|
+
|
2663
|
+
@classmethod
|
2664
|
+
def of(
|
2665
|
+
cls,
|
2666
|
+
obj: ta.Optional[TimeoutLike],
|
2667
|
+
default: ta.Union[TimeoutLike, ta.Type[_NOT_SPECIFIED]] = _NOT_SPECIFIED,
|
2668
|
+
) -> 'Timeout':
|
2669
|
+
if obj is None:
|
2670
|
+
return InfiniteTimeout()
|
2671
|
+
|
2672
|
+
elif isinstance(obj, Timeout):
|
2673
|
+
return obj
|
2674
|
+
|
2675
|
+
elif isinstance(obj, (float, int)):
|
2676
|
+
return DeadlineTimeout(cls._now() + obj)
|
2677
|
+
|
2678
|
+
elif isinstance(obj, ta.Iterable):
|
2679
|
+
return CompositeTimeout(*[Timeout.of(c) for c in obj])
|
2680
|
+
|
2681
|
+
elif obj is Timeout.Default:
|
2682
|
+
if default is Timeout._NOT_SPECIFIED or default is Timeout.Default:
|
2683
|
+
raise RuntimeError('Must specify a default timeout')
|
2684
|
+
|
2685
|
+
else:
|
2686
|
+
return Timeout.of(default) # type: ignore[arg-type]
|
2687
|
+
|
2688
|
+
else:
|
2689
|
+
raise TypeError(obj)
|
2690
|
+
|
2691
|
+
@classmethod
|
2692
|
+
def of_deadline(cls, deadline: float) -> 'DeadlineTimeout':
|
2693
|
+
return DeadlineTimeout(deadline)
|
2694
|
+
|
2695
|
+
@classmethod
|
2696
|
+
def of_predicate(cls, expired_fn: ta.Callable[[], bool]) -> 'PredicateTimeout':
|
2697
|
+
return PredicateTimeout(expired_fn)
|
2698
|
+
|
2699
|
+
|
2700
|
+
class DeadlineTimeout(Timeout):
|
2701
|
+
def __init__(
|
2702
|
+
self,
|
2703
|
+
deadline: float,
|
2704
|
+
exc: ta.Union[ta.Type[BaseException], BaseException] = TimeoutError,
|
2705
|
+
) -> None:
|
2706
|
+
super().__init__()
|
2707
|
+
|
2708
|
+
self.deadline = deadline
|
2709
|
+
self.exc = exc
|
2710
|
+
|
2711
|
+
@property
|
2712
|
+
def can_expire(self) -> bool:
|
2713
|
+
return True
|
2714
|
+
|
2715
|
+
def expired(self) -> bool:
|
2716
|
+
return not (self.remaining() > 0)
|
2717
|
+
|
2718
|
+
def remaining(self) -> float:
|
2719
|
+
return self.deadline - self._now()
|
2720
|
+
|
2721
|
+
def __call__(self) -> float:
|
2722
|
+
if (rem := self.remaining()) > 0:
|
2723
|
+
return rem
|
2724
|
+
raise self.exc
|
2725
|
+
|
2726
|
+
def or_(self, o: ta.Any) -> ta.Any:
|
2727
|
+
return self()
|
2728
|
+
|
2729
|
+
|
2730
|
+
class InfiniteTimeout(Timeout):
|
2731
|
+
@property
|
2732
|
+
def can_expire(self) -> bool:
|
2733
|
+
return False
|
2734
|
+
|
2735
|
+
def expired(self) -> bool:
|
2736
|
+
return False
|
2737
|
+
|
2738
|
+
def remaining(self) -> float:
|
2739
|
+
return float('inf')
|
2740
|
+
|
2741
|
+
def __call__(self) -> float:
|
2742
|
+
return float('inf')
|
2743
|
+
|
2744
|
+
def or_(self, o: ta.Any) -> ta.Any:
|
2745
|
+
return o
|
2746
|
+
|
2747
|
+
|
2748
|
+
class CompositeTimeout(Timeout):
|
2749
|
+
def __init__(self, *children: Timeout) -> None:
|
2750
|
+
super().__init__()
|
2751
|
+
|
2752
|
+
self.children = children
|
2753
|
+
|
2754
|
+
@property
|
2755
|
+
def can_expire(self) -> bool:
|
2756
|
+
return any(c.can_expire for c in self.children)
|
2757
|
+
|
2758
|
+
def expired(self) -> bool:
|
2759
|
+
return any(c.expired() for c in self.children)
|
2760
|
+
|
2761
|
+
def remaining(self) -> float:
|
2762
|
+
return min(c.remaining() for c in self.children)
|
2763
|
+
|
2764
|
+
def __call__(self) -> float:
|
2765
|
+
return min(c() for c in self.children)
|
2766
|
+
|
2767
|
+
def or_(self, o: ta.Any) -> ta.Any:
|
2768
|
+
if self.can_expire:
|
2769
|
+
return self()
|
2770
|
+
return o
|
2771
|
+
|
2772
|
+
|
2773
|
+
class PredicateTimeout(Timeout):
|
2774
|
+
def __init__(
|
2775
|
+
self,
|
2776
|
+
expired_fn: ta.Callable[[], bool],
|
2777
|
+
exc: ta.Union[ta.Type[BaseException], BaseException] = TimeoutError,
|
2778
|
+
) -> None:
|
2779
|
+
super().__init__()
|
2780
|
+
|
2781
|
+
self.expired_fn = expired_fn
|
2782
|
+
self.exc = exc
|
2783
|
+
|
2784
|
+
@property
|
2785
|
+
def can_expire(self) -> bool:
|
2786
|
+
return True
|
2787
|
+
|
2788
|
+
def expired(self) -> bool:
|
2789
|
+
return self.expired_fn()
|
2790
|
+
|
2791
|
+
def remaining(self) -> float:
|
2792
|
+
return float('inf')
|
2793
|
+
|
2794
|
+
def __call__(self) -> float:
|
2795
|
+
if not self.expired_fn():
|
2796
|
+
return float('inf')
|
2797
|
+
raise self.exc
|
2798
|
+
|
2799
|
+
def or_(self, o: ta.Any) -> ta.Any:
|
2800
|
+
return self()
|
2801
|
+
|
2802
|
+
|
2614
2803
|
########################################
|
2615
2804
|
# ../../../omlish/lite/typing.py
|
2616
2805
|
|
@@ -3882,6 +4071,19 @@ class ArgparseCli:
|
|
3882
4071
|
return fn()
|
3883
4072
|
|
3884
4073
|
|
4074
|
+
########################################
|
4075
|
+
# ../../../omlish/asyncs/asyncio/timeouts.py
|
4076
|
+
|
4077
|
+
|
4078
|
+
def asyncio_maybe_timeout(
|
4079
|
+
fut: AwaitableT,
|
4080
|
+
timeout: ta.Optional[TimeoutLike] = None,
|
4081
|
+
) -> AwaitableT:
|
4082
|
+
if timeout is not None:
|
4083
|
+
fut = asyncio.wait_for(fut, Timeout.of(timeout)()) # type: ignore
|
4084
|
+
return fut
|
4085
|
+
|
4086
|
+
|
3885
4087
|
########################################
|
3886
4088
|
# ../../../omlish/lite/inject.py
|
3887
4089
|
|
@@ -5649,17 +5851,43 @@ class SubprocessRunOutput(ta.Generic[T]):
|
|
5649
5851
|
class SubprocessRun:
|
5650
5852
|
cmd: ta.Sequence[str]
|
5651
5853
|
input: ta.Any = None
|
5652
|
-
timeout: ta.Optional[
|
5854
|
+
timeout: ta.Optional[TimeoutLike] = None
|
5653
5855
|
check: bool = False
|
5654
5856
|
capture_output: ta.Optional[bool] = None
|
5655
5857
|
kwargs: ta.Optional[ta.Mapping[str, ta.Any]] = None
|
5656
5858
|
|
5859
|
+
#
|
5860
|
+
|
5861
|
+
_FIELD_NAMES: ta.ClassVar[ta.FrozenSet[str]]
|
5862
|
+
|
5863
|
+
def replace(self, **kwargs: ta.Any) -> 'SubprocessRun':
|
5864
|
+
if not kwargs:
|
5865
|
+
return self
|
5866
|
+
|
5867
|
+
field_kws = {}
|
5868
|
+
extra_kws = {}
|
5869
|
+
for k, v in kwargs.items():
|
5870
|
+
if k in self._FIELD_NAMES:
|
5871
|
+
field_kws[k] = v
|
5872
|
+
else:
|
5873
|
+
extra_kws[k] = v
|
5874
|
+
|
5875
|
+
return dc.replace(self, **{
|
5876
|
+
**dict(kwargs={
|
5877
|
+
**(self.kwargs or {}),
|
5878
|
+
**extra_kws,
|
5879
|
+
}),
|
5880
|
+
**field_kws, # passing a kwarg named 'kwargs' intentionally clobbers
|
5881
|
+
})
|
5882
|
+
|
5883
|
+
#
|
5884
|
+
|
5657
5885
|
@classmethod
|
5658
5886
|
def of(
|
5659
5887
|
cls,
|
5660
5888
|
*cmd: str,
|
5661
5889
|
input: ta.Any = None, # noqa
|
5662
|
-
timeout: ta.Optional[
|
5890
|
+
timeout: ta.Optional[TimeoutLike] = None,
|
5663
5891
|
check: bool = False, # noqa
|
5664
5892
|
capture_output: ta.Optional[bool] = None,
|
5665
5893
|
**kwargs: ta.Any,
|
@@ -5680,20 +5908,25 @@ class SubprocessRun:
|
|
5680
5908
|
def run(
|
5681
5909
|
self,
|
5682
5910
|
subprocesses: ta.Optional[ta.Any] = None, # AbstractSubprocesses
|
5911
|
+
**kwargs: ta.Any,
|
5683
5912
|
) -> SubprocessRunOutput:
|
5684
5913
|
if subprocesses is None:
|
5685
5914
|
subprocesses = self._DEFAULT_SUBPROCESSES
|
5686
|
-
return check.not_none(subprocesses).run_(self) # type: ignore[attr-defined]
|
5915
|
+
return check.not_none(subprocesses).run_(self.replace(**kwargs)) # type: ignore[attr-defined]
|
5687
5916
|
|
5688
5917
|
_DEFAULT_ASYNC_SUBPROCESSES: ta.ClassVar[ta.Optional[ta.Any]] = None # AbstractAsyncSubprocesses
|
5689
5918
|
|
5690
5919
|
async def async_run(
|
5691
5920
|
self,
|
5692
5921
|
async_subprocesses: ta.Optional[ta.Any] = None, # AbstractAsyncSubprocesses
|
5922
|
+
**kwargs: ta.Any,
|
5693
5923
|
) -> SubprocessRunOutput:
|
5694
5924
|
if async_subprocesses is None:
|
5695
5925
|
async_subprocesses = self._DEFAULT_ASYNC_SUBPROCESSES
|
5696
|
-
return await check.not_none(async_subprocesses).run_(self) # type: ignore[attr-defined]
|
5926
|
+
return await check.not_none(async_subprocesses).run_(self.replace(**kwargs)) # type: ignore[attr-defined]
|
5927
|
+
|
5928
|
+
|
5929
|
+
SubprocessRun._FIELD_NAMES = frozenset(fld.name for fld in dc.fields(SubprocessRun)) # noqa
|
5697
5930
|
|
5698
5931
|
|
5699
5932
|
##
|
@@ -5710,11 +5943,19 @@ class SubprocessRunnable(abc.ABC, ta.Generic[T]):
|
|
5710
5943
|
|
5711
5944
|
#
|
5712
5945
|
|
5713
|
-
def run(
|
5714
|
-
|
5946
|
+
def run(
|
5947
|
+
self,
|
5948
|
+
subprocesses: ta.Optional[ta.Any] = None, # AbstractSubprocesses
|
5949
|
+
**kwargs: ta.Any,
|
5950
|
+
) -> T:
|
5951
|
+
return self.handle_run_output(self.make_run().run(subprocesses, **kwargs))
|
5715
5952
|
|
5716
|
-
async def async_run(
|
5717
|
-
|
5953
|
+
async def async_run(
|
5954
|
+
self,
|
5955
|
+
async_subprocesses: ta.Optional[ta.Any] = None, # AbstractAsyncSubprocesses
|
5956
|
+
**kwargs: ta.Any,
|
5957
|
+
) -> T:
|
5958
|
+
return self.handle_run_output(await self.make_run().async_run(async_subprocesses, **kwargs))
|
5718
5959
|
|
5719
5960
|
|
5720
5961
|
########################################
|
@@ -6119,6 +6360,11 @@ class BaseSubprocesses(abc.ABC): # noqa
|
|
6119
6360
|
|
6120
6361
|
#
|
6121
6362
|
|
6363
|
+
if 'timeout' in kwargs:
|
6364
|
+
kwargs['timeout'] = Timeout.of(kwargs['timeout']).or_(None)
|
6365
|
+
|
6366
|
+
#
|
6367
|
+
|
6122
6368
|
return cmd, dict(
|
6123
6369
|
env=env,
|
6124
6370
|
shell=shell,
|
@@ -6327,7 +6573,7 @@ class AbstractAsyncSubprocesses(BaseSubprocesses):
|
|
6327
6573
|
self,
|
6328
6574
|
*cmd: str,
|
6329
6575
|
input: ta.Any = None, # noqa
|
6330
|
-
timeout: ta.Optional[
|
6576
|
+
timeout: ta.Optional[TimeoutLike] = None,
|
6331
6577
|
check: bool = False,
|
6332
6578
|
capture_output: ta.Optional[bool] = None,
|
6333
6579
|
**kwargs: ta.Any,
|
@@ -6404,6 +6650,11 @@ class AbstractAsyncSubprocesses(BaseSubprocesses):
|
|
6404
6650
|
|
6405
6651
|
########################################
|
6406
6652
|
# ../../../omlish/subprocesses/sync.py
|
6653
|
+
"""
|
6654
|
+
TODO:
|
6655
|
+
- popen
|
6656
|
+
- route check_calls through run_?
|
6657
|
+
"""
|
6407
6658
|
|
6408
6659
|
|
6409
6660
|
##
|
@@ -6418,7 +6669,7 @@ class AbstractSubprocesses(BaseSubprocesses, abc.ABC):
|
|
6418
6669
|
self,
|
6419
6670
|
*cmd: str,
|
6420
6671
|
input: ta.Any = None, # noqa
|
6421
|
-
timeout: ta.Optional[
|
6672
|
+
timeout: ta.Optional[TimeoutLike] = None,
|
6422
6673
|
check: bool = False,
|
6423
6674
|
capture_output: ta.Optional[bool] = None,
|
6424
6675
|
**kwargs: ta.Any,
|
@@ -6704,7 +6955,7 @@ class AsyncioProcessCommunicator:
|
|
6704
6955
|
async def communicate(
|
6705
6956
|
self,
|
6706
6957
|
input: ta.Any = None, # noqa
|
6707
|
-
timeout: ta.Optional[
|
6958
|
+
timeout: ta.Optional[TimeoutLike] = None,
|
6708
6959
|
) -> Communication:
|
6709
6960
|
return await asyncio_maybe_timeout(self._communicate(input), timeout)
|
6710
6961
|
|
@@ -6717,7 +6968,7 @@ class AsyncioSubprocesses(AbstractAsyncSubprocesses):
|
|
6717
6968
|
self,
|
6718
6969
|
proc: asyncio.subprocess.Process,
|
6719
6970
|
input: ta.Any = None, # noqa
|
6720
|
-
timeout: ta.Optional[
|
6971
|
+
timeout: ta.Optional[TimeoutLike] = None,
|
6721
6972
|
) -> ta.Tuple[ta.Optional[bytes], ta.Optional[bytes]]:
|
6722
6973
|
return await AsyncioProcessCommunicator(proc).communicate(input, timeout) # noqa
|
6723
6974
|
|
@@ -6728,7 +6979,7 @@ class AsyncioSubprocesses(AbstractAsyncSubprocesses):
|
|
6728
6979
|
self,
|
6729
6980
|
*cmd: str,
|
6730
6981
|
shell: bool = False,
|
6731
|
-
timeout: ta.Optional[
|
6982
|
+
timeout: ta.Optional[TimeoutLike] = None,
|
6732
6983
|
**kwargs: ta.Any,
|
6733
6984
|
) -> ta.AsyncGenerator[asyncio.subprocess.Process, None]:
|
6734
6985
|
with self.prepare_and_wrap( *cmd, shell=shell, **kwargs) as (cmd, kwargs): # noqa
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.2
|
2
2
|
Name: omdev
|
3
|
-
Version: 0.0.0.
|
3
|
+
Version: 0.0.0.dev226
|
4
4
|
Summary: omdev
|
5
5
|
Author: wrmsr
|
6
6
|
License: BSD-3-Clause
|
@@ -12,7 +12,7 @@ Classifier: Operating System :: OS Independent
|
|
12
12
|
Classifier: Operating System :: POSIX
|
13
13
|
Requires-Python: >=3.12
|
14
14
|
License-File: LICENSE
|
15
|
-
Requires-Dist: omlish==0.0.0.
|
15
|
+
Requires-Dist: omlish==0.0.0.dev226
|
16
16
|
Provides-Extra: all
|
17
17
|
Requires-Dist: black~=24.10; extra == "all"
|
18
18
|
Requires-Dist: pycparser~=2.22; extra == "all"
|
@@ -206,12 +206,12 @@ omdev/pyproject/resources/docker-dev.sh,sha256=DHkz5D18jok_oDolfg2mqrvGRWFoCe9GQ
|
|
206
206
|
omdev/pyproject/resources/python.sh,sha256=rFaN4SiJ9hdLDXXsDTwugI6zsw6EPkgYMmtacZeTbvw,749
|
207
207
|
omdev/scripts/__init__.py,sha256=MKCvUAEQwsIvwLixwtPlpBqmkMXLCnjjXyAXvVpDwVk,91
|
208
208
|
omdev/scripts/bumpversion.py,sha256=Kn7fo73Hs8uJh3Hi3EIyLOlzLPWAC6dwuD_lZ3cIzuY,1064
|
209
|
-
omdev/scripts/ci.py,sha256=
|
209
|
+
omdev/scripts/ci.py,sha256=IZYSToZ9UyNZKiyOnbrk7pfuJhlyamMLmkQX6nwYKP8,159949
|
210
210
|
omdev/scripts/execrss.py,sha256=mR0G0wERBYtQmVIn63lCIIFb5zkCM6X_XOENDFYDBKc,651
|
211
211
|
omdev/scripts/exectime.py,sha256=S2O4MgtzTsFOY2IUJxsrnOIame9tEFc6aOlKP-F1JSg,1541
|
212
212
|
omdev/scripts/importtrace.py,sha256=oa7CtcWJVMNDbyIEiRHej6ICfABfErMeo4_haIqe18Q,14041
|
213
|
-
omdev/scripts/interp.py,sha256=
|
214
|
-
omdev/scripts/pyproject.py,sha256=
|
213
|
+
omdev/scripts/interp.py,sha256=AYxF2dftxs1anS211-qWmJKzw_B_HIbZIyP6OC5eFdY,150405
|
214
|
+
omdev/scripts/pyproject.py,sha256=D8GgeTEOC8pKEwUX8whjOPuMGsYGRRKA8nIzXOAli_Y,258078
|
215
215
|
omdev/scripts/slowcat.py,sha256=lssv4yrgJHiWfOiHkUut2p8E8Tq32zB-ujXESQxFFHY,2728
|
216
216
|
omdev/scripts/tmpexec.py,sha256=WTYcf56Tj2qjYV14AWmV8SfT0u6Y8eIU6cKgQRvEK3c,1442
|
217
217
|
omdev/tokens/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
@@ -243,9 +243,9 @@ omdev/tools/json/rendering.py,sha256=tMcjOW5edfozcMSTxxvF7WVTsbYLoe9bCKFh50qyaGw
|
|
243
243
|
omdev/tools/pawk/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
244
244
|
omdev/tools/pawk/__main__.py,sha256=VCqeRVnqT1RPEoIrqHFSu4PXVMg4YEgF4qCQm90-eRI,66
|
245
245
|
omdev/tools/pawk/pawk.py,sha256=zsEkfQX0jF5bn712uqPAyBSdJt2dno1LH2oeSMNfXQI,11424
|
246
|
-
omdev-0.0.0.
|
247
|
-
omdev-0.0.0.
|
248
|
-
omdev-0.0.0.
|
249
|
-
omdev-0.0.0.
|
250
|
-
omdev-0.0.0.
|
251
|
-
omdev-0.0.0.
|
246
|
+
omdev-0.0.0.dev226.dist-info/LICENSE,sha256=B_hVtavaA8zCYDW99DYdcpDLKz1n3BBRjZrcbv8uG8c,1451
|
247
|
+
omdev-0.0.0.dev226.dist-info/METADATA,sha256=XK1jVJw9D5_tEULYgkiKcbQYJBjQJE0QVddRh7NsU4c,1638
|
248
|
+
omdev-0.0.0.dev226.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
|
249
|
+
omdev-0.0.0.dev226.dist-info/entry_points.txt,sha256=dHLXFmq5D9B8qUyhRtFqTGWGxlbx3t5ejedjrnXNYLU,33
|
250
|
+
omdev-0.0.0.dev226.dist-info/top_level.txt,sha256=1nr7j30fEWgLYHW3lGR9pkdHkb7knv1U1ES1XRNVQ6k,6
|
251
|
+
omdev-0.0.0.dev226.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|