ominfra 0.0.0.dev148__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/cli.py +1 -1
- 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 +3 -3
- 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 +508 -147
- ominfra/scripts/manage.py +772 -183
- ominfra/scripts/supervisor.py +1144 -783
- ominfra/supervisor/dispatchers.py +1 -1
- ominfra/supervisor/groupsimpl.py +2 -2
- ominfra/supervisor/http.py +7 -7
- ominfra/supervisor/inject.py +4 -4
- ominfra/supervisor/io.py +1 -1
- ominfra/supervisor/main.py +1 -1
- ominfra/supervisor/processimpl.py +2 -2
- ominfra/supervisor/spawningimpl.py +9 -10
- ominfra/supervisor/supervisor.py +3 -3
- ominfra/supervisor/types.py +1 -1
- ominfra/tailscale/cli.py +1 -1
- {ominfra-0.0.0.dev148.dist-info → ominfra-0.0.0.dev150.dist-info}/METADATA +3 -3
- {ominfra-0.0.0.dev148.dist-info → ominfra-0.0.0.dev150.dist-info}/RECORD +36 -36
- {ominfra-0.0.0.dev148.dist-info → ominfra-0.0.0.dev150.dist-info}/LICENSE +0 -0
- {ominfra-0.0.0.dev148.dist-info → ominfra-0.0.0.dev150.dist-info}/WHEEL +0 -0
- {ominfra-0.0.0.dev148.dist-info → ominfra-0.0.0.dev150.dist-info}/entry_points.txt +0 -0
- {ominfra-0.0.0.dev148.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,99 +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]
|
1155
1212
|
|
1213
|
+
def _late_configure(self) -> None:
|
1214
|
+
if not self._late_configure_fns:
|
1215
|
+
return
|
1156
1216
|
|
1157
|
-
|
1158
|
-
|
1159
|
-
|
1160
|
-
return v
|
1217
|
+
with self._config_lock:
|
1218
|
+
if not (lc := self._late_configure_fns):
|
1219
|
+
return
|
1161
1220
|
|
1221
|
+
for fn in lc:
|
1222
|
+
fn(self)
|
1162
1223
|
|
1163
|
-
|
1164
|
-
if isinstance(v, spec):
|
1165
|
-
raise TypeError(v)
|
1166
|
-
return v
|
1224
|
+
self._late_configure_fns = []
|
1167
1225
|
|
1226
|
+
#
|
1168
1227
|
|
1169
|
-
|
1170
|
-
|
1171
|
-
|
1228
|
+
class _ArgsKwargs:
|
1229
|
+
def __init__(self, *args, **kwargs):
|
1230
|
+
self.args = args
|
1231
|
+
self.kwargs = kwargs
|
1172
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
|
+
)
|
1173
1265
|
|
1174
|
-
|
1175
|
-
|
1176
|
-
raise ValueError
|
1177
|
-
return v
|
1266
|
+
for fn in self._on_raise_fns:
|
1267
|
+
fn(exc)
|
1178
1268
|
|
1269
|
+
raise exc
|
1179
1270
|
|
1180
|
-
|
1181
|
-
if v:
|
1182
|
-
raise ValueError(v)
|
1183
|
-
return v
|
1271
|
+
#
|
1184
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
|
+
)
|
1185
1293
|
|
1186
|
-
|
1187
|
-
if not v:
|
1188
|
-
raise ValueError
|
1189
|
-
return v
|
1294
|
+
return v
|
1190
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)
|
1191
1299
|
|
1192
|
-
|
1193
|
-
if not v:
|
1194
|
-
raise ValueError(msg)
|
1300
|
+
return inner
|
1195
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
|
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)
|
1196
1316
|
|
1197
|
-
|
1198
|
-
if l != r:
|
1199
|
-
raise ValueError(l, r)
|
1200
|
-
return l
|
1317
|
+
return inner
|
1201
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
|
+
)
|
1202
1328
|
|
1203
|
-
|
1204
|
-
if l == r:
|
1205
|
-
raise ValueError(l, r)
|
1206
|
-
return l
|
1329
|
+
return v
|
1207
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)
|
1208
1334
|
|
1209
|
-
|
1210
|
-
if l is not r:
|
1211
|
-
raise ValueError(l, r)
|
1212
|
-
return l
|
1335
|
+
return inner
|
1213
1336
|
|
1337
|
+
##
|
1214
1338
|
|
1215
|
-
def
|
1216
|
-
|
1217
|
-
|
1218
|
-
|
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
|
+
)
|
1219
1348
|
|
1349
|
+
return v
|
1220
1350
|
|
1221
|
-
def
|
1222
|
-
|
1223
|
-
|
1224
|
-
|
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
|
+
)
|
1225
1360
|
|
1361
|
+
return v
|
1226
1362
|
|
1227
|
-
|
1228
|
-
|
1229
|
-
|
1230
|
-
|
1363
|
+
#
|
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
|
+
)
|
1374
|
+
|
1375
|
+
return v
|
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
|
+
)
|
1386
|
+
|
1387
|
+
return v
|
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
|
+
)
|
1398
|
+
|
1399
|
+
return v
|
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
|
+
)
|
1415
|
+
|
1416
|
+
return v
|
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
|
+
)
|
1427
|
+
|
1428
|
+
return v
|
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
|
+
)
|
1439
|
+
|
1440
|
+
return it
|
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
|
1477
|
+
|
1478
|
+
#
|
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
|
+
)
|
1489
|
+
|
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
|
+
)
|
1499
|
+
|
1500
|
+
return v
|
1501
|
+
|
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
|
+
)
|
1231
1585
|
|
1586
|
+
return new
|
1232
1587
|
|
1233
|
-
|
1234
|
-
[v] = vs
|
1235
|
-
return v
|
1588
|
+
#
|
1236
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
|
+
)
|
1237
1599
|
|
1238
|
-
def
|
1239
|
-
|
1240
|
-
|
1241
|
-
|
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
|
+
)
|
1242
1609
|
|
1243
1610
|
|
1244
|
-
|
1245
|
-
if not len(v):
|
1246
|
-
raise ValueError(v)
|
1247
|
-
return v
|
1611
|
+
check = Checks()
|
1248
1612
|
|
1249
1613
|
|
1250
1614
|
########################################
|
@@ -2053,7 +2417,7 @@ class Command(abc.ABC, ta.Generic[CommandOutputT]):
|
|
2053
2417
|
|
2054
2418
|
@ta.final
|
2055
2419
|
async def execute(self, executor: 'CommandExecutor') -> CommandOutputT:
|
2056
|
-
return
|
2420
|
+
return check.isinstance(await executor.execute(self), self.Output) # type: ignore[return-value]
|
2057
2421
|
|
2058
2422
|
|
2059
2423
|
##
|
@@ -2248,6 +2612,237 @@ def get_remote_payload_src(
|
|
2248
2612
|
return importlib.resources.files(__package__.split('.')[0] + '.scripts').joinpath('manage.py').read_text()
|
2249
2613
|
|
2250
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
|
+
|
2251
2846
|
########################################
|
2252
2847
|
# ../../../omlish/lite/inject.py
|
2253
2848
|
|
@@ -2392,7 +2987,7 @@ class FnInjectorProvider(InjectorProvider):
|
|
2392
2987
|
fn: ta.Any
|
2393
2988
|
|
2394
2989
|
def __post_init__(self) -> None:
|
2395
|
-
|
2990
|
+
check.not_isinstance(self.fn, type)
|
2396
2991
|
|
2397
2992
|
def provider_fn(self) -> InjectorProviderFn:
|
2398
2993
|
def pfn(i: Injector) -> ta.Any:
|
@@ -2406,7 +3001,7 @@ class CtorInjectorProvider(InjectorProvider):
|
|
2406
3001
|
cls_: type
|
2407
3002
|
|
2408
3003
|
def __post_init__(self) -> None:
|
2409
|
-
|
3004
|
+
check.isinstance(self.cls_, type)
|
2410
3005
|
|
2411
3006
|
def provider_fn(self) -> InjectorProviderFn:
|
2412
3007
|
def pfn(i: Injector) -> ta.Any:
|
@@ -2428,7 +3023,7 @@ class SingletonInjectorProvider(InjectorProvider):
|
|
2428
3023
|
p: InjectorProvider
|
2429
3024
|
|
2430
3025
|
def __post_init__(self) -> None:
|
2431
|
-
|
3026
|
+
check.isinstance(self.p, InjectorProvider)
|
2432
3027
|
|
2433
3028
|
def provider_fn(self) -> InjectorProviderFn:
|
2434
3029
|
v = not_set = object()
|
@@ -2448,7 +3043,7 @@ class LinkInjectorProvider(InjectorProvider):
|
|
2448
3043
|
k: InjectorKey
|
2449
3044
|
|
2450
3045
|
def __post_init__(self) -> None:
|
2451
|
-
|
3046
|
+
check.isinstance(self.k, InjectorKey)
|
2452
3047
|
|
2453
3048
|
def provider_fn(self) -> InjectorProviderFn:
|
2454
3049
|
def pfn(i: Injector) -> ta.Any:
|
@@ -2645,7 +3240,7 @@ def build_injection_kwargs_target(
|
|
2645
3240
|
|
2646
3241
|
skip_names: ta.Set[str] = set()
|
2647
3242
|
if skip_kwargs is not None:
|
2648
|
-
skip_names.update(
|
3243
|
+
skip_names.update(check.not_isinstance(skip_kwargs, str))
|
2649
3244
|
|
2650
3245
|
seen: ta.Set[InjectorKey] = set()
|
2651
3246
|
kws: ta.List[InjectionKwarg] = []
|
@@ -2706,8 +3301,8 @@ class _Injector(Injector):
|
|
2706
3301
|
def __init__(self, bs: InjectorBindings, p: ta.Optional[Injector] = None) -> None:
|
2707
3302
|
super().__init__()
|
2708
3303
|
|
2709
|
-
self._bs =
|
2710
|
-
self._p: ta.Optional[Injector] =
|
3304
|
+
self._bs = check.isinstance(bs, InjectorBindings)
|
3305
|
+
self._p: ta.Optional[Injector] = check.isinstance(p, (Injector, type(None)))
|
2711
3306
|
|
2712
3307
|
self._pfm = {k: v.provider_fn() for k, v in build_injector_provider_map(bs).items()}
|
2713
3308
|
|
@@ -2738,8 +3333,8 @@ class _Injector(Injector):
|
|
2738
3333
|
return Maybe.empty()
|
2739
3334
|
|
2740
3335
|
def handle_provision(self, key: InjectorKey, mv: Maybe) -> Maybe:
|
2741
|
-
|
2742
|
-
|
3336
|
+
check.in_(key, self._seen_keys)
|
3337
|
+
check.not_in(key, self._provisions)
|
2743
3338
|
self._provisions[key] = mv
|
2744
3339
|
return mv
|
2745
3340
|
|
@@ -2853,7 +3448,7 @@ class InjectorBinder:
|
|
2853
3448
|
|
2854
3449
|
@classmethod
|
2855
3450
|
def bind_as_fn(cls, icls: ta.Type[T]) -> ta.Type[T]:
|
2856
|
-
|
3451
|
+
check.isinstance(icls, type)
|
2857
3452
|
if icls not in cls._FN_TYPES:
|
2858
3453
|
cls._FN_TYPES = (*cls._FN_TYPES, icls)
|
2859
3454
|
return icls
|
@@ -2910,7 +3505,7 @@ class InjectorBinder:
|
|
2910
3505
|
to_fn = obj
|
2911
3506
|
if key is None:
|
2912
3507
|
insp = _injection_inspect(obj)
|
2913
|
-
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')))
|
2914
3509
|
key = InjectorKey(key_cls)
|
2915
3510
|
else:
|
2916
3511
|
if to_const is not None:
|
@@ -3452,10 +4047,10 @@ class ProxyObjMarshaler(ObjMarshaler):
|
|
3452
4047
|
m: ta.Optional[ObjMarshaler] = None
|
3453
4048
|
|
3454
4049
|
def marshal(self, o: ta.Any, ctx: 'ObjMarshalContext') -> ta.Any:
|
3455
|
-
return
|
4050
|
+
return check.not_none(self.m).marshal(o, ctx)
|
3456
4051
|
|
3457
4052
|
def unmarshal(self, o: ta.Any, ctx: 'ObjMarshalContext') -> ta.Any:
|
3458
|
-
return
|
4053
|
+
return check.not_none(self.m).unmarshal(o, ctx)
|
3459
4054
|
|
3460
4055
|
|
3461
4056
|
@dc.dataclass(frozen=True)
|
@@ -3614,19 +4209,19 @@ class DatetimeObjMarshaler(ObjMarshaler):
|
|
3614
4209
|
|
3615
4210
|
class DecimalObjMarshaler(ObjMarshaler):
|
3616
4211
|
def marshal(self, o: ta.Any, ctx: 'ObjMarshalContext') -> ta.Any:
|
3617
|
-
return str(
|
4212
|
+
return str(check.isinstance(o, decimal.Decimal))
|
3618
4213
|
|
3619
4214
|
def unmarshal(self, v: ta.Any, ctx: 'ObjMarshalContext') -> ta.Any:
|
3620
|
-
return decimal.Decimal(
|
4215
|
+
return decimal.Decimal(check.isinstance(v, str))
|
3621
4216
|
|
3622
4217
|
|
3623
4218
|
class FractionObjMarshaler(ObjMarshaler):
|
3624
4219
|
def marshal(self, o: ta.Any, ctx: 'ObjMarshalContext') -> ta.Any:
|
3625
|
-
fr =
|
4220
|
+
fr = check.isinstance(o, fractions.Fraction)
|
3626
4221
|
return [fr.numerator, fr.denominator]
|
3627
4222
|
|
3628
4223
|
def unmarshal(self, v: ta.Any, ctx: 'ObjMarshalContext') -> ta.Any:
|
3629
|
-
num, denom =
|
4224
|
+
num, denom = check.isinstance(v, list)
|
3630
4225
|
return fractions.Fraction(num, denom)
|
3631
4226
|
|
3632
4227
|
|
@@ -4431,7 +5026,7 @@ class _RemoteCommandHandler:
|
|
4431
5026
|
], return_when=asyncio.FIRST_COMPLETED)
|
4432
5027
|
|
4433
5028
|
if recv_task in done:
|
4434
|
-
msg: ta.Optional[_RemoteProtocol.Message] =
|
5029
|
+
msg: ta.Optional[_RemoteProtocol.Message] = check.isinstance(
|
4435
5030
|
recv_task.result(),
|
4436
5031
|
(_RemoteProtocol.Message, type(None)),
|
4437
5032
|
)
|
@@ -4500,8 +5095,8 @@ class RemoteCommandExecutor(CommandExecutor):
|
|
4500
5095
|
#
|
4501
5096
|
|
4502
5097
|
async def start(self) -> None:
|
4503
|
-
|
4504
|
-
|
5098
|
+
check.none(self._loop_task)
|
5099
|
+
check.state(not self._stop.is_set())
|
4505
5100
|
self._loop_task = asyncio.create_task(self._loop())
|
4506
5101
|
|
4507
5102
|
async def aclose(self) -> None:
|
@@ -4537,12 +5132,12 @@ class RemoteCommandExecutor(CommandExecutor):
|
|
4537
5132
|
], return_when=asyncio.FIRST_COMPLETED)
|
4538
5133
|
|
4539
5134
|
if queue_task in done:
|
4540
|
-
req =
|
5135
|
+
req = check.isinstance(queue_task.result(), RemoteCommandExecutor._Request)
|
4541
5136
|
queue_task = None
|
4542
5137
|
await self._handle_request(req)
|
4543
5138
|
|
4544
5139
|
if recv_task in done:
|
4545
|
-
msg: ta.Optional[_RemoteProtocol.Message] =
|
5140
|
+
msg: ta.Optional[_RemoteProtocol.Message] = check.isinstance(
|
4546
5141
|
recv_task.result(),
|
4547
5142
|
(_RemoteProtocol.Message, type(None)),
|
4548
5143
|
)
|
@@ -4610,7 +5205,7 @@ class RemoteCommandExecutor(CommandExecutor):
|
|
4610
5205
|
if (e := r.exception) is not None:
|
4611
5206
|
raise RemoteCommandError(e)
|
4612
5207
|
else:
|
4613
|
-
return
|
5208
|
+
return check.not_none(r.output)
|
4614
5209
|
|
4615
5210
|
# @ta.override
|
4616
5211
|
async def try_execute(
|
@@ -4655,7 +5250,7 @@ async def asyncio_subprocess_popen(
|
|
4655
5250
|
if shell:
|
4656
5251
|
fac = functools.partial(
|
4657
5252
|
asyncio.create_subprocess_shell,
|
4658
|
-
|
5253
|
+
check.single(cmd),
|
4659
5254
|
)
|
4660
5255
|
else:
|
4661
5256
|
fac = functools.partial(
|
@@ -4695,7 +5290,7 @@ class AsyncioProcessCommunicator:
|
|
4695
5290
|
self._proc = proc
|
4696
5291
|
self._loop = loop
|
4697
5292
|
|
4698
|
-
self._transport: asyncio.base_subprocess.BaseSubprocessTransport =
|
5293
|
+
self._transport: asyncio.base_subprocess.BaseSubprocessTransport = check.isinstance(
|
4699
5294
|
proc._transport, # type: ignore # noqa
|
4700
5295
|
asyncio.base_subprocess.BaseSubprocessTransport,
|
4701
5296
|
)
|
@@ -4705,7 +5300,7 @@ class AsyncioProcessCommunicator:
|
|
4705
5300
|
return self._loop.get_debug()
|
4706
5301
|
|
4707
5302
|
async def _feed_stdin(self, input: bytes) -> None: # noqa
|
4708
|
-
stdin =
|
5303
|
+
stdin = check.not_none(self._proc.stdin)
|
4709
5304
|
try:
|
4710
5305
|
if input is not None:
|
4711
5306
|
stdin.write(input)
|
@@ -4729,13 +5324,13 @@ class AsyncioProcessCommunicator:
|
|
4729
5324
|
return None
|
4730
5325
|
|
4731
5326
|
async def _read_stream(self, fd: int) -> bytes:
|
4732
|
-
transport: ta.Any =
|
5327
|
+
transport: ta.Any = check.not_none(self._transport.get_pipe_transport(fd))
|
4733
5328
|
|
4734
5329
|
if fd == 2:
|
4735
|
-
stream =
|
5330
|
+
stream = check.not_none(self._proc.stderr)
|
4736
5331
|
else:
|
4737
|
-
|
4738
|
-
stream =
|
5332
|
+
check.equal(fd, 1)
|
5333
|
+
stream = check.not_none(self._proc.stdout)
|
4739
5334
|
|
4740
5335
|
if self._debug:
|
4741
5336
|
name = 'stdout' if fd == 1 else 'stderr'
|
@@ -4855,7 +5450,7 @@ async def asyncio_subprocess_check_output(
|
|
4855
5450
|
**kwargs,
|
4856
5451
|
)
|
4857
5452
|
|
4858
|
-
return
|
5453
|
+
return check.not_none(stdout)
|
4859
5454
|
|
4860
5455
|
|
4861
5456
|
async def asyncio_subprocess_check_output_str(*args: str, **kwargs: ta.Any) -> str:
|
@@ -5033,7 +5628,7 @@ class SubprocessCommand(Command['SubprocessCommand.Output']):
|
|
5033
5628
|
timeout: ta.Optional[float] = None
|
5034
5629
|
|
5035
5630
|
def __post_init__(self) -> None:
|
5036
|
-
|
5631
|
+
check.not_isinstance(self.cmd, str)
|
5037
5632
|
|
5038
5633
|
@dc.dataclass(frozen=True)
|
5039
5634
|
class Output(Command.Output):
|
@@ -5074,7 +5669,7 @@ class SubprocessCommandExecutor(CommandExecutor[SubprocessCommand, SubprocessCom
|
|
5074
5669
|
end_time = time.time()
|
5075
5670
|
|
5076
5671
|
return SubprocessCommand.Output(
|
5077
|
-
rc=
|
5672
|
+
rc=check.not_none(proc.returncode),
|
5078
5673
|
pid=proc.pid,
|
5079
5674
|
|
5080
5675
|
elapsed_s=end_time - start_time,
|
@@ -5118,11 +5713,11 @@ class _RemoteExecutionMain:
|
|
5118
5713
|
|
5119
5714
|
@property
|
5120
5715
|
def _bootstrap(self) -> MainBootstrap:
|
5121
|
-
return
|
5716
|
+
return check.not_none(self.__bootstrap)
|
5122
5717
|
|
5123
5718
|
@property
|
5124
5719
|
def _injector(self) -> Injector:
|
5125
|
-
return
|
5720
|
+
return check.not_none(self.__injector)
|
5126
5721
|
|
5127
5722
|
#
|
5128
5723
|
|
@@ -5166,12 +5761,12 @@ class _RemoteExecutionMain:
|
|
5166
5761
|
#
|
5167
5762
|
|
5168
5763
|
async def _setup(self) -> None:
|
5169
|
-
|
5170
|
-
|
5764
|
+
check.none(self.__bootstrap)
|
5765
|
+
check.none(self.__injector)
|
5171
5766
|
|
5172
5767
|
# Bootstrap
|
5173
5768
|
|
5174
|
-
self.__bootstrap =
|
5769
|
+
self.__bootstrap = check.not_none(await self._chan.recv_obj(MainBootstrap))
|
5175
5770
|
|
5176
5771
|
if (prd := self._bootstrap.remote_config.pycharm_remote_debug) is not None:
|
5177
5772
|
pycharm_debug_connect(prd)
|
@@ -5313,8 +5908,8 @@ class SubprocessRemoteSpawning(RemoteSpawning):
|
|
5313
5908
|
),
|
5314
5909
|
timeout=timeout,
|
5315
5910
|
) as proc:
|
5316
|
-
stdin =
|
5317
|
-
stdout =
|
5911
|
+
stdin = check.not_none(proc.stdin)
|
5912
|
+
stdout = check.not_none(proc.stdout)
|
5318
5913
|
|
5319
5914
|
try:
|
5320
5915
|
yield RemoteSpawning.Spawned(
|
@@ -5530,7 +6125,7 @@ class Pyenv:
|
|
5530
6125
|
|
5531
6126
|
@async_cached_nullary
|
5532
6127
|
async def exe(self) -> str:
|
5533
|
-
return os.path.join(
|
6128
|
+
return os.path.join(check.not_none(await self.root()), 'bin', 'pyenv')
|
5534
6129
|
|
5535
6130
|
async def version_exes(self) -> ta.List[ta.Tuple[str, str]]:
|
5536
6131
|
if (root := await self.root()) is None:
|
@@ -5756,7 +6351,7 @@ class PyenvVersionInstaller:
|
|
5756
6351
|
|
5757
6352
|
@async_cached_nullary
|
5758
6353
|
async def install_dir(self) -> str:
|
5759
|
-
return str(os.path.join(
|
6354
|
+
return str(os.path.join(check.not_none(await self._pyenv.root()), 'versions', self.install_name()))
|
5760
6355
|
|
5761
6356
|
@async_cached_nullary
|
5762
6357
|
async def install(self) -> str:
|
@@ -5779,7 +6374,7 @@ class PyenvVersionInstaller:
|
|
5779
6374
|
|
5780
6375
|
if self._given_install_name is not None:
|
5781
6376
|
full_args = [
|
5782
|
-
os.path.join(
|
6377
|
+
os.path.join(check.not_none(await self._pyenv.root()), 'plugins', 'python-build', 'bin', 'python-build'), # noqa
|
5783
6378
|
*conf_args,
|
5784
6379
|
self.install_dir(),
|
5785
6380
|
]
|
@@ -5851,7 +6446,7 @@ class PyenvInterpProvider(InterpProvider):
|
|
5851
6446
|
iv: ta.Optional[InterpVersion]
|
5852
6447
|
if self._inspect:
|
5853
6448
|
try:
|
5854
|
-
iv =
|
6449
|
+
iv = check.not_none(await self._inspector.inspect(ep)).iv
|
5855
6450
|
except Exception as e: # noqa
|
5856
6451
|
return None
|
5857
6452
|
else:
|
@@ -6186,8 +6781,8 @@ class InterpCommand(Command['InterpCommand.Output']):
|
|
6186
6781
|
|
6187
6782
|
class InterpCommandExecutor(CommandExecutor[InterpCommand, InterpCommand.Output]):
|
6188
6783
|
async def execute(self, cmd: InterpCommand) -> InterpCommand.Output:
|
6189
|
-
i = InterpSpecifier.parse(
|
6190
|
-
o =
|
6784
|
+
i = InterpSpecifier.parse(check.not_none(cmd.spec))
|
6785
|
+
o = check.not_none(await DEFAULT_INTERP_RESOLVER.resolve(i, install=cmd.install))
|
6191
6786
|
return InterpCommand.Output(
|
6192
6787
|
exe=o.exe,
|
6193
6788
|
version=str(o.version.version),
|
@@ -6378,108 +6973,102 @@ def main_bootstrap(bs: MainBootstrap) -> Injector:
|
|
6378
6973
|
# main.py
|
6379
6974
|
|
6380
6975
|
|
6381
|
-
|
6976
|
+
class MainCli(ArgparseCli):
|
6977
|
+
@argparse_command(
|
6978
|
+
argparse_arg('--payload-file'),
|
6382
6979
|
|
6980
|
+
argparse_arg('-s', '--shell'),
|
6981
|
+
argparse_arg('-q', '--shell-quote', action='store_true'),
|
6982
|
+
argparse_arg('--python', default='python3'),
|
6383
6983
|
|
6384
|
-
|
6385
|
-
|
6386
|
-
|
6387
|
-
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'),
|
6388
6987
|
|
6389
|
-
|
6390
|
-
),
|
6988
|
+
argparse_arg('--remote-timebomb-delay-s', type=float),
|
6391
6989
|
|
6392
|
-
|
6393
|
-
payload_file=args._payload_file, # noqa
|
6990
|
+
argparse_arg('--debug', action='store_true'),
|
6394
6991
|
|
6395
|
-
|
6396
|
-
port=args.pycharm_debug_port,
|
6397
|
-
**(dict(host=args.pycharm_debug_host) if args.pycharm_debug_host is not None else {}),
|
6398
|
-
install_version=args.pycharm_debug_version,
|
6399
|
-
) if args.pycharm_debug_port is not None else None,
|
6992
|
+
argparse_arg('--local', action='store_true'),
|
6400
6993
|
|
6401
|
-
|
6402
|
-
),
|
6994
|
+
argparse_arg('command', nargs='+'),
|
6403
6995
|
)
|
6996
|
+
def run(self) -> None:
|
6997
|
+
asyncio.run(self._async_run())
|
6404
6998
|
|
6405
|
-
|
6406
|
-
|
6407
|
-
|
6408
|
-
|
6409
|
-
)
|
6999
|
+
async def _async_run(self) -> None:
|
7000
|
+
bs = MainBootstrap(
|
7001
|
+
main_config=MainConfig(
|
7002
|
+
log_level='DEBUG' if self.args.debug else 'INFO',
|
6410
7003
|
|
6411
|
-
|
6412
|
-
|
6413
|
-
msh = injector[ObjMarshalerManager]
|
6414
|
-
|
6415
|
-
cmds: ta.List[Command] = []
|
6416
|
-
cmd: Command
|
6417
|
-
for c in args.command:
|
6418
|
-
if not c.startswith('{'):
|
6419
|
-
c = json.dumps({c: {}})
|
6420
|
-
cmd = msh.unmarshal_obj(json.loads(c), Command)
|
6421
|
-
cmds.append(cmd)
|
6422
|
-
|
6423
|
-
#
|
6424
|
-
|
6425
|
-
async with contextlib.AsyncExitStack() as es:
|
6426
|
-
ce: CommandExecutor
|
6427
|
-
|
6428
|
-
if args.local:
|
6429
|
-
ce = injector[LocalCommandExecutor]
|
7004
|
+
debug=bool(self.args.debug),
|
7005
|
+
),
|
6430
7006
|
|
6431
|
-
|
6432
|
-
|
6433
|
-
shell=args.shell,
|
6434
|
-
shell_quote=args.shell_quote,
|
6435
|
-
python=args.python,
|
6436
|
-
)
|
7007
|
+
remote_config=RemoteConfig(
|
7008
|
+
payload_file=self.args.payload_file, # noqa
|
6437
7009
|
|
6438
|
-
|
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,
|
6439
7015
|
|
6440
|
-
|
6441
|
-
|
6442
|
-
|
6443
|
-
log=log,
|
6444
|
-
omit_exc_object=True,
|
6445
|
-
)
|
7016
|
+
timebomb_delay_s=self.args.remote_timebomb_delay_s,
|
7017
|
+
),
|
7018
|
+
)
|
6446
7019
|
|
6447
|
-
|
7020
|
+
#
|
6448
7021
|
|
6449
|
-
|
6450
|
-
|
6451
|
-
|
6452
|
-
])
|
7022
|
+
injector = main_bootstrap(
|
7023
|
+
bs,
|
7024
|
+
)
|
6453
7025
|
|
7026
|
+
#
|
6454
7027
|
|
6455
|
-
|
6456
|
-
import argparse
|
7028
|
+
msh = injector[ObjMarshalerManager]
|
6457
7029
|
|
6458
|
-
|
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)
|
6459
7037
|
|
6460
|
-
|
7038
|
+
#
|
6461
7039
|
|
6462
|
-
|
6463
|
-
|
6464
|
-
parser.add_argument('--python', default='python3')
|
7040
|
+
async with contextlib.AsyncExitStack() as es:
|
7041
|
+
ce: CommandExecutor
|
6465
7042
|
|
6466
|
-
|
6467
|
-
|
6468
|
-
parser.add_argument('--pycharm-debug-version')
|
7043
|
+
if self.args.local:
|
7044
|
+
ce = injector[LocalCommandExecutor]
|
6469
7045
|
|
6470
|
-
|
7046
|
+
else:
|
7047
|
+
tgt = RemoteSpawning.Target(
|
7048
|
+
shell=self.args.shell,
|
7049
|
+
shell_quote=self.args.shell_quote,
|
7050
|
+
python=self.args.python,
|
7051
|
+
)
|
6471
7052
|
|
6472
|
-
|
7053
|
+
ce = await es.enter_async_context(injector[RemoteExecutionConnector].connect(tgt, bs)) # noqa
|
6473
7054
|
|
6474
|
-
|
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
|
+
)
|
6475
7061
|
|
6476
|
-
|
7062
|
+
print(msh.marshal_obj(res, opts=ObjMarshalOptions(raw_bytes=True)))
|
6477
7063
|
|
6478
|
-
|
7064
|
+
await asyncio.gather(*[
|
7065
|
+
run_command(cmd)
|
7066
|
+
for cmd in cmds
|
7067
|
+
])
|
6479
7068
|
|
6480
|
-
#
|
6481
7069
|
|
6482
|
-
|
7070
|
+
def _main() -> None:
|
7071
|
+
MainCli().call_and_exit()
|
6483
7072
|
|
6484
7073
|
|
6485
7074
|
if __name__ == '__main__':
|