omdev 0.0.0.dev155__py3-none-any.whl → 0.0.0.dev157__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.
- omdev/interp/inspect.py +2 -2
- omdev/interp/pyenv.py +10 -11
- omdev/pyproject/cli.py +3 -3
- omdev/pyproject/pkg.py +4 -4
- omdev/pyproject/venvs.py +4 -4
- omdev/scripts/interp.py +309 -292
- omdev/scripts/pyproject.py +318 -298
- {omdev-0.0.0.dev155.dist-info → omdev-0.0.0.dev157.dist-info}/METADATA +2 -2
- {omdev-0.0.0.dev155.dist-info → omdev-0.0.0.dev157.dist-info}/RECORD +13 -13
- {omdev-0.0.0.dev155.dist-info → omdev-0.0.0.dev157.dist-info}/LICENSE +0 -0
- {omdev-0.0.0.dev155.dist-info → omdev-0.0.0.dev157.dist-info}/WHEEL +0 -0
- {omdev-0.0.0.dev155.dist-info → omdev-0.0.0.dev157.dist-info}/entry_points.txt +0 -0
- {omdev-0.0.0.dev155.dist-info → omdev-0.0.0.dev157.dist-info}/top_level.txt +0 -0
omdev/scripts/pyproject.py
CHANGED
|
@@ -1823,8 +1823,8 @@ class _CachedNullary(_AbstractCachedNullary):
|
|
|
1823
1823
|
return self._value
|
|
1824
1824
|
|
|
1825
1825
|
|
|
1826
|
-
def cached_nullary(fn
|
|
1827
|
-
return _CachedNullary(fn)
|
|
1826
|
+
def cached_nullary(fn: CallableT) -> CallableT:
|
|
1827
|
+
return _CachedNullary(fn) # type: ignore
|
|
1828
1828
|
|
|
1829
1829
|
|
|
1830
1830
|
def static_init(fn: CallableT) -> CallableT:
|
|
@@ -3316,6 +3316,8 @@ def _get_argparse_arg_ann_kwargs(ann: ta.Any) -> ta.Mapping[str, ta.Any]:
|
|
|
3316
3316
|
return {'action': 'store_true'}
|
|
3317
3317
|
elif ann is list:
|
|
3318
3318
|
return {'action': 'append'}
|
|
3319
|
+
elif is_optional_alias(ann):
|
|
3320
|
+
return _get_argparse_arg_ann_kwargs(get_optional_alias_arg(ann))
|
|
3319
3321
|
else:
|
|
3320
3322
|
raise TypeError(ann)
|
|
3321
3323
|
|
|
@@ -3756,6 +3758,7 @@ TODO:
|
|
|
3756
3758
|
- pickle stdlib objs? have to pin to 3.8 pickle protocol, will be cross-version
|
|
3757
3759
|
- namedtuple
|
|
3758
3760
|
- literals
|
|
3761
|
+
- newtypes?
|
|
3759
3762
|
"""
|
|
3760
3763
|
|
|
3761
3764
|
|
|
@@ -4498,168 +4501,222 @@ SUBPROCESS_CHANNEL_OPTION_VALUES: ta.Mapping[SubprocessChannelOption, int] = {
|
|
|
4498
4501
|
_SUBPROCESS_SHELL_WRAP_EXECS = False
|
|
4499
4502
|
|
|
4500
4503
|
|
|
4501
|
-
def subprocess_shell_wrap_exec(*
|
|
4502
|
-
return ('sh', '-c', ' '.join(map(shlex.quote,
|
|
4504
|
+
def subprocess_shell_wrap_exec(*cmd: str) -> ta.Tuple[str, ...]:
|
|
4505
|
+
return ('sh', '-c', ' '.join(map(shlex.quote, cmd)))
|
|
4503
4506
|
|
|
4504
4507
|
|
|
4505
|
-
def subprocess_maybe_shell_wrap_exec(*
|
|
4508
|
+
def subprocess_maybe_shell_wrap_exec(*cmd: str) -> ta.Tuple[str, ...]:
|
|
4506
4509
|
if _SUBPROCESS_SHELL_WRAP_EXECS or is_debugger_attached():
|
|
4507
|
-
return subprocess_shell_wrap_exec(*
|
|
4510
|
+
return subprocess_shell_wrap_exec(*cmd)
|
|
4508
4511
|
else:
|
|
4509
|
-
return
|
|
4512
|
+
return cmd
|
|
4510
4513
|
|
|
4511
4514
|
|
|
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}
|
|
4515
|
+
##
|
|
4526
4516
|
|
|
4527
|
-
if quiet and 'stderr' not in kwargs:
|
|
4528
|
-
if not log.isEnabledFor(logging.DEBUG):
|
|
4529
|
-
kwargs['stderr'] = subprocess.DEVNULL
|
|
4530
4517
|
|
|
4531
|
-
|
|
4532
|
-
|
|
4518
|
+
def subprocess_close(
|
|
4519
|
+
proc: subprocess.Popen,
|
|
4520
|
+
timeout: ta.Optional[float] = None,
|
|
4521
|
+
) -> None:
|
|
4522
|
+
# TODO: terminate, sleep, kill
|
|
4523
|
+
if proc.stdout:
|
|
4524
|
+
proc.stdout.close()
|
|
4525
|
+
if proc.stderr:
|
|
4526
|
+
proc.stderr.close()
|
|
4527
|
+
if proc.stdin:
|
|
4528
|
+
proc.stdin.close()
|
|
4533
4529
|
|
|
4534
|
-
|
|
4535
|
-
env=env,
|
|
4536
|
-
shell=shell,
|
|
4537
|
-
**kwargs,
|
|
4538
|
-
)
|
|
4530
|
+
proc.wait(timeout)
|
|
4539
4531
|
|
|
4540
4532
|
|
|
4541
4533
|
##
|
|
4542
4534
|
|
|
4543
4535
|
|
|
4544
|
-
|
|
4545
|
-
|
|
4546
|
-
start_time = time.time()
|
|
4547
|
-
try:
|
|
4548
|
-
log.debug('subprocess_common_context.try: args=%r', args)
|
|
4549
|
-
yield
|
|
4536
|
+
class AbstractSubprocesses(abc.ABC): # noqa
|
|
4537
|
+
DEFAULT_LOGGER: ta.ClassVar[ta.Optional[logging.Logger]] = log
|
|
4550
4538
|
|
|
4551
|
-
|
|
4552
|
-
|
|
4553
|
-
|
|
4539
|
+
def __init__(
|
|
4540
|
+
self,
|
|
4541
|
+
*,
|
|
4542
|
+
log: ta.Optional[logging.Logger] = None,
|
|
4543
|
+
try_exceptions: ta.Optional[ta.Tuple[ta.Type[Exception], ...]] = None,
|
|
4544
|
+
) -> None:
|
|
4545
|
+
super().__init__()
|
|
4554
4546
|
|
|
4555
|
-
|
|
4556
|
-
|
|
4557
|
-
elapsed_s = end_time - start_time
|
|
4558
|
-
log.debug('subprocess_common_context.finally: elapsed_s=%f args=%r', elapsed_s, args)
|
|
4547
|
+
self._log = log if log is not None else self.DEFAULT_LOGGER
|
|
4548
|
+
self._try_exceptions = try_exceptions if try_exceptions is not None else self.DEFAULT_TRY_EXCEPTIONS
|
|
4559
4549
|
|
|
4550
|
+
#
|
|
4560
4551
|
|
|
4561
|
-
|
|
4552
|
+
def prepare_args(
|
|
4553
|
+
self,
|
|
4554
|
+
*cmd: str,
|
|
4555
|
+
env: ta.Optional[ta.Mapping[str, ta.Any]] = None,
|
|
4556
|
+
extra_env: ta.Optional[ta.Mapping[str, ta.Any]] = None,
|
|
4557
|
+
quiet: bool = False,
|
|
4558
|
+
shell: bool = False,
|
|
4559
|
+
**kwargs: ta.Any,
|
|
4560
|
+
) -> ta.Tuple[ta.Tuple[ta.Any, ...], ta.Dict[str, ta.Any]]:
|
|
4561
|
+
if self._log:
|
|
4562
|
+
self._log.debug('Subprocesses.prepare_args: cmd=%r', cmd)
|
|
4563
|
+
if extra_env:
|
|
4564
|
+
self._log.debug('Subprocesses.prepare_args: extra_env=%r', extra_env)
|
|
4562
4565
|
|
|
4566
|
+
if extra_env:
|
|
4567
|
+
env = {**(env if env is not None else os.environ), **extra_env}
|
|
4563
4568
|
|
|
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
|
|
4569
|
+
if quiet and 'stderr' not in kwargs:
|
|
4570
|
+
if self._log and not self._log.isEnabledFor(logging.DEBUG):
|
|
4571
|
+
kwargs['stderr'] = subprocess.DEVNULL
|
|
4572
4572
|
|
|
4573
|
+
if not shell:
|
|
4574
|
+
cmd = subprocess_maybe_shell_wrap_exec(*cmd)
|
|
4573
4575
|
|
|
4574
|
-
|
|
4575
|
-
|
|
4576
|
-
|
|
4577
|
-
|
|
4578
|
-
|
|
4579
|
-
with subprocess_common_context(*args, **kwargs):
|
|
4580
|
-
return subprocess.check_output(args, **kwargs)
|
|
4576
|
+
return cmd, dict(
|
|
4577
|
+
env=env,
|
|
4578
|
+
shell=shell,
|
|
4579
|
+
**kwargs,
|
|
4580
|
+
)
|
|
4581
4581
|
|
|
4582
|
+
@contextlib.contextmanager
|
|
4583
|
+
def wrap_call(self, *cmd: ta.Any, **kwargs: ta.Any) -> ta.Iterator[None]:
|
|
4584
|
+
start_time = time.time()
|
|
4585
|
+
try:
|
|
4586
|
+
if self._log:
|
|
4587
|
+
self._log.debug('Subprocesses.wrap_call.try: cmd=%r', cmd)
|
|
4588
|
+
yield
|
|
4582
4589
|
|
|
4583
|
-
|
|
4584
|
-
|
|
4590
|
+
except Exception as exc: # noqa
|
|
4591
|
+
if self._log:
|
|
4592
|
+
self._log.debug('Subprocesses.wrap_call.except: exc=%r', exc)
|
|
4593
|
+
raise
|
|
4585
4594
|
|
|
4595
|
+
finally:
|
|
4596
|
+
end_time = time.time()
|
|
4597
|
+
elapsed_s = end_time - start_time
|
|
4598
|
+
if self._log:
|
|
4599
|
+
self._log.debug('sSubprocesses.wrap_call.finally: elapsed_s=%f cmd=%r', elapsed_s, cmd)
|
|
4586
4600
|
|
|
4587
|
-
|
|
4601
|
+
@contextlib.contextmanager
|
|
4602
|
+
def prepare_and_wrap(
|
|
4603
|
+
self,
|
|
4604
|
+
*cmd: ta.Any,
|
|
4605
|
+
**kwargs: ta.Any,
|
|
4606
|
+
) -> ta.Iterator[ta.Tuple[
|
|
4607
|
+
ta.Tuple[ta.Any, ...],
|
|
4608
|
+
ta.Dict[str, ta.Any],
|
|
4609
|
+
]]:
|
|
4610
|
+
cmd, kwargs = self.prepare_args(*cmd, **kwargs)
|
|
4611
|
+
with self.wrap_call(*cmd, **kwargs):
|
|
4612
|
+
yield cmd, kwargs
|
|
4588
4613
|
|
|
4614
|
+
#
|
|
4589
4615
|
|
|
4590
|
-
|
|
4591
|
-
|
|
4592
|
-
|
|
4593
|
-
)
|
|
4616
|
+
DEFAULT_TRY_EXCEPTIONS: ta.Tuple[ta.Type[Exception], ...] = (
|
|
4617
|
+
FileNotFoundError,
|
|
4618
|
+
subprocess.CalledProcessError,
|
|
4619
|
+
)
|
|
4594
4620
|
|
|
4621
|
+
def try_fn(
|
|
4622
|
+
self,
|
|
4623
|
+
fn: ta.Callable[..., T],
|
|
4624
|
+
*cmd: str,
|
|
4625
|
+
try_exceptions: ta.Optional[ta.Tuple[ta.Type[Exception], ...]] = None,
|
|
4626
|
+
**kwargs: ta.Any,
|
|
4627
|
+
) -> ta.Union[T, Exception]:
|
|
4628
|
+
if try_exceptions is None:
|
|
4629
|
+
try_exceptions = self._try_exceptions
|
|
4595
4630
|
|
|
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
|
|
4631
|
+
try:
|
|
4632
|
+
return fn(*cmd, **kwargs)
|
|
4608
4633
|
|
|
4634
|
+
except try_exceptions as e: # noqa
|
|
4635
|
+
if self._log and self._log.isEnabledFor(logging.DEBUG):
|
|
4636
|
+
self._log.exception('command failed')
|
|
4637
|
+
return e
|
|
4609
4638
|
|
|
4610
|
-
def
|
|
4611
|
-
|
|
4612
|
-
|
|
4613
|
-
|
|
4614
|
-
|
|
4615
|
-
|
|
4616
|
-
|
|
4617
|
-
|
|
4618
|
-
try_exceptions=
|
|
4619
|
-
**kwargs,
|
|
4620
|
-
), Exception):
|
|
4621
|
-
return False
|
|
4622
|
-
else:
|
|
4623
|
-
return True
|
|
4639
|
+
async def async_try_fn(
|
|
4640
|
+
self,
|
|
4641
|
+
fn: ta.Callable[..., ta.Awaitable[T]],
|
|
4642
|
+
*cmd: ta.Any,
|
|
4643
|
+
try_exceptions: ta.Optional[ta.Tuple[ta.Type[Exception], ...]] = None,
|
|
4644
|
+
**kwargs: ta.Any,
|
|
4645
|
+
) -> ta.Union[T, Exception]:
|
|
4646
|
+
if try_exceptions is None:
|
|
4647
|
+
try_exceptions = self._try_exceptions
|
|
4624
4648
|
|
|
4649
|
+
try:
|
|
4650
|
+
return await fn(*cmd, **kwargs)
|
|
4625
4651
|
|
|
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
|
|
4652
|
+
except try_exceptions as e: # noqa
|
|
4653
|
+
if self._log and self._log.isEnabledFor(logging.DEBUG):
|
|
4654
|
+
self._log.exception('command failed')
|
|
4655
|
+
return e
|
|
4640
4656
|
|
|
4641
4657
|
|
|
4642
|
-
|
|
4643
|
-
out = subprocess_try_output(*args, **kwargs)
|
|
4644
|
-
return out.decode().strip() if out is not None else None
|
|
4658
|
+
##
|
|
4645
4659
|
|
|
4646
4660
|
|
|
4647
|
-
|
|
4661
|
+
class Subprocesses(AbstractSubprocesses):
|
|
4662
|
+
def check_call(
|
|
4663
|
+
self,
|
|
4664
|
+
*cmd: str,
|
|
4665
|
+
stdout: ta.Any = sys.stderr,
|
|
4666
|
+
**kwargs: ta.Any,
|
|
4667
|
+
) -> None:
|
|
4668
|
+
with self.prepare_and_wrap(*cmd, stdout=stdout, **kwargs) as (cmd, kwargs): # noqa
|
|
4669
|
+
subprocess.check_call(cmd, **kwargs)
|
|
4648
4670
|
|
|
4671
|
+
def check_output(
|
|
4672
|
+
self,
|
|
4673
|
+
*cmd: str,
|
|
4674
|
+
**kwargs: ta.Any,
|
|
4675
|
+
) -> bytes:
|
|
4676
|
+
with self.prepare_and_wrap(*cmd, **kwargs) as (cmd, kwargs): # noqa
|
|
4677
|
+
return subprocess.check_output(cmd, **kwargs)
|
|
4649
4678
|
|
|
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()
|
|
4679
|
+
def check_output_str(
|
|
4680
|
+
self,
|
|
4681
|
+
*cmd: str,
|
|
4682
|
+
**kwargs: ta.Any,
|
|
4683
|
+
) -> str:
|
|
4684
|
+
return self.check_output(*cmd, **kwargs).decode().strip()
|
|
4661
4685
|
|
|
4662
|
-
|
|
4686
|
+
#
|
|
4687
|
+
|
|
4688
|
+
def try_call(
|
|
4689
|
+
self,
|
|
4690
|
+
*cmd: str,
|
|
4691
|
+
**kwargs: ta.Any,
|
|
4692
|
+
) -> bool:
|
|
4693
|
+
if isinstance(self.try_fn(self.check_call, *cmd, **kwargs), Exception):
|
|
4694
|
+
return False
|
|
4695
|
+
else:
|
|
4696
|
+
return True
|
|
4697
|
+
|
|
4698
|
+
def try_output(
|
|
4699
|
+
self,
|
|
4700
|
+
*cmd: str,
|
|
4701
|
+
**kwargs: ta.Any,
|
|
4702
|
+
) -> ta.Optional[bytes]:
|
|
4703
|
+
if isinstance(ret := self.try_fn(self.check_output, *cmd, **kwargs), Exception):
|
|
4704
|
+
return None
|
|
4705
|
+
else:
|
|
4706
|
+
return ret
|
|
4707
|
+
|
|
4708
|
+
def try_output_str(
|
|
4709
|
+
self,
|
|
4710
|
+
*cmd: str,
|
|
4711
|
+
**kwargs: ta.Any,
|
|
4712
|
+
) -> ta.Optional[str]:
|
|
4713
|
+
if (ret := self.try_output(*cmd, **kwargs)) is None:
|
|
4714
|
+
return None
|
|
4715
|
+
else:
|
|
4716
|
+
return ret.decode().strip()
|
|
4717
|
+
|
|
4718
|
+
|
|
4719
|
+
subprocesses = Subprocesses()
|
|
4663
4720
|
|
|
4664
4721
|
|
|
4665
4722
|
########################################
|
|
@@ -5070,43 +5127,6 @@ def get_git_status(
|
|
|
5070
5127
|
##
|
|
5071
5128
|
|
|
5072
5129
|
|
|
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
5130
|
class AsyncioProcessCommunicator:
|
|
5111
5131
|
def __init__(
|
|
5112
5132
|
self,
|
|
@@ -5217,148 +5237,147 @@ class AsyncioProcessCommunicator:
|
|
|
5217
5237
|
return await asyncio_maybe_timeout(self._communicate(input), timeout)
|
|
5218
5238
|
|
|
5219
5239
|
|
|
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)
|
|
5240
|
+
##
|
|
5252
5241
|
|
|
5253
|
-
if check and proc.returncode:
|
|
5254
|
-
raise subprocess.CalledProcessError(
|
|
5255
|
-
proc.returncode,
|
|
5256
|
-
args,
|
|
5257
|
-
output=stdout,
|
|
5258
|
-
stderr=stderr,
|
|
5259
|
-
)
|
|
5260
5242
|
|
|
5261
|
-
|
|
5262
|
-
|
|
5263
|
-
|
|
5264
|
-
|
|
5265
|
-
|
|
5243
|
+
class AsyncioSubprocesses(AbstractSubprocesses):
|
|
5244
|
+
async def communicate(
|
|
5245
|
+
self,
|
|
5246
|
+
proc: asyncio.subprocess.Process,
|
|
5247
|
+
input: ta.Any = None, # noqa
|
|
5248
|
+
timeout: ta.Optional[float] = None,
|
|
5249
|
+
) -> ta.Tuple[ta.Optional[bytes], ta.Optional[bytes]]:
|
|
5250
|
+
return await AsyncioProcessCommunicator(proc).communicate(input, timeout) # noqa
|
|
5266
5251
|
|
|
5252
|
+
#
|
|
5267
5253
|
|
|
5268
|
-
|
|
5254
|
+
@contextlib.asynccontextmanager
|
|
5255
|
+
async def popen(
|
|
5256
|
+
self,
|
|
5257
|
+
*cmd: str,
|
|
5258
|
+
shell: bool = False,
|
|
5259
|
+
timeout: ta.Optional[float] = None,
|
|
5260
|
+
**kwargs: ta.Any,
|
|
5261
|
+
) -> ta.AsyncGenerator[asyncio.subprocess.Process, None]:
|
|
5262
|
+
fac: ta.Any
|
|
5263
|
+
if shell:
|
|
5264
|
+
fac = functools.partial(
|
|
5265
|
+
asyncio.create_subprocess_shell,
|
|
5266
|
+
check.single(cmd),
|
|
5267
|
+
)
|
|
5268
|
+
else:
|
|
5269
|
+
fac = functools.partial(
|
|
5270
|
+
asyncio.create_subprocess_exec,
|
|
5271
|
+
*cmd,
|
|
5272
|
+
)
|
|
5269
5273
|
|
|
5274
|
+
with self.prepare_and_wrap( *cmd, shell=shell, **kwargs) as (cmd, kwargs): # noqa
|
|
5275
|
+
proc: asyncio.subprocess.Process = await fac(**kwargs)
|
|
5276
|
+
try:
|
|
5277
|
+
yield proc
|
|
5270
5278
|
|
|
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
|
-
)
|
|
5279
|
+
finally:
|
|
5280
|
+
await asyncio_maybe_timeout(proc.wait(), timeout)
|
|
5286
5281
|
|
|
5282
|
+
#
|
|
5287
5283
|
|
|
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
|
-
)
|
|
5284
|
+
@dc.dataclass(frozen=True)
|
|
5285
|
+
class RunOutput:
|
|
5286
|
+
proc: asyncio.subprocess.Process
|
|
5287
|
+
stdout: ta.Optional[bytes]
|
|
5288
|
+
stderr: ta.Optional[bytes]
|
|
5302
5289
|
|
|
5303
|
-
|
|
5290
|
+
async def run(
|
|
5291
|
+
self,
|
|
5292
|
+
*cmd: str,
|
|
5293
|
+
input: ta.Any = None, # noqa
|
|
5294
|
+
timeout: ta.Optional[float] = None,
|
|
5295
|
+
check: bool = False, # noqa
|
|
5296
|
+
capture_output: ta.Optional[bool] = None,
|
|
5297
|
+
**kwargs: ta.Any,
|
|
5298
|
+
) -> RunOutput:
|
|
5299
|
+
if capture_output:
|
|
5300
|
+
kwargs.setdefault('stdout', subprocess.PIPE)
|
|
5301
|
+
kwargs.setdefault('stderr', subprocess.PIPE)
|
|
5304
5302
|
|
|
5303
|
+
proc: asyncio.subprocess.Process
|
|
5304
|
+
async with self.popen(*cmd, **kwargs) as proc:
|
|
5305
|
+
stdout, stderr = await self.communicate(proc, input, timeout)
|
|
5306
|
+
|
|
5307
|
+
if check and proc.returncode:
|
|
5308
|
+
raise subprocess.CalledProcessError(
|
|
5309
|
+
proc.returncode,
|
|
5310
|
+
cmd,
|
|
5311
|
+
output=stdout,
|
|
5312
|
+
stderr=stderr,
|
|
5313
|
+
)
|
|
5305
5314
|
|
|
5306
|
-
|
|
5307
|
-
|
|
5315
|
+
return self.RunOutput(
|
|
5316
|
+
proc,
|
|
5317
|
+
stdout,
|
|
5318
|
+
stderr,
|
|
5319
|
+
)
|
|
5308
5320
|
|
|
5321
|
+
#
|
|
5309
5322
|
|
|
5310
|
-
|
|
5323
|
+
async def check_call(
|
|
5324
|
+
self,
|
|
5325
|
+
*cmd: str,
|
|
5326
|
+
stdout: ta.Any = sys.stderr,
|
|
5327
|
+
**kwargs: ta.Any,
|
|
5328
|
+
) -> None:
|
|
5329
|
+
with self.prepare_and_wrap(*cmd, stdout=stdout, check=True, **kwargs) as (cmd, kwargs): # noqa
|
|
5330
|
+
await self.run(*cmd, **kwargs)
|
|
5311
5331
|
|
|
5332
|
+
async def check_output(
|
|
5333
|
+
self,
|
|
5334
|
+
*cmd: str,
|
|
5335
|
+
**kwargs: ta.Any,
|
|
5336
|
+
) -> bytes:
|
|
5337
|
+
with self.prepare_and_wrap(*cmd, stdout=subprocess.PIPE, check=True, **kwargs) as (cmd, kwargs): # noqa
|
|
5338
|
+
return check.not_none((await self.run(*cmd, **kwargs)).stdout)
|
|
5312
5339
|
|
|
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
|
|
5340
|
+
async def check_output_str(
|
|
5341
|
+
self,
|
|
5342
|
+
*cmd: str,
|
|
5343
|
+
**kwargs: ta.Any,
|
|
5344
|
+
) -> str:
|
|
5345
|
+
return (await self.check_output(*cmd, **kwargs)).decode().strip()
|
|
5325
5346
|
|
|
5347
|
+
#
|
|
5326
5348
|
|
|
5327
|
-
async def
|
|
5328
|
-
|
|
5329
|
-
|
|
5330
|
-
|
|
5331
|
-
) -> bool:
|
|
5332
|
-
|
|
5333
|
-
|
|
5334
|
-
|
|
5335
|
-
|
|
5336
|
-
**kwargs,
|
|
5337
|
-
), Exception):
|
|
5338
|
-
return False
|
|
5339
|
-
else:
|
|
5340
|
-
return True
|
|
5349
|
+
async def try_call(
|
|
5350
|
+
self,
|
|
5351
|
+
*cmd: str,
|
|
5352
|
+
**kwargs: ta.Any,
|
|
5353
|
+
) -> bool:
|
|
5354
|
+
if isinstance(await self.async_try_fn(self.check_call, *cmd, **kwargs), Exception):
|
|
5355
|
+
return False
|
|
5356
|
+
else:
|
|
5357
|
+
return True
|
|
5341
5358
|
|
|
5359
|
+
async def try_output(
|
|
5360
|
+
self,
|
|
5361
|
+
*cmd: str,
|
|
5362
|
+
**kwargs: ta.Any,
|
|
5363
|
+
) -> ta.Optional[bytes]:
|
|
5364
|
+
if isinstance(ret := await self.async_try_fn(self.check_output, *cmd, **kwargs), Exception):
|
|
5365
|
+
return None
|
|
5366
|
+
else:
|
|
5367
|
+
return ret
|
|
5342
5368
|
|
|
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
|
|
5369
|
+
async def try_output_str(
|
|
5370
|
+
self,
|
|
5371
|
+
*cmd: str,
|
|
5372
|
+
**kwargs: ta.Any,
|
|
5373
|
+
) -> ta.Optional[str]:
|
|
5374
|
+
if (ret := await self.try_output(*cmd, **kwargs)) is None:
|
|
5375
|
+
return None
|
|
5376
|
+
else:
|
|
5377
|
+
return ret.decode().strip()
|
|
5357
5378
|
|
|
5358
5379
|
|
|
5359
|
-
|
|
5360
|
-
out = await asyncio_subprocess_try_output(*args, **kwargs)
|
|
5361
|
-
return out.decode().strip() if out is not None else None
|
|
5380
|
+
asyncio_subprocesses = AsyncioSubprocesses()
|
|
5362
5381
|
|
|
5363
5382
|
|
|
5364
5383
|
########################################
|
|
@@ -5435,7 +5454,7 @@ class InterpInspector:
|
|
|
5435
5454
|
return cls._build_inspection(sys.executable, eval(cls._INSPECTION_CODE)) # noqa
|
|
5436
5455
|
|
|
5437
5456
|
async def _inspect(self, exe: str) -> InterpInspection:
|
|
5438
|
-
output = await
|
|
5457
|
+
output = await asyncio_subprocesses.check_output(exe, '-c', f'print({self._INSPECTION_CODE})', quiet=True)
|
|
5439
5458
|
return self._build_inspection(exe, output.decode())
|
|
5440
5459
|
|
|
5441
5460
|
async def inspect(self, exe: str) -> ta.Optional[InterpInspection]:
|
|
@@ -5836,7 +5855,7 @@ class BasePyprojectPackageGenerator(abc.ABC):
|
|
|
5836
5855
|
output_dir: ta.Optional[str] = None,
|
|
5837
5856
|
opts: BuildOpts = BuildOpts(),
|
|
5838
5857
|
) -> None:
|
|
5839
|
-
|
|
5858
|
+
subprocesses.check_call(
|
|
5840
5859
|
sys.executable,
|
|
5841
5860
|
'-m',
|
|
5842
5861
|
'build',
|
|
@@ -5852,14 +5871,14 @@ class BasePyprojectPackageGenerator(abc.ABC):
|
|
|
5852
5871
|
for fn in os.listdir(dist_dir):
|
|
5853
5872
|
tmp_dir = tempfile.mkdtemp()
|
|
5854
5873
|
|
|
5855
|
-
|
|
5874
|
+
subprocesses.check_call(
|
|
5856
5875
|
sys.executable,
|
|
5857
5876
|
'-m', 'venv',
|
|
5858
5877
|
'test-install',
|
|
5859
5878
|
cwd=tmp_dir,
|
|
5860
5879
|
)
|
|
5861
5880
|
|
|
5862
|
-
|
|
5881
|
+
subprocesses.check_call(
|
|
5863
5882
|
os.path.join(tmp_dir, 'test-install', 'bin', 'python3'),
|
|
5864
5883
|
'-m', 'pip',
|
|
5865
5884
|
'install',
|
|
@@ -6232,7 +6251,7 @@ class Pyenv:
|
|
|
6232
6251
|
return self._root_kw
|
|
6233
6252
|
|
|
6234
6253
|
if shutil.which('pyenv'):
|
|
6235
|
-
return await
|
|
6254
|
+
return await asyncio_subprocesses.check_output_str('pyenv', 'root')
|
|
6236
6255
|
|
|
6237
6256
|
d = os.path.expanduser('~/.pyenv')
|
|
6238
6257
|
if os.path.isdir(d) and os.path.isfile(os.path.join(d, 'bin', 'pyenv')):
|
|
@@ -6261,7 +6280,7 @@ class Pyenv:
|
|
|
6261
6280
|
if await self.root() is None:
|
|
6262
6281
|
return []
|
|
6263
6282
|
ret = []
|
|
6264
|
-
s = await
|
|
6283
|
+
s = await asyncio_subprocesses.check_output_str(await self.exe(), 'install', '--list')
|
|
6265
6284
|
for l in s.splitlines():
|
|
6266
6285
|
if not l.startswith(' '):
|
|
6267
6286
|
continue
|
|
@@ -6276,7 +6295,7 @@ class Pyenv:
|
|
|
6276
6295
|
return False
|
|
6277
6296
|
if not os.path.isdir(os.path.join(root, '.git')):
|
|
6278
6297
|
return False
|
|
6279
|
-
await
|
|
6298
|
+
await asyncio_subprocesses.check_call('git', 'pull', cwd=root)
|
|
6280
6299
|
return True
|
|
6281
6300
|
|
|
6282
6301
|
|
|
@@ -6367,7 +6386,7 @@ class DarwinPyenvInstallOpts(PyenvInstallOptsProvider):
|
|
|
6367
6386
|
cflags = []
|
|
6368
6387
|
ldflags = []
|
|
6369
6388
|
for dep in self.BREW_DEPS:
|
|
6370
|
-
dep_prefix = await
|
|
6389
|
+
dep_prefix = await asyncio_subprocesses.check_output_str('brew', '--prefix', dep)
|
|
6371
6390
|
cflags.append(f'-I{dep_prefix}/include')
|
|
6372
6391
|
ldflags.append(f'-L{dep_prefix}/lib')
|
|
6373
6392
|
return PyenvInstallOpts(
|
|
@@ -6377,11 +6396,11 @@ class DarwinPyenvInstallOpts(PyenvInstallOptsProvider):
|
|
|
6377
6396
|
|
|
6378
6397
|
@async_cached_nullary
|
|
6379
6398
|
async def brew_tcl_opts(self) -> PyenvInstallOpts:
|
|
6380
|
-
if await
|
|
6399
|
+
if await asyncio_subprocesses.try_output('brew', '--prefix', 'tcl-tk') is None:
|
|
6381
6400
|
return PyenvInstallOpts()
|
|
6382
6401
|
|
|
6383
|
-
tcl_tk_prefix = await
|
|
6384
|
-
tcl_tk_ver_str = await
|
|
6402
|
+
tcl_tk_prefix = await asyncio_subprocesses.check_output_str('brew', '--prefix', 'tcl-tk')
|
|
6403
|
+
tcl_tk_ver_str = await asyncio_subprocesses.check_output_str('brew', 'ls', '--versions', 'tcl-tk')
|
|
6385
6404
|
tcl_tk_ver = '.'.join(tcl_tk_ver_str.split()[1].split('.')[:2])
|
|
6386
6405
|
|
|
6387
6406
|
return PyenvInstallOpts(conf_opts=[
|
|
@@ -6489,6 +6508,7 @@ class PyenvVersionInstaller:
|
|
|
6489
6508
|
self._version,
|
|
6490
6509
|
]
|
|
6491
6510
|
|
|
6511
|
+
full_args: ta.List[str]
|
|
6492
6512
|
if self._given_install_name is not None:
|
|
6493
6513
|
full_args = [
|
|
6494
6514
|
os.path.join(check.not_none(await self._pyenv.root()), 'plugins', 'python-build', 'bin', 'python-build'), # noqa
|
|
@@ -6502,7 +6522,7 @@ class PyenvVersionInstaller:
|
|
|
6502
6522
|
*conf_args,
|
|
6503
6523
|
]
|
|
6504
6524
|
|
|
6505
|
-
await
|
|
6525
|
+
await asyncio_subprocesses.check_call(
|
|
6506
6526
|
*full_args,
|
|
6507
6527
|
env=env,
|
|
6508
6528
|
)
|
|
@@ -6897,12 +6917,12 @@ class Venv:
|
|
|
6897
6917
|
return False
|
|
6898
6918
|
|
|
6899
6919
|
log.info('Using interpreter %s', (ie := await self.interp_exe()))
|
|
6900
|
-
await
|
|
6920
|
+
await asyncio_subprocesses.check_call(ie, '-m', 'venv', dn)
|
|
6901
6921
|
|
|
6902
6922
|
ve = self.exe()
|
|
6903
6923
|
uv = self._cfg.use_uv
|
|
6904
6924
|
|
|
6905
|
-
await
|
|
6925
|
+
await asyncio_subprocesses.check_call(
|
|
6906
6926
|
ve,
|
|
6907
6927
|
'-m', 'pip',
|
|
6908
6928
|
'install', '-v', '--upgrade',
|
|
@@ -6920,7 +6940,7 @@ class Venv:
|
|
|
6920
6940
|
# Caused by: Failed to download distribution due to network timeout. Try increasing UV_HTTP_TIMEOUT (current value: 30s). # noqa
|
|
6921
6941
|
# UV_CONCURRENT_DOWNLOADS=4 UV_HTTP_TIMEOUT=3600
|
|
6922
6942
|
|
|
6923
|
-
await
|
|
6943
|
+
await asyncio_subprocesses.check_call(
|
|
6924
6944
|
ve,
|
|
6925
6945
|
'-m',
|
|
6926
6946
|
*(['uv'] if uv else []),
|
|
@@ -7074,7 +7094,7 @@ class PyprojectCli(ArgparseCli):
|
|
|
7074
7094
|
else:
|
|
7075
7095
|
docker_env[e] = os.environ.get(e, '')
|
|
7076
7096
|
|
|
7077
|
-
await
|
|
7097
|
+
await asyncio_subprocesses.check_call(
|
|
7078
7098
|
'docker',
|
|
7079
7099
|
'compose',
|
|
7080
7100
|
'-f', 'docker/compose.yml',
|
|
@@ -7125,7 +7145,7 @@ class PyprojectCli(ArgparseCli):
|
|
|
7125
7145
|
|
|
7126
7146
|
elif cmd == 'test':
|
|
7127
7147
|
await venv.create()
|
|
7128
|
-
await
|
|
7148
|
+
await asyncio_subprocesses.check_call(venv.exe(), '-m', 'pytest', *(self.args.args or []), *venv.srcs())
|
|
7129
7149
|
|
|
7130
7150
|
else:
|
|
7131
7151
|
raise Exception(f'unknown subcommand: {cmd}')
|