omdev 0.0.0.dev225__py3-none-any.whl → 0.0.0.dev226__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/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
|