omdev 0.0.0.dev155__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/interp/inspect.py +2 -2
- omdev/interp/pyenv.py +9 -11
- omdev/pyproject/cli.py +3 -3
- omdev/pyproject/pkg.py +4 -4
- omdev/pyproject/venvs.py +4 -4
- omdev/scripts/interp.py +306 -290
- omdev/scripts/pyproject.py +312 -296
- {omdev-0.0.0.dev155.dist-info → omdev-0.0.0.dev156.dist-info}/METADATA +2 -2
- {omdev-0.0.0.dev155.dist-info → omdev-0.0.0.dev156.dist-info}/RECORD +13 -13
- {omdev-0.0.0.dev155.dist-info → omdev-0.0.0.dev156.dist-info}/LICENSE +0 -0
- {omdev-0.0.0.dev155.dist-info → omdev-0.0.0.dev156.dist-info}/WHEEL +0 -0
- {omdev-0.0.0.dev155.dist-info → omdev-0.0.0.dev156.dist-info}/entry_points.txt +0 -0
- {omdev-0.0.0.dev155.dist-info → omdev-0.0.0.dev156.dist-info}/top_level.txt +0 -0
omdev/scripts/pyproject.py
CHANGED
|
@@ -4498,168 +4498,222 @@ SUBPROCESS_CHANNEL_OPTION_VALUES: ta.Mapping[SubprocessChannelOption, int] = {
|
|
|
4498
4498
|
_SUBPROCESS_SHELL_WRAP_EXECS = False
|
|
4499
4499
|
|
|
4500
4500
|
|
|
4501
|
-
def subprocess_shell_wrap_exec(*
|
|
4502
|
-
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)))
|
|
4503
4503
|
|
|
4504
4504
|
|
|
4505
|
-
def subprocess_maybe_shell_wrap_exec(*
|
|
4505
|
+
def subprocess_maybe_shell_wrap_exec(*cmd: str) -> ta.Tuple[str, ...]:
|
|
4506
4506
|
if _SUBPROCESS_SHELL_WRAP_EXECS or is_debugger_attached():
|
|
4507
|
-
return subprocess_shell_wrap_exec(*
|
|
4507
|
+
return subprocess_shell_wrap_exec(*cmd)
|
|
4508
4508
|
else:
|
|
4509
|
-
return
|
|
4509
|
+
return cmd
|
|
4510
4510
|
|
|
4511
4511
|
|
|
4512
|
-
|
|
4513
|
-
*args: str,
|
|
4514
|
-
env: ta.Optional[ta.Mapping[str, ta.Any]] = None,
|
|
4515
|
-
extra_env: ta.Optional[ta.Mapping[str, ta.Any]] = None,
|
|
4516
|
-
quiet: bool = False,
|
|
4517
|
-
shell: bool = False,
|
|
4518
|
-
**kwargs: ta.Any,
|
|
4519
|
-
) -> ta.Tuple[ta.Tuple[ta.Any, ...], ta.Dict[str, ta.Any]]:
|
|
4520
|
-
log.debug('prepare_subprocess_invocation: args=%r', args)
|
|
4521
|
-
if extra_env:
|
|
4522
|
-
log.debug('prepare_subprocess_invocation: extra_env=%r', extra_env)
|
|
4523
|
-
|
|
4524
|
-
if extra_env:
|
|
4525
|
-
env = {**(env if env is not None else os.environ), **extra_env}
|
|
4512
|
+
##
|
|
4526
4513
|
|
|
4527
|
-
if quiet and 'stderr' not in kwargs:
|
|
4528
|
-
if not log.isEnabledFor(logging.DEBUG):
|
|
4529
|
-
kwargs['stderr'] = subprocess.DEVNULL
|
|
4530
4514
|
|
|
4531
|
-
|
|
4532
|
-
|
|
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()
|
|
4533
4526
|
|
|
4534
|
-
|
|
4535
|
-
env=env,
|
|
4536
|
-
shell=shell,
|
|
4537
|
-
**kwargs,
|
|
4538
|
-
)
|
|
4527
|
+
proc.wait(timeout)
|
|
4539
4528
|
|
|
4540
4529
|
|
|
4541
4530
|
##
|
|
4542
4531
|
|
|
4543
4532
|
|
|
4544
|
-
|
|
4545
|
-
|
|
4546
|
-
start_time = time.time()
|
|
4547
|
-
try:
|
|
4548
|
-
log.debug('subprocess_common_context.try: args=%r', args)
|
|
4549
|
-
yield
|
|
4533
|
+
class AbstractSubprocesses(abc.ABC): # noqa
|
|
4534
|
+
DEFAULT_LOGGER: ta.ClassVar[ta.Optional[logging.Logger]] = log
|
|
4550
4535
|
|
|
4551
|
-
|
|
4552
|
-
|
|
4553
|
-
|
|
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__()
|
|
4554
4543
|
|
|
4555
|
-
|
|
4556
|
-
|
|
4557
|
-
elapsed_s = end_time - start_time
|
|
4558
|
-
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
|
|
4559
4546
|
|
|
4547
|
+
#
|
|
4560
4548
|
|
|
4561
|
-
|
|
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)
|
|
4562
4562
|
|
|
4563
|
+
if extra_env:
|
|
4564
|
+
env = {**(env if env is not None else os.environ), **extra_env}
|
|
4563
4565
|
|
|
4564
|
-
|
|
4565
|
-
|
|
4566
|
-
|
|
4567
|
-
**kwargs: ta.Any,
|
|
4568
|
-
) -> None:
|
|
4569
|
-
args, kwargs = prepare_subprocess_invocation(*args, stdout=stdout, **kwargs)
|
|
4570
|
-
with subprocess_common_context(*args, **kwargs):
|
|
4571
|
-
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
|
|
4572
4569
|
|
|
4570
|
+
if not shell:
|
|
4571
|
+
cmd = subprocess_maybe_shell_wrap_exec(*cmd)
|
|
4573
4572
|
|
|
4574
|
-
|
|
4575
|
-
|
|
4576
|
-
|
|
4577
|
-
|
|
4578
|
-
|
|
4579
|
-
with subprocess_common_context(*args, **kwargs):
|
|
4580
|
-
return subprocess.check_output(args, **kwargs)
|
|
4573
|
+
return cmd, dict(
|
|
4574
|
+
env=env,
|
|
4575
|
+
shell=shell,
|
|
4576
|
+
**kwargs,
|
|
4577
|
+
)
|
|
4581
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
|
|
4582
4586
|
|
|
4583
|
-
|
|
4584
|
-
|
|
4587
|
+
except Exception as exc: # noqa
|
|
4588
|
+
if self._log:
|
|
4589
|
+
self._log.debug('Subprocesses.wrap_call.except: exc=%r', exc)
|
|
4590
|
+
raise
|
|
4585
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)
|
|
4586
4597
|
|
|
4587
|
-
|
|
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
|
|
4588
4610
|
|
|
4611
|
+
#
|
|
4589
4612
|
|
|
4590
|
-
|
|
4591
|
-
|
|
4592
|
-
|
|
4593
|
-
)
|
|
4613
|
+
DEFAULT_TRY_EXCEPTIONS: ta.Tuple[ta.Type[Exception], ...] = (
|
|
4614
|
+
FileNotFoundError,
|
|
4615
|
+
subprocess.CalledProcessError,
|
|
4616
|
+
)
|
|
4594
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
|
|
4595
4627
|
|
|
4596
|
-
|
|
4597
|
-
|
|
4598
|
-
*args: ta.Any,
|
|
4599
|
-
try_exceptions: ta.Tuple[ta.Type[Exception], ...] = DEFAULT_SUBPROCESS_TRY_EXCEPTIONS,
|
|
4600
|
-
**kwargs: ta.Any,
|
|
4601
|
-
) -> ta.Union[T, Exception]:
|
|
4602
|
-
try:
|
|
4603
|
-
return fn(*args, **kwargs)
|
|
4604
|
-
except try_exceptions as e: # noqa
|
|
4605
|
-
if log.isEnabledFor(logging.DEBUG):
|
|
4606
|
-
log.exception('command failed')
|
|
4607
|
-
return e
|
|
4628
|
+
try:
|
|
4629
|
+
return fn(*cmd, **kwargs)
|
|
4608
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
|
|
4609
4635
|
|
|
4610
|
-
def
|
|
4611
|
-
|
|
4612
|
-
|
|
4613
|
-
|
|
4614
|
-
|
|
4615
|
-
|
|
4616
|
-
|
|
4617
|
-
|
|
4618
|
-
try_exceptions=
|
|
4619
|
-
**kwargs,
|
|
4620
|
-
), Exception):
|
|
4621
|
-
return False
|
|
4622
|
-
else:
|
|
4623
|
-
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
|
|
4624
4645
|
|
|
4646
|
+
try:
|
|
4647
|
+
return await fn(*cmd, **kwargs)
|
|
4625
4648
|
|
|
4626
|
-
|
|
4627
|
-
|
|
4628
|
-
|
|
4629
|
-
|
|
4630
|
-
) -> ta.Optional[bytes]:
|
|
4631
|
-
if isinstance(ret := _subprocess_try_run(
|
|
4632
|
-
subprocess_check_output,
|
|
4633
|
-
*args,
|
|
4634
|
-
try_exceptions=try_exceptions,
|
|
4635
|
-
**kwargs,
|
|
4636
|
-
), Exception):
|
|
4637
|
-
return None
|
|
4638
|
-
else:
|
|
4639
|
-
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
|
|
4640
4653
|
|
|
4641
4654
|
|
|
4642
|
-
|
|
4643
|
-
out = subprocess_try_output(*args, **kwargs)
|
|
4644
|
-
return out.decode().strip() if out is not None else None
|
|
4655
|
+
##
|
|
4645
4656
|
|
|
4646
4657
|
|
|
4647
|
-
|
|
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)
|
|
4648
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)
|
|
4649
4675
|
|
|
4650
|
-
def
|
|
4651
|
-
|
|
4652
|
-
|
|
4653
|
-
|
|
4654
|
-
|
|
4655
|
-
|
|
4656
|
-
proc.stdout.close()
|
|
4657
|
-
if proc.stderr:
|
|
4658
|
-
proc.stderr.close()
|
|
4659
|
-
if proc.stdin:
|
|
4660
|
-
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()
|
|
4661
4682
|
|
|
4662
|
-
|
|
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()
|
|
4663
4717
|
|
|
4664
4718
|
|
|
4665
4719
|
########################################
|
|
@@ -5070,43 +5124,6 @@ def get_git_status(
|
|
|
5070
5124
|
##
|
|
5071
5125
|
|
|
5072
5126
|
|
|
5073
|
-
@contextlib.asynccontextmanager
|
|
5074
|
-
async def asyncio_subprocess_popen(
|
|
5075
|
-
*cmd: str,
|
|
5076
|
-
shell: bool = False,
|
|
5077
|
-
timeout: ta.Optional[float] = None,
|
|
5078
|
-
**kwargs: ta.Any,
|
|
5079
|
-
) -> ta.AsyncGenerator[asyncio.subprocess.Process, None]:
|
|
5080
|
-
fac: ta.Any
|
|
5081
|
-
if shell:
|
|
5082
|
-
fac = functools.partial(
|
|
5083
|
-
asyncio.create_subprocess_shell,
|
|
5084
|
-
check.single(cmd),
|
|
5085
|
-
)
|
|
5086
|
-
else:
|
|
5087
|
-
fac = functools.partial(
|
|
5088
|
-
asyncio.create_subprocess_exec,
|
|
5089
|
-
*cmd,
|
|
5090
|
-
)
|
|
5091
|
-
|
|
5092
|
-
with subprocess_common_context(
|
|
5093
|
-
*cmd,
|
|
5094
|
-
shell=shell,
|
|
5095
|
-
timeout=timeout,
|
|
5096
|
-
**kwargs,
|
|
5097
|
-
):
|
|
5098
|
-
proc: asyncio.subprocess.Process
|
|
5099
|
-
proc = await fac(**kwargs)
|
|
5100
|
-
try:
|
|
5101
|
-
yield proc
|
|
5102
|
-
|
|
5103
|
-
finally:
|
|
5104
|
-
await asyncio_maybe_timeout(proc.wait(), timeout)
|
|
5105
|
-
|
|
5106
|
-
|
|
5107
|
-
##
|
|
5108
|
-
|
|
5109
|
-
|
|
5110
5127
|
class AsyncioProcessCommunicator:
|
|
5111
5128
|
def __init__(
|
|
5112
5129
|
self,
|
|
@@ -5217,148 +5234,147 @@ class AsyncioProcessCommunicator:
|
|
|
5217
5234
|
return await asyncio_maybe_timeout(self._communicate(input), timeout)
|
|
5218
5235
|
|
|
5219
5236
|
|
|
5220
|
-
|
|
5221
|
-
proc: asyncio.subprocess.Process,
|
|
5222
|
-
input: ta.Any = None, # noqa
|
|
5223
|
-
timeout: ta.Optional[float] = None,
|
|
5224
|
-
) -> ta.Tuple[ta.Optional[bytes], ta.Optional[bytes]]:
|
|
5225
|
-
return await AsyncioProcessCommunicator(proc).communicate(input, timeout) # noqa
|
|
5226
|
-
|
|
5227
|
-
|
|
5228
|
-
@dc.dataclass(frozen=True)
|
|
5229
|
-
class AsyncioSubprocessOutput:
|
|
5230
|
-
proc: asyncio.subprocess.Process
|
|
5231
|
-
stdout: ta.Optional[bytes]
|
|
5232
|
-
stderr: ta.Optional[bytes]
|
|
5233
|
-
|
|
5234
|
-
|
|
5235
|
-
async def asyncio_subprocess_run(
|
|
5236
|
-
*args: str,
|
|
5237
|
-
input: ta.Any = None, # noqa
|
|
5238
|
-
timeout: ta.Optional[float] = None,
|
|
5239
|
-
check: bool = False, # noqa
|
|
5240
|
-
capture_output: ta.Optional[bool] = None,
|
|
5241
|
-
**kwargs: ta.Any,
|
|
5242
|
-
) -> AsyncioSubprocessOutput:
|
|
5243
|
-
if capture_output:
|
|
5244
|
-
kwargs.setdefault('stdout', subprocess.PIPE)
|
|
5245
|
-
kwargs.setdefault('stderr', subprocess.PIPE)
|
|
5246
|
-
|
|
5247
|
-
args, kwargs = prepare_subprocess_invocation(*args, **kwargs)
|
|
5248
|
-
|
|
5249
|
-
proc: asyncio.subprocess.Process
|
|
5250
|
-
async with asyncio_subprocess_popen(*args, **kwargs) as proc:
|
|
5251
|
-
stdout, stderr = await asyncio_subprocess_communicate(proc, input, timeout)
|
|
5237
|
+
##
|
|
5252
5238
|
|
|
5253
|
-
if check and proc.returncode:
|
|
5254
|
-
raise subprocess.CalledProcessError(
|
|
5255
|
-
proc.returncode,
|
|
5256
|
-
args,
|
|
5257
|
-
output=stdout,
|
|
5258
|
-
stderr=stderr,
|
|
5259
|
-
)
|
|
5260
5239
|
|
|
5261
|
-
|
|
5262
|
-
|
|
5263
|
-
|
|
5264
|
-
|
|
5265
|
-
|
|
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
|
|
5266
5248
|
|
|
5249
|
+
#
|
|
5267
5250
|
|
|
5268
|
-
|
|
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
|
+
)
|
|
5269
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
|
|
5270
5275
|
|
|
5271
|
-
|
|
5272
|
-
|
|
5273
|
-
stdout: ta.Any = sys.stderr,
|
|
5274
|
-
input: ta.Any = None, # noqa
|
|
5275
|
-
timeout: ta.Optional[float] = None,
|
|
5276
|
-
**kwargs: ta.Any,
|
|
5277
|
-
) -> None:
|
|
5278
|
-
await asyncio_subprocess_run(
|
|
5279
|
-
*args,
|
|
5280
|
-
stdout=stdout,
|
|
5281
|
-
input=input,
|
|
5282
|
-
timeout=timeout,
|
|
5283
|
-
check=True,
|
|
5284
|
-
**kwargs,
|
|
5285
|
-
)
|
|
5276
|
+
finally:
|
|
5277
|
+
await asyncio_maybe_timeout(proc.wait(), timeout)
|
|
5286
5278
|
|
|
5279
|
+
#
|
|
5287
5280
|
|
|
5288
|
-
|
|
5289
|
-
|
|
5290
|
-
|
|
5291
|
-
|
|
5292
|
-
|
|
5293
|
-
) -> bytes:
|
|
5294
|
-
out = await asyncio_subprocess_run(
|
|
5295
|
-
*args,
|
|
5296
|
-
stdout=asyncio.subprocess.PIPE,
|
|
5297
|
-
input=input,
|
|
5298
|
-
timeout=timeout,
|
|
5299
|
-
check=True,
|
|
5300
|
-
**kwargs,
|
|
5301
|
-
)
|
|
5281
|
+
@dc.dataclass(frozen=True)
|
|
5282
|
+
class RunOutput:
|
|
5283
|
+
proc: asyncio.subprocess.Process
|
|
5284
|
+
stdout: ta.Optional[bytes]
|
|
5285
|
+
stderr: ta.Optional[bytes]
|
|
5302
5286
|
|
|
5303
|
-
|
|
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)
|
|
5304
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
|
+
)
|
|
5305
5311
|
|
|
5306
|
-
|
|
5307
|
-
|
|
5312
|
+
return self.RunOutput(
|
|
5313
|
+
proc,
|
|
5314
|
+
stdout,
|
|
5315
|
+
stderr,
|
|
5316
|
+
)
|
|
5308
5317
|
|
|
5318
|
+
#
|
|
5309
5319
|
|
|
5310
|
-
|
|
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)
|
|
5311
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)
|
|
5312
5336
|
|
|
5313
|
-
async def
|
|
5314
|
-
|
|
5315
|
-
|
|
5316
|
-
|
|
5317
|
-
|
|
5318
|
-
|
|
5319
|
-
try:
|
|
5320
|
-
return await fn(*args, **kwargs)
|
|
5321
|
-
except try_exceptions as e: # noqa
|
|
5322
|
-
if log.isEnabledFor(logging.DEBUG):
|
|
5323
|
-
log.exception('command failed')
|
|
5324
|
-
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()
|
|
5325
5343
|
|
|
5344
|
+
#
|
|
5326
5345
|
|
|
5327
|
-
async def
|
|
5328
|
-
|
|
5329
|
-
|
|
5330
|
-
|
|
5331
|
-
) -> bool:
|
|
5332
|
-
|
|
5333
|
-
|
|
5334
|
-
|
|
5335
|
-
|
|
5336
|
-
**kwargs,
|
|
5337
|
-
), Exception):
|
|
5338
|
-
return False
|
|
5339
|
-
else:
|
|
5340
|
-
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
|
|
5341
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
|
|
5342
5365
|
|
|
5343
|
-
async def
|
|
5344
|
-
|
|
5345
|
-
|
|
5346
|
-
|
|
5347
|
-
) -> ta.Optional[
|
|
5348
|
-
|
|
5349
|
-
|
|
5350
|
-
|
|
5351
|
-
|
|
5352
|
-
**kwargs,
|
|
5353
|
-
), Exception):
|
|
5354
|
-
return None
|
|
5355
|
-
else:
|
|
5356
|
-
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()
|
|
5357
5375
|
|
|
5358
5376
|
|
|
5359
|
-
|
|
5360
|
-
out = await asyncio_subprocess_try_output(*args, **kwargs)
|
|
5361
|
-
return out.decode().strip() if out is not None else None
|
|
5377
|
+
asyncio_subprocesses = AsyncioSubprocesses()
|
|
5362
5378
|
|
|
5363
5379
|
|
|
5364
5380
|
########################################
|
|
@@ -5435,7 +5451,7 @@ class InterpInspector:
|
|
|
5435
5451
|
return cls._build_inspection(sys.executable, eval(cls._INSPECTION_CODE)) # noqa
|
|
5436
5452
|
|
|
5437
5453
|
async def _inspect(self, exe: str) -> InterpInspection:
|
|
5438
|
-
output = await
|
|
5454
|
+
output = await asyncio_subprocesses.check_output(exe, '-c', f'print({self._INSPECTION_CODE})', quiet=True)
|
|
5439
5455
|
return self._build_inspection(exe, output.decode())
|
|
5440
5456
|
|
|
5441
5457
|
async def inspect(self, exe: str) -> ta.Optional[InterpInspection]:
|
|
@@ -5836,7 +5852,7 @@ class BasePyprojectPackageGenerator(abc.ABC):
|
|
|
5836
5852
|
output_dir: ta.Optional[str] = None,
|
|
5837
5853
|
opts: BuildOpts = BuildOpts(),
|
|
5838
5854
|
) -> None:
|
|
5839
|
-
|
|
5855
|
+
subprocesses.check_call(
|
|
5840
5856
|
sys.executable,
|
|
5841
5857
|
'-m',
|
|
5842
5858
|
'build',
|
|
@@ -5852,14 +5868,14 @@ class BasePyprojectPackageGenerator(abc.ABC):
|
|
|
5852
5868
|
for fn in os.listdir(dist_dir):
|
|
5853
5869
|
tmp_dir = tempfile.mkdtemp()
|
|
5854
5870
|
|
|
5855
|
-
|
|
5871
|
+
subprocesses.check_call(
|
|
5856
5872
|
sys.executable,
|
|
5857
5873
|
'-m', 'venv',
|
|
5858
5874
|
'test-install',
|
|
5859
5875
|
cwd=tmp_dir,
|
|
5860
5876
|
)
|
|
5861
5877
|
|
|
5862
|
-
|
|
5878
|
+
subprocesses.check_call(
|
|
5863
5879
|
os.path.join(tmp_dir, 'test-install', 'bin', 'python3'),
|
|
5864
5880
|
'-m', 'pip',
|
|
5865
5881
|
'install',
|
|
@@ -6232,7 +6248,7 @@ class Pyenv:
|
|
|
6232
6248
|
return self._root_kw
|
|
6233
6249
|
|
|
6234
6250
|
if shutil.which('pyenv'):
|
|
6235
|
-
return await
|
|
6251
|
+
return await asyncio_subprocesses.check_output_str('pyenv', 'root')
|
|
6236
6252
|
|
|
6237
6253
|
d = os.path.expanduser('~/.pyenv')
|
|
6238
6254
|
if os.path.isdir(d) and os.path.isfile(os.path.join(d, 'bin', 'pyenv')):
|
|
@@ -6261,7 +6277,7 @@ class Pyenv:
|
|
|
6261
6277
|
if await self.root() is None:
|
|
6262
6278
|
return []
|
|
6263
6279
|
ret = []
|
|
6264
|
-
s = await
|
|
6280
|
+
s = await asyncio_subprocesses.check_output_str(await self.exe(), 'install', '--list')
|
|
6265
6281
|
for l in s.splitlines():
|
|
6266
6282
|
if not l.startswith(' '):
|
|
6267
6283
|
continue
|
|
@@ -6276,7 +6292,7 @@ class Pyenv:
|
|
|
6276
6292
|
return False
|
|
6277
6293
|
if not os.path.isdir(os.path.join(root, '.git')):
|
|
6278
6294
|
return False
|
|
6279
|
-
await
|
|
6295
|
+
await asyncio_subprocesses.check_call('git', 'pull', cwd=root)
|
|
6280
6296
|
return True
|
|
6281
6297
|
|
|
6282
6298
|
|
|
@@ -6367,7 +6383,7 @@ class DarwinPyenvInstallOpts(PyenvInstallOptsProvider):
|
|
|
6367
6383
|
cflags = []
|
|
6368
6384
|
ldflags = []
|
|
6369
6385
|
for dep in self.BREW_DEPS:
|
|
6370
|
-
dep_prefix = await
|
|
6386
|
+
dep_prefix = await asyncio_subprocesses.check_output_str('brew', '--prefix', dep)
|
|
6371
6387
|
cflags.append(f'-I{dep_prefix}/include')
|
|
6372
6388
|
ldflags.append(f'-L{dep_prefix}/lib')
|
|
6373
6389
|
return PyenvInstallOpts(
|
|
@@ -6377,11 +6393,11 @@ class DarwinPyenvInstallOpts(PyenvInstallOptsProvider):
|
|
|
6377
6393
|
|
|
6378
6394
|
@async_cached_nullary
|
|
6379
6395
|
async def brew_tcl_opts(self) -> PyenvInstallOpts:
|
|
6380
|
-
if await
|
|
6396
|
+
if await asyncio_subprocesses.try_output('brew', '--prefix', 'tcl-tk') is None:
|
|
6381
6397
|
return PyenvInstallOpts()
|
|
6382
6398
|
|
|
6383
|
-
tcl_tk_prefix = await
|
|
6384
|
-
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')
|
|
6385
6401
|
tcl_tk_ver = '.'.join(tcl_tk_ver_str.split()[1].split('.')[:2])
|
|
6386
6402
|
|
|
6387
6403
|
return PyenvInstallOpts(conf_opts=[
|
|
@@ -6502,7 +6518,7 @@ class PyenvVersionInstaller:
|
|
|
6502
6518
|
*conf_args,
|
|
6503
6519
|
]
|
|
6504
6520
|
|
|
6505
|
-
await
|
|
6521
|
+
await asyncio_subprocesses.check_call(
|
|
6506
6522
|
*full_args,
|
|
6507
6523
|
env=env,
|
|
6508
6524
|
)
|
|
@@ -6897,12 +6913,12 @@ class Venv:
|
|
|
6897
6913
|
return False
|
|
6898
6914
|
|
|
6899
6915
|
log.info('Using interpreter %s', (ie := await self.interp_exe()))
|
|
6900
|
-
await
|
|
6916
|
+
await asyncio_subprocesses.check_call(ie, '-m', 'venv', dn)
|
|
6901
6917
|
|
|
6902
6918
|
ve = self.exe()
|
|
6903
6919
|
uv = self._cfg.use_uv
|
|
6904
6920
|
|
|
6905
|
-
await
|
|
6921
|
+
await asyncio_subprocesses.check_call(
|
|
6906
6922
|
ve,
|
|
6907
6923
|
'-m', 'pip',
|
|
6908
6924
|
'install', '-v', '--upgrade',
|
|
@@ -6920,7 +6936,7 @@ class Venv:
|
|
|
6920
6936
|
# Caused by: Failed to download distribution due to network timeout. Try increasing UV_HTTP_TIMEOUT (current value: 30s). # noqa
|
|
6921
6937
|
# UV_CONCURRENT_DOWNLOADS=4 UV_HTTP_TIMEOUT=3600
|
|
6922
6938
|
|
|
6923
|
-
await
|
|
6939
|
+
await asyncio_subprocesses.check_call(
|
|
6924
6940
|
ve,
|
|
6925
6941
|
'-m',
|
|
6926
6942
|
*(['uv'] if uv else []),
|
|
@@ -7074,7 +7090,7 @@ class PyprojectCli(ArgparseCli):
|
|
|
7074
7090
|
else:
|
|
7075
7091
|
docker_env[e] = os.environ.get(e, '')
|
|
7076
7092
|
|
|
7077
|
-
await
|
|
7093
|
+
await asyncio_subprocesses.check_call(
|
|
7078
7094
|
'docker',
|
|
7079
7095
|
'compose',
|
|
7080
7096
|
'-f', 'docker/compose.yml',
|
|
@@ -7125,7 +7141,7 @@ class PyprojectCli(ArgparseCli):
|
|
|
7125
7141
|
|
|
7126
7142
|
elif cmd == 'test':
|
|
7127
7143
|
await venv.create()
|
|
7128
|
-
await
|
|
7144
|
+
await asyncio_subprocesses.check_call(venv.exe(), '-m', 'pytest', *(self.args.args or []), *venv.srcs())
|
|
7129
7145
|
|
|
7130
7146
|
else:
|
|
7131
7147
|
raise Exception(f'unknown subcommand: {cmd}')
|