ominfra 0.0.0.dev149__py3-none-any.whl → 0.0.0.dev151__py3-none-any.whl
Sign up to get free protection for your applications and to get access to all the features.
- 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.dev151.dist-info}/METADATA +3 -3
- {ominfra-0.0.0.dev149.dist-info → ominfra-0.0.0.dev151.dist-info}/RECORD +30 -30
- {ominfra-0.0.0.dev149.dist-info → ominfra-0.0.0.dev151.dist-info}/LICENSE +0 -0
- {ominfra-0.0.0.dev149.dist-info → ominfra-0.0.0.dev151.dist-info}/WHEEL +0 -0
- {ominfra-0.0.0.dev149.dist-info → ominfra-0.0.0.dev151.dist-info}/entry_points.txt +0 -0
- {ominfra-0.0.0.dev149.dist-info → ominfra-0.0.0.dev151.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] # ta.TypeAlias
|
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__':
|