ominfra 0.0.0.dev471__py3-none-any.whl → 0.0.0.dev473__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.
- ominfra/scripts/journald2aws.py +197 -29
- ominfra/scripts/manage.py +56 -29
- ominfra/scripts/supervisor.py +193 -25
- {ominfra-0.0.0.dev471.dist-info → ominfra-0.0.0.dev473.dist-info}/METADATA +3 -3
- {ominfra-0.0.0.dev471.dist-info → ominfra-0.0.0.dev473.dist-info}/RECORD +9 -9
- {ominfra-0.0.0.dev471.dist-info → ominfra-0.0.0.dev473.dist-info}/WHEEL +0 -0
- {ominfra-0.0.0.dev471.dist-info → ominfra-0.0.0.dev473.dist-info}/entry_points.txt +0 -0
- {ominfra-0.0.0.dev471.dist-info → ominfra-0.0.0.dev473.dist-info}/licenses/LICENSE +0 -0
- {ominfra-0.0.0.dev471.dist-info → ominfra-0.0.0.dev473.dist-info}/top_level.txt +0 -0
ominfra/scripts/journald2aws.py
CHANGED
|
@@ -68,7 +68,7 @@ TomlParseFloat = ta.Callable[[str], ta.Any] # ta.TypeAlias
|
|
|
68
68
|
TomlKey = ta.Tuple[str, ...] # ta.TypeAlias
|
|
69
69
|
TomlPos = int # ta.TypeAlias
|
|
70
70
|
|
|
71
|
-
# ../../../../omlish/lite/
|
|
71
|
+
# ../../../../omlish/lite/abstract.py
|
|
72
72
|
T = ta.TypeVar('T')
|
|
73
73
|
|
|
74
74
|
# ../../../../omlish/lite/cached.py
|
|
@@ -1200,6 +1200,36 @@ class TomlWriter:
|
|
|
1200
1200
|
return out.getvalue()
|
|
1201
1201
|
|
|
1202
1202
|
|
|
1203
|
+
########################################
|
|
1204
|
+
# ../../../../../omlish/io/readers.py
|
|
1205
|
+
|
|
1206
|
+
|
|
1207
|
+
##
|
|
1208
|
+
|
|
1209
|
+
|
|
1210
|
+
class RawBytesReader(ta.Protocol):
|
|
1211
|
+
def read1(self, /, n: int = -1) -> bytes: ...
|
|
1212
|
+
|
|
1213
|
+
|
|
1214
|
+
class BufferedBytesReader(RawBytesReader, ta.Protocol):
|
|
1215
|
+
def read(self, /, n: int = -1) -> bytes: ...
|
|
1216
|
+
|
|
1217
|
+
def readall(self) -> bytes: ...
|
|
1218
|
+
|
|
1219
|
+
|
|
1220
|
+
#
|
|
1221
|
+
|
|
1222
|
+
|
|
1223
|
+
class AsyncRawBytesReader(ta.Protocol):
|
|
1224
|
+
def read1(self, /, n: int = -1) -> ta.Awaitable[bytes]: ...
|
|
1225
|
+
|
|
1226
|
+
|
|
1227
|
+
class AsyncBufferedBytesReader(AsyncRawBytesReader, ta.Protocol):
|
|
1228
|
+
def read(self, /, n: int = -1) -> ta.Awaitable[bytes]: ...
|
|
1229
|
+
|
|
1230
|
+
def readall(self) -> ta.Awaitable[bytes]: ...
|
|
1231
|
+
|
|
1232
|
+
|
|
1203
1233
|
########################################
|
|
1204
1234
|
# ../../../../../omlish/lite/abstract.py
|
|
1205
1235
|
|
|
@@ -1215,25 +1245,49 @@ def is_abstract_method(obj: ta.Any) -> bool:
|
|
|
1215
1245
|
return bool(getattr(obj, _IS_ABSTRACT_METHOD_ATTR, False))
|
|
1216
1246
|
|
|
1217
1247
|
|
|
1218
|
-
def
|
|
1248
|
+
def compute_abstract_methods(cls: type) -> ta.FrozenSet[str]:
|
|
1249
|
+
# ~> https://github.com/python/cpython/blob/f3476c6507381ca860eec0989f53647b13517423/Modules/_abc.c#L358
|
|
1250
|
+
|
|
1251
|
+
# Stage 1: direct abstract methods
|
|
1252
|
+
|
|
1253
|
+
abstracts = {
|
|
1254
|
+
a
|
|
1255
|
+
# Get items as a list to avoid mutation issues during iteration
|
|
1256
|
+
for a, v in list(cls.__dict__.items())
|
|
1257
|
+
if is_abstract_method(v)
|
|
1258
|
+
}
|
|
1259
|
+
|
|
1260
|
+
# Stage 2: inherited abstract methods
|
|
1261
|
+
|
|
1262
|
+
for base in cls.__bases__:
|
|
1263
|
+
# Get __abstractmethods__ from base if it exists
|
|
1264
|
+
if (base_abstracts := getattr(base, _ABSTRACT_METHODS_ATTR, None)) is None:
|
|
1265
|
+
continue
|
|
1266
|
+
|
|
1267
|
+
# Iterate over abstract methods in base
|
|
1268
|
+
for key in base_abstracts:
|
|
1269
|
+
# Check if this class has an attribute with this name
|
|
1270
|
+
try:
|
|
1271
|
+
value = getattr(cls, key)
|
|
1272
|
+
except AttributeError:
|
|
1273
|
+
# Attribute not found in this class, skip
|
|
1274
|
+
continue
|
|
1275
|
+
|
|
1276
|
+
# Check if it's still abstract
|
|
1277
|
+
if is_abstract_method(value):
|
|
1278
|
+
abstracts.add(key)
|
|
1279
|
+
|
|
1280
|
+
return frozenset(abstracts)
|
|
1281
|
+
|
|
1282
|
+
|
|
1283
|
+
def update_abstracts(cls: ta.Type[T], *, force: bool = False) -> ta.Type[T]:
|
|
1219
1284
|
if not force and not hasattr(cls, _ABSTRACT_METHODS_ATTR):
|
|
1220
1285
|
# Per stdlib: We check for __abstractmethods__ here because cls might by a C implementation or a python
|
|
1221
1286
|
# implementation (especially during testing), and we want to handle both cases.
|
|
1222
1287
|
return cls
|
|
1223
1288
|
|
|
1224
|
-
abstracts
|
|
1225
|
-
|
|
1226
|
-
for scls in cls.__bases__:
|
|
1227
|
-
for name in getattr(scls, _ABSTRACT_METHODS_ATTR, ()):
|
|
1228
|
-
value = getattr(cls, name, None)
|
|
1229
|
-
if getattr(value, _IS_ABSTRACT_METHOD_ATTR, False):
|
|
1230
|
-
abstracts.add(name)
|
|
1231
|
-
|
|
1232
|
-
for name, value in cls.__dict__.items():
|
|
1233
|
-
if getattr(value, _IS_ABSTRACT_METHOD_ATTR, False):
|
|
1234
|
-
abstracts.add(name)
|
|
1235
|
-
|
|
1236
|
-
setattr(cls, _ABSTRACT_METHODS_ATTR, frozenset(abstracts))
|
|
1289
|
+
abstracts = compute_abstract_methods(cls)
|
|
1290
|
+
setattr(cls, _ABSTRACT_METHODS_ATTR, abstracts)
|
|
1237
1291
|
return cls
|
|
1238
1292
|
|
|
1239
1293
|
|
|
@@ -1287,23 +1341,26 @@ class Abstract:
|
|
|
1287
1341
|
super().__init_subclass__(**kwargs)
|
|
1288
1342
|
|
|
1289
1343
|
if not (Abstract in cls.__bases__ or abc.ABC in cls.__bases__):
|
|
1290
|
-
ams
|
|
1344
|
+
if ams := compute_abstract_methods(cls):
|
|
1345
|
+
amd = {
|
|
1346
|
+
a: mcls
|
|
1347
|
+
for mcls in cls.__mro__[::-1]
|
|
1348
|
+
for a in ams
|
|
1349
|
+
if a in mcls.__dict__
|
|
1350
|
+
}
|
|
1291
1351
|
|
|
1292
|
-
seen = set(cls.__dict__)
|
|
1293
|
-
for b in cls.__bases__:
|
|
1294
|
-
ams.update({a: b for a in set(getattr(b, _ABSTRACT_METHODS_ATTR, [])) - seen}) # noqa
|
|
1295
|
-
seen.update(dir(b))
|
|
1296
|
-
|
|
1297
|
-
if ams:
|
|
1298
1352
|
raise AbstractTypeError(
|
|
1299
1353
|
f'Cannot subclass abstract class {cls.__name__} with abstract methods: ' +
|
|
1300
1354
|
', '.join(sorted([
|
|
1301
1355
|
'.'.join([
|
|
1302
|
-
*([
|
|
1303
|
-
|
|
1356
|
+
*([
|
|
1357
|
+
*([m] if (m := getattr(c, '__module__')) else []),
|
|
1358
|
+
getattr(c, '__qualname__', getattr(c, '__name__')),
|
|
1359
|
+
] if c is not None else '?'),
|
|
1304
1360
|
a,
|
|
1305
1361
|
])
|
|
1306
|
-
for a
|
|
1362
|
+
for a in ams
|
|
1363
|
+
for c in [amd.get(a)]
|
|
1307
1364
|
])),
|
|
1308
1365
|
)
|
|
1309
1366
|
|
|
@@ -2384,7 +2441,7 @@ class ExitStacked:
|
|
|
2384
2441
|
es.__enter__()
|
|
2385
2442
|
try:
|
|
2386
2443
|
self._enter_contexts()
|
|
2387
|
-
except
|
|
2444
|
+
except BaseException: # noqa
|
|
2388
2445
|
es.__exit__(*sys.exc_info())
|
|
2389
2446
|
raise
|
|
2390
2447
|
return self
|
|
@@ -2395,7 +2452,7 @@ class ExitStacked:
|
|
|
2395
2452
|
return None
|
|
2396
2453
|
try:
|
|
2397
2454
|
self._exit_contexts()
|
|
2398
|
-
except
|
|
2455
|
+
except BaseException: # noqa
|
|
2399
2456
|
es.__exit__(*sys.exc_info())
|
|
2400
2457
|
raise
|
|
2401
2458
|
return es.__exit__(exc_type, exc_val, exc_tb)
|
|
@@ -2443,7 +2500,7 @@ class AsyncExitStacked:
|
|
|
2443
2500
|
await es.__aenter__()
|
|
2444
2501
|
try:
|
|
2445
2502
|
await self._async_enter_contexts()
|
|
2446
|
-
except
|
|
2503
|
+
except BaseException: # noqa
|
|
2447
2504
|
await es.__aexit__(*sys.exc_info())
|
|
2448
2505
|
raise
|
|
2449
2506
|
return self
|
|
@@ -2454,7 +2511,7 @@ class AsyncExitStacked:
|
|
|
2454
2511
|
return None
|
|
2455
2512
|
try:
|
|
2456
2513
|
await self._async_exit_contexts()
|
|
2457
|
-
except
|
|
2514
|
+
except BaseException: # noqa
|
|
2458
2515
|
await es.__aexit__(*sys.exc_info())
|
|
2459
2516
|
raise
|
|
2460
2517
|
return await es.__aexit__(exc_type, exc_val, exc_tb)
|
|
@@ -3881,6 +3938,10 @@ DEFAULT_CONFIG_RENDERER = SwitchedConfigRenderer(DEFAULT_CONFIG_RENDERERS)
|
|
|
3881
3938
|
|
|
3882
3939
|
########################################
|
|
3883
3940
|
# ../../../../../omlish/io/buffers.py
|
|
3941
|
+
"""
|
|
3942
|
+
TODO:
|
|
3943
|
+
- overhaul and just coro-ify pyio?
|
|
3944
|
+
"""
|
|
3884
3945
|
|
|
3885
3946
|
|
|
3886
3947
|
##
|
|
@@ -4059,6 +4120,9 @@ class ReadableListBuffer:
|
|
|
4059
4120
|
|
|
4060
4121
|
self._lst: list[bytes] = []
|
|
4061
4122
|
|
|
4123
|
+
def __bool__(self) -> ta.NoReturn:
|
|
4124
|
+
raise TypeError("Use 'buf is not None' or 'len(buf)'.")
|
|
4125
|
+
|
|
4062
4126
|
def __len__(self) -> int:
|
|
4063
4127
|
return sum(map(len, self._lst))
|
|
4064
4128
|
|
|
@@ -4125,6 +4189,110 @@ class ReadableListBuffer:
|
|
|
4125
4189
|
r = self.read_until_(delim)
|
|
4126
4190
|
return r if isinstance(r, bytes) else None
|
|
4127
4191
|
|
|
4192
|
+
#
|
|
4193
|
+
|
|
4194
|
+
DEFAULT_BUFFERED_READER_CHUNK_SIZE: ta.ClassVar[int] = -1
|
|
4195
|
+
|
|
4196
|
+
@ta.final
|
|
4197
|
+
class _BufferedBytesReader(BufferedBytesReader):
|
|
4198
|
+
def __init__(
|
|
4199
|
+
self,
|
|
4200
|
+
raw: RawBytesReader,
|
|
4201
|
+
buf: 'ReadableListBuffer',
|
|
4202
|
+
*,
|
|
4203
|
+
chunk_size: ta.Optional[int] = None,
|
|
4204
|
+
) -> None:
|
|
4205
|
+
self._raw = raw
|
|
4206
|
+
self._buf = buf
|
|
4207
|
+
self._chunk_size = chunk_size or ReadableListBuffer.DEFAULT_BUFFERED_READER_CHUNK_SIZE
|
|
4208
|
+
|
|
4209
|
+
def read1(self, /, n: int = -1) -> bytes:
|
|
4210
|
+
if n < 0:
|
|
4211
|
+
n = self._chunk_size
|
|
4212
|
+
if not n:
|
|
4213
|
+
return b''
|
|
4214
|
+
if 0 < n <= len(self._buf):
|
|
4215
|
+
return self._buf.read(n) or b''
|
|
4216
|
+
return self._raw.read1(n)
|
|
4217
|
+
|
|
4218
|
+
def read(self, /, n: int = -1) -> bytes:
|
|
4219
|
+
if n < 0:
|
|
4220
|
+
return self.readall()
|
|
4221
|
+
while len(self._buf) < n:
|
|
4222
|
+
if not (b := self._raw.read1(n)):
|
|
4223
|
+
break
|
|
4224
|
+
self._buf.feed(b)
|
|
4225
|
+
return self._buf.read(n) or b''
|
|
4226
|
+
|
|
4227
|
+
def readall(self) -> bytes:
|
|
4228
|
+
buf = io.BytesIO()
|
|
4229
|
+
buf.write(self._buf.read() or b'')
|
|
4230
|
+
while (b := self._raw.read1(self._chunk_size)):
|
|
4231
|
+
buf.write(b)
|
|
4232
|
+
return buf.getvalue()
|
|
4233
|
+
|
|
4234
|
+
def new_buffered_reader(
|
|
4235
|
+
self,
|
|
4236
|
+
raw: RawBytesReader,
|
|
4237
|
+
*,
|
|
4238
|
+
chunk_size: ta.Optional[int] = None,
|
|
4239
|
+
) -> BufferedBytesReader:
|
|
4240
|
+
return self._BufferedBytesReader(
|
|
4241
|
+
raw,
|
|
4242
|
+
self,
|
|
4243
|
+
chunk_size=chunk_size,
|
|
4244
|
+
)
|
|
4245
|
+
|
|
4246
|
+
@ta.final
|
|
4247
|
+
class _AsyncBufferedBytesReader(AsyncBufferedBytesReader):
|
|
4248
|
+
def __init__(
|
|
4249
|
+
self,
|
|
4250
|
+
raw: AsyncRawBytesReader,
|
|
4251
|
+
buf: 'ReadableListBuffer',
|
|
4252
|
+
*,
|
|
4253
|
+
chunk_size: ta.Optional[int] = None,
|
|
4254
|
+
) -> None:
|
|
4255
|
+
self._raw = raw
|
|
4256
|
+
self._buf = buf
|
|
4257
|
+
self._chunk_size = chunk_size or ReadableListBuffer.DEFAULT_BUFFERED_READER_CHUNK_SIZE
|
|
4258
|
+
|
|
4259
|
+
async def read1(self, /, n: int = -1) -> bytes:
|
|
4260
|
+
if n < 0:
|
|
4261
|
+
n = self._chunk_size
|
|
4262
|
+
if not n:
|
|
4263
|
+
return b''
|
|
4264
|
+
if 0 < n <= len(self._buf):
|
|
4265
|
+
return self._buf.read(n) or b''
|
|
4266
|
+
return await self._raw.read1(n)
|
|
4267
|
+
|
|
4268
|
+
async def read(self, /, n: int = -1) -> bytes:
|
|
4269
|
+
if n < 0:
|
|
4270
|
+
return await self.readall()
|
|
4271
|
+
while len(self._buf) < n:
|
|
4272
|
+
if not (b := await self._raw.read1(n)):
|
|
4273
|
+
break
|
|
4274
|
+
self._buf.feed(b)
|
|
4275
|
+
return self._buf.read(n) or b''
|
|
4276
|
+
|
|
4277
|
+
async def readall(self) -> bytes:
|
|
4278
|
+
buf = io.BytesIO()
|
|
4279
|
+
buf.write(self._buf.read() or b'')
|
|
4280
|
+
while b := await self._raw.read1(self._chunk_size):
|
|
4281
|
+
buf.write(b)
|
|
4282
|
+
return buf.getvalue()
|
|
4283
|
+
|
|
4284
|
+
def new_async_buffered_reader(
|
|
4285
|
+
self,
|
|
4286
|
+
raw: AsyncRawBytesReader,
|
|
4287
|
+
*,
|
|
4288
|
+
chunk_size: ta.Optional[int] = None,
|
|
4289
|
+
) -> AsyncBufferedBytesReader:
|
|
4290
|
+
return self._AsyncBufferedBytesReader(
|
|
4291
|
+
raw,
|
|
4292
|
+
self,
|
|
4293
|
+
chunk_size=chunk_size,
|
|
4294
|
+
)
|
|
4295
|
+
|
|
4128
4296
|
|
|
4129
4297
|
##
|
|
4130
4298
|
|
ominfra/scripts/manage.py
CHANGED
|
@@ -91,7 +91,7 @@ TomlParseFloat = ta.Callable[[str], ta.Any] # ta.TypeAlias
|
|
|
91
91
|
TomlKey = ta.Tuple[str, ...] # ta.TypeAlias
|
|
92
92
|
TomlPos = int # ta.TypeAlias
|
|
93
93
|
|
|
94
|
-
# ../../omlish/lite/
|
|
94
|
+
# ../../omlish/lite/abstract.py
|
|
95
95
|
T = ta.TypeVar('T')
|
|
96
96
|
|
|
97
97
|
# ../../omlish/lite/cached.py
|
|
@@ -2395,25 +2395,49 @@ def is_abstract_method(obj: ta.Any) -> bool:
|
|
|
2395
2395
|
return bool(getattr(obj, _IS_ABSTRACT_METHOD_ATTR, False))
|
|
2396
2396
|
|
|
2397
2397
|
|
|
2398
|
-
def
|
|
2398
|
+
def compute_abstract_methods(cls: type) -> ta.FrozenSet[str]:
|
|
2399
|
+
# ~> https://github.com/python/cpython/blob/f3476c6507381ca860eec0989f53647b13517423/Modules/_abc.c#L358
|
|
2400
|
+
|
|
2401
|
+
# Stage 1: direct abstract methods
|
|
2402
|
+
|
|
2403
|
+
abstracts = {
|
|
2404
|
+
a
|
|
2405
|
+
# Get items as a list to avoid mutation issues during iteration
|
|
2406
|
+
for a, v in list(cls.__dict__.items())
|
|
2407
|
+
if is_abstract_method(v)
|
|
2408
|
+
}
|
|
2409
|
+
|
|
2410
|
+
# Stage 2: inherited abstract methods
|
|
2411
|
+
|
|
2412
|
+
for base in cls.__bases__:
|
|
2413
|
+
# Get __abstractmethods__ from base if it exists
|
|
2414
|
+
if (base_abstracts := getattr(base, _ABSTRACT_METHODS_ATTR, None)) is None:
|
|
2415
|
+
continue
|
|
2416
|
+
|
|
2417
|
+
# Iterate over abstract methods in base
|
|
2418
|
+
for key in base_abstracts:
|
|
2419
|
+
# Check if this class has an attribute with this name
|
|
2420
|
+
try:
|
|
2421
|
+
value = getattr(cls, key)
|
|
2422
|
+
except AttributeError:
|
|
2423
|
+
# Attribute not found in this class, skip
|
|
2424
|
+
continue
|
|
2425
|
+
|
|
2426
|
+
# Check if it's still abstract
|
|
2427
|
+
if is_abstract_method(value):
|
|
2428
|
+
abstracts.add(key)
|
|
2429
|
+
|
|
2430
|
+
return frozenset(abstracts)
|
|
2431
|
+
|
|
2432
|
+
|
|
2433
|
+
def update_abstracts(cls: ta.Type[T], *, force: bool = False) -> ta.Type[T]:
|
|
2399
2434
|
if not force and not hasattr(cls, _ABSTRACT_METHODS_ATTR):
|
|
2400
2435
|
# Per stdlib: We check for __abstractmethods__ here because cls might by a C implementation or a python
|
|
2401
2436
|
# implementation (especially during testing), and we want to handle both cases.
|
|
2402
2437
|
return cls
|
|
2403
2438
|
|
|
2404
|
-
abstracts
|
|
2405
|
-
|
|
2406
|
-
for scls in cls.__bases__:
|
|
2407
|
-
for name in getattr(scls, _ABSTRACT_METHODS_ATTR, ()):
|
|
2408
|
-
value = getattr(cls, name, None)
|
|
2409
|
-
if getattr(value, _IS_ABSTRACT_METHOD_ATTR, False):
|
|
2410
|
-
abstracts.add(name)
|
|
2411
|
-
|
|
2412
|
-
for name, value in cls.__dict__.items():
|
|
2413
|
-
if getattr(value, _IS_ABSTRACT_METHOD_ATTR, False):
|
|
2414
|
-
abstracts.add(name)
|
|
2415
|
-
|
|
2416
|
-
setattr(cls, _ABSTRACT_METHODS_ATTR, frozenset(abstracts))
|
|
2439
|
+
abstracts = compute_abstract_methods(cls)
|
|
2440
|
+
setattr(cls, _ABSTRACT_METHODS_ATTR, abstracts)
|
|
2417
2441
|
return cls
|
|
2418
2442
|
|
|
2419
2443
|
|
|
@@ -2467,23 +2491,26 @@ class Abstract:
|
|
|
2467
2491
|
super().__init_subclass__(**kwargs)
|
|
2468
2492
|
|
|
2469
2493
|
if not (Abstract in cls.__bases__ or abc.ABC in cls.__bases__):
|
|
2470
|
-
ams
|
|
2494
|
+
if ams := compute_abstract_methods(cls):
|
|
2495
|
+
amd = {
|
|
2496
|
+
a: mcls
|
|
2497
|
+
for mcls in cls.__mro__[::-1]
|
|
2498
|
+
for a in ams
|
|
2499
|
+
if a in mcls.__dict__
|
|
2500
|
+
}
|
|
2471
2501
|
|
|
2472
|
-
seen = set(cls.__dict__)
|
|
2473
|
-
for b in cls.__bases__:
|
|
2474
|
-
ams.update({a: b for a in set(getattr(b, _ABSTRACT_METHODS_ATTR, [])) - seen}) # noqa
|
|
2475
|
-
seen.update(dir(b))
|
|
2476
|
-
|
|
2477
|
-
if ams:
|
|
2478
2502
|
raise AbstractTypeError(
|
|
2479
2503
|
f'Cannot subclass abstract class {cls.__name__} with abstract methods: ' +
|
|
2480
2504
|
', '.join(sorted([
|
|
2481
2505
|
'.'.join([
|
|
2482
|
-
*([
|
|
2483
|
-
|
|
2506
|
+
*([
|
|
2507
|
+
*([m] if (m := getattr(c, '__module__')) else []),
|
|
2508
|
+
getattr(c, '__qualname__', getattr(c, '__name__')),
|
|
2509
|
+
] if c is not None else '?'),
|
|
2484
2510
|
a,
|
|
2485
2511
|
])
|
|
2486
|
-
for a
|
|
2512
|
+
for a in ams
|
|
2513
|
+
for c in [amd.get(a)]
|
|
2487
2514
|
])),
|
|
2488
2515
|
)
|
|
2489
2516
|
|
|
@@ -3564,7 +3591,7 @@ class ExitStacked:
|
|
|
3564
3591
|
es.__enter__()
|
|
3565
3592
|
try:
|
|
3566
3593
|
self._enter_contexts()
|
|
3567
|
-
except
|
|
3594
|
+
except BaseException: # noqa
|
|
3568
3595
|
es.__exit__(*sys.exc_info())
|
|
3569
3596
|
raise
|
|
3570
3597
|
return self
|
|
@@ -3575,7 +3602,7 @@ class ExitStacked:
|
|
|
3575
3602
|
return None
|
|
3576
3603
|
try:
|
|
3577
3604
|
self._exit_contexts()
|
|
3578
|
-
except
|
|
3605
|
+
except BaseException: # noqa
|
|
3579
3606
|
es.__exit__(*sys.exc_info())
|
|
3580
3607
|
raise
|
|
3581
3608
|
return es.__exit__(exc_type, exc_val, exc_tb)
|
|
@@ -3623,7 +3650,7 @@ class AsyncExitStacked:
|
|
|
3623
3650
|
await es.__aenter__()
|
|
3624
3651
|
try:
|
|
3625
3652
|
await self._async_enter_contexts()
|
|
3626
|
-
except
|
|
3653
|
+
except BaseException: # noqa
|
|
3627
3654
|
await es.__aexit__(*sys.exc_info())
|
|
3628
3655
|
raise
|
|
3629
3656
|
return self
|
|
@@ -3634,7 +3661,7 @@ class AsyncExitStacked:
|
|
|
3634
3661
|
return None
|
|
3635
3662
|
try:
|
|
3636
3663
|
await self._async_exit_contexts()
|
|
3637
|
-
except
|
|
3664
|
+
except BaseException: # noqa
|
|
3638
3665
|
await es.__aexit__(*sys.exc_info())
|
|
3639
3666
|
raise
|
|
3640
3667
|
return await es.__aexit__(exc_type, exc_val, exc_tb)
|
ominfra/scripts/supervisor.py
CHANGED
|
@@ -113,7 +113,7 @@ TomlParseFloat = ta.Callable[[str], ta.Any] # ta.TypeAlias
|
|
|
113
113
|
TomlKey = ta.Tuple[str, ...] # ta.TypeAlias
|
|
114
114
|
TomlPos = int # ta.TypeAlias
|
|
115
115
|
|
|
116
|
-
# ../../omlish/lite/
|
|
116
|
+
# ../../omlish/lite/abstract.py
|
|
117
117
|
T = ta.TypeVar('T')
|
|
118
118
|
|
|
119
119
|
# ../../omlish/lite/cached.py
|
|
@@ -1726,6 +1726,36 @@ class HttpProtocolVersions:
|
|
|
1726
1726
|
HTTP_2_0 = HttpProtocolVersion(2, 0)
|
|
1727
1727
|
|
|
1728
1728
|
|
|
1729
|
+
########################################
|
|
1730
|
+
# ../../../omlish/io/readers.py
|
|
1731
|
+
|
|
1732
|
+
|
|
1733
|
+
##
|
|
1734
|
+
|
|
1735
|
+
|
|
1736
|
+
class RawBytesReader(ta.Protocol):
|
|
1737
|
+
def read1(self, /, n: int = -1) -> bytes: ...
|
|
1738
|
+
|
|
1739
|
+
|
|
1740
|
+
class BufferedBytesReader(RawBytesReader, ta.Protocol):
|
|
1741
|
+
def read(self, /, n: int = -1) -> bytes: ...
|
|
1742
|
+
|
|
1743
|
+
def readall(self) -> bytes: ...
|
|
1744
|
+
|
|
1745
|
+
|
|
1746
|
+
#
|
|
1747
|
+
|
|
1748
|
+
|
|
1749
|
+
class AsyncRawBytesReader(ta.Protocol):
|
|
1750
|
+
def read1(self, /, n: int = -1) -> ta.Awaitable[bytes]: ...
|
|
1751
|
+
|
|
1752
|
+
|
|
1753
|
+
class AsyncBufferedBytesReader(AsyncRawBytesReader, ta.Protocol):
|
|
1754
|
+
def read(self, /, n: int = -1) -> ta.Awaitable[bytes]: ...
|
|
1755
|
+
|
|
1756
|
+
def readall(self) -> ta.Awaitable[bytes]: ...
|
|
1757
|
+
|
|
1758
|
+
|
|
1729
1759
|
########################################
|
|
1730
1760
|
# ../../../omlish/lite/abstract.py
|
|
1731
1761
|
|
|
@@ -1741,25 +1771,49 @@ def is_abstract_method(obj: ta.Any) -> bool:
|
|
|
1741
1771
|
return bool(getattr(obj, _IS_ABSTRACT_METHOD_ATTR, False))
|
|
1742
1772
|
|
|
1743
1773
|
|
|
1744
|
-
def
|
|
1774
|
+
def compute_abstract_methods(cls: type) -> ta.FrozenSet[str]:
|
|
1775
|
+
# ~> https://github.com/python/cpython/blob/f3476c6507381ca860eec0989f53647b13517423/Modules/_abc.c#L358
|
|
1776
|
+
|
|
1777
|
+
# Stage 1: direct abstract methods
|
|
1778
|
+
|
|
1779
|
+
abstracts = {
|
|
1780
|
+
a
|
|
1781
|
+
# Get items as a list to avoid mutation issues during iteration
|
|
1782
|
+
for a, v in list(cls.__dict__.items())
|
|
1783
|
+
if is_abstract_method(v)
|
|
1784
|
+
}
|
|
1785
|
+
|
|
1786
|
+
# Stage 2: inherited abstract methods
|
|
1787
|
+
|
|
1788
|
+
for base in cls.__bases__:
|
|
1789
|
+
# Get __abstractmethods__ from base if it exists
|
|
1790
|
+
if (base_abstracts := getattr(base, _ABSTRACT_METHODS_ATTR, None)) is None:
|
|
1791
|
+
continue
|
|
1792
|
+
|
|
1793
|
+
# Iterate over abstract methods in base
|
|
1794
|
+
for key in base_abstracts:
|
|
1795
|
+
# Check if this class has an attribute with this name
|
|
1796
|
+
try:
|
|
1797
|
+
value = getattr(cls, key)
|
|
1798
|
+
except AttributeError:
|
|
1799
|
+
# Attribute not found in this class, skip
|
|
1800
|
+
continue
|
|
1801
|
+
|
|
1802
|
+
# Check if it's still abstract
|
|
1803
|
+
if is_abstract_method(value):
|
|
1804
|
+
abstracts.add(key)
|
|
1805
|
+
|
|
1806
|
+
return frozenset(abstracts)
|
|
1807
|
+
|
|
1808
|
+
|
|
1809
|
+
def update_abstracts(cls: ta.Type[T], *, force: bool = False) -> ta.Type[T]:
|
|
1745
1810
|
if not force and not hasattr(cls, _ABSTRACT_METHODS_ATTR):
|
|
1746
1811
|
# Per stdlib: We check for __abstractmethods__ here because cls might by a C implementation or a python
|
|
1747
1812
|
# implementation (especially during testing), and we want to handle both cases.
|
|
1748
1813
|
return cls
|
|
1749
1814
|
|
|
1750
|
-
abstracts
|
|
1751
|
-
|
|
1752
|
-
for scls in cls.__bases__:
|
|
1753
|
-
for name in getattr(scls, _ABSTRACT_METHODS_ATTR, ()):
|
|
1754
|
-
value = getattr(cls, name, None)
|
|
1755
|
-
if getattr(value, _IS_ABSTRACT_METHOD_ATTR, False):
|
|
1756
|
-
abstracts.add(name)
|
|
1757
|
-
|
|
1758
|
-
for name, value in cls.__dict__.items():
|
|
1759
|
-
if getattr(value, _IS_ABSTRACT_METHOD_ATTR, False):
|
|
1760
|
-
abstracts.add(name)
|
|
1761
|
-
|
|
1762
|
-
setattr(cls, _ABSTRACT_METHODS_ATTR, frozenset(abstracts))
|
|
1815
|
+
abstracts = compute_abstract_methods(cls)
|
|
1816
|
+
setattr(cls, _ABSTRACT_METHODS_ATTR, abstracts)
|
|
1763
1817
|
return cls
|
|
1764
1818
|
|
|
1765
1819
|
|
|
@@ -1813,23 +1867,26 @@ class Abstract:
|
|
|
1813
1867
|
super().__init_subclass__(**kwargs)
|
|
1814
1868
|
|
|
1815
1869
|
if not (Abstract in cls.__bases__ or abc.ABC in cls.__bases__):
|
|
1816
|
-
ams
|
|
1817
|
-
|
|
1818
|
-
|
|
1819
|
-
|
|
1820
|
-
|
|
1821
|
-
|
|
1870
|
+
if ams := compute_abstract_methods(cls):
|
|
1871
|
+
amd = {
|
|
1872
|
+
a: mcls
|
|
1873
|
+
for mcls in cls.__mro__[::-1]
|
|
1874
|
+
for a in ams
|
|
1875
|
+
if a in mcls.__dict__
|
|
1876
|
+
}
|
|
1822
1877
|
|
|
1823
|
-
if ams:
|
|
1824
1878
|
raise AbstractTypeError(
|
|
1825
1879
|
f'Cannot subclass abstract class {cls.__name__} with abstract methods: ' +
|
|
1826
1880
|
', '.join(sorted([
|
|
1827
1881
|
'.'.join([
|
|
1828
|
-
*([
|
|
1829
|
-
|
|
1882
|
+
*([
|
|
1883
|
+
*([m] if (m := getattr(c, '__module__')) else []),
|
|
1884
|
+
getattr(c, '__qualname__', getattr(c, '__name__')),
|
|
1885
|
+
] if c is not None else '?'),
|
|
1830
1886
|
a,
|
|
1831
1887
|
])
|
|
1832
|
-
for a
|
|
1888
|
+
for a in ams
|
|
1889
|
+
for c in [amd.get(a)]
|
|
1833
1890
|
])),
|
|
1834
1891
|
)
|
|
1835
1892
|
|
|
@@ -4736,6 +4793,10 @@ class HttpRequestParser:
|
|
|
4736
4793
|
|
|
4737
4794
|
########################################
|
|
4738
4795
|
# ../../../omlish/io/buffers.py
|
|
4796
|
+
"""
|
|
4797
|
+
TODO:
|
|
4798
|
+
- overhaul and just coro-ify pyio?
|
|
4799
|
+
"""
|
|
4739
4800
|
|
|
4740
4801
|
|
|
4741
4802
|
##
|
|
@@ -4914,6 +4975,9 @@ class ReadableListBuffer:
|
|
|
4914
4975
|
|
|
4915
4976
|
self._lst: list[bytes] = []
|
|
4916
4977
|
|
|
4978
|
+
def __bool__(self) -> ta.NoReturn:
|
|
4979
|
+
raise TypeError("Use 'buf is not None' or 'len(buf)'.")
|
|
4980
|
+
|
|
4917
4981
|
def __len__(self) -> int:
|
|
4918
4982
|
return sum(map(len, self._lst))
|
|
4919
4983
|
|
|
@@ -4980,6 +5044,110 @@ class ReadableListBuffer:
|
|
|
4980
5044
|
r = self.read_until_(delim)
|
|
4981
5045
|
return r if isinstance(r, bytes) else None
|
|
4982
5046
|
|
|
5047
|
+
#
|
|
5048
|
+
|
|
5049
|
+
DEFAULT_BUFFERED_READER_CHUNK_SIZE: ta.ClassVar[int] = -1
|
|
5050
|
+
|
|
5051
|
+
@ta.final
|
|
5052
|
+
class _BufferedBytesReader(BufferedBytesReader):
|
|
5053
|
+
def __init__(
|
|
5054
|
+
self,
|
|
5055
|
+
raw: RawBytesReader,
|
|
5056
|
+
buf: 'ReadableListBuffer',
|
|
5057
|
+
*,
|
|
5058
|
+
chunk_size: ta.Optional[int] = None,
|
|
5059
|
+
) -> None:
|
|
5060
|
+
self._raw = raw
|
|
5061
|
+
self._buf = buf
|
|
5062
|
+
self._chunk_size = chunk_size or ReadableListBuffer.DEFAULT_BUFFERED_READER_CHUNK_SIZE
|
|
5063
|
+
|
|
5064
|
+
def read1(self, /, n: int = -1) -> bytes:
|
|
5065
|
+
if n < 0:
|
|
5066
|
+
n = self._chunk_size
|
|
5067
|
+
if not n:
|
|
5068
|
+
return b''
|
|
5069
|
+
if 0 < n <= len(self._buf):
|
|
5070
|
+
return self._buf.read(n) or b''
|
|
5071
|
+
return self._raw.read1(n)
|
|
5072
|
+
|
|
5073
|
+
def read(self, /, n: int = -1) -> bytes:
|
|
5074
|
+
if n < 0:
|
|
5075
|
+
return self.readall()
|
|
5076
|
+
while len(self._buf) < n:
|
|
5077
|
+
if not (b := self._raw.read1(n)):
|
|
5078
|
+
break
|
|
5079
|
+
self._buf.feed(b)
|
|
5080
|
+
return self._buf.read(n) or b''
|
|
5081
|
+
|
|
5082
|
+
def readall(self) -> bytes:
|
|
5083
|
+
buf = io.BytesIO()
|
|
5084
|
+
buf.write(self._buf.read() or b'')
|
|
5085
|
+
while (b := self._raw.read1(self._chunk_size)):
|
|
5086
|
+
buf.write(b)
|
|
5087
|
+
return buf.getvalue()
|
|
5088
|
+
|
|
5089
|
+
def new_buffered_reader(
|
|
5090
|
+
self,
|
|
5091
|
+
raw: RawBytesReader,
|
|
5092
|
+
*,
|
|
5093
|
+
chunk_size: ta.Optional[int] = None,
|
|
5094
|
+
) -> BufferedBytesReader:
|
|
5095
|
+
return self._BufferedBytesReader(
|
|
5096
|
+
raw,
|
|
5097
|
+
self,
|
|
5098
|
+
chunk_size=chunk_size,
|
|
5099
|
+
)
|
|
5100
|
+
|
|
5101
|
+
@ta.final
|
|
5102
|
+
class _AsyncBufferedBytesReader(AsyncBufferedBytesReader):
|
|
5103
|
+
def __init__(
|
|
5104
|
+
self,
|
|
5105
|
+
raw: AsyncRawBytesReader,
|
|
5106
|
+
buf: 'ReadableListBuffer',
|
|
5107
|
+
*,
|
|
5108
|
+
chunk_size: ta.Optional[int] = None,
|
|
5109
|
+
) -> None:
|
|
5110
|
+
self._raw = raw
|
|
5111
|
+
self._buf = buf
|
|
5112
|
+
self._chunk_size = chunk_size or ReadableListBuffer.DEFAULT_BUFFERED_READER_CHUNK_SIZE
|
|
5113
|
+
|
|
5114
|
+
async def read1(self, /, n: int = -1) -> bytes:
|
|
5115
|
+
if n < 0:
|
|
5116
|
+
n = self._chunk_size
|
|
5117
|
+
if not n:
|
|
5118
|
+
return b''
|
|
5119
|
+
if 0 < n <= len(self._buf):
|
|
5120
|
+
return self._buf.read(n) or b''
|
|
5121
|
+
return await self._raw.read1(n)
|
|
5122
|
+
|
|
5123
|
+
async def read(self, /, n: int = -1) -> bytes:
|
|
5124
|
+
if n < 0:
|
|
5125
|
+
return await self.readall()
|
|
5126
|
+
while len(self._buf) < n:
|
|
5127
|
+
if not (b := await self._raw.read1(n)):
|
|
5128
|
+
break
|
|
5129
|
+
self._buf.feed(b)
|
|
5130
|
+
return self._buf.read(n) or b''
|
|
5131
|
+
|
|
5132
|
+
async def readall(self) -> bytes:
|
|
5133
|
+
buf = io.BytesIO()
|
|
5134
|
+
buf.write(self._buf.read() or b'')
|
|
5135
|
+
while b := await self._raw.read1(self._chunk_size):
|
|
5136
|
+
buf.write(b)
|
|
5137
|
+
return buf.getvalue()
|
|
5138
|
+
|
|
5139
|
+
def new_async_buffered_reader(
|
|
5140
|
+
self,
|
|
5141
|
+
raw: AsyncRawBytesReader,
|
|
5142
|
+
*,
|
|
5143
|
+
chunk_size: ta.Optional[int] = None,
|
|
5144
|
+
) -> AsyncBufferedBytesReader:
|
|
5145
|
+
return self._AsyncBufferedBytesReader(
|
|
5146
|
+
raw,
|
|
5147
|
+
self,
|
|
5148
|
+
chunk_size=chunk_size,
|
|
5149
|
+
)
|
|
5150
|
+
|
|
4983
5151
|
|
|
4984
5152
|
##
|
|
4985
5153
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: ominfra
|
|
3
|
-
Version: 0.0.0.
|
|
3
|
+
Version: 0.0.0.dev473
|
|
4
4
|
Summary: ominfra
|
|
5
5
|
Author: wrmsr
|
|
6
6
|
License-Expression: BSD-3-Clause
|
|
@@ -14,8 +14,8 @@ Classifier: Programming Language :: Python :: 3.13
|
|
|
14
14
|
Requires-Python: >=3.13
|
|
15
15
|
Description-Content-Type: text/markdown
|
|
16
16
|
License-File: LICENSE
|
|
17
|
-
Requires-Dist: omdev==0.0.0.
|
|
18
|
-
Requires-Dist: omlish==0.0.0.
|
|
17
|
+
Requires-Dist: omdev==0.0.0.dev473
|
|
18
|
+
Requires-Dist: omlish==0.0.0.dev473
|
|
19
19
|
Provides-Extra: all
|
|
20
20
|
Requires-Dist: paramiko~=4.0; extra == "all"
|
|
21
21
|
Requires-Dist: asyncssh~=2.21; extra == "all"
|
|
@@ -112,9 +112,9 @@ ominfra/manage/targets/connection.py,sha256=mOHCsDVG-DZBhl3Mb7TTr1vhPb0gxDOOMW1x
|
|
|
112
112
|
ominfra/manage/targets/inject.py,sha256=3M4wBkxtvymq_yhiotHlTN8iydELMjVCndyp9Bq-4eo,1572
|
|
113
113
|
ominfra/manage/targets/targets.py,sha256=LjSQrDsHEjEQMDHcxtNKmLjy0YGLXJRGPFdUjazzFIM,1918
|
|
114
114
|
ominfra/scripts/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
115
|
-
ominfra/scripts/journald2aws.py,sha256=
|
|
116
|
-
ominfra/scripts/manage.py,sha256=
|
|
117
|
-
ominfra/scripts/supervisor.py,sha256=
|
|
115
|
+
ominfra/scripts/journald2aws.py,sha256=zv0LkRqqecTkjxn06dRvRFOw6NdYapvqXbfJrwhQjNE,251716
|
|
116
|
+
ominfra/scripts/manage.py,sha256=K0P2XHrGGhyV0iaR4AE-qrY5WOIKyc5QvtJjoe85t88,471985
|
|
117
|
+
ominfra/scripts/supervisor.py,sha256=HN3vrLIKy0Xf-0-DYqVm8EKdn-pC2umOQOTcADm1GBs,386410
|
|
118
118
|
ominfra/supervisor/LICENSE.txt,sha256=ZrHY15PVR98y26Yg6iQfa-SXnUaYTDhrUsPVcEO5OKM,1874
|
|
119
119
|
ominfra/supervisor/__init__.py,sha256=Y3l4WY4JRi2uLG6kgbGp93fuGfkxkKwZDvhsa0Rwgtk,15
|
|
120
120
|
ominfra/supervisor/__main__.py,sha256=I0yFw-C08OOiZ3BF6lF1Oiv789EQXu-_j6whDhQUTEA,66
|
|
@@ -156,9 +156,9 @@ ominfra/tailscale/api.py,sha256=XASv9C_CWI-u-yX5jVzhJrkJhlwQRkYQWQQG1uJwAd8,1375
|
|
|
156
156
|
ominfra/tailscale/cli.py,sha256=zRV7-tKB7kBah1oTVZlol-vwx1FBlnfzYAPGkeU5jX4,3543
|
|
157
157
|
ominfra/tools/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
158
158
|
ominfra/tools/listresources.py,sha256=ePmo7cUAiBZARkM_3K4GKYZXxV73An_aioS1m-AAJis,6181
|
|
159
|
-
ominfra-0.0.0.
|
|
160
|
-
ominfra-0.0.0.
|
|
161
|
-
ominfra-0.0.0.
|
|
162
|
-
ominfra-0.0.0.
|
|
163
|
-
ominfra-0.0.0.
|
|
164
|
-
ominfra-0.0.0.
|
|
159
|
+
ominfra-0.0.0.dev473.dist-info/licenses/LICENSE,sha256=B_hVtavaA8zCYDW99DYdcpDLKz1n3BBRjZrcbv8uG8c,1451
|
|
160
|
+
ominfra-0.0.0.dev473.dist-info/METADATA,sha256=Q5_KNTkLxq2H9PSaDy_CACJl_-j3372MKA1huehi1Hw,2377
|
|
161
|
+
ominfra-0.0.0.dev473.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
162
|
+
ominfra-0.0.0.dev473.dist-info/entry_points.txt,sha256=kgecQ2MgGrM9qK744BoKS3tMesaC3yjLnl9pa5CRczg,37
|
|
163
|
+
ominfra-0.0.0.dev473.dist-info/top_level.txt,sha256=E-b2OHkk_AOBLXHYZQ2EOFKl-_6uOGd8EjeG-Zy6h_w,8
|
|
164
|
+
ominfra-0.0.0.dev473.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|