ominfra 0.0.0.dev155__py3-none-any.whl → 0.0.0.dev156__py3-none-any.whl

Sign up to get free protection for your applications and to get access to all the features.
@@ -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
  ########################################