omdev 0.0.0.dev154__py3-none-any.whl → 0.0.0.dev156__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.
Potentially problematic release.
This version of omdev might be problematic. Click here for more details.
- omdev/.manifests.json +1 -1
- omdev/interp/inspect.py +2 -2
- omdev/interp/pyenv.py +9 -11
- omdev/manifests/__init__.py +1 -0
- omdev/manifests/build.py +0 -1
- omdev/manifests/main.py +1 -0
- omdev/pyproject/cli.py +3 -3
- omdev/pyproject/pkg.py +4 -4
- omdev/pyproject/venvs.py +4 -4
- omdev/scripts/interp.py +307 -282
- omdev/scripts/pyproject.py +322 -292
- omdev/tools/docker.py +14 -5
- {omdev-0.0.0.dev154.dist-info → omdev-0.0.0.dev156.dist-info}/METADATA +2 -2
- {omdev-0.0.0.dev154.dist-info → omdev-0.0.0.dev156.dist-info}/RECORD +18 -18
- {omdev-0.0.0.dev154.dist-info → omdev-0.0.0.dev156.dist-info}/LICENSE +0 -0
- {omdev-0.0.0.dev154.dist-info → omdev-0.0.0.dev156.dist-info}/WHEEL +0 -0
- {omdev-0.0.0.dev154.dist-info → omdev-0.0.0.dev156.dist-info}/entry_points.txt +0 -0
- {omdev-0.0.0.dev154.dist-info → omdev-0.0.0.dev156.dist-info}/top_level.txt +0 -0
omdev/scripts/pyproject.py
CHANGED
|
@@ -1852,8 +1852,6 @@ def async_cached_nullary(fn): # ta.Callable[..., T]) -> ta.Callable[..., T]:
|
|
|
1852
1852
|
"""
|
|
1853
1853
|
TODO:
|
|
1854
1854
|
- def maybe(v: lang.Maybe[T])
|
|
1855
|
-
- patch / override lite.check ?
|
|
1856
|
-
- checker interface?
|
|
1857
1855
|
"""
|
|
1858
1856
|
|
|
1859
1857
|
|
|
@@ -3756,7 +3754,8 @@ def configure_standard_logging(
|
|
|
3756
3754
|
"""
|
|
3757
3755
|
TODO:
|
|
3758
3756
|
- pickle stdlib objs? have to pin to 3.8 pickle protocol, will be cross-version
|
|
3759
|
-
-
|
|
3757
|
+
- namedtuple
|
|
3758
|
+
- literals
|
|
3760
3759
|
"""
|
|
3761
3760
|
|
|
3762
3761
|
|
|
@@ -4046,14 +4045,18 @@ class ObjMarshalerManager:
|
|
|
4046
4045
|
) -> ObjMarshaler:
|
|
4047
4046
|
if isinstance(ty, type):
|
|
4048
4047
|
if abc.ABC in ty.__bases__:
|
|
4049
|
-
|
|
4048
|
+
impls = [ity for ity in deep_subclasses(ty) if abc.ABC not in ity.__bases__] # type: ignore
|
|
4049
|
+
if all(ity.__qualname__.endswith(ty.__name__) for ity in impls):
|
|
4050
|
+
ins = {ity: snake_case(ity.__qualname__[:-len(ty.__name__)]) for ity in impls}
|
|
4051
|
+
else:
|
|
4052
|
+
ins = {ity: ity.__qualname__ for ity in impls}
|
|
4053
|
+
return PolymorphicObjMarshaler.of([
|
|
4050
4054
|
PolymorphicObjMarshaler.Impl(
|
|
4051
4055
|
ity,
|
|
4052
|
-
|
|
4056
|
+
itn,
|
|
4053
4057
|
rec(ity),
|
|
4054
4058
|
)
|
|
4055
|
-
for ity in
|
|
4056
|
-
if abc.ABC not in ity.__bases__
|
|
4059
|
+
for ity, itn in ins.items()
|
|
4057
4060
|
])
|
|
4058
4061
|
|
|
4059
4062
|
if issubclass(ty, enum.Enum):
|
|
@@ -4495,168 +4498,222 @@ SUBPROCESS_CHANNEL_OPTION_VALUES: ta.Mapping[SubprocessChannelOption, int] = {
|
|
|
4495
4498
|
_SUBPROCESS_SHELL_WRAP_EXECS = False
|
|
4496
4499
|
|
|
4497
4500
|
|
|
4498
|
-
def subprocess_shell_wrap_exec(*
|
|
4499
|
-
return ('sh', '-c', ' '.join(map(shlex.quote,
|
|
4501
|
+
def subprocess_shell_wrap_exec(*cmd: str) -> ta.Tuple[str, ...]:
|
|
4502
|
+
return ('sh', '-c', ' '.join(map(shlex.quote, cmd)))
|
|
4500
4503
|
|
|
4501
4504
|
|
|
4502
|
-
def subprocess_maybe_shell_wrap_exec(*
|
|
4505
|
+
def subprocess_maybe_shell_wrap_exec(*cmd: str) -> ta.Tuple[str, ...]:
|
|
4503
4506
|
if _SUBPROCESS_SHELL_WRAP_EXECS or is_debugger_attached():
|
|
4504
|
-
return subprocess_shell_wrap_exec(*
|
|
4507
|
+
return subprocess_shell_wrap_exec(*cmd)
|
|
4505
4508
|
else:
|
|
4506
|
-
return
|
|
4507
|
-
|
|
4509
|
+
return cmd
|
|
4508
4510
|
|
|
4509
|
-
def prepare_subprocess_invocation(
|
|
4510
|
-
*args: str,
|
|
4511
|
-
env: ta.Optional[ta.Mapping[str, ta.Any]] = None,
|
|
4512
|
-
extra_env: ta.Optional[ta.Mapping[str, ta.Any]] = None,
|
|
4513
|
-
quiet: bool = False,
|
|
4514
|
-
shell: bool = False,
|
|
4515
|
-
**kwargs: ta.Any,
|
|
4516
|
-
) -> ta.Tuple[ta.Tuple[ta.Any, ...], ta.Dict[str, ta.Any]]:
|
|
4517
|
-
log.debug('prepare_subprocess_invocation: args=%r', args)
|
|
4518
|
-
if extra_env:
|
|
4519
|
-
log.debug('prepare_subprocess_invocation: extra_env=%r', extra_env)
|
|
4520
4511
|
|
|
4521
|
-
|
|
4522
|
-
env = {**(env if env is not None else os.environ), **extra_env}
|
|
4512
|
+
##
|
|
4523
4513
|
|
|
4524
|
-
if quiet and 'stderr' not in kwargs:
|
|
4525
|
-
if not log.isEnabledFor(logging.DEBUG):
|
|
4526
|
-
kwargs['stderr'] = subprocess.DEVNULL
|
|
4527
4514
|
|
|
4528
|
-
|
|
4529
|
-
|
|
4515
|
+
def subprocess_close(
|
|
4516
|
+
proc: subprocess.Popen,
|
|
4517
|
+
timeout: ta.Optional[float] = None,
|
|
4518
|
+
) -> None:
|
|
4519
|
+
# TODO: terminate, sleep, kill
|
|
4520
|
+
if proc.stdout:
|
|
4521
|
+
proc.stdout.close()
|
|
4522
|
+
if proc.stderr:
|
|
4523
|
+
proc.stderr.close()
|
|
4524
|
+
if proc.stdin:
|
|
4525
|
+
proc.stdin.close()
|
|
4530
4526
|
|
|
4531
|
-
|
|
4532
|
-
env=env,
|
|
4533
|
-
shell=shell,
|
|
4534
|
-
**kwargs,
|
|
4535
|
-
)
|
|
4527
|
+
proc.wait(timeout)
|
|
4536
4528
|
|
|
4537
4529
|
|
|
4538
4530
|
##
|
|
4539
4531
|
|
|
4540
4532
|
|
|
4541
|
-
|
|
4542
|
-
|
|
4543
|
-
start_time = time.time()
|
|
4544
|
-
try:
|
|
4545
|
-
log.debug('subprocess_common_context.try: args=%r', args)
|
|
4546
|
-
yield
|
|
4533
|
+
class AbstractSubprocesses(abc.ABC): # noqa
|
|
4534
|
+
DEFAULT_LOGGER: ta.ClassVar[ta.Optional[logging.Logger]] = log
|
|
4547
4535
|
|
|
4548
|
-
|
|
4549
|
-
|
|
4550
|
-
|
|
4536
|
+
def __init__(
|
|
4537
|
+
self,
|
|
4538
|
+
*,
|
|
4539
|
+
log: ta.Optional[logging.Logger] = None,
|
|
4540
|
+
try_exceptions: ta.Optional[ta.Tuple[ta.Type[Exception], ...]] = None,
|
|
4541
|
+
) -> None:
|
|
4542
|
+
super().__init__()
|
|
4551
4543
|
|
|
4552
|
-
|
|
4553
|
-
|
|
4554
|
-
elapsed_s = end_time - start_time
|
|
4555
|
-
log.debug('subprocess_common_context.finally: elapsed_s=%f args=%r', elapsed_s, args)
|
|
4544
|
+
self._log = log if log is not None else self.DEFAULT_LOGGER
|
|
4545
|
+
self._try_exceptions = try_exceptions if try_exceptions is not None else self.DEFAULT_TRY_EXCEPTIONS
|
|
4556
4546
|
|
|
4547
|
+
#
|
|
4557
4548
|
|
|
4558
|
-
|
|
4549
|
+
def prepare_args(
|
|
4550
|
+
self,
|
|
4551
|
+
*cmd: str,
|
|
4552
|
+
env: ta.Optional[ta.Mapping[str, ta.Any]] = None,
|
|
4553
|
+
extra_env: ta.Optional[ta.Mapping[str, ta.Any]] = None,
|
|
4554
|
+
quiet: bool = False,
|
|
4555
|
+
shell: bool = False,
|
|
4556
|
+
**kwargs: ta.Any,
|
|
4557
|
+
) -> ta.Tuple[ta.Tuple[ta.Any, ...], ta.Dict[str, ta.Any]]:
|
|
4558
|
+
if self._log:
|
|
4559
|
+
self._log.debug('Subprocesses.prepare_args: cmd=%r', cmd)
|
|
4560
|
+
if extra_env:
|
|
4561
|
+
self._log.debug('Subprocesses.prepare_args: extra_env=%r', extra_env)
|
|
4559
4562
|
|
|
4563
|
+
if extra_env:
|
|
4564
|
+
env = {**(env if env is not None else os.environ), **extra_env}
|
|
4560
4565
|
|
|
4561
|
-
|
|
4562
|
-
|
|
4563
|
-
|
|
4564
|
-
**kwargs: ta.Any,
|
|
4565
|
-
) -> None:
|
|
4566
|
-
args, kwargs = prepare_subprocess_invocation(*args, stdout=stdout, **kwargs)
|
|
4567
|
-
with subprocess_common_context(*args, **kwargs):
|
|
4568
|
-
return subprocess.check_call(args, **kwargs) # type: ignore
|
|
4566
|
+
if quiet and 'stderr' not in kwargs:
|
|
4567
|
+
if self._log and not self._log.isEnabledFor(logging.DEBUG):
|
|
4568
|
+
kwargs['stderr'] = subprocess.DEVNULL
|
|
4569
4569
|
|
|
4570
|
+
if not shell:
|
|
4571
|
+
cmd = subprocess_maybe_shell_wrap_exec(*cmd)
|
|
4570
4572
|
|
|
4571
|
-
|
|
4572
|
-
|
|
4573
|
-
|
|
4574
|
-
|
|
4575
|
-
|
|
4576
|
-
with subprocess_common_context(*args, **kwargs):
|
|
4577
|
-
return subprocess.check_output(args, **kwargs)
|
|
4573
|
+
return cmd, dict(
|
|
4574
|
+
env=env,
|
|
4575
|
+
shell=shell,
|
|
4576
|
+
**kwargs,
|
|
4577
|
+
)
|
|
4578
4578
|
|
|
4579
|
+
@contextlib.contextmanager
|
|
4580
|
+
def wrap_call(self, *cmd: ta.Any, **kwargs: ta.Any) -> ta.Iterator[None]:
|
|
4581
|
+
start_time = time.time()
|
|
4582
|
+
try:
|
|
4583
|
+
if self._log:
|
|
4584
|
+
self._log.debug('Subprocesses.wrap_call.try: cmd=%r', cmd)
|
|
4585
|
+
yield
|
|
4579
4586
|
|
|
4580
|
-
|
|
4581
|
-
|
|
4587
|
+
except Exception as exc: # noqa
|
|
4588
|
+
if self._log:
|
|
4589
|
+
self._log.debug('Subprocesses.wrap_call.except: exc=%r', exc)
|
|
4590
|
+
raise
|
|
4582
4591
|
|
|
4592
|
+
finally:
|
|
4593
|
+
end_time = time.time()
|
|
4594
|
+
elapsed_s = end_time - start_time
|
|
4595
|
+
if self._log:
|
|
4596
|
+
self._log.debug('sSubprocesses.wrap_call.finally: elapsed_s=%f cmd=%r', elapsed_s, cmd)
|
|
4583
4597
|
|
|
4584
|
-
|
|
4598
|
+
@contextlib.contextmanager
|
|
4599
|
+
def prepare_and_wrap(
|
|
4600
|
+
self,
|
|
4601
|
+
*cmd: ta.Any,
|
|
4602
|
+
**kwargs: ta.Any,
|
|
4603
|
+
) -> ta.Iterator[ta.Tuple[
|
|
4604
|
+
ta.Tuple[ta.Any, ...],
|
|
4605
|
+
ta.Dict[str, ta.Any],
|
|
4606
|
+
]]:
|
|
4607
|
+
cmd, kwargs = self.prepare_args(*cmd, **kwargs)
|
|
4608
|
+
with self.wrap_call(*cmd, **kwargs):
|
|
4609
|
+
yield cmd, kwargs
|
|
4585
4610
|
|
|
4611
|
+
#
|
|
4586
4612
|
|
|
4587
|
-
|
|
4588
|
-
|
|
4589
|
-
|
|
4590
|
-
)
|
|
4613
|
+
DEFAULT_TRY_EXCEPTIONS: ta.Tuple[ta.Type[Exception], ...] = (
|
|
4614
|
+
FileNotFoundError,
|
|
4615
|
+
subprocess.CalledProcessError,
|
|
4616
|
+
)
|
|
4591
4617
|
|
|
4618
|
+
def try_fn(
|
|
4619
|
+
self,
|
|
4620
|
+
fn: ta.Callable[..., T],
|
|
4621
|
+
*cmd: str,
|
|
4622
|
+
try_exceptions: ta.Optional[ta.Tuple[ta.Type[Exception], ...]] = None,
|
|
4623
|
+
**kwargs: ta.Any,
|
|
4624
|
+
) -> ta.Union[T, Exception]:
|
|
4625
|
+
if try_exceptions is None:
|
|
4626
|
+
try_exceptions = self._try_exceptions
|
|
4592
4627
|
|
|
4593
|
-
|
|
4594
|
-
|
|
4595
|
-
*args: ta.Any,
|
|
4596
|
-
try_exceptions: ta.Tuple[ta.Type[Exception], ...] = DEFAULT_SUBPROCESS_TRY_EXCEPTIONS,
|
|
4597
|
-
**kwargs: ta.Any,
|
|
4598
|
-
) -> ta.Union[T, Exception]:
|
|
4599
|
-
try:
|
|
4600
|
-
return fn(*args, **kwargs)
|
|
4601
|
-
except try_exceptions as e: # noqa
|
|
4602
|
-
if log.isEnabledFor(logging.DEBUG):
|
|
4603
|
-
log.exception('command failed')
|
|
4604
|
-
return e
|
|
4628
|
+
try:
|
|
4629
|
+
return fn(*cmd, **kwargs)
|
|
4605
4630
|
|
|
4631
|
+
except try_exceptions as e: # noqa
|
|
4632
|
+
if self._log and self._log.isEnabledFor(logging.DEBUG):
|
|
4633
|
+
self._log.exception('command failed')
|
|
4634
|
+
return e
|
|
4606
4635
|
|
|
4607
|
-
def
|
|
4608
|
-
|
|
4609
|
-
|
|
4610
|
-
|
|
4611
|
-
|
|
4612
|
-
|
|
4613
|
-
|
|
4614
|
-
|
|
4615
|
-
try_exceptions=
|
|
4616
|
-
**kwargs,
|
|
4617
|
-
), Exception):
|
|
4618
|
-
return False
|
|
4619
|
-
else:
|
|
4620
|
-
return True
|
|
4636
|
+
async def async_try_fn(
|
|
4637
|
+
self,
|
|
4638
|
+
fn: ta.Callable[..., ta.Awaitable[T]],
|
|
4639
|
+
*cmd: ta.Any,
|
|
4640
|
+
try_exceptions: ta.Optional[ta.Tuple[ta.Type[Exception], ...]] = None,
|
|
4641
|
+
**kwargs: ta.Any,
|
|
4642
|
+
) -> ta.Union[T, Exception]:
|
|
4643
|
+
if try_exceptions is None:
|
|
4644
|
+
try_exceptions = self._try_exceptions
|
|
4621
4645
|
|
|
4646
|
+
try:
|
|
4647
|
+
return await fn(*cmd, **kwargs)
|
|
4622
4648
|
|
|
4623
|
-
|
|
4624
|
-
|
|
4625
|
-
|
|
4626
|
-
|
|
4627
|
-
) -> ta.Optional[bytes]:
|
|
4628
|
-
if isinstance(ret := _subprocess_try_run(
|
|
4629
|
-
subprocess_check_output,
|
|
4630
|
-
*args,
|
|
4631
|
-
try_exceptions=try_exceptions,
|
|
4632
|
-
**kwargs,
|
|
4633
|
-
), Exception):
|
|
4634
|
-
return None
|
|
4635
|
-
else:
|
|
4636
|
-
return ret
|
|
4649
|
+
except try_exceptions as e: # noqa
|
|
4650
|
+
if self._log and self._log.isEnabledFor(logging.DEBUG):
|
|
4651
|
+
self._log.exception('command failed')
|
|
4652
|
+
return e
|
|
4637
4653
|
|
|
4638
4654
|
|
|
4639
|
-
|
|
4640
|
-
out = subprocess_try_output(*args, **kwargs)
|
|
4641
|
-
return out.decode().strip() if out is not None else None
|
|
4655
|
+
##
|
|
4642
4656
|
|
|
4643
4657
|
|
|
4644
|
-
|
|
4658
|
+
class Subprocesses(AbstractSubprocesses):
|
|
4659
|
+
def check_call(
|
|
4660
|
+
self,
|
|
4661
|
+
*cmd: str,
|
|
4662
|
+
stdout: ta.Any = sys.stderr,
|
|
4663
|
+
**kwargs: ta.Any,
|
|
4664
|
+
) -> None:
|
|
4665
|
+
with self.prepare_and_wrap(*cmd, stdout=stdout, **kwargs) as (cmd, kwargs): # noqa
|
|
4666
|
+
subprocess.check_call(cmd, **kwargs)
|
|
4645
4667
|
|
|
4668
|
+
def check_output(
|
|
4669
|
+
self,
|
|
4670
|
+
*cmd: str,
|
|
4671
|
+
**kwargs: ta.Any,
|
|
4672
|
+
) -> bytes:
|
|
4673
|
+
with self.prepare_and_wrap(*cmd, **kwargs) as (cmd, kwargs): # noqa
|
|
4674
|
+
return subprocess.check_output(cmd, **kwargs)
|
|
4646
4675
|
|
|
4647
|
-
def
|
|
4648
|
-
|
|
4649
|
-
|
|
4650
|
-
|
|
4651
|
-
|
|
4652
|
-
|
|
4653
|
-
proc.stdout.close()
|
|
4654
|
-
if proc.stderr:
|
|
4655
|
-
proc.stderr.close()
|
|
4656
|
-
if proc.stdin:
|
|
4657
|
-
proc.stdin.close()
|
|
4676
|
+
def check_output_str(
|
|
4677
|
+
self,
|
|
4678
|
+
*cmd: str,
|
|
4679
|
+
**kwargs: ta.Any,
|
|
4680
|
+
) -> str:
|
|
4681
|
+
return self.check_output(*cmd, **kwargs).decode().strip()
|
|
4658
4682
|
|
|
4659
|
-
|
|
4683
|
+
#
|
|
4684
|
+
|
|
4685
|
+
def try_call(
|
|
4686
|
+
self,
|
|
4687
|
+
*cmd: str,
|
|
4688
|
+
**kwargs: ta.Any,
|
|
4689
|
+
) -> bool:
|
|
4690
|
+
if isinstance(self.try_fn(self.check_call, *cmd, **kwargs), Exception):
|
|
4691
|
+
return False
|
|
4692
|
+
else:
|
|
4693
|
+
return True
|
|
4694
|
+
|
|
4695
|
+
def try_output(
|
|
4696
|
+
self,
|
|
4697
|
+
*cmd: str,
|
|
4698
|
+
**kwargs: ta.Any,
|
|
4699
|
+
) -> ta.Optional[bytes]:
|
|
4700
|
+
if isinstance(ret := self.try_fn(self.check_output, *cmd, **kwargs), Exception):
|
|
4701
|
+
return None
|
|
4702
|
+
else:
|
|
4703
|
+
return ret
|
|
4704
|
+
|
|
4705
|
+
def try_output_str(
|
|
4706
|
+
self,
|
|
4707
|
+
*cmd: str,
|
|
4708
|
+
**kwargs: ta.Any,
|
|
4709
|
+
) -> ta.Optional[str]:
|
|
4710
|
+
if (ret := self.try_output(*cmd, **kwargs)) is None:
|
|
4711
|
+
return None
|
|
4712
|
+
else:
|
|
4713
|
+
return ret.decode().strip()
|
|
4714
|
+
|
|
4715
|
+
|
|
4716
|
+
subprocesses = Subprocesses()
|
|
4660
4717
|
|
|
4661
4718
|
|
|
4662
4719
|
########################################
|
|
@@ -5067,43 +5124,6 @@ def get_git_status(
|
|
|
5067
5124
|
##
|
|
5068
5125
|
|
|
5069
5126
|
|
|
5070
|
-
@contextlib.asynccontextmanager
|
|
5071
|
-
async def asyncio_subprocess_popen(
|
|
5072
|
-
*cmd: str,
|
|
5073
|
-
shell: bool = False,
|
|
5074
|
-
timeout: ta.Optional[float] = None,
|
|
5075
|
-
**kwargs: ta.Any,
|
|
5076
|
-
) -> ta.AsyncGenerator[asyncio.subprocess.Process, None]:
|
|
5077
|
-
fac: ta.Any
|
|
5078
|
-
if shell:
|
|
5079
|
-
fac = functools.partial(
|
|
5080
|
-
asyncio.create_subprocess_shell,
|
|
5081
|
-
check.single(cmd),
|
|
5082
|
-
)
|
|
5083
|
-
else:
|
|
5084
|
-
fac = functools.partial(
|
|
5085
|
-
asyncio.create_subprocess_exec,
|
|
5086
|
-
*cmd,
|
|
5087
|
-
)
|
|
5088
|
-
|
|
5089
|
-
with subprocess_common_context(
|
|
5090
|
-
*cmd,
|
|
5091
|
-
shell=shell,
|
|
5092
|
-
timeout=timeout,
|
|
5093
|
-
**kwargs,
|
|
5094
|
-
):
|
|
5095
|
-
proc: asyncio.subprocess.Process
|
|
5096
|
-
proc = await fac(**kwargs)
|
|
5097
|
-
try:
|
|
5098
|
-
yield proc
|
|
5099
|
-
|
|
5100
|
-
finally:
|
|
5101
|
-
await asyncio_maybe_timeout(proc.wait(), timeout)
|
|
5102
|
-
|
|
5103
|
-
|
|
5104
|
-
##
|
|
5105
|
-
|
|
5106
|
-
|
|
5107
5127
|
class AsyncioProcessCommunicator:
|
|
5108
5128
|
def __init__(
|
|
5109
5129
|
self,
|
|
@@ -5214,137 +5234,147 @@ class AsyncioProcessCommunicator:
|
|
|
5214
5234
|
return await asyncio_maybe_timeout(self._communicate(input), timeout)
|
|
5215
5235
|
|
|
5216
5236
|
|
|
5217
|
-
|
|
5218
|
-
proc: asyncio.subprocess.Process,
|
|
5219
|
-
input: ta.Any = None, # noqa
|
|
5220
|
-
timeout: ta.Optional[float] = None,
|
|
5221
|
-
) -> ta.Tuple[ta.Optional[bytes], ta.Optional[bytes]]:
|
|
5222
|
-
return await AsyncioProcessCommunicator(proc).communicate(input, timeout) # noqa
|
|
5223
|
-
|
|
5224
|
-
|
|
5225
|
-
async def asyncio_subprocess_run(
|
|
5226
|
-
*args: str,
|
|
5227
|
-
input: ta.Any = None, # noqa
|
|
5228
|
-
timeout: ta.Optional[float] = None,
|
|
5229
|
-
check: bool = False, # noqa
|
|
5230
|
-
capture_output: ta.Optional[bool] = None,
|
|
5231
|
-
**kwargs: ta.Any,
|
|
5232
|
-
) -> ta.Tuple[ta.Optional[bytes], ta.Optional[bytes]]:
|
|
5233
|
-
if capture_output:
|
|
5234
|
-
kwargs.setdefault('stdout', subprocess.PIPE)
|
|
5235
|
-
kwargs.setdefault('stderr', subprocess.PIPE)
|
|
5236
|
-
|
|
5237
|
-
args, kwargs = prepare_subprocess_invocation(*args, **kwargs)
|
|
5238
|
-
|
|
5239
|
-
proc: asyncio.subprocess.Process
|
|
5240
|
-
async with asyncio_subprocess_popen(*args, **kwargs) as proc:
|
|
5241
|
-
stdout, stderr = await asyncio_subprocess_communicate(proc, input, timeout)
|
|
5237
|
+
##
|
|
5242
5238
|
|
|
5243
|
-
if check and proc.returncode:
|
|
5244
|
-
raise subprocess.CalledProcessError(
|
|
5245
|
-
proc.returncode,
|
|
5246
|
-
args,
|
|
5247
|
-
output=stdout,
|
|
5248
|
-
stderr=stderr,
|
|
5249
|
-
)
|
|
5250
5239
|
|
|
5251
|
-
|
|
5240
|
+
class AsyncioSubprocesses(AbstractSubprocesses):
|
|
5241
|
+
async def communicate(
|
|
5242
|
+
self,
|
|
5243
|
+
proc: asyncio.subprocess.Process,
|
|
5244
|
+
input: ta.Any = None, # noqa
|
|
5245
|
+
timeout: ta.Optional[float] = None,
|
|
5246
|
+
) -> ta.Tuple[ta.Optional[bytes], ta.Optional[bytes]]:
|
|
5247
|
+
return await AsyncioProcessCommunicator(proc).communicate(input, timeout) # noqa
|
|
5252
5248
|
|
|
5249
|
+
#
|
|
5253
5250
|
|
|
5254
|
-
|
|
5251
|
+
@contextlib.asynccontextmanager
|
|
5252
|
+
async def popen(
|
|
5253
|
+
self,
|
|
5254
|
+
*cmd: str,
|
|
5255
|
+
shell: bool = False,
|
|
5256
|
+
timeout: ta.Optional[float] = None,
|
|
5257
|
+
**kwargs: ta.Any,
|
|
5258
|
+
) -> ta.AsyncGenerator[asyncio.subprocess.Process, None]:
|
|
5259
|
+
fac: ta.Any
|
|
5260
|
+
if shell:
|
|
5261
|
+
fac = functools.partial(
|
|
5262
|
+
asyncio.create_subprocess_shell,
|
|
5263
|
+
check.single(cmd),
|
|
5264
|
+
)
|
|
5265
|
+
else:
|
|
5266
|
+
fac = functools.partial(
|
|
5267
|
+
asyncio.create_subprocess_exec,
|
|
5268
|
+
*cmd,
|
|
5269
|
+
)
|
|
5255
5270
|
|
|
5271
|
+
with self.prepare_and_wrap( *cmd, shell=shell, **kwargs) as (cmd, kwargs): # noqa
|
|
5272
|
+
proc: asyncio.subprocess.Process = await fac(**kwargs)
|
|
5273
|
+
try:
|
|
5274
|
+
yield proc
|
|
5256
5275
|
|
|
5257
|
-
|
|
5258
|
-
|
|
5259
|
-
stdout: ta.Any = sys.stderr,
|
|
5260
|
-
input: ta.Any = None, # noqa
|
|
5261
|
-
timeout: ta.Optional[float] = None,
|
|
5262
|
-
**kwargs: ta.Any,
|
|
5263
|
-
) -> None:
|
|
5264
|
-
_, _ = await asyncio_subprocess_run(
|
|
5265
|
-
*args,
|
|
5266
|
-
stdout=stdout,
|
|
5267
|
-
input=input,
|
|
5268
|
-
timeout=timeout,
|
|
5269
|
-
check=True,
|
|
5270
|
-
**kwargs,
|
|
5271
|
-
)
|
|
5276
|
+
finally:
|
|
5277
|
+
await asyncio_maybe_timeout(proc.wait(), timeout)
|
|
5272
5278
|
|
|
5279
|
+
#
|
|
5273
5280
|
|
|
5274
|
-
|
|
5275
|
-
|
|
5276
|
-
|
|
5277
|
-
|
|
5278
|
-
|
|
5279
|
-
) -> bytes:
|
|
5280
|
-
stdout, stderr = await asyncio_subprocess_run(
|
|
5281
|
-
*args,
|
|
5282
|
-
stdout=asyncio.subprocess.PIPE,
|
|
5283
|
-
input=input,
|
|
5284
|
-
timeout=timeout,
|
|
5285
|
-
check=True,
|
|
5286
|
-
**kwargs,
|
|
5287
|
-
)
|
|
5281
|
+
@dc.dataclass(frozen=True)
|
|
5282
|
+
class RunOutput:
|
|
5283
|
+
proc: asyncio.subprocess.Process
|
|
5284
|
+
stdout: ta.Optional[bytes]
|
|
5285
|
+
stderr: ta.Optional[bytes]
|
|
5288
5286
|
|
|
5289
|
-
|
|
5287
|
+
async def run(
|
|
5288
|
+
self,
|
|
5289
|
+
*cmd: str,
|
|
5290
|
+
input: ta.Any = None, # noqa
|
|
5291
|
+
timeout: ta.Optional[float] = None,
|
|
5292
|
+
check: bool = False, # noqa
|
|
5293
|
+
capture_output: ta.Optional[bool] = None,
|
|
5294
|
+
**kwargs: ta.Any,
|
|
5295
|
+
) -> RunOutput:
|
|
5296
|
+
if capture_output:
|
|
5297
|
+
kwargs.setdefault('stdout', subprocess.PIPE)
|
|
5298
|
+
kwargs.setdefault('stderr', subprocess.PIPE)
|
|
5290
5299
|
|
|
5300
|
+
proc: asyncio.subprocess.Process
|
|
5301
|
+
async with self.popen(*cmd, **kwargs) as proc:
|
|
5302
|
+
stdout, stderr = await self.communicate(proc, input, timeout)
|
|
5303
|
+
|
|
5304
|
+
if check and proc.returncode:
|
|
5305
|
+
raise subprocess.CalledProcessError(
|
|
5306
|
+
proc.returncode,
|
|
5307
|
+
cmd,
|
|
5308
|
+
output=stdout,
|
|
5309
|
+
stderr=stderr,
|
|
5310
|
+
)
|
|
5291
5311
|
|
|
5292
|
-
|
|
5293
|
-
|
|
5312
|
+
return self.RunOutput(
|
|
5313
|
+
proc,
|
|
5314
|
+
stdout,
|
|
5315
|
+
stderr,
|
|
5316
|
+
)
|
|
5294
5317
|
|
|
5318
|
+
#
|
|
5295
5319
|
|
|
5296
|
-
|
|
5320
|
+
async def check_call(
|
|
5321
|
+
self,
|
|
5322
|
+
*cmd: str,
|
|
5323
|
+
stdout: ta.Any = sys.stderr,
|
|
5324
|
+
**kwargs: ta.Any,
|
|
5325
|
+
) -> None:
|
|
5326
|
+
with self.prepare_and_wrap(*cmd, stdout=stdout, check=True, **kwargs) as (cmd, kwargs): # noqa
|
|
5327
|
+
await self.run(*cmd, **kwargs)
|
|
5297
5328
|
|
|
5329
|
+
async def check_output(
|
|
5330
|
+
self,
|
|
5331
|
+
*cmd: str,
|
|
5332
|
+
**kwargs: ta.Any,
|
|
5333
|
+
) -> bytes:
|
|
5334
|
+
with self.prepare_and_wrap(*cmd, stdout=subprocess.PIPE, check=True, **kwargs) as (cmd, kwargs): # noqa
|
|
5335
|
+
return check.not_none((await self.run(*cmd, **kwargs)).stdout)
|
|
5298
5336
|
|
|
5299
|
-
async def
|
|
5300
|
-
|
|
5301
|
-
|
|
5302
|
-
|
|
5303
|
-
|
|
5304
|
-
|
|
5305
|
-
try:
|
|
5306
|
-
return await fn(*args, **kwargs)
|
|
5307
|
-
except try_exceptions as e: # noqa
|
|
5308
|
-
if log.isEnabledFor(logging.DEBUG):
|
|
5309
|
-
log.exception('command failed')
|
|
5310
|
-
return e
|
|
5337
|
+
async def check_output_str(
|
|
5338
|
+
self,
|
|
5339
|
+
*cmd: str,
|
|
5340
|
+
**kwargs: ta.Any,
|
|
5341
|
+
) -> str:
|
|
5342
|
+
return (await self.check_output(*cmd, **kwargs)).decode().strip()
|
|
5311
5343
|
|
|
5344
|
+
#
|
|
5312
5345
|
|
|
5313
|
-
async def
|
|
5314
|
-
|
|
5315
|
-
|
|
5316
|
-
|
|
5317
|
-
) -> bool:
|
|
5318
|
-
|
|
5319
|
-
|
|
5320
|
-
|
|
5321
|
-
|
|
5322
|
-
**kwargs,
|
|
5323
|
-
), Exception):
|
|
5324
|
-
return False
|
|
5325
|
-
else:
|
|
5326
|
-
return True
|
|
5346
|
+
async def try_call(
|
|
5347
|
+
self,
|
|
5348
|
+
*cmd: str,
|
|
5349
|
+
**kwargs: ta.Any,
|
|
5350
|
+
) -> bool:
|
|
5351
|
+
if isinstance(await self.async_try_fn(self.check_call, *cmd, **kwargs), Exception):
|
|
5352
|
+
return False
|
|
5353
|
+
else:
|
|
5354
|
+
return True
|
|
5327
5355
|
|
|
5356
|
+
async def try_output(
|
|
5357
|
+
self,
|
|
5358
|
+
*cmd: str,
|
|
5359
|
+
**kwargs: ta.Any,
|
|
5360
|
+
) -> ta.Optional[bytes]:
|
|
5361
|
+
if isinstance(ret := await self.async_try_fn(self.check_output, *cmd, **kwargs), Exception):
|
|
5362
|
+
return None
|
|
5363
|
+
else:
|
|
5364
|
+
return ret
|
|
5328
5365
|
|
|
5329
|
-
async def
|
|
5330
|
-
|
|
5331
|
-
|
|
5332
|
-
|
|
5333
|
-
) -> ta.Optional[
|
|
5334
|
-
|
|
5335
|
-
|
|
5336
|
-
|
|
5337
|
-
|
|
5338
|
-
**kwargs,
|
|
5339
|
-
), Exception):
|
|
5340
|
-
return None
|
|
5341
|
-
else:
|
|
5342
|
-
return ret
|
|
5366
|
+
async def try_output_str(
|
|
5367
|
+
self,
|
|
5368
|
+
*cmd: str,
|
|
5369
|
+
**kwargs: ta.Any,
|
|
5370
|
+
) -> ta.Optional[str]:
|
|
5371
|
+
if (ret := await self.try_output(*cmd, **kwargs)) is None:
|
|
5372
|
+
return None
|
|
5373
|
+
else:
|
|
5374
|
+
return ret.decode().strip()
|
|
5343
5375
|
|
|
5344
5376
|
|
|
5345
|
-
|
|
5346
|
-
out = await asyncio_subprocess_try_output(*args, **kwargs)
|
|
5347
|
-
return out.decode().strip() if out is not None else None
|
|
5377
|
+
asyncio_subprocesses = AsyncioSubprocesses()
|
|
5348
5378
|
|
|
5349
5379
|
|
|
5350
5380
|
########################################
|
|
@@ -5421,7 +5451,7 @@ class InterpInspector:
|
|
|
5421
5451
|
return cls._build_inspection(sys.executable, eval(cls._INSPECTION_CODE)) # noqa
|
|
5422
5452
|
|
|
5423
5453
|
async def _inspect(self, exe: str) -> InterpInspection:
|
|
5424
|
-
output = await
|
|
5454
|
+
output = await asyncio_subprocesses.check_output(exe, '-c', f'print({self._INSPECTION_CODE})', quiet=True)
|
|
5425
5455
|
return self._build_inspection(exe, output.decode())
|
|
5426
5456
|
|
|
5427
5457
|
async def inspect(self, exe: str) -> ta.Optional[InterpInspection]:
|
|
@@ -5822,7 +5852,7 @@ class BasePyprojectPackageGenerator(abc.ABC):
|
|
|
5822
5852
|
output_dir: ta.Optional[str] = None,
|
|
5823
5853
|
opts: BuildOpts = BuildOpts(),
|
|
5824
5854
|
) -> None:
|
|
5825
|
-
|
|
5855
|
+
subprocesses.check_call(
|
|
5826
5856
|
sys.executable,
|
|
5827
5857
|
'-m',
|
|
5828
5858
|
'build',
|
|
@@ -5838,14 +5868,14 @@ class BasePyprojectPackageGenerator(abc.ABC):
|
|
|
5838
5868
|
for fn in os.listdir(dist_dir):
|
|
5839
5869
|
tmp_dir = tempfile.mkdtemp()
|
|
5840
5870
|
|
|
5841
|
-
|
|
5871
|
+
subprocesses.check_call(
|
|
5842
5872
|
sys.executable,
|
|
5843
5873
|
'-m', 'venv',
|
|
5844
5874
|
'test-install',
|
|
5845
5875
|
cwd=tmp_dir,
|
|
5846
5876
|
)
|
|
5847
5877
|
|
|
5848
|
-
|
|
5878
|
+
subprocesses.check_call(
|
|
5849
5879
|
os.path.join(tmp_dir, 'test-install', 'bin', 'python3'),
|
|
5850
5880
|
'-m', 'pip',
|
|
5851
5881
|
'install',
|
|
@@ -6218,7 +6248,7 @@ class Pyenv:
|
|
|
6218
6248
|
return self._root_kw
|
|
6219
6249
|
|
|
6220
6250
|
if shutil.which('pyenv'):
|
|
6221
|
-
return await
|
|
6251
|
+
return await asyncio_subprocesses.check_output_str('pyenv', 'root')
|
|
6222
6252
|
|
|
6223
6253
|
d = os.path.expanduser('~/.pyenv')
|
|
6224
6254
|
if os.path.isdir(d) and os.path.isfile(os.path.join(d, 'bin', 'pyenv')):
|
|
@@ -6247,7 +6277,7 @@ class Pyenv:
|
|
|
6247
6277
|
if await self.root() is None:
|
|
6248
6278
|
return []
|
|
6249
6279
|
ret = []
|
|
6250
|
-
s = await
|
|
6280
|
+
s = await asyncio_subprocesses.check_output_str(await self.exe(), 'install', '--list')
|
|
6251
6281
|
for l in s.splitlines():
|
|
6252
6282
|
if not l.startswith(' '):
|
|
6253
6283
|
continue
|
|
@@ -6262,7 +6292,7 @@ class Pyenv:
|
|
|
6262
6292
|
return False
|
|
6263
6293
|
if not os.path.isdir(os.path.join(root, '.git')):
|
|
6264
6294
|
return False
|
|
6265
|
-
await
|
|
6295
|
+
await asyncio_subprocesses.check_call('git', 'pull', cwd=root)
|
|
6266
6296
|
return True
|
|
6267
6297
|
|
|
6268
6298
|
|
|
@@ -6353,7 +6383,7 @@ class DarwinPyenvInstallOpts(PyenvInstallOptsProvider):
|
|
|
6353
6383
|
cflags = []
|
|
6354
6384
|
ldflags = []
|
|
6355
6385
|
for dep in self.BREW_DEPS:
|
|
6356
|
-
dep_prefix = await
|
|
6386
|
+
dep_prefix = await asyncio_subprocesses.check_output_str('brew', '--prefix', dep)
|
|
6357
6387
|
cflags.append(f'-I{dep_prefix}/include')
|
|
6358
6388
|
ldflags.append(f'-L{dep_prefix}/lib')
|
|
6359
6389
|
return PyenvInstallOpts(
|
|
@@ -6363,11 +6393,11 @@ class DarwinPyenvInstallOpts(PyenvInstallOptsProvider):
|
|
|
6363
6393
|
|
|
6364
6394
|
@async_cached_nullary
|
|
6365
6395
|
async def brew_tcl_opts(self) -> PyenvInstallOpts:
|
|
6366
|
-
if await
|
|
6396
|
+
if await asyncio_subprocesses.try_output('brew', '--prefix', 'tcl-tk') is None:
|
|
6367
6397
|
return PyenvInstallOpts()
|
|
6368
6398
|
|
|
6369
|
-
tcl_tk_prefix = await
|
|
6370
|
-
tcl_tk_ver_str = await
|
|
6399
|
+
tcl_tk_prefix = await asyncio_subprocesses.check_output_str('brew', '--prefix', 'tcl-tk')
|
|
6400
|
+
tcl_tk_ver_str = await asyncio_subprocesses.check_output_str('brew', 'ls', '--versions', 'tcl-tk')
|
|
6371
6401
|
tcl_tk_ver = '.'.join(tcl_tk_ver_str.split()[1].split('.')[:2])
|
|
6372
6402
|
|
|
6373
6403
|
return PyenvInstallOpts(conf_opts=[
|
|
@@ -6488,7 +6518,7 @@ class PyenvVersionInstaller:
|
|
|
6488
6518
|
*conf_args,
|
|
6489
6519
|
]
|
|
6490
6520
|
|
|
6491
|
-
await
|
|
6521
|
+
await asyncio_subprocesses.check_call(
|
|
6492
6522
|
*full_args,
|
|
6493
6523
|
env=env,
|
|
6494
6524
|
)
|
|
@@ -6883,12 +6913,12 @@ class Venv:
|
|
|
6883
6913
|
return False
|
|
6884
6914
|
|
|
6885
6915
|
log.info('Using interpreter %s', (ie := await self.interp_exe()))
|
|
6886
|
-
await
|
|
6916
|
+
await asyncio_subprocesses.check_call(ie, '-m', 'venv', dn)
|
|
6887
6917
|
|
|
6888
6918
|
ve = self.exe()
|
|
6889
6919
|
uv = self._cfg.use_uv
|
|
6890
6920
|
|
|
6891
|
-
await
|
|
6921
|
+
await asyncio_subprocesses.check_call(
|
|
6892
6922
|
ve,
|
|
6893
6923
|
'-m', 'pip',
|
|
6894
6924
|
'install', '-v', '--upgrade',
|
|
@@ -6906,7 +6936,7 @@ class Venv:
|
|
|
6906
6936
|
# Caused by: Failed to download distribution due to network timeout. Try increasing UV_HTTP_TIMEOUT (current value: 30s). # noqa
|
|
6907
6937
|
# UV_CONCURRENT_DOWNLOADS=4 UV_HTTP_TIMEOUT=3600
|
|
6908
6938
|
|
|
6909
|
-
await
|
|
6939
|
+
await asyncio_subprocesses.check_call(
|
|
6910
6940
|
ve,
|
|
6911
6941
|
'-m',
|
|
6912
6942
|
*(['uv'] if uv else []),
|
|
@@ -7060,7 +7090,7 @@ class PyprojectCli(ArgparseCli):
|
|
|
7060
7090
|
else:
|
|
7061
7091
|
docker_env[e] = os.environ.get(e, '')
|
|
7062
7092
|
|
|
7063
|
-
await
|
|
7093
|
+
await asyncio_subprocesses.check_call(
|
|
7064
7094
|
'docker',
|
|
7065
7095
|
'compose',
|
|
7066
7096
|
'-f', 'docker/compose.yml',
|
|
@@ -7111,7 +7141,7 @@ class PyprojectCli(ArgparseCli):
|
|
|
7111
7141
|
|
|
7112
7142
|
elif cmd == 'test':
|
|
7113
7143
|
await venv.create()
|
|
7114
|
-
await
|
|
7144
|
+
await asyncio_subprocesses.check_call(venv.exe(), '-m', 'pytest', *(self.args.args or []), *venv.srcs())
|
|
7115
7145
|
|
|
7116
7146
|
else:
|
|
7117
7147
|
raise Exception(f'unknown subcommand: {cmd}')
|