|
24 | 24 | from ctypes.wintypes import LPCWSTR, HLOCAL |
25 | 25 | from subprocess import STDOUT, TimeoutExpired |
26 | 26 | from threading import Thread |
| 27 | +import subprocess |
27 | 28 |
|
28 | 29 | # our own imports |
29 | 30 | from ._process_common import read_no_interrupt, process_handler, arg_split as py_arg_split |
|
34 | 35 | # Function definitions |
35 | 36 | #----------------------------------------------------------------------------- |
36 | 37 |
|
37 | | -class AvoidUNCPath(object): |
| 38 | +class AvoidUNCPath: |
38 | 39 | """A context manager to protect command execution from UNC paths. |
39 | 40 |
|
40 | 41 | In the Win32 API, commands can't be invoked with the cwd being a UNC path. |
@@ -71,35 +72,50 @@ def __exit__(self, exc_type, exc_value, traceback): |
71 | 72 | os.chdir(self.path) |
72 | 73 |
|
73 | 74 |
|
74 | | -def _system_body(p): |
| 75 | +def _system_body(p: subprocess.Popen) -> int: |
75 | 76 | """Callback for _system.""" |
76 | 77 | enc = DEFAULT_ENCODING |
77 | 78 |
|
78 | 79 | def stdout_read(): |
79 | | - for line in read_no_interrupt(p.stdout).splitlines(): |
80 | | - line = line.decode(enc, 'replace') |
81 | | - print(line, file=sys.stdout) |
| 80 | + try: |
| 81 | + for line in read_no_interrupt(p.stdout).splitlines(): |
| 82 | + line = line.decode(enc, 'replace') |
| 83 | + print(line, file=sys.stdout) |
| 84 | + except Exception as e: |
| 85 | + print(f"Error reading stdout: {e}", file=sys.stderr) |
82 | 86 |
|
83 | 87 | def stderr_read(): |
84 | | - for line in read_no_interrupt(p.stderr).splitlines(): |
85 | | - line = line.decode(enc, 'replace') |
86 | | - print(line, file=sys.stderr) |
| 88 | + try: |
| 89 | + for line in read_no_interrupt(p.stderr).splitlines(): |
| 90 | + line = line.decode(enc, 'replace') |
| 91 | + print(line, file=sys.stderr) |
| 92 | + except Exception as e: |
| 93 | + print(f"Error reading stderr: {e}", file=sys.stderr) |
87 | 94 |
|
88 | | - Thread(target=stdout_read).start() |
89 | | - Thread(target=stderr_read).start() |
| 95 | + stdout_thread = Thread(target=stdout_read) |
| 96 | + stderr_thread = Thread(target=stderr_read) |
| 97 | + |
| 98 | + stdout_thread.start() |
| 99 | + stderr_thread.start() |
90 | 100 |
|
91 | 101 | # Wait to finish for returncode. Unfortunately, Python has a bug where |
92 | 102 | # wait() isn't interruptible (https://bugs.python.org/issue28168) so poll in |
93 | | - # a loop instead of just doing `return p.wait()`. |
| 103 | + # a loop instead of just doing `return p.wait()` |
94 | 104 | while True: |
95 | 105 | result = p.poll() |
96 | 106 | if result is None: |
97 | 107 | time.sleep(0.01) |
98 | 108 | else: |
99 | | - return result |
| 109 | + break |
| 110 | + |
| 111 | + # Join the threads to ensure they complete before returning |
| 112 | + stdout_thread.join() |
| 113 | + stderr_thread.join() |
| 114 | + |
| 115 | + return result |
100 | 116 |
|
101 | 117 |
|
102 | | -def system(cmd): |
| 118 | +def system(cmd: str): |
103 | 119 | """Win32 version of os.system() that works with network shares. |
104 | 120 |
|
105 | 121 | Note that this implementation returns None, as meant for use in IPython. |
|
0 commit comments