ominfra 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.
@@ -6,8 +6,7 @@ import subprocess
6
6
  import time
7
7
  import typing as ta
8
8
 
9
- from omlish.lite.asyncio.subprocesses import asyncio_subprocess_communicate
10
- from omlish.lite.asyncio.subprocesses import asyncio_subprocess_popen
9
+ from omlish.lite.asyncio.subprocesses import asyncio_subprocesses
11
10
  from omlish.lite.check import check
12
11
  from omlish.lite.subprocesses import SUBPROCESS_CHANNEL_OPTION_VALUES
13
12
  from omlish.lite.subprocesses import SubprocessChannelOption
@@ -51,7 +50,7 @@ class SubprocessCommand(Command['SubprocessCommand.Output']):
51
50
  class SubprocessCommandExecutor(CommandExecutor[SubprocessCommand, SubprocessCommand.Output]):
52
51
  async def execute(self, cmd: SubprocessCommand) -> SubprocessCommand.Output:
53
52
  proc: asyncio.subprocess.Process
54
- async with asyncio_subprocess_popen(
53
+ async with asyncio_subprocesses.popen(
55
54
  *subprocess_maybe_shell_wrap_exec(*cmd.cmd),
56
55
 
57
56
  shell=cmd.shell,
@@ -65,7 +64,7 @@ class SubprocessCommandExecutor(CommandExecutor[SubprocessCommand, SubprocessCom
65
64
  timeout=cmd.timeout,
66
65
  ) as proc:
67
66
  start_time = time.time()
68
- stdout, stderr = await asyncio_subprocess_communicate(
67
+ stdout, stderr = await asyncio_subprocesses.communicate(
69
68
  proc,
70
69
  input=cmd.input,
71
70
  timeout=cmd.timeout,
@@ -13,7 +13,7 @@ import functools
13
13
  import os.path
14
14
  import typing as ta
15
15
 
16
- from omlish.lite.asyncio.subprocesses import asyncio_subprocess_check_call
16
+ from omlish.lite.asyncio.subprocesses import asyncio_subprocesses
17
17
  from omlish.lite.cached import async_cached_nullary
18
18
  from omlish.lite.check import check
19
19
 
@@ -92,7 +92,7 @@ class DeployGitManager(DeployPathOwner):
92
92
  return f'https://{self._repo.host}/{self._repo.path}'
93
93
 
94
94
  async def _call(self, *cmd: str) -> None:
95
- await asyncio_subprocess_check_call(
95
+ await asyncio_subprocesses.check_call(
96
96
  *cmd,
97
97
  cwd=self._dir,
98
98
  )
@@ -118,7 +118,7 @@ class DeployGitManager(DeployPathOwner):
118
118
  # FIXME: temp dir swap
119
119
  os.makedirs(dst_dir)
120
120
 
121
- dst_call = functools.partial(asyncio_subprocess_check_call, cwd=dst_dir)
121
+ dst_call = functools.partial(asyncio_subprocesses.check_call, cwd=dst_dir)
122
122
  await dst_call('git', 'init')
123
123
 
124
124
  await dst_call('git', 'remote', 'add', 'local', self._dir)
@@ -7,7 +7,7 @@ TODO:
7
7
  import os.path
8
8
  import typing as ta
9
9
 
10
- from omlish.lite.asyncio.subprocesses import asyncio_subprocess_check_call
10
+ from omlish.lite.asyncio.subprocesses import asyncio_subprocesses
11
11
 
12
12
  from .paths import DeployPath
13
13
  from .paths import DeployPathOwner
@@ -40,7 +40,7 @@ class DeployVenvManager(DeployPathOwner):
40
40
  ) -> None:
41
41
  sys_exe = 'python3'
42
42
 
43
- await asyncio_subprocess_check_call(sys_exe, '-m', 'venv', venv_dir)
43
+ await asyncio_subprocesses.check_call(sys_exe, '-m', 'venv', venv_dir)
44
44
 
45
45
  #
46
46
 
@@ -52,12 +52,12 @@ class DeployVenvManager(DeployPathOwner):
52
52
 
53
53
  if os.path.isfile(reqs_txt):
54
54
  if use_uv:
55
- await asyncio_subprocess_check_call(venv_exe, '-m', 'pip', 'install', 'uv')
55
+ await asyncio_subprocesses.check_call(venv_exe, '-m', 'pip', 'install', 'uv')
56
56
  pip_cmd = ['-m', 'uv', 'pip']
57
57
  else:
58
58
  pip_cmd = ['-m', 'pip']
59
59
 
60
- await asyncio_subprocess_check_call(venv_exe, *pip_cmd,'install', '-r', reqs_txt)
60
+ await asyncio_subprocesses.check_call(venv_exe, *pip_cmd,'install', '-r', reqs_txt)
61
61
 
62
62
  async def setup_app_venv(self, app_tag: DeployAppTag) -> None:
63
63
  await self.setup_venv(
@@ -7,7 +7,7 @@ import shlex
7
7
  import subprocess
8
8
  import typing as ta
9
9
 
10
- from omlish.lite.asyncio.subprocesses import asyncio_subprocess_popen
10
+ from omlish.lite.asyncio.subprocesses import asyncio_subprocesses
11
11
  from omlish.lite.check import check
12
12
  from omlish.lite.subprocesses import SUBPROCESS_CHANNEL_OPTION_VALUES
13
13
  from omlish.lite.subprocesses import SubprocessChannelOption
@@ -86,7 +86,7 @@ class SubprocessRemoteSpawning(RemoteSpawning):
86
86
  if not debug:
87
87
  cmd = subprocess_maybe_shell_wrap_exec(*cmd)
88
88
 
89
- async with asyncio_subprocess_popen(
89
+ async with asyncio_subprocesses.popen(
90
90
  *cmd,
91
91
  shell=pc.shell,
92
92
  stdin=subprocess.PIPE,
@@ -9,9 +9,7 @@ import json
9
9
  import os
10
10
  import typing as ta
11
11
 
12
- from omlish.lite.asyncio.subprocesses import asyncio_subprocess_check_call
13
- from omlish.lite.asyncio.subprocesses import asyncio_subprocess_check_output
14
- from omlish.lite.asyncio.subprocesses import asyncio_subprocess_run
12
+ from omlish.lite.asyncio.subprocesses import asyncio_subprocesses
15
13
  from omlish.lite.check import check
16
14
 
17
15
 
@@ -44,10 +42,10 @@ class SystemPackageManager(abc.ABC):
44
42
 
45
43
  class BrewSystemPackageManager(SystemPackageManager):
46
44
  async def update(self) -> None:
47
- await asyncio_subprocess_check_call('brew', 'update')
45
+ await asyncio_subprocesses.check_call('brew', 'update')
48
46
 
49
47
  async def upgrade(self) -> None:
50
- await asyncio_subprocess_check_call('brew', 'upgrade')
48
+ await asyncio_subprocesses.check_call('brew', 'upgrade')
51
49
 
52
50
  async def install(self, *packages: SystemPackageOrStr) -> None:
53
51
  es: ta.List[str] = []
@@ -56,11 +54,11 @@ class BrewSystemPackageManager(SystemPackageManager):
56
54
  es.append(p.name + (f'@{p.version}' if p.version is not None else ''))
57
55
  else:
58
56
  es.append(p)
59
- await asyncio_subprocess_check_call('brew', 'install', *es)
57
+ await asyncio_subprocesses.check_call('brew', 'install', *es)
60
58
 
61
59
  async def query(self, *packages: SystemPackageOrStr) -> ta.Mapping[str, SystemPackage]:
62
60
  pns = [p.name if isinstance(p, SystemPackage) else p for p in packages]
63
- o = await asyncio_subprocess_check_output('brew', 'info', '--json', *pns)
61
+ o = await asyncio_subprocesses.check_output('brew', 'info', '--json', *pns)
64
62
  j = json.loads(o.decode())
65
63
  d: ta.Dict[str, SystemPackage] = {}
66
64
  for e in j:
@@ -79,18 +77,18 @@ class AptSystemPackageManager(SystemPackageManager):
79
77
  }
80
78
 
81
79
  async def update(self) -> None:
82
- await asyncio_subprocess_check_call('sudo', 'apt', 'update', env={**os.environ, **self._APT_ENV})
80
+ await asyncio_subprocesses.check_call('sudo', 'apt', 'update', env={**os.environ, **self._APT_ENV})
83
81
 
84
82
  async def upgrade(self) -> None:
85
- await asyncio_subprocess_check_call('sudo', 'apt', 'upgrade', '-y', env={**os.environ, **self._APT_ENV})
83
+ await asyncio_subprocesses.check_call('sudo', 'apt', 'upgrade', '-y', env={**os.environ, **self._APT_ENV})
86
84
 
87
85
  async def install(self, *packages: SystemPackageOrStr) -> None:
88
86
  pns = [p.name if isinstance(p, SystemPackage) else p for p in packages] # FIXME: versions
89
- await asyncio_subprocess_check_call('sudo', 'apt', 'install', '-y', *pns, env={**os.environ, **self._APT_ENV})
87
+ await asyncio_subprocesses.check_call('sudo', 'apt', 'install', '-y', *pns, env={**os.environ, **self._APT_ENV})
90
88
 
91
89
  async def query(self, *packages: SystemPackageOrStr) -> ta.Mapping[str, SystemPackage]:
92
90
  pns = [p.name if isinstance(p, SystemPackage) else p for p in packages]
93
- out = await asyncio_subprocess_run(
91
+ out = await asyncio_subprocesses.run(
94
92
  'dpkg-query', '-W', '-f=${Package}=${Version}\n', *pns,
95
93
  capture_output=True,
96
94
  check=False,
@@ -107,20 +105,20 @@ class AptSystemPackageManager(SystemPackageManager):
107
105
 
108
106
  class YumSystemPackageManager(SystemPackageManager):
109
107
  async def update(self) -> None:
110
- await asyncio_subprocess_check_call('sudo', 'yum', 'check-update')
108
+ await asyncio_subprocesses.check_call('sudo', 'yum', 'check-update')
111
109
 
112
110
  async def upgrade(self) -> None:
113
- await asyncio_subprocess_check_call('sudo', 'yum', 'update')
111
+ await asyncio_subprocesses.check_call('sudo', 'yum', 'update')
114
112
 
115
113
  async def install(self, *packages: SystemPackageOrStr) -> None:
116
114
  pns = [p.name if isinstance(p, SystemPackage) else p for p in packages] # FIXME: versions
117
- await asyncio_subprocess_check_call('sudo', 'yum', 'install', *pns)
115
+ await asyncio_subprocesses.check_call('sudo', 'yum', 'install', *pns)
118
116
 
119
117
  async def query(self, *packages: SystemPackageOrStr) -> ta.Mapping[str, SystemPackage]:
120
118
  pns = [p.name if isinstance(p, SystemPackage) else p for p in packages]
121
119
  d: ta.Dict[str, SystemPackage] = {}
122
120
  for pn in pns:
123
- out = await asyncio_subprocess_run(
121
+ out = await asyncio_subprocesses.run(
124
122
  'rpm', '-q', pn,
125
123
  capture_output=True,
126
124
  )
@@ -3593,168 +3593,222 @@ SUBPROCESS_CHANNEL_OPTION_VALUES: ta.Mapping[SubprocessChannelOption, int] = {
3593
3593
  _SUBPROCESS_SHELL_WRAP_EXECS = False
3594
3594
 
3595
3595
 
3596
- def subprocess_shell_wrap_exec(*args: str) -> ta.Tuple[str, ...]:
3597
- return ('sh', '-c', ' '.join(map(shlex.quote, args)))
3596
+ def subprocess_shell_wrap_exec(*cmd: str) -> ta.Tuple[str, ...]:
3597
+ return ('sh', '-c', ' '.join(map(shlex.quote, cmd)))
3598
3598
 
3599
3599
 
3600
- def subprocess_maybe_shell_wrap_exec(*args: str) -> ta.Tuple[str, ...]:
3600
+ def subprocess_maybe_shell_wrap_exec(*cmd: str) -> ta.Tuple[str, ...]:
3601
3601
  if _SUBPROCESS_SHELL_WRAP_EXECS or is_debugger_attached():
3602
- return subprocess_shell_wrap_exec(*args)
3602
+ return subprocess_shell_wrap_exec(*cmd)
3603
3603
  else:
3604
- return args
3605
-
3606
-
3607
- def prepare_subprocess_invocation(
3608
- *args: str,
3609
- env: ta.Optional[ta.Mapping[str, ta.Any]] = None,
3610
- extra_env: ta.Optional[ta.Mapping[str, ta.Any]] = None,
3611
- quiet: bool = False,
3612
- shell: bool = False,
3613
- **kwargs: ta.Any,
3614
- ) -> ta.Tuple[ta.Tuple[ta.Any, ...], ta.Dict[str, ta.Any]]:
3615
- log.debug('prepare_subprocess_invocation: args=%r', args)
3616
- if extra_env:
3617
- log.debug('prepare_subprocess_invocation: extra_env=%r', extra_env)
3618
-
3619
- if extra_env:
3620
- env = {**(env if env is not None else os.environ), **extra_env}
3621
-
3622
- if quiet and 'stderr' not in kwargs:
3623
- if not log.isEnabledFor(logging.DEBUG):
3624
- kwargs['stderr'] = subprocess.DEVNULL
3625
-
3626
- if not shell:
3627
- args = subprocess_maybe_shell_wrap_exec(*args)
3628
-
3629
- return args, dict(
3630
- env=env,
3631
- shell=shell,
3632
- **kwargs,
3633
- )
3604
+ return cmd
3634
3605
 
3635
3606
 
3636
3607
  ##
3637
3608
 
3638
3609
 
3639
- @contextlib.contextmanager
3640
- def subprocess_common_context(*args: ta.Any, **kwargs: ta.Any) -> ta.Iterator[None]:
3641
- start_time = time.time()
3642
- try:
3643
- log.debug('subprocess_common_context.try: args=%r', args)
3644
- yield
3645
-
3646
- except Exception as exc: # noqa
3647
- log.debug('subprocess_common_context.except: exc=%r', exc)
3648
- raise
3610
+ def subprocess_close(
3611
+ proc: subprocess.Popen,
3612
+ timeout: ta.Optional[float] = None,
3613
+ ) -> None:
3614
+ # TODO: terminate, sleep, kill
3615
+ if proc.stdout:
3616
+ proc.stdout.close()
3617
+ if proc.stderr:
3618
+ proc.stderr.close()
3619
+ if proc.stdin:
3620
+ proc.stdin.close()
3649
3621
 
3650
- finally:
3651
- end_time = time.time()
3652
- elapsed_s = end_time - start_time
3653
- log.debug('subprocess_common_context.finally: elapsed_s=%f args=%r', elapsed_s, args)
3622
+ proc.wait(timeout)
3654
3623
 
3655
3624
 
3656
3625
  ##
3657
3626
 
3658
3627
 
3659
- def subprocess_check_call(
3660
- *args: str,
3661
- stdout: ta.Any = sys.stderr,
3662
- **kwargs: ta.Any,
3663
- ) -> None:
3664
- args, kwargs = prepare_subprocess_invocation(*args, stdout=stdout, **kwargs)
3665
- with subprocess_common_context(*args, **kwargs):
3666
- return subprocess.check_call(args, **kwargs) # type: ignore
3628
+ class AbstractSubprocesses(abc.ABC): # noqa
3629
+ DEFAULT_LOGGER: ta.ClassVar[ta.Optional[logging.Logger]] = log
3630
+
3631
+ def __init__(
3632
+ self,
3633
+ *,
3634
+ log: ta.Optional[logging.Logger] = None,
3635
+ try_exceptions: ta.Optional[ta.Tuple[ta.Type[Exception], ...]] = None,
3636
+ ) -> None:
3637
+ super().__init__()
3667
3638
 
3639
+ self._log = log if log is not None else self.DEFAULT_LOGGER
3640
+ self._try_exceptions = try_exceptions if try_exceptions is not None else self.DEFAULT_TRY_EXCEPTIONS
3668
3641
 
3669
- def subprocess_check_output(
3670
- *args: str,
3671
- **kwargs: ta.Any,
3672
- ) -> bytes:
3673
- args, kwargs = prepare_subprocess_invocation(*args, **kwargs)
3674
- with subprocess_common_context(*args, **kwargs):
3675
- return subprocess.check_output(args, **kwargs)
3642
+ #
3676
3643
 
3644
+ def prepare_args(
3645
+ self,
3646
+ *cmd: str,
3647
+ env: ta.Optional[ta.Mapping[str, ta.Any]] = None,
3648
+ extra_env: ta.Optional[ta.Mapping[str, ta.Any]] = None,
3649
+ quiet: bool = False,
3650
+ shell: bool = False,
3651
+ **kwargs: ta.Any,
3652
+ ) -> ta.Tuple[ta.Tuple[ta.Any, ...], ta.Dict[str, ta.Any]]:
3653
+ if self._log:
3654
+ self._log.debug('Subprocesses.prepare_args: cmd=%r', cmd)
3655
+ if extra_env:
3656
+ self._log.debug('Subprocesses.prepare_args: extra_env=%r', extra_env)
3677
3657
 
3678
- def subprocess_check_output_str(*args: str, **kwargs: ta.Any) -> str:
3679
- return subprocess_check_output(*args, **kwargs).decode().strip()
3658
+ if extra_env:
3659
+ env = {**(env if env is not None else os.environ), **extra_env}
3680
3660
 
3661
+ if quiet and 'stderr' not in kwargs:
3662
+ if self._log and not self._log.isEnabledFor(logging.DEBUG):
3663
+ kwargs['stderr'] = subprocess.DEVNULL
3681
3664
 
3682
- ##
3665
+ if not shell:
3666
+ cmd = subprocess_maybe_shell_wrap_exec(*cmd)
3683
3667
 
3668
+ return cmd, dict(
3669
+ env=env,
3670
+ shell=shell,
3671
+ **kwargs,
3672
+ )
3684
3673
 
3685
- DEFAULT_SUBPROCESS_TRY_EXCEPTIONS: ta.Tuple[ta.Type[Exception], ...] = (
3686
- FileNotFoundError,
3687
- subprocess.CalledProcessError,
3688
- )
3674
+ @contextlib.contextmanager
3675
+ def wrap_call(self, *cmd: ta.Any, **kwargs: ta.Any) -> ta.Iterator[None]:
3676
+ start_time = time.time()
3677
+ try:
3678
+ if self._log:
3679
+ self._log.debug('Subprocesses.wrap_call.try: cmd=%r', cmd)
3680
+ yield
3689
3681
 
3682
+ except Exception as exc: # noqa
3683
+ if self._log:
3684
+ self._log.debug('Subprocesses.wrap_call.except: exc=%r', exc)
3685
+ raise
3690
3686
 
3691
- def _subprocess_try_run(
3692
- fn: ta.Callable[..., T],
3693
- *args: ta.Any,
3694
- try_exceptions: ta.Tuple[ta.Type[Exception], ...] = DEFAULT_SUBPROCESS_TRY_EXCEPTIONS,
3695
- **kwargs: ta.Any,
3696
- ) -> ta.Union[T, Exception]:
3697
- try:
3698
- return fn(*args, **kwargs)
3699
- except try_exceptions as e: # noqa
3700
- if log.isEnabledFor(logging.DEBUG):
3701
- log.exception('command failed')
3702
- return e
3703
-
3704
-
3705
- def subprocess_try_call(
3706
- *args: str,
3707
- try_exceptions: ta.Tuple[ta.Type[Exception], ...] = DEFAULT_SUBPROCESS_TRY_EXCEPTIONS,
3708
- **kwargs: ta.Any,
3709
- ) -> bool:
3710
- if isinstance(_subprocess_try_run(
3711
- subprocess_check_call,
3712
- *args,
3713
- try_exceptions=try_exceptions,
3714
- **kwargs,
3715
- ), Exception):
3716
- return False
3717
- else:
3718
- return True
3687
+ finally:
3688
+ end_time = time.time()
3689
+ elapsed_s = end_time - start_time
3690
+ if self._log:
3691
+ self._log.debug('sSubprocesses.wrap_call.finally: elapsed_s=%f cmd=%r', elapsed_s, cmd)
3719
3692
 
3693
+ @contextlib.contextmanager
3694
+ def prepare_and_wrap(
3695
+ self,
3696
+ *cmd: ta.Any,
3697
+ **kwargs: ta.Any,
3698
+ ) -> ta.Iterator[ta.Tuple[
3699
+ ta.Tuple[ta.Any, ...],
3700
+ ta.Dict[str, ta.Any],
3701
+ ]]:
3702
+ cmd, kwargs = self.prepare_args(*cmd, **kwargs)
3703
+ with self.wrap_call(*cmd, **kwargs):
3704
+ yield cmd, kwargs
3720
3705
 
3721
- def subprocess_try_output(
3722
- *args: str,
3723
- try_exceptions: ta.Tuple[ta.Type[Exception], ...] = DEFAULT_SUBPROCESS_TRY_EXCEPTIONS,
3724
- **kwargs: ta.Any,
3725
- ) -> ta.Optional[bytes]:
3726
- if isinstance(ret := _subprocess_try_run(
3727
- subprocess_check_output,
3728
- *args,
3729
- try_exceptions=try_exceptions,
3730
- **kwargs,
3731
- ), Exception):
3732
- return None
3733
- else:
3734
- return ret
3706
+ #
3707
+
3708
+ DEFAULT_TRY_EXCEPTIONS: ta.Tuple[ta.Type[Exception], ...] = (
3709
+ FileNotFoundError,
3710
+ subprocess.CalledProcessError,
3711
+ )
3735
3712
 
3713
+ def try_fn(
3714
+ self,
3715
+ fn: ta.Callable[..., T],
3716
+ *cmd: str,
3717
+ try_exceptions: ta.Optional[ta.Tuple[ta.Type[Exception], ...]] = None,
3718
+ **kwargs: ta.Any,
3719
+ ) -> ta.Union[T, Exception]:
3720
+ if try_exceptions is None:
3721
+ try_exceptions = self._try_exceptions
3736
3722
 
3737
- def subprocess_try_output_str(*args: str, **kwargs: ta.Any) -> ta.Optional[str]:
3738
- out = subprocess_try_output(*args, **kwargs)
3739
- return out.decode().strip() if out is not None else None
3723
+ try:
3724
+ return fn(*cmd, **kwargs)
3725
+
3726
+ except try_exceptions as e: # noqa
3727
+ if self._log and self._log.isEnabledFor(logging.DEBUG):
3728
+ self._log.exception('command failed')
3729
+ return e
3730
+
3731
+ async def async_try_fn(
3732
+ self,
3733
+ fn: ta.Callable[..., ta.Awaitable[T]],
3734
+ *cmd: ta.Any,
3735
+ try_exceptions: ta.Optional[ta.Tuple[ta.Type[Exception], ...]] = None,
3736
+ **kwargs: ta.Any,
3737
+ ) -> ta.Union[T, Exception]:
3738
+ if try_exceptions is None:
3739
+ try_exceptions = self._try_exceptions
3740
+
3741
+ try:
3742
+ return await fn(*cmd, **kwargs)
3743
+
3744
+ except try_exceptions as e: # noqa
3745
+ if self._log and self._log.isEnabledFor(logging.DEBUG):
3746
+ self._log.exception('command failed')
3747
+ return e
3740
3748
 
3741
3749
 
3742
3750
  ##
3743
3751
 
3744
3752
 
3745
- def subprocess_close(
3746
- proc: subprocess.Popen,
3747
- timeout: ta.Optional[float] = None,
3748
- ) -> None:
3749
- # TODO: terminate, sleep, kill
3750
- if proc.stdout:
3751
- proc.stdout.close()
3752
- if proc.stderr:
3753
- proc.stderr.close()
3754
- if proc.stdin:
3755
- proc.stdin.close()
3753
+ class Subprocesses(AbstractSubprocesses):
3754
+ def check_call(
3755
+ self,
3756
+ *cmd: str,
3757
+ stdout: ta.Any = sys.stderr,
3758
+ **kwargs: ta.Any,
3759
+ ) -> None:
3760
+ with self.prepare_and_wrap(*cmd, stdout=stdout, **kwargs) as (cmd, kwargs): # noqa
3761
+ subprocess.check_call(cmd, **kwargs)
3756
3762
 
3757
- proc.wait(timeout)
3763
+ def check_output(
3764
+ self,
3765
+ *cmd: str,
3766
+ **kwargs: ta.Any,
3767
+ ) -> bytes:
3768
+ with self.prepare_and_wrap(*cmd, **kwargs) as (cmd, kwargs): # noqa
3769
+ return subprocess.check_output(cmd, **kwargs)
3770
+
3771
+ def check_output_str(
3772
+ self,
3773
+ *cmd: str,
3774
+ **kwargs: ta.Any,
3775
+ ) -> str:
3776
+ return self.check_output(*cmd, **kwargs).decode().strip()
3777
+
3778
+ #
3779
+
3780
+ def try_call(
3781
+ self,
3782
+ *cmd: str,
3783
+ **kwargs: ta.Any,
3784
+ ) -> bool:
3785
+ if isinstance(self.try_fn(self.check_call, *cmd, **kwargs), Exception):
3786
+ return False
3787
+ else:
3788
+ return True
3789
+
3790
+ def try_output(
3791
+ self,
3792
+ *cmd: str,
3793
+ **kwargs: ta.Any,
3794
+ ) -> ta.Optional[bytes]:
3795
+ if isinstance(ret := self.try_fn(self.check_output, *cmd, **kwargs), Exception):
3796
+ return None
3797
+ else:
3798
+ return ret
3799
+
3800
+ def try_output_str(
3801
+ self,
3802
+ *cmd: str,
3803
+ **kwargs: ta.Any,
3804
+ ) -> ta.Optional[str]:
3805
+ if (ret := self.try_output(*cmd, **kwargs)) is None:
3806
+ return None
3807
+ else:
3808
+ return ret.decode().strip()
3809
+
3810
+
3811
+ subprocesses = Subprocesses()
3758
3812
 
3759
3813
 
3760
3814
  ########################################