ominfra 0.0.0.dev149__py3-none-any.whl → 0.0.0.dev150__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/clouds/aws/auth.py +7 -9
- ominfra/clouds/aws/journald2aws/driver.py +4 -4
- ominfra/clouds/aws/logs.py +4 -5
- ominfra/clouds/gcp/auth.py +1 -1
- ominfra/configs.py +3 -4
- ominfra/journald/messages.py +2 -2
- ominfra/journald/tailer.py +2 -2
- ominfra/manage/commands/base.py +2 -2
- ominfra/manage/commands/interp.py +3 -3
- ominfra/manage/commands/subprocess.py +3 -4
- ominfra/manage/deploy/paths.py +12 -15
- ominfra/manage/main.py +72 -75
- ominfra/manage/remote/_main.py +6 -7
- ominfra/manage/remote/execution.py +7 -10
- ominfra/manage/remote/spawning.py +3 -3
- ominfra/scripts/journald2aws.py +449 -93
- ominfra/scripts/manage.py +770 -186
- ominfra/scripts/supervisor.py +1137 -781
- ominfra/supervisor/groupsimpl.py +2 -2
- ominfra/supervisor/http.py +5 -5
- ominfra/supervisor/main.py +1 -1
- ominfra/supervisor/processimpl.py +2 -2
- ominfra/supervisor/spawningimpl.py +8 -9
- ominfra/supervisor/supervisor.py +2 -2
- {ominfra-0.0.0.dev149.dist-info → ominfra-0.0.0.dev150.dist-info}/METADATA +3 -3
- {ominfra-0.0.0.dev149.dist-info → ominfra-0.0.0.dev150.dist-info}/RECORD +30 -30
- {ominfra-0.0.0.dev149.dist-info → ominfra-0.0.0.dev150.dist-info}/LICENSE +0 -0
- {ominfra-0.0.0.dev149.dist-info → ominfra-0.0.0.dev150.dist-info}/WHEEL +0 -0
- {ominfra-0.0.0.dev149.dist-info → ominfra-0.0.0.dev150.dist-info}/entry_points.txt +0 -0
- {ominfra-0.0.0.dev149.dist-info → ominfra-0.0.0.dev150.dist-info}/top_level.txt +0 -0
ominfra/scripts/manage.py
CHANGED
@@ -9,6 +9,7 @@ manage.py -s 'docker run -i python:3.12'
|
|
9
9
|
manage.py -s 'ssh -i /foo/bar.pem foo@bar.baz' -q --python=python3.8
|
10
10
|
"""
|
11
11
|
import abc
|
12
|
+
import argparse
|
12
13
|
import asyncio
|
13
14
|
import asyncio.base_subprocess
|
14
15
|
import asyncio.subprocess
|
@@ -76,6 +77,11 @@ CallableT = ta.TypeVar('CallableT', bound=ta.Callable)
|
|
76
77
|
|
77
78
|
# ../../omlish/lite/check.py
|
78
79
|
SizedT = ta.TypeVar('SizedT', bound=ta.Sized)
|
80
|
+
CheckMessage = ta.Union[str, ta.Callable[..., ta.Optional[str]], None] # ta.TypeAlias
|
81
|
+
CheckLateConfigureFn = ta.Callable[['Checks'], None]
|
82
|
+
CheckOnRaiseFn = ta.Callable[[Exception], None] # ta.TypeAlias
|
83
|
+
CheckExceptionFactory = ta.Callable[..., Exception] # ta.TypeAlias
|
84
|
+
CheckArgsRenderer = ta.Callable[..., ta.Optional[str]] # ta.TypeAlias
|
79
85
|
|
80
86
|
# ../../omdev/packaging/specifiers.py
|
81
87
|
UnparsedVersion = ta.Union['Version', str]
|
@@ -86,6 +92,9 @@ CallableVersionOperator = ta.Callable[['Version', str], bool]
|
|
86
92
|
CommandT = ta.TypeVar('CommandT', bound='Command')
|
87
93
|
CommandOutputT = ta.TypeVar('CommandOutputT', bound='Command.Output')
|
88
94
|
|
95
|
+
# ../../omlish/argparse/cli.py
|
96
|
+
ArgparseCommandFn = ta.Callable[[], ta.Optional[int]] # ta.TypeAlias
|
97
|
+
|
89
98
|
# ../../omlish/lite/inject.py
|
90
99
|
U = ta.TypeVar('U')
|
91
100
|
InjectorKeyCls = ta.Union[type, ta.NewType]
|
@@ -1152,104 +1161,454 @@ def async_cached_nullary(fn): # ta.Callable[..., T]) -> ta.Callable[..., T]:
|
|
1152
1161
|
|
1153
1162
|
########################################
|
1154
1163
|
# ../../../omlish/lite/check.py
|
1164
|
+
"""
|
1165
|
+
TODO:
|
1166
|
+
- def maybe(v: lang.Maybe[T])
|
1167
|
+
- patch / override lite.check ?
|
1168
|
+
- checker interface?
|
1169
|
+
"""
|
1170
|
+
|
1171
|
+
|
1172
|
+
##
|
1173
|
+
|
1174
|
+
|
1175
|
+
class Checks:
|
1176
|
+
def __init__(self) -> None:
|
1177
|
+
super().__init__()
|
1178
|
+
|
1179
|
+
self._config_lock = threading.RLock()
|
1180
|
+
self._on_raise_fns: ta.Sequence[CheckOnRaiseFn] = []
|
1181
|
+
self._exception_factory: CheckExceptionFactory = Checks.default_exception_factory
|
1182
|
+
self._args_renderer: ta.Optional[CheckArgsRenderer] = None
|
1183
|
+
self._late_configure_fns: ta.Sequence[CheckLateConfigureFn] = []
|
1184
|
+
|
1185
|
+
@staticmethod
|
1186
|
+
def default_exception_factory(exc_cls: ta.Type[Exception], *args, **kwargs) -> Exception:
|
1187
|
+
return exc_cls(*args, **kwargs) # noqa
|
1188
|
+
|
1189
|
+
#
|
1190
|
+
|
1191
|
+
def register_on_raise(self, fn: CheckOnRaiseFn) -> None:
|
1192
|
+
with self._config_lock:
|
1193
|
+
self._on_raise_fns = [*self._on_raise_fns, fn]
|
1194
|
+
|
1195
|
+
def unregister_on_raise(self, fn: CheckOnRaiseFn) -> None:
|
1196
|
+
with self._config_lock:
|
1197
|
+
self._on_raise_fns = [e for e in self._on_raise_fns if e != fn]
|
1198
|
+
|
1199
|
+
#
|
1200
|
+
|
1201
|
+
def set_exception_factory(self, factory: CheckExceptionFactory) -> None:
|
1202
|
+
self._exception_factory = factory
|
1203
|
+
|
1204
|
+
def set_args_renderer(self, renderer: ta.Optional[CheckArgsRenderer]) -> None:
|
1205
|
+
self._args_renderer = renderer
|
1206
|
+
|
1207
|
+
#
|
1208
|
+
|
1209
|
+
def register_late_configure(self, fn: CheckLateConfigureFn) -> None:
|
1210
|
+
with self._config_lock:
|
1211
|
+
self._late_configure_fns = [*self._late_configure_fns, fn]
|
1212
|
+
|
1213
|
+
def _late_configure(self) -> None:
|
1214
|
+
if not self._late_configure_fns:
|
1215
|
+
return
|
1216
|
+
|
1217
|
+
with self._config_lock:
|
1218
|
+
if not (lc := self._late_configure_fns):
|
1219
|
+
return
|
1220
|
+
|
1221
|
+
for fn in lc:
|
1222
|
+
fn(self)
|
1223
|
+
|
1224
|
+
self._late_configure_fns = []
|
1225
|
+
|
1226
|
+
#
|
1227
|
+
|
1228
|
+
class _ArgsKwargs:
|
1229
|
+
def __init__(self, *args, **kwargs):
|
1230
|
+
self.args = args
|
1231
|
+
self.kwargs = kwargs
|
1232
|
+
|
1233
|
+
def _raise(
|
1234
|
+
self,
|
1235
|
+
exception_type: ta.Type[Exception],
|
1236
|
+
default_message: str,
|
1237
|
+
message: CheckMessage,
|
1238
|
+
ak: _ArgsKwargs = _ArgsKwargs(),
|
1239
|
+
*,
|
1240
|
+
render_fmt: ta.Optional[str] = None,
|
1241
|
+
) -> ta.NoReturn:
|
1242
|
+
exc_args = ()
|
1243
|
+
if callable(message):
|
1244
|
+
message = ta.cast(ta.Callable, message)(*ak.args, **ak.kwargs)
|
1245
|
+
if isinstance(message, tuple):
|
1246
|
+
message, *exc_args = message # type: ignore
|
1247
|
+
|
1248
|
+
if message is None:
|
1249
|
+
message = default_message
|
1250
|
+
|
1251
|
+
self._late_configure()
|
1252
|
+
|
1253
|
+
if render_fmt is not None and (af := self._args_renderer) is not None:
|
1254
|
+
rendered_args = af(render_fmt, *ak.args)
|
1255
|
+
if rendered_args is not None:
|
1256
|
+
message = f'{message} : {rendered_args}'
|
1257
|
+
|
1258
|
+
exc = self._exception_factory(
|
1259
|
+
exception_type,
|
1260
|
+
message,
|
1261
|
+
*exc_args,
|
1262
|
+
*ak.args,
|
1263
|
+
**ak.kwargs,
|
1264
|
+
)
|
1265
|
+
|
1266
|
+
for fn in self._on_raise_fns:
|
1267
|
+
fn(exc)
|
1268
|
+
|
1269
|
+
raise exc
|
1270
|
+
|
1271
|
+
#
|
1272
|
+
|
1273
|
+
def _unpack_isinstance_spec(self, spec: ta.Any) -> tuple:
|
1274
|
+
if isinstance(spec, type):
|
1275
|
+
return (spec,)
|
1276
|
+
if not isinstance(spec, tuple):
|
1277
|
+
spec = (spec,)
|
1278
|
+
if None in spec:
|
1279
|
+
spec = tuple(filter(None, spec)) + (None.__class__,) # noqa
|
1280
|
+
if ta.Any in spec:
|
1281
|
+
spec = (object,)
|
1282
|
+
return spec
|
1283
|
+
|
1284
|
+
def isinstance(self, v: ta.Any, spec: ta.Union[ta.Type[T], tuple], msg: CheckMessage = None) -> T: # noqa
|
1285
|
+
if not isinstance(v, self._unpack_isinstance_spec(spec)):
|
1286
|
+
self._raise(
|
1287
|
+
TypeError,
|
1288
|
+
'Must be instance',
|
1289
|
+
msg,
|
1290
|
+
Checks._ArgsKwargs(v, spec),
|
1291
|
+
render_fmt='not isinstance(%s, %s)',
|
1292
|
+
)
|
1293
|
+
|
1294
|
+
return v
|
1295
|
+
|
1296
|
+
def of_isinstance(self, spec: ta.Union[ta.Type[T], tuple], msg: CheckMessage = None) -> ta.Callable[[ta.Any], T]:
|
1297
|
+
def inner(v):
|
1298
|
+
return self.isinstance(v, self._unpack_isinstance_spec(spec), msg)
|
1299
|
+
|
1300
|
+
return inner
|
1301
|
+
|
1302
|
+
def cast(self, v: ta.Any, cls: ta.Type[T], msg: CheckMessage = None) -> T: # noqa
|
1303
|
+
if not isinstance(v, cls):
|
1304
|
+
self._raise(
|
1305
|
+
TypeError,
|
1306
|
+
'Must be instance',
|
1307
|
+
msg,
|
1308
|
+
Checks._ArgsKwargs(v, cls),
|
1309
|
+
)
|
1310
|
+
|
1311
|
+
return v
|
1155
1312
|
|
1313
|
+
def of_cast(self, cls: ta.Type[T], msg: CheckMessage = None) -> ta.Callable[[T], T]:
|
1314
|
+
def inner(v):
|
1315
|
+
return self.cast(v, cls, msg)
|
1156
1316
|
|
1157
|
-
|
1158
|
-
if not isinstance(v, spec):
|
1159
|
-
raise TypeError(v)
|
1160
|
-
return v
|
1317
|
+
return inner
|
1161
1318
|
|
1319
|
+
def not_isinstance(self, v: T, spec: ta.Any, msg: CheckMessage = None) -> T: # noqa
|
1320
|
+
if isinstance(v, self._unpack_isinstance_spec(spec)):
|
1321
|
+
self._raise(
|
1322
|
+
TypeError,
|
1323
|
+
'Must not be instance',
|
1324
|
+
msg,
|
1325
|
+
Checks._ArgsKwargs(v, spec),
|
1326
|
+
render_fmt='isinstance(%s, %s)',
|
1327
|
+
)
|
1162
1328
|
|
1163
|
-
|
1164
|
-
if isinstance(v, spec):
|
1165
|
-
raise TypeError(v)
|
1166
|
-
return v
|
1329
|
+
return v
|
1167
1330
|
|
1331
|
+
def of_not_isinstance(self, spec: ta.Any, msg: CheckMessage = None) -> ta.Callable[[T], T]:
|
1332
|
+
def inner(v):
|
1333
|
+
return self.not_isinstance(v, self._unpack_isinstance_spec(spec), msg)
|
1168
1334
|
|
1169
|
-
|
1170
|
-
if v is not None:
|
1171
|
-
raise ValueError(v)
|
1335
|
+
return inner
|
1172
1336
|
|
1337
|
+
##
|
1173
1338
|
|
1174
|
-
def
|
1175
|
-
|
1176
|
-
|
1177
|
-
|
1339
|
+
def issubclass(self, v: ta.Type[T], spec: ta.Any, msg: CheckMessage = None) -> ta.Type[T]: # noqa
|
1340
|
+
if not issubclass(v, spec):
|
1341
|
+
self._raise(
|
1342
|
+
TypeError,
|
1343
|
+
'Must be subclass',
|
1344
|
+
msg,
|
1345
|
+
Checks._ArgsKwargs(v, spec),
|
1346
|
+
render_fmt='not issubclass(%s, %s)',
|
1347
|
+
)
|
1178
1348
|
|
1349
|
+
return v
|
1179
1350
|
|
1180
|
-
def
|
1181
|
-
|
1182
|
-
|
1183
|
-
|
1351
|
+
def not_issubclass(self, v: ta.Type[T], spec: ta.Any, msg: CheckMessage = None) -> ta.Type[T]: # noqa
|
1352
|
+
if issubclass(v, spec):
|
1353
|
+
self._raise(
|
1354
|
+
TypeError,
|
1355
|
+
'Must not be subclass',
|
1356
|
+
msg,
|
1357
|
+
Checks._ArgsKwargs(v, spec),
|
1358
|
+
render_fmt='issubclass(%s, %s)',
|
1359
|
+
)
|
1184
1360
|
|
1361
|
+
return v
|
1185
1362
|
|
1186
|
-
|
1187
|
-
if not v:
|
1188
|
-
raise ValueError
|
1189
|
-
return v
|
1363
|
+
#
|
1190
1364
|
|
1365
|
+
def in_(self, v: T, c: ta.Container[T], msg: CheckMessage = None) -> T:
|
1366
|
+
if v not in c:
|
1367
|
+
self._raise(
|
1368
|
+
ValueError,
|
1369
|
+
'Must be in',
|
1370
|
+
msg,
|
1371
|
+
Checks._ArgsKwargs(v, c),
|
1372
|
+
render_fmt='%s not in %s',
|
1373
|
+
)
|
1191
1374
|
|
1192
|
-
|
1193
|
-
if not v:
|
1194
|
-
raise ValueError(msg)
|
1375
|
+
return v
|
1195
1376
|
|
1377
|
+
def not_in(self, v: T, c: ta.Container[T], msg: CheckMessage = None) -> T:
|
1378
|
+
if v in c:
|
1379
|
+
self._raise(
|
1380
|
+
ValueError,
|
1381
|
+
'Must not be in',
|
1382
|
+
msg,
|
1383
|
+
Checks._ArgsKwargs(v, c),
|
1384
|
+
render_fmt='%s in %s',
|
1385
|
+
)
|
1196
1386
|
|
1197
|
-
|
1198
|
-
if not v:
|
1199
|
-
raise ValueError(msg)
|
1387
|
+
return v
|
1200
1388
|
|
1389
|
+
def empty(self, v: SizedT, msg: CheckMessage = None) -> SizedT:
|
1390
|
+
if len(v) != 0:
|
1391
|
+
self._raise(
|
1392
|
+
ValueError,
|
1393
|
+
'Must be empty',
|
1394
|
+
msg,
|
1395
|
+
Checks._ArgsKwargs(v),
|
1396
|
+
render_fmt='%s',
|
1397
|
+
)
|
1201
1398
|
|
1202
|
-
|
1203
|
-
if l != r:
|
1204
|
-
raise ValueError(l, r)
|
1205
|
-
return l
|
1399
|
+
return v
|
1206
1400
|
|
1401
|
+
def iterempty(self, v: ta.Iterable[T], msg: CheckMessage = None) -> ta.Iterable[T]:
|
1402
|
+
it = iter(v)
|
1403
|
+
try:
|
1404
|
+
next(it)
|
1405
|
+
except StopIteration:
|
1406
|
+
pass
|
1407
|
+
else:
|
1408
|
+
self._raise(
|
1409
|
+
ValueError,
|
1410
|
+
'Must be empty',
|
1411
|
+
msg,
|
1412
|
+
Checks._ArgsKwargs(v),
|
1413
|
+
render_fmt='%s',
|
1414
|
+
)
|
1207
1415
|
|
1208
|
-
|
1209
|
-
if l == r:
|
1210
|
-
raise ValueError(l, r)
|
1211
|
-
return l
|
1416
|
+
return v
|
1212
1417
|
|
1418
|
+
def not_empty(self, v: SizedT, msg: CheckMessage = None) -> SizedT:
|
1419
|
+
if len(v) == 0:
|
1420
|
+
self._raise(
|
1421
|
+
ValueError,
|
1422
|
+
'Must not be empty',
|
1423
|
+
msg,
|
1424
|
+
Checks._ArgsKwargs(v),
|
1425
|
+
render_fmt='%s',
|
1426
|
+
)
|
1213
1427
|
|
1214
|
-
|
1215
|
-
if l is not r:
|
1216
|
-
raise ValueError(l, r)
|
1217
|
-
return l
|
1428
|
+
return v
|
1218
1429
|
|
1430
|
+
def unique(self, it: ta.Iterable[T], msg: CheckMessage = None) -> ta.Iterable[T]:
|
1431
|
+
dupes = [e for e, c in collections.Counter(it).items() if c > 1]
|
1432
|
+
if dupes:
|
1433
|
+
self._raise(
|
1434
|
+
ValueError,
|
1435
|
+
'Must be unique',
|
1436
|
+
msg,
|
1437
|
+
Checks._ArgsKwargs(it, dupes),
|
1438
|
+
)
|
1219
1439
|
|
1220
|
-
|
1221
|
-
if l is r:
|
1222
|
-
raise ValueError(l, r)
|
1223
|
-
return l
|
1440
|
+
return it
|
1224
1441
|
|
1442
|
+
def single(self, obj: ta.Iterable[T], message: CheckMessage = None) -> T:
|
1443
|
+
try:
|
1444
|
+
[value] = obj
|
1445
|
+
except ValueError:
|
1446
|
+
self._raise(
|
1447
|
+
ValueError,
|
1448
|
+
'Must be single',
|
1449
|
+
message,
|
1450
|
+
Checks._ArgsKwargs(obj),
|
1451
|
+
render_fmt='%s',
|
1452
|
+
)
|
1453
|
+
|
1454
|
+
return value
|
1455
|
+
|
1456
|
+
def opt_single(self, obj: ta.Iterable[T], message: CheckMessage = None) -> ta.Optional[T]:
|
1457
|
+
it = iter(obj)
|
1458
|
+
try:
|
1459
|
+
value = next(it)
|
1460
|
+
except StopIteration:
|
1461
|
+
return None
|
1462
|
+
|
1463
|
+
try:
|
1464
|
+
next(it)
|
1465
|
+
except StopIteration:
|
1466
|
+
return value # noqa
|
1467
|
+
|
1468
|
+
self._raise(
|
1469
|
+
ValueError,
|
1470
|
+
'Must be empty or single',
|
1471
|
+
message,
|
1472
|
+
Checks._ArgsKwargs(obj),
|
1473
|
+
render_fmt='%s',
|
1474
|
+
)
|
1475
|
+
|
1476
|
+
raise RuntimeError # noqa
|
1225
1477
|
|
1226
|
-
|
1227
|
-
if v not in c:
|
1228
|
-
raise ValueError(v, c)
|
1229
|
-
return v
|
1478
|
+
#
|
1230
1479
|
|
1480
|
+
def none(self, v: ta.Any, msg: CheckMessage = None) -> None:
|
1481
|
+
if v is not None:
|
1482
|
+
self._raise(
|
1483
|
+
ValueError,
|
1484
|
+
'Must be None',
|
1485
|
+
msg,
|
1486
|
+
Checks._ArgsKwargs(v),
|
1487
|
+
render_fmt='%s',
|
1488
|
+
)
|
1231
1489
|
|
1232
|
-
def
|
1233
|
-
|
1234
|
-
|
1235
|
-
|
1490
|
+
def not_none(self, v: ta.Optional[T], msg: CheckMessage = None) -> T:
|
1491
|
+
if v is None:
|
1492
|
+
self._raise(
|
1493
|
+
ValueError,
|
1494
|
+
'Must not be None',
|
1495
|
+
msg,
|
1496
|
+
Checks._ArgsKwargs(v),
|
1497
|
+
render_fmt='%s',
|
1498
|
+
)
|
1236
1499
|
|
1500
|
+
return v
|
1237
1501
|
|
1238
|
-
|
1239
|
-
|
1240
|
-
|
1502
|
+
#
|
1503
|
+
|
1504
|
+
def equal(self, v: T, o: ta.Any, msg: CheckMessage = None) -> T:
|
1505
|
+
if o != v:
|
1506
|
+
self._raise(
|
1507
|
+
ValueError,
|
1508
|
+
'Must be equal',
|
1509
|
+
msg,
|
1510
|
+
Checks._ArgsKwargs(v, o),
|
1511
|
+
render_fmt='%s != %s',
|
1512
|
+
)
|
1513
|
+
|
1514
|
+
return v
|
1515
|
+
|
1516
|
+
def is_(self, v: T, o: ta.Any, msg: CheckMessage = None) -> T:
|
1517
|
+
if o is not v:
|
1518
|
+
self._raise(
|
1519
|
+
ValueError,
|
1520
|
+
'Must be the same',
|
1521
|
+
msg,
|
1522
|
+
Checks._ArgsKwargs(v, o),
|
1523
|
+
render_fmt='%s is not %s',
|
1524
|
+
)
|
1525
|
+
|
1526
|
+
return v
|
1527
|
+
|
1528
|
+
def is_not(self, v: T, o: ta.Any, msg: CheckMessage = None) -> T:
|
1529
|
+
if o is v:
|
1530
|
+
self._raise(
|
1531
|
+
ValueError,
|
1532
|
+
'Must not be the same',
|
1533
|
+
msg,
|
1534
|
+
Checks._ArgsKwargs(v, o),
|
1535
|
+
render_fmt='%s is %s',
|
1536
|
+
)
|
1537
|
+
|
1538
|
+
return v
|
1539
|
+
|
1540
|
+
def callable(self, v: T, msg: CheckMessage = None) -> T: # noqa
|
1541
|
+
if not callable(v):
|
1542
|
+
self._raise(
|
1543
|
+
TypeError,
|
1544
|
+
'Must be callable',
|
1545
|
+
msg,
|
1546
|
+
Checks._ArgsKwargs(v),
|
1547
|
+
render_fmt='%s',
|
1548
|
+
)
|
1549
|
+
|
1550
|
+
return v # type: ignore
|
1551
|
+
|
1552
|
+
def non_empty_str(self, v: ta.Optional[str], msg: CheckMessage = None) -> str:
|
1553
|
+
if not isinstance(v, str) or not v:
|
1554
|
+
self._raise(
|
1555
|
+
ValueError,
|
1556
|
+
'Must be non-empty str',
|
1557
|
+
msg,
|
1558
|
+
Checks._ArgsKwargs(v),
|
1559
|
+
render_fmt='%s',
|
1560
|
+
)
|
1561
|
+
|
1562
|
+
return v
|
1563
|
+
|
1564
|
+
def replacing(self, expected: ta.Any, old: ta.Any, new: T, msg: CheckMessage = None) -> T:
|
1565
|
+
if old != expected:
|
1566
|
+
self._raise(
|
1567
|
+
ValueError,
|
1568
|
+
'Must be replacing',
|
1569
|
+
msg,
|
1570
|
+
Checks._ArgsKwargs(expected, old, new),
|
1571
|
+
render_fmt='%s -> %s -> %s',
|
1572
|
+
)
|
1573
|
+
|
1574
|
+
return new
|
1575
|
+
|
1576
|
+
def replacing_none(self, old: ta.Any, new: T, msg: CheckMessage = None) -> T:
|
1577
|
+
if old is not None:
|
1578
|
+
self._raise(
|
1579
|
+
ValueError,
|
1580
|
+
'Must be replacing None',
|
1581
|
+
msg,
|
1582
|
+
Checks._ArgsKwargs(old, new),
|
1583
|
+
render_fmt='%s -> %s',
|
1584
|
+
)
|
1585
|
+
|
1586
|
+
return new
|
1587
|
+
|
1588
|
+
#
|
1241
1589
|
|
1590
|
+
def arg(self, v: bool, msg: CheckMessage = None) -> None:
|
1591
|
+
if not v:
|
1592
|
+
self._raise(
|
1593
|
+
RuntimeError,
|
1594
|
+
'Argument condition not met',
|
1595
|
+
msg,
|
1596
|
+
Checks._ArgsKwargs(v),
|
1597
|
+
render_fmt='%s',
|
1598
|
+
)
|
1242
1599
|
|
1243
|
-
def
|
1244
|
-
|
1245
|
-
|
1246
|
-
|
1600
|
+
def state(self, v: bool, msg: CheckMessage = None) -> None:
|
1601
|
+
if not v:
|
1602
|
+
self._raise(
|
1603
|
+
RuntimeError,
|
1604
|
+
'State condition not met',
|
1605
|
+
msg,
|
1606
|
+
Checks._ArgsKwargs(v),
|
1607
|
+
render_fmt='%s',
|
1608
|
+
)
|
1247
1609
|
|
1248
1610
|
|
1249
|
-
|
1250
|
-
if not len(v):
|
1251
|
-
raise ValueError(v)
|
1252
|
-
return v
|
1611
|
+
check = Checks()
|
1253
1612
|
|
1254
1613
|
|
1255
1614
|
########################################
|
@@ -2058,7 +2417,7 @@ class Command(abc.ABC, ta.Generic[CommandOutputT]):
|
|
2058
2417
|
|
2059
2418
|
@ta.final
|
2060
2419
|
async def execute(self, executor: 'CommandExecutor') -> CommandOutputT:
|
2061
|
-
return
|
2420
|
+
return check.isinstance(await executor.execute(self), self.Output) # type: ignore[return-value]
|
2062
2421
|
|
2063
2422
|
|
2064
2423
|
##
|
@@ -2253,6 +2612,237 @@ def get_remote_payload_src(
|
|
2253
2612
|
return importlib.resources.files(__package__.split('.')[0] + '.scripts').joinpath('manage.py').read_text()
|
2254
2613
|
|
2255
2614
|
|
2615
|
+
########################################
|
2616
|
+
# ../../../omlish/argparse/cli.py
|
2617
|
+
"""
|
2618
|
+
TODO:
|
2619
|
+
- default command
|
2620
|
+
- auto match all underscores to hyphens
|
2621
|
+
"""
|
2622
|
+
|
2623
|
+
|
2624
|
+
##
|
2625
|
+
|
2626
|
+
|
2627
|
+
@dc.dataclass(eq=False)
|
2628
|
+
class ArgparseArg:
|
2629
|
+
args: ta.Sequence[ta.Any]
|
2630
|
+
kwargs: ta.Mapping[str, ta.Any]
|
2631
|
+
dest: ta.Optional[str] = None
|
2632
|
+
|
2633
|
+
def __get__(self, instance, owner=None):
|
2634
|
+
if instance is None:
|
2635
|
+
return self
|
2636
|
+
return getattr(instance.args, self.dest) # type: ignore
|
2637
|
+
|
2638
|
+
|
2639
|
+
def argparse_arg(*args, **kwargs) -> ArgparseArg:
|
2640
|
+
return ArgparseArg(args, kwargs)
|
2641
|
+
|
2642
|
+
|
2643
|
+
#
|
2644
|
+
|
2645
|
+
|
2646
|
+
@dc.dataclass(eq=False)
|
2647
|
+
class ArgparseCommand:
|
2648
|
+
name: str
|
2649
|
+
fn: ArgparseCommandFn
|
2650
|
+
args: ta.Sequence[ArgparseArg] = () # noqa
|
2651
|
+
|
2652
|
+
# _: dc.KW_ONLY
|
2653
|
+
|
2654
|
+
aliases: ta.Optional[ta.Sequence[str]] = None
|
2655
|
+
parent: ta.Optional['ArgparseCommand'] = None
|
2656
|
+
accepts_unknown: bool = False
|
2657
|
+
|
2658
|
+
def __post_init__(self) -> None:
|
2659
|
+
def check_name(s: str) -> None:
|
2660
|
+
check.isinstance(s, str)
|
2661
|
+
check.not_in('_', s)
|
2662
|
+
check.not_empty(s)
|
2663
|
+
check_name(self.name)
|
2664
|
+
check.not_isinstance(self.aliases, str)
|
2665
|
+
for a in self.aliases or []:
|
2666
|
+
check_name(a)
|
2667
|
+
|
2668
|
+
check.arg(callable(self.fn))
|
2669
|
+
check.arg(all(isinstance(a, ArgparseArg) for a in self.args))
|
2670
|
+
check.isinstance(self.parent, (ArgparseCommand, type(None)))
|
2671
|
+
check.isinstance(self.accepts_unknown, bool)
|
2672
|
+
|
2673
|
+
functools.update_wrapper(self, self.fn)
|
2674
|
+
|
2675
|
+
def __get__(self, instance, owner=None):
|
2676
|
+
if instance is None:
|
2677
|
+
return self
|
2678
|
+
return dc.replace(self, fn=self.fn.__get__(instance, owner)) # noqa
|
2679
|
+
|
2680
|
+
def __call__(self, *args, **kwargs) -> ta.Optional[int]:
|
2681
|
+
return self.fn(*args, **kwargs)
|
2682
|
+
|
2683
|
+
|
2684
|
+
def argparse_command(
|
2685
|
+
*args: ArgparseArg,
|
2686
|
+
name: ta.Optional[str] = None,
|
2687
|
+
aliases: ta.Optional[ta.Iterable[str]] = None,
|
2688
|
+
parent: ta.Optional[ArgparseCommand] = None,
|
2689
|
+
accepts_unknown: bool = False,
|
2690
|
+
) -> ta.Any: # ta.Callable[[ArgparseCommandFn], ArgparseCommand]: # FIXME
|
2691
|
+
for arg in args:
|
2692
|
+
check.isinstance(arg, ArgparseArg)
|
2693
|
+
check.isinstance(name, (str, type(None)))
|
2694
|
+
check.isinstance(parent, (ArgparseCommand, type(None)))
|
2695
|
+
check.not_isinstance(aliases, str)
|
2696
|
+
|
2697
|
+
def inner(fn):
|
2698
|
+
return ArgparseCommand(
|
2699
|
+
(name if name is not None else fn.__name__).replace('_', '-'),
|
2700
|
+
fn,
|
2701
|
+
args,
|
2702
|
+
aliases=tuple(aliases) if aliases is not None else None,
|
2703
|
+
parent=parent,
|
2704
|
+
accepts_unknown=accepts_unknown,
|
2705
|
+
)
|
2706
|
+
|
2707
|
+
return inner
|
2708
|
+
|
2709
|
+
|
2710
|
+
##
|
2711
|
+
|
2712
|
+
|
2713
|
+
def _get_argparse_arg_ann_kwargs(ann: ta.Any) -> ta.Mapping[str, ta.Any]:
|
2714
|
+
if ann is str:
|
2715
|
+
return {}
|
2716
|
+
elif ann is int:
|
2717
|
+
return {'type': int}
|
2718
|
+
elif ann is bool:
|
2719
|
+
return {'action': 'store_true'}
|
2720
|
+
elif ann is list:
|
2721
|
+
return {'action': 'append'}
|
2722
|
+
else:
|
2723
|
+
raise TypeError(ann)
|
2724
|
+
|
2725
|
+
|
2726
|
+
class _ArgparseCliAnnotationBox:
|
2727
|
+
def __init__(self, annotations: ta.Mapping[str, ta.Any]) -> None:
|
2728
|
+
super().__init__()
|
2729
|
+
self.__annotations__ = annotations # type: ignore
|
2730
|
+
|
2731
|
+
|
2732
|
+
class ArgparseCli:
|
2733
|
+
def __init__(self, argv: ta.Optional[ta.Sequence[str]] = None) -> None:
|
2734
|
+
super().__init__()
|
2735
|
+
|
2736
|
+
self._argv = argv if argv is not None else sys.argv[1:]
|
2737
|
+
|
2738
|
+
self._args, self._unknown_args = self.get_parser().parse_known_args(self._argv)
|
2739
|
+
|
2740
|
+
def __init_subclass__(cls, **kwargs: ta.Any) -> None:
|
2741
|
+
super().__init_subclass__(**kwargs)
|
2742
|
+
|
2743
|
+
ns = cls.__dict__
|
2744
|
+
|
2745
|
+
objs = {}
|
2746
|
+
mro = cls.__mro__[::-1]
|
2747
|
+
for bns in [bcls.__dict__ for bcls in reversed(mro)] + [ns]:
|
2748
|
+
bseen = set() # type: ignore
|
2749
|
+
for k, v in bns.items():
|
2750
|
+
if isinstance(v, (ArgparseCommand, ArgparseArg)):
|
2751
|
+
check.not_in(v, bseen)
|
2752
|
+
bseen.add(v)
|
2753
|
+
objs[k] = v
|
2754
|
+
elif k in objs:
|
2755
|
+
del [k]
|
2756
|
+
|
2757
|
+
anns = ta.get_type_hints(_ArgparseCliAnnotationBox({
|
2758
|
+
**{k: v for bcls in reversed(mro) for k, v in getattr(bcls, '__annotations__', {}).items()},
|
2759
|
+
**ns.get('__annotations__', {}),
|
2760
|
+
}), globalns=ns.get('__globals__', {}))
|
2761
|
+
|
2762
|
+
if '_parser' in ns:
|
2763
|
+
parser = check.isinstance(ns['_parser'], argparse.ArgumentParser)
|
2764
|
+
else:
|
2765
|
+
parser = argparse.ArgumentParser()
|
2766
|
+
setattr(cls, '_parser', parser)
|
2767
|
+
|
2768
|
+
subparsers = parser.add_subparsers()
|
2769
|
+
for att, obj in objs.items():
|
2770
|
+
if isinstance(obj, ArgparseCommand):
|
2771
|
+
if obj.parent is not None:
|
2772
|
+
raise NotImplementedError
|
2773
|
+
for cn in [obj.name, *(obj.aliases or [])]:
|
2774
|
+
cparser = subparsers.add_parser(cn)
|
2775
|
+
for arg in (obj.args or []):
|
2776
|
+
if (
|
2777
|
+
len(arg.args) == 1 and
|
2778
|
+
isinstance(arg.args[0], str) and
|
2779
|
+
not (n := check.isinstance(arg.args[0], str)).startswith('-') and
|
2780
|
+
'metavar' not in arg.kwargs
|
2781
|
+
):
|
2782
|
+
cparser.add_argument(
|
2783
|
+
n.replace('-', '_'),
|
2784
|
+
**arg.kwargs,
|
2785
|
+
metavar=n,
|
2786
|
+
)
|
2787
|
+
else:
|
2788
|
+
cparser.add_argument(*arg.args, **arg.kwargs)
|
2789
|
+
cparser.set_defaults(_cmd=obj)
|
2790
|
+
|
2791
|
+
elif isinstance(obj, ArgparseArg):
|
2792
|
+
if att in anns:
|
2793
|
+
akwargs = _get_argparse_arg_ann_kwargs(anns[att])
|
2794
|
+
obj.kwargs = {**akwargs, **obj.kwargs}
|
2795
|
+
if not obj.dest:
|
2796
|
+
if 'dest' in obj.kwargs:
|
2797
|
+
obj.dest = obj.kwargs['dest']
|
2798
|
+
else:
|
2799
|
+
obj.dest = obj.kwargs['dest'] = att # type: ignore
|
2800
|
+
parser.add_argument(*obj.args, **obj.kwargs)
|
2801
|
+
|
2802
|
+
else:
|
2803
|
+
raise TypeError(obj)
|
2804
|
+
|
2805
|
+
_parser: ta.ClassVar[argparse.ArgumentParser]
|
2806
|
+
|
2807
|
+
@classmethod
|
2808
|
+
def get_parser(cls) -> argparse.ArgumentParser:
|
2809
|
+
return cls._parser
|
2810
|
+
|
2811
|
+
@property
|
2812
|
+
def argv(self) -> ta.Sequence[str]:
|
2813
|
+
return self._argv
|
2814
|
+
|
2815
|
+
@property
|
2816
|
+
def args(self) -> argparse.Namespace:
|
2817
|
+
return self._args
|
2818
|
+
|
2819
|
+
@property
|
2820
|
+
def unknown_args(self) -> ta.Sequence[str]:
|
2821
|
+
return self._unknown_args
|
2822
|
+
|
2823
|
+
def _run_cmd(self, cmd: ArgparseCommand) -> ta.Optional[int]:
|
2824
|
+
return cmd.__get__(self, type(self))()
|
2825
|
+
|
2826
|
+
def __call__(self) -> ta.Optional[int]:
|
2827
|
+
cmd = getattr(self.args, '_cmd', None)
|
2828
|
+
|
2829
|
+
if self._unknown_args and not (cmd is not None and cmd.accepts_unknown):
|
2830
|
+
msg = f'unrecognized arguments: {" ".join(self._unknown_args)}'
|
2831
|
+
if (parser := self.get_parser()).exit_on_error: # type: ignore
|
2832
|
+
parser.error(msg)
|
2833
|
+
else:
|
2834
|
+
raise argparse.ArgumentError(None, msg)
|
2835
|
+
|
2836
|
+
if cmd is None:
|
2837
|
+
self.get_parser().print_help()
|
2838
|
+
return 0
|
2839
|
+
|
2840
|
+
return self._run_cmd(cmd)
|
2841
|
+
|
2842
|
+
def call_and_exit(self) -> ta.NoReturn:
|
2843
|
+
sys.exit(rc if isinstance(rc := self(), int) else 0)
|
2844
|
+
|
2845
|
+
|
2256
2846
|
########################################
|
2257
2847
|
# ../../../omlish/lite/inject.py
|
2258
2848
|
|
@@ -2397,7 +2987,7 @@ class FnInjectorProvider(InjectorProvider):
|
|
2397
2987
|
fn: ta.Any
|
2398
2988
|
|
2399
2989
|
def __post_init__(self) -> None:
|
2400
|
-
|
2990
|
+
check.not_isinstance(self.fn, type)
|
2401
2991
|
|
2402
2992
|
def provider_fn(self) -> InjectorProviderFn:
|
2403
2993
|
def pfn(i: Injector) -> ta.Any:
|
@@ -2411,7 +3001,7 @@ class CtorInjectorProvider(InjectorProvider):
|
|
2411
3001
|
cls_: type
|
2412
3002
|
|
2413
3003
|
def __post_init__(self) -> None:
|
2414
|
-
|
3004
|
+
check.isinstance(self.cls_, type)
|
2415
3005
|
|
2416
3006
|
def provider_fn(self) -> InjectorProviderFn:
|
2417
3007
|
def pfn(i: Injector) -> ta.Any:
|
@@ -2433,7 +3023,7 @@ class SingletonInjectorProvider(InjectorProvider):
|
|
2433
3023
|
p: InjectorProvider
|
2434
3024
|
|
2435
3025
|
def __post_init__(self) -> None:
|
2436
|
-
|
3026
|
+
check.isinstance(self.p, InjectorProvider)
|
2437
3027
|
|
2438
3028
|
def provider_fn(self) -> InjectorProviderFn:
|
2439
3029
|
v = not_set = object()
|
@@ -2453,7 +3043,7 @@ class LinkInjectorProvider(InjectorProvider):
|
|
2453
3043
|
k: InjectorKey
|
2454
3044
|
|
2455
3045
|
def __post_init__(self) -> None:
|
2456
|
-
|
3046
|
+
check.isinstance(self.k, InjectorKey)
|
2457
3047
|
|
2458
3048
|
def provider_fn(self) -> InjectorProviderFn:
|
2459
3049
|
def pfn(i: Injector) -> ta.Any:
|
@@ -2650,7 +3240,7 @@ def build_injection_kwargs_target(
|
|
2650
3240
|
|
2651
3241
|
skip_names: ta.Set[str] = set()
|
2652
3242
|
if skip_kwargs is not None:
|
2653
|
-
skip_names.update(
|
3243
|
+
skip_names.update(check.not_isinstance(skip_kwargs, str))
|
2654
3244
|
|
2655
3245
|
seen: ta.Set[InjectorKey] = set()
|
2656
3246
|
kws: ta.List[InjectionKwarg] = []
|
@@ -2711,8 +3301,8 @@ class _Injector(Injector):
|
|
2711
3301
|
def __init__(self, bs: InjectorBindings, p: ta.Optional[Injector] = None) -> None:
|
2712
3302
|
super().__init__()
|
2713
3303
|
|
2714
|
-
self._bs =
|
2715
|
-
self._p: ta.Optional[Injector] =
|
3304
|
+
self._bs = check.isinstance(bs, InjectorBindings)
|
3305
|
+
self._p: ta.Optional[Injector] = check.isinstance(p, (Injector, type(None)))
|
2716
3306
|
|
2717
3307
|
self._pfm = {k: v.provider_fn() for k, v in build_injector_provider_map(bs).items()}
|
2718
3308
|
|
@@ -2743,8 +3333,8 @@ class _Injector(Injector):
|
|
2743
3333
|
return Maybe.empty()
|
2744
3334
|
|
2745
3335
|
def handle_provision(self, key: InjectorKey, mv: Maybe) -> Maybe:
|
2746
|
-
|
2747
|
-
|
3336
|
+
check.in_(key, self._seen_keys)
|
3337
|
+
check.not_in(key, self._provisions)
|
2748
3338
|
self._provisions[key] = mv
|
2749
3339
|
return mv
|
2750
3340
|
|
@@ -2858,7 +3448,7 @@ class InjectorBinder:
|
|
2858
3448
|
|
2859
3449
|
@classmethod
|
2860
3450
|
def bind_as_fn(cls, icls: ta.Type[T]) -> ta.Type[T]:
|
2861
|
-
|
3451
|
+
check.isinstance(icls, type)
|
2862
3452
|
if icls not in cls._FN_TYPES:
|
2863
3453
|
cls._FN_TYPES = (*cls._FN_TYPES, icls)
|
2864
3454
|
return icls
|
@@ -2915,7 +3505,7 @@ class InjectorBinder:
|
|
2915
3505
|
to_fn = obj
|
2916
3506
|
if key is None:
|
2917
3507
|
insp = _injection_inspect(obj)
|
2918
|
-
key_cls: ta.Any = check_valid_injector_key_cls(
|
3508
|
+
key_cls: ta.Any = check_valid_injector_key_cls(check.not_none(insp.type_hints.get('return')))
|
2919
3509
|
key = InjectorKey(key_cls)
|
2920
3510
|
else:
|
2921
3511
|
if to_const is not None:
|
@@ -3457,10 +4047,10 @@ class ProxyObjMarshaler(ObjMarshaler):
|
|
3457
4047
|
m: ta.Optional[ObjMarshaler] = None
|
3458
4048
|
|
3459
4049
|
def marshal(self, o: ta.Any, ctx: 'ObjMarshalContext') -> ta.Any:
|
3460
|
-
return
|
4050
|
+
return check.not_none(self.m).marshal(o, ctx)
|
3461
4051
|
|
3462
4052
|
def unmarshal(self, o: ta.Any, ctx: 'ObjMarshalContext') -> ta.Any:
|
3463
|
-
return
|
4053
|
+
return check.not_none(self.m).unmarshal(o, ctx)
|
3464
4054
|
|
3465
4055
|
|
3466
4056
|
@dc.dataclass(frozen=True)
|
@@ -3619,19 +4209,19 @@ class DatetimeObjMarshaler(ObjMarshaler):
|
|
3619
4209
|
|
3620
4210
|
class DecimalObjMarshaler(ObjMarshaler):
|
3621
4211
|
def marshal(self, o: ta.Any, ctx: 'ObjMarshalContext') -> ta.Any:
|
3622
|
-
return str(
|
4212
|
+
return str(check.isinstance(o, decimal.Decimal))
|
3623
4213
|
|
3624
4214
|
def unmarshal(self, v: ta.Any, ctx: 'ObjMarshalContext') -> ta.Any:
|
3625
|
-
return decimal.Decimal(
|
4215
|
+
return decimal.Decimal(check.isinstance(v, str))
|
3626
4216
|
|
3627
4217
|
|
3628
4218
|
class FractionObjMarshaler(ObjMarshaler):
|
3629
4219
|
def marshal(self, o: ta.Any, ctx: 'ObjMarshalContext') -> ta.Any:
|
3630
|
-
fr =
|
4220
|
+
fr = check.isinstance(o, fractions.Fraction)
|
3631
4221
|
return [fr.numerator, fr.denominator]
|
3632
4222
|
|
3633
4223
|
def unmarshal(self, v: ta.Any, ctx: 'ObjMarshalContext') -> ta.Any:
|
3634
|
-
num, denom =
|
4224
|
+
num, denom = check.isinstance(v, list)
|
3635
4225
|
return fractions.Fraction(num, denom)
|
3636
4226
|
|
3637
4227
|
|
@@ -4436,7 +5026,7 @@ class _RemoteCommandHandler:
|
|
4436
5026
|
], return_when=asyncio.FIRST_COMPLETED)
|
4437
5027
|
|
4438
5028
|
if recv_task in done:
|
4439
|
-
msg: ta.Optional[_RemoteProtocol.Message] =
|
5029
|
+
msg: ta.Optional[_RemoteProtocol.Message] = check.isinstance(
|
4440
5030
|
recv_task.result(),
|
4441
5031
|
(_RemoteProtocol.Message, type(None)),
|
4442
5032
|
)
|
@@ -4505,8 +5095,8 @@ class RemoteCommandExecutor(CommandExecutor):
|
|
4505
5095
|
#
|
4506
5096
|
|
4507
5097
|
async def start(self) -> None:
|
4508
|
-
|
4509
|
-
|
5098
|
+
check.none(self._loop_task)
|
5099
|
+
check.state(not self._stop.is_set())
|
4510
5100
|
self._loop_task = asyncio.create_task(self._loop())
|
4511
5101
|
|
4512
5102
|
async def aclose(self) -> None:
|
@@ -4542,12 +5132,12 @@ class RemoteCommandExecutor(CommandExecutor):
|
|
4542
5132
|
], return_when=asyncio.FIRST_COMPLETED)
|
4543
5133
|
|
4544
5134
|
if queue_task in done:
|
4545
|
-
req =
|
5135
|
+
req = check.isinstance(queue_task.result(), RemoteCommandExecutor._Request)
|
4546
5136
|
queue_task = None
|
4547
5137
|
await self._handle_request(req)
|
4548
5138
|
|
4549
5139
|
if recv_task in done:
|
4550
|
-
msg: ta.Optional[_RemoteProtocol.Message] =
|
5140
|
+
msg: ta.Optional[_RemoteProtocol.Message] = check.isinstance(
|
4551
5141
|
recv_task.result(),
|
4552
5142
|
(_RemoteProtocol.Message, type(None)),
|
4553
5143
|
)
|
@@ -4615,7 +5205,7 @@ class RemoteCommandExecutor(CommandExecutor):
|
|
4615
5205
|
if (e := r.exception) is not None:
|
4616
5206
|
raise RemoteCommandError(e)
|
4617
5207
|
else:
|
4618
|
-
return
|
5208
|
+
return check.not_none(r.output)
|
4619
5209
|
|
4620
5210
|
# @ta.override
|
4621
5211
|
async def try_execute(
|
@@ -4660,7 +5250,7 @@ async def asyncio_subprocess_popen(
|
|
4660
5250
|
if shell:
|
4661
5251
|
fac = functools.partial(
|
4662
5252
|
asyncio.create_subprocess_shell,
|
4663
|
-
|
5253
|
+
check.single(cmd),
|
4664
5254
|
)
|
4665
5255
|
else:
|
4666
5256
|
fac = functools.partial(
|
@@ -4700,7 +5290,7 @@ class AsyncioProcessCommunicator:
|
|
4700
5290
|
self._proc = proc
|
4701
5291
|
self._loop = loop
|
4702
5292
|
|
4703
|
-
self._transport: asyncio.base_subprocess.BaseSubprocessTransport =
|
5293
|
+
self._transport: asyncio.base_subprocess.BaseSubprocessTransport = check.isinstance(
|
4704
5294
|
proc._transport, # type: ignore # noqa
|
4705
5295
|
asyncio.base_subprocess.BaseSubprocessTransport,
|
4706
5296
|
)
|
@@ -4710,7 +5300,7 @@ class AsyncioProcessCommunicator:
|
|
4710
5300
|
return self._loop.get_debug()
|
4711
5301
|
|
4712
5302
|
async def _feed_stdin(self, input: bytes) -> None: # noqa
|
4713
|
-
stdin =
|
5303
|
+
stdin = check.not_none(self._proc.stdin)
|
4714
5304
|
try:
|
4715
5305
|
if input is not None:
|
4716
5306
|
stdin.write(input)
|
@@ -4734,13 +5324,13 @@ class AsyncioProcessCommunicator:
|
|
4734
5324
|
return None
|
4735
5325
|
|
4736
5326
|
async def _read_stream(self, fd: int) -> bytes:
|
4737
|
-
transport: ta.Any =
|
5327
|
+
transport: ta.Any = check.not_none(self._transport.get_pipe_transport(fd))
|
4738
5328
|
|
4739
5329
|
if fd == 2:
|
4740
|
-
stream =
|
5330
|
+
stream = check.not_none(self._proc.stderr)
|
4741
5331
|
else:
|
4742
|
-
|
4743
|
-
stream =
|
5332
|
+
check.equal(fd, 1)
|
5333
|
+
stream = check.not_none(self._proc.stdout)
|
4744
5334
|
|
4745
5335
|
if self._debug:
|
4746
5336
|
name = 'stdout' if fd == 1 else 'stderr'
|
@@ -4860,7 +5450,7 @@ async def asyncio_subprocess_check_output(
|
|
4860
5450
|
**kwargs,
|
4861
5451
|
)
|
4862
5452
|
|
4863
|
-
return
|
5453
|
+
return check.not_none(stdout)
|
4864
5454
|
|
4865
5455
|
|
4866
5456
|
async def asyncio_subprocess_check_output_str(*args: str, **kwargs: ta.Any) -> str:
|
@@ -5038,7 +5628,7 @@ class SubprocessCommand(Command['SubprocessCommand.Output']):
|
|
5038
5628
|
timeout: ta.Optional[float] = None
|
5039
5629
|
|
5040
5630
|
def __post_init__(self) -> None:
|
5041
|
-
|
5631
|
+
check.not_isinstance(self.cmd, str)
|
5042
5632
|
|
5043
5633
|
@dc.dataclass(frozen=True)
|
5044
5634
|
class Output(Command.Output):
|
@@ -5079,7 +5669,7 @@ class SubprocessCommandExecutor(CommandExecutor[SubprocessCommand, SubprocessCom
|
|
5079
5669
|
end_time = time.time()
|
5080
5670
|
|
5081
5671
|
return SubprocessCommand.Output(
|
5082
|
-
rc=
|
5672
|
+
rc=check.not_none(proc.returncode),
|
5083
5673
|
pid=proc.pid,
|
5084
5674
|
|
5085
5675
|
elapsed_s=end_time - start_time,
|
@@ -5123,11 +5713,11 @@ class _RemoteExecutionMain:
|
|
5123
5713
|
|
5124
5714
|
@property
|
5125
5715
|
def _bootstrap(self) -> MainBootstrap:
|
5126
|
-
return
|
5716
|
+
return check.not_none(self.__bootstrap)
|
5127
5717
|
|
5128
5718
|
@property
|
5129
5719
|
def _injector(self) -> Injector:
|
5130
|
-
return
|
5720
|
+
return check.not_none(self.__injector)
|
5131
5721
|
|
5132
5722
|
#
|
5133
5723
|
|
@@ -5171,12 +5761,12 @@ class _RemoteExecutionMain:
|
|
5171
5761
|
#
|
5172
5762
|
|
5173
5763
|
async def _setup(self) -> None:
|
5174
|
-
|
5175
|
-
|
5764
|
+
check.none(self.__bootstrap)
|
5765
|
+
check.none(self.__injector)
|
5176
5766
|
|
5177
5767
|
# Bootstrap
|
5178
5768
|
|
5179
|
-
self.__bootstrap =
|
5769
|
+
self.__bootstrap = check.not_none(await self._chan.recv_obj(MainBootstrap))
|
5180
5770
|
|
5181
5771
|
if (prd := self._bootstrap.remote_config.pycharm_remote_debug) is not None:
|
5182
5772
|
pycharm_debug_connect(prd)
|
@@ -5318,8 +5908,8 @@ class SubprocessRemoteSpawning(RemoteSpawning):
|
|
5318
5908
|
),
|
5319
5909
|
timeout=timeout,
|
5320
5910
|
) as proc:
|
5321
|
-
stdin =
|
5322
|
-
stdout =
|
5911
|
+
stdin = check.not_none(proc.stdin)
|
5912
|
+
stdout = check.not_none(proc.stdout)
|
5323
5913
|
|
5324
5914
|
try:
|
5325
5915
|
yield RemoteSpawning.Spawned(
|
@@ -5535,7 +6125,7 @@ class Pyenv:
|
|
5535
6125
|
|
5536
6126
|
@async_cached_nullary
|
5537
6127
|
async def exe(self) -> str:
|
5538
|
-
return os.path.join(
|
6128
|
+
return os.path.join(check.not_none(await self.root()), 'bin', 'pyenv')
|
5539
6129
|
|
5540
6130
|
async def version_exes(self) -> ta.List[ta.Tuple[str, str]]:
|
5541
6131
|
if (root := await self.root()) is None:
|
@@ -5761,7 +6351,7 @@ class PyenvVersionInstaller:
|
|
5761
6351
|
|
5762
6352
|
@async_cached_nullary
|
5763
6353
|
async def install_dir(self) -> str:
|
5764
|
-
return str(os.path.join(
|
6354
|
+
return str(os.path.join(check.not_none(await self._pyenv.root()), 'versions', self.install_name()))
|
5765
6355
|
|
5766
6356
|
@async_cached_nullary
|
5767
6357
|
async def install(self) -> str:
|
@@ -5784,7 +6374,7 @@ class PyenvVersionInstaller:
|
|
5784
6374
|
|
5785
6375
|
if self._given_install_name is not None:
|
5786
6376
|
full_args = [
|
5787
|
-
os.path.join(
|
6377
|
+
os.path.join(check.not_none(await self._pyenv.root()), 'plugins', 'python-build', 'bin', 'python-build'), # noqa
|
5788
6378
|
*conf_args,
|
5789
6379
|
self.install_dir(),
|
5790
6380
|
]
|
@@ -5856,7 +6446,7 @@ class PyenvInterpProvider(InterpProvider):
|
|
5856
6446
|
iv: ta.Optional[InterpVersion]
|
5857
6447
|
if self._inspect:
|
5858
6448
|
try:
|
5859
|
-
iv =
|
6449
|
+
iv = check.not_none(await self._inspector.inspect(ep)).iv
|
5860
6450
|
except Exception as e: # noqa
|
5861
6451
|
return None
|
5862
6452
|
else:
|
@@ -6191,8 +6781,8 @@ class InterpCommand(Command['InterpCommand.Output']):
|
|
6191
6781
|
|
6192
6782
|
class InterpCommandExecutor(CommandExecutor[InterpCommand, InterpCommand.Output]):
|
6193
6783
|
async def execute(self, cmd: InterpCommand) -> InterpCommand.Output:
|
6194
|
-
i = InterpSpecifier.parse(
|
6195
|
-
o =
|
6784
|
+
i = InterpSpecifier.parse(check.not_none(cmd.spec))
|
6785
|
+
o = check.not_none(await DEFAULT_INTERP_RESOLVER.resolve(i, install=cmd.install))
|
6196
6786
|
return InterpCommand.Output(
|
6197
6787
|
exe=o.exe,
|
6198
6788
|
version=str(o.version.version),
|
@@ -6383,108 +6973,102 @@ def main_bootstrap(bs: MainBootstrap) -> Injector:
|
|
6383
6973
|
# main.py
|
6384
6974
|
|
6385
6975
|
|
6386
|
-
|
6976
|
+
class MainCli(ArgparseCli):
|
6977
|
+
@argparse_command(
|
6978
|
+
argparse_arg('--payload-file'),
|
6387
6979
|
|
6980
|
+
argparse_arg('-s', '--shell'),
|
6981
|
+
argparse_arg('-q', '--shell-quote', action='store_true'),
|
6982
|
+
argparse_arg('--python', default='python3'),
|
6388
6983
|
|
6389
|
-
|
6390
|
-
|
6391
|
-
|
6392
|
-
log_level='DEBUG' if args.debug else 'INFO',
|
6984
|
+
argparse_arg('--pycharm-debug-port', type=int),
|
6985
|
+
argparse_arg('--pycharm-debug-host'),
|
6986
|
+
argparse_arg('--pycharm-debug-version'),
|
6393
6987
|
|
6394
|
-
|
6395
|
-
),
|
6988
|
+
argparse_arg('--remote-timebomb-delay-s', type=float),
|
6396
6989
|
|
6397
|
-
|
6398
|
-
payload_file=args._payload_file, # noqa
|
6990
|
+
argparse_arg('--debug', action='store_true'),
|
6399
6991
|
|
6400
|
-
|
6401
|
-
port=args.pycharm_debug_port,
|
6402
|
-
**(dict(host=args.pycharm_debug_host) if args.pycharm_debug_host is not None else {}),
|
6403
|
-
install_version=args.pycharm_debug_version,
|
6404
|
-
) if args.pycharm_debug_port is not None else None,
|
6992
|
+
argparse_arg('--local', action='store_true'),
|
6405
6993
|
|
6406
|
-
|
6407
|
-
),
|
6994
|
+
argparse_arg('command', nargs='+'),
|
6408
6995
|
)
|
6996
|
+
def run(self) -> None:
|
6997
|
+
asyncio.run(self._async_run())
|
6409
6998
|
|
6410
|
-
|
6411
|
-
|
6412
|
-
|
6413
|
-
|
6414
|
-
)
|
6999
|
+
async def _async_run(self) -> None:
|
7000
|
+
bs = MainBootstrap(
|
7001
|
+
main_config=MainConfig(
|
7002
|
+
log_level='DEBUG' if self.args.debug else 'INFO',
|
6415
7003
|
|
6416
|
-
|
6417
|
-
|
6418
|
-
msh = injector[ObjMarshalerManager]
|
6419
|
-
|
6420
|
-
cmds: ta.List[Command] = []
|
6421
|
-
cmd: Command
|
6422
|
-
for c in args.command:
|
6423
|
-
if not c.startswith('{'):
|
6424
|
-
c = json.dumps({c: {}})
|
6425
|
-
cmd = msh.unmarshal_obj(json.loads(c), Command)
|
6426
|
-
cmds.append(cmd)
|
6427
|
-
|
6428
|
-
#
|
6429
|
-
|
6430
|
-
async with contextlib.AsyncExitStack() as es:
|
6431
|
-
ce: CommandExecutor
|
6432
|
-
|
6433
|
-
if args.local:
|
6434
|
-
ce = injector[LocalCommandExecutor]
|
7004
|
+
debug=bool(self.args.debug),
|
7005
|
+
),
|
6435
7006
|
|
6436
|
-
|
6437
|
-
|
6438
|
-
shell=args.shell,
|
6439
|
-
shell_quote=args.shell_quote,
|
6440
|
-
python=args.python,
|
6441
|
-
)
|
7007
|
+
remote_config=RemoteConfig(
|
7008
|
+
payload_file=self.args.payload_file, # noqa
|
6442
7009
|
|
6443
|
-
|
7010
|
+
pycharm_remote_debug=PycharmRemoteDebug(
|
7011
|
+
port=self.args.pycharm_debug_port,
|
7012
|
+
**(dict(host=self.args.pycharm_debug_host) if self.args.pycharm_debug_host is not None else {}),
|
7013
|
+
install_version=self.args.pycharm_debug_version,
|
7014
|
+
) if self.args.pycharm_debug_port is not None else None,
|
6444
7015
|
|
6445
|
-
|
6446
|
-
|
6447
|
-
|
6448
|
-
log=log,
|
6449
|
-
omit_exc_object=True,
|
6450
|
-
)
|
7016
|
+
timebomb_delay_s=self.args.remote_timebomb_delay_s,
|
7017
|
+
),
|
7018
|
+
)
|
6451
7019
|
|
6452
|
-
|
7020
|
+
#
|
6453
7021
|
|
6454
|
-
|
6455
|
-
|
6456
|
-
|
6457
|
-
])
|
7022
|
+
injector = main_bootstrap(
|
7023
|
+
bs,
|
7024
|
+
)
|
6458
7025
|
|
7026
|
+
#
|
6459
7027
|
|
6460
|
-
|
6461
|
-
import argparse
|
7028
|
+
msh = injector[ObjMarshalerManager]
|
6462
7029
|
|
6463
|
-
|
7030
|
+
cmds: ta.List[Command] = []
|
7031
|
+
cmd: Command
|
7032
|
+
for c in self.args.command:
|
7033
|
+
if not c.startswith('{'):
|
7034
|
+
c = json.dumps({c: {}})
|
7035
|
+
cmd = msh.unmarshal_obj(json.loads(c), Command)
|
7036
|
+
cmds.append(cmd)
|
6464
7037
|
|
6465
|
-
|
7038
|
+
#
|
6466
7039
|
|
6467
|
-
|
6468
|
-
|
6469
|
-
parser.add_argument('--python', default='python3')
|
7040
|
+
async with contextlib.AsyncExitStack() as es:
|
7041
|
+
ce: CommandExecutor
|
6470
7042
|
|
6471
|
-
|
6472
|
-
|
6473
|
-
parser.add_argument('--pycharm-debug-version')
|
7043
|
+
if self.args.local:
|
7044
|
+
ce = injector[LocalCommandExecutor]
|
6474
7045
|
|
6475
|
-
|
7046
|
+
else:
|
7047
|
+
tgt = RemoteSpawning.Target(
|
7048
|
+
shell=self.args.shell,
|
7049
|
+
shell_quote=self.args.shell_quote,
|
7050
|
+
python=self.args.python,
|
7051
|
+
)
|
6476
7052
|
|
6477
|
-
|
7053
|
+
ce = await es.enter_async_context(injector[RemoteExecutionConnector].connect(tgt, bs)) # noqa
|
6478
7054
|
|
6479
|
-
|
7055
|
+
async def run_command(cmd: Command) -> None:
|
7056
|
+
res = await ce.try_execute(
|
7057
|
+
cmd,
|
7058
|
+
log=log,
|
7059
|
+
omit_exc_object=True,
|
7060
|
+
)
|
6480
7061
|
|
6481
|
-
|
7062
|
+
print(msh.marshal_obj(res, opts=ObjMarshalOptions(raw_bytes=True)))
|
6482
7063
|
|
6483
|
-
|
7064
|
+
await asyncio.gather(*[
|
7065
|
+
run_command(cmd)
|
7066
|
+
for cmd in cmds
|
7067
|
+
])
|
6484
7068
|
|
6485
|
-
#
|
6486
7069
|
|
6487
|
-
|
7070
|
+
def _main() -> None:
|
7071
|
+
MainCli().call_and_exit()
|
6488
7072
|
|
6489
7073
|
|
6490
7074
|
if __name__ == '__main__':
|