subprocess.py 2.9 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798
  1. # !/usr/bin/env python3
  2. # -*- coding: UTF-8 -*-
  3. ################################################################################
  4. #
  5. # Copyright (c) 2024 Baidu.com, Inc. All Rights Reserved
  6. #
  7. ################################################################################
  8. """
  9. Author: PaddlePaddle Authors
  10. """
  11. import asyncio
  12. import subprocess
  13. from ....utils.logging import info
  14. __all__ = ['run_cmd', 'CompletedProcess']
  15. def run_cmd(cmd,
  16. env=None,
  17. silent=True,
  18. cwd=None,
  19. timeout=None,
  20. echo=False,
  21. pipe_stdout=False,
  22. pipe_stderr=False,
  23. blocking=True,
  24. async_run=False,
  25. text=True):
  26. """Wrap around `subprocess.Popen` to execute a shell command."""
  27. # TODO: Limit argument length
  28. cfg = dict(env=env, cwd=cwd)
  29. async_run = async_run and not blocking
  30. if blocking:
  31. cfg['timeout'] = timeout
  32. if silent:
  33. cfg['stdout'] = subprocess.DEVNULL if not async_run else asyncio.subprocess.DEVNULL
  34. cfg['stderr'] = subprocess.STDOUT if not async_run else asyncio.subprocess.STDOUT
  35. if not async_run and (pipe_stdout or pipe_stderr):
  36. cfg['text'] = True
  37. if pipe_stdout:
  38. cfg['stdout'] = subprocess.PIPE if not async_run else asyncio.subprocess.PIPE
  39. if pipe_stderr:
  40. cfg['stderr'] = subprocess.PIPE if not async_run else asyncio.subprocess.PIPE
  41. if echo:
  42. info(str(cmd))
  43. if blocking:
  44. return subprocess.run(cmd, **cfg, check=False)
  45. else:
  46. if async_run:
  47. return asyncio.create_subprocess_exec(cmd[0], *cmd[1:], **cfg)
  48. else:
  49. if text:
  50. cfg.update(dict(bufsize=1, text=True))
  51. else:
  52. cfg.update(dict(bufsize=0, text=False))
  53. return subprocess.Popen(cmd, **cfg)
  54. class CompletedProcess(object):
  55. """ CompletedProcess """
  56. __slots__ = ['args', 'returncode', 'stdout', 'stderr', '_add_attrs']
  57. def __init__(self, args, returncode, stdout=None, stderr=None):
  58. super().__init__()
  59. self.args = args
  60. self.returncode = returncode
  61. self.stdout = stdout
  62. self.stderr = stderr
  63. self._add_attrs = dict()
  64. def __getattr__(self, name):
  65. try:
  66. val = self._add_attrs[name]
  67. return val
  68. except KeyError:
  69. raise AttributeError
  70. def __setattr__(self, name, val):
  71. try:
  72. super().__setattr__(name, val)
  73. except AttributeError:
  74. self._add_attrs[name] = val
  75. def __repr__(self):
  76. args = [
  77. f"args={repr(self.args)}", f"returncode={repr(self.returncode)}"
  78. ]
  79. if self.stdout is not None:
  80. args.append(f"stdout={repr(self.stdout)}")
  81. if self.stderr is not None:
  82. args.append(f"stderr={repr(self.stderr)}")
  83. return f"{self.__class__.__name__}({', '.join(args)})"