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.

@@ -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(*args: str) -> ta.Tuple[str, ...]:
4502
- return ('sh', '-c', ' '.join(map(shlex.quote, args)))
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(*args: str) -> ta.Tuple[str, ...]:
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(*args)
4507
+ return subprocess_shell_wrap_exec(*cmd)
4508
4508
  else:
4509
- return args
4509
+ return cmd
4510
4510
 
4511
4511
 
4512
- def prepare_subprocess_invocation(
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
- if not shell:
4532
- args = subprocess_maybe_shell_wrap_exec(*args)
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
- return args, dict(
4535
- env=env,
4536
- shell=shell,
4537
- **kwargs,
4538
- )
4527
+ proc.wait(timeout)
4539
4528
 
4540
4529
 
4541
4530
  ##
4542
4531
 
4543
4532
 
4544
- @contextlib.contextmanager
4545
- def subprocess_common_context(*args: ta.Any, **kwargs: ta.Any) -> ta.Iterator[None]:
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
- except Exception as exc: # noqa
4552
- log.debug('subprocess_common_context.except: exc=%r', exc)
4553
- raise
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
- finally:
4556
- end_time = time.time()
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
- def subprocess_check_call(
4565
- *args: str,
4566
- stdout: ta.Any = sys.stderr,
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
- def subprocess_check_output(
4575
- *args: str,
4576
- **kwargs: ta.Any,
4577
- ) -> bytes:
4578
- args, kwargs = prepare_subprocess_invocation(*args, **kwargs)
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
- def subprocess_check_output_str(*args: str, **kwargs: ta.Any) -> str:
4584
- return subprocess_check_output(*args, **kwargs).decode().strip()
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
- DEFAULT_SUBPROCESS_TRY_EXCEPTIONS: ta.Tuple[ta.Type[Exception], ...] = (
4591
- FileNotFoundError,
4592
- subprocess.CalledProcessError,
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
- def _subprocess_try_run(
4597
- fn: ta.Callable[..., T],
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 subprocess_try_call(
4611
- *args: str,
4612
- try_exceptions: ta.Tuple[ta.Type[Exception], ...] = DEFAULT_SUBPROCESS_TRY_EXCEPTIONS,
4613
- **kwargs: ta.Any,
4614
- ) -> bool:
4615
- if isinstance(_subprocess_try_run(
4616
- subprocess_check_call,
4617
- *args,
4618
- try_exceptions=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
- def subprocess_try_output(
4627
- *args: str,
4628
- try_exceptions: ta.Tuple[ta.Type[Exception], ...] = DEFAULT_SUBPROCESS_TRY_EXCEPTIONS,
4629
- **kwargs: ta.Any,
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
- def subprocess_try_output_str(*args: str, **kwargs: ta.Any) -> ta.Optional[str]:
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 subprocess_close(
4651
- proc: subprocess.Popen,
4652
- timeout: ta.Optional[float] = None,
4653
- ) -> None:
4654
- # TODO: terminate, sleep, kill
4655
- if proc.stdout:
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
- proc.wait(timeout)
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
- async def asyncio_subprocess_communicate(
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
- return AsyncioSubprocessOutput(
5262
- proc,
5263
- stdout,
5264
- stderr,
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
- async def asyncio_subprocess_check_call(
5272
- *args: str,
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
- async def asyncio_subprocess_check_output(
5289
- *args: str,
5290
- input: ta.Any = None, # noqa
5291
- timeout: ta.Optional[float] = None,
5292
- **kwargs: ta.Any,
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
- return check.not_none(out.stdout)
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
- async def asyncio_subprocess_check_output_str(*args: str, **kwargs: ta.Any) -> str:
5307
- return (await asyncio_subprocess_check_output(*args, **kwargs)).decode().strip()
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 _asyncio_subprocess_try_run(
5314
- fn: ta.Callable[..., ta.Awaitable[T]],
5315
- *args: ta.Any,
5316
- try_exceptions: ta.Tuple[ta.Type[Exception], ...] = DEFAULT_SUBPROCESS_TRY_EXCEPTIONS,
5317
- **kwargs: ta.Any,
5318
- ) -> ta.Union[T, Exception]:
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 asyncio_subprocess_try_call(
5328
- *args: str,
5329
- try_exceptions: ta.Tuple[ta.Type[Exception], ...] = DEFAULT_SUBPROCESS_TRY_EXCEPTIONS,
5330
- **kwargs: ta.Any,
5331
- ) -> bool:
5332
- if isinstance(await _asyncio_subprocess_try_run(
5333
- asyncio_subprocess_check_call,
5334
- *args,
5335
- try_exceptions=try_exceptions,
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 asyncio_subprocess_try_output(
5344
- *args: str,
5345
- try_exceptions: ta.Tuple[ta.Type[Exception], ...] = DEFAULT_SUBPROCESS_TRY_EXCEPTIONS,
5346
- **kwargs: ta.Any,
5347
- ) -> ta.Optional[bytes]:
5348
- if isinstance(ret := await _asyncio_subprocess_try_run(
5349
- asyncio_subprocess_check_output,
5350
- *args,
5351
- try_exceptions=try_exceptions,
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
- async def asyncio_subprocess_try_output_str(*args: str, **kwargs: ta.Any) -> ta.Optional[str]:
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 asyncio_subprocess_check_output(exe, '-c', f'print({self._INSPECTION_CODE})', quiet=True)
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
- subprocess_check_call(
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
- subprocess_check_call(
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
- subprocess_check_call(
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 asyncio_subprocess_check_output_str('pyenv', 'root')
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 asyncio_subprocess_check_output_str(await self.exe(), 'install', '--list')
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 asyncio_subprocess_check_call('git', 'pull', cwd=root)
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 asyncio_subprocess_check_output_str('brew', '--prefix', dep)
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 asyncio_subprocess_try_output('brew', '--prefix', 'tcl-tk') is None:
6396
+ if await asyncio_subprocesses.try_output('brew', '--prefix', 'tcl-tk') is None:
6381
6397
  return PyenvInstallOpts()
6382
6398
 
6383
- tcl_tk_prefix = await asyncio_subprocess_check_output_str('brew', '--prefix', 'tcl-tk')
6384
- tcl_tk_ver_str = await asyncio_subprocess_check_output_str('brew', 'ls', '--versions', 'tcl-tk')
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 asyncio_subprocess_check_call(
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 asyncio_subprocess_check_call(ie, '-m', 'venv', dn)
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 asyncio_subprocess_check_call(
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 asyncio_subprocess_check_call(
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 asyncio_subprocess_check_call(
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 asyncio_subprocess_check_call(venv.exe(), '-m', 'pytest', *(self.args.args or []), *venv.srcs())
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}')