Show More
@@ -14,18 +14,19 of subprocess utilities, and it contains tools that are common to all of them. | |||||
14 | #----------------------------------------------------------------------------- |
|
14 | #----------------------------------------------------------------------------- | |
15 | # Imports |
|
15 | # Imports | |
16 | #----------------------------------------------------------------------------- |
|
16 | #----------------------------------------------------------------------------- | |
17 |
import |
|
17 | import os | |
18 | import shlex |
|
18 | import shlex | |
|
19 | import subprocess | |||
19 | import sys |
|
20 | import sys | |
20 | import os |
|
21 | from typing import IO, Any, Callable, List, Union | |
21 | from typing import Callable, Optional, Union, List |
|
22 | ||
22 | from IPython.utils import py3compat |
|
23 | from IPython.utils import py3compat | |
23 |
|
24 | |||
24 | #----------------------------------------------------------------------------- |
|
25 | #----------------------------------------------------------------------------- | |
25 | # Function definitions |
|
26 | # Function definitions | |
26 | #----------------------------------------------------------------------------- |
|
27 | #----------------------------------------------------------------------------- | |
27 |
|
28 | |||
28 |
def read_no_interrupt( |
|
29 | def read_no_interrupt(stream: IO[Any]) -> bytes: | |
29 | """Read from a pipe ignoring EINTR errors. |
|
30 | """Read from a pipe ignoring EINTR errors. | |
30 |
|
31 | |||
31 | This is necessary because when reading from pipes with GUI event loops |
|
32 | This is necessary because when reading from pipes with GUI event loops | |
@@ -34,7 +35,7 def read_no_interrupt(p: subprocess.Popen) -> str: | |||||
34 | import errno |
|
35 | import errno | |
35 |
|
36 | |||
36 | try: |
|
37 | try: | |
37 |
return |
|
38 | return stream.read() | |
38 | except IOError as err: |
|
39 | except IOError as err: | |
39 | if err.errno != errno.EINTR: |
|
40 | if err.errno != errno.EINTR: | |
40 | raise |
|
41 | raise |
@@ -15,23 +15,23 This file is only meant to be imported by process.py, not by end-users. | |||||
15 | #----------------------------------------------------------------------------- |
|
15 | #----------------------------------------------------------------------------- | |
16 |
|
16 | |||
17 | # stdlib |
|
17 | # stdlib | |
|
18 | import ctypes | |||
18 | import os |
|
19 | import os | |
|
20 | import subprocess | |||
19 | import sys |
|
21 | import sys | |
20 | import ctypes |
|
|||
21 | import time |
|
22 | import time | |
22 |
|
23 | from ctypes import POINTER, c_int | ||
23 |
from ctypes import |
|
24 | from ctypes.wintypes import HLOCAL, LPCWSTR | |
24 | from ctypes.wintypes import LPCWSTR, HLOCAL |
|
25 | from subprocess import STDOUT | |
25 | from subprocess import STDOUT, TimeoutExpired |
|
|||
26 | from threading import Thread |
|
26 | from threading import Thread | |
27 | import subprocess |
|
27 | from types import TracebackType | |
|
28 | from typing import IO, Any, List, Optional | |||
28 |
|
29 | |||
29 | from typing import Optional, List |
|
30 | from . import py3compat | |
30 | import traceback |
|
31 | from ._process_common import arg_split as py_arg_split | |
31 |
|
32 | |||
32 | # our own imports |
|
33 | # our own imports | |
33 |
from ._process_common import |
|
34 | from ._process_common import process_handler, read_no_interrupt | |
34 | from . import py3compat |
|
|||
35 | from .encoding import DEFAULT_ENCODING |
|
35 | from .encoding import DEFAULT_ENCODING | |
36 |
|
36 | |||
37 | #----------------------------------------------------------------------------- |
|
37 | #----------------------------------------------------------------------------- | |
@@ -72,7 +72,7 class AvoidUNCPath: | |||||
72 | return None |
|
72 | return None | |
73 |
|
73 | |||
74 | def __exit__( |
|
74 | def __exit__( | |
75 | self, exc_type: Optional[type], exc_value: Optional[BaseException], traceback |
|
75 | self, exc_type: Optional[type[BaseException]], exc_value: Optional[BaseException], traceback:TracebackType | |
76 | ) -> None: |
|
76 | ) -> None: | |
77 | if self.is_unc_path: |
|
77 | if self.is_unc_path: | |
78 | os.chdir(self.path) |
|
78 | os.chdir(self.path) | |
@@ -82,18 +82,23 def _system_body(p: subprocess.Popen) -> int: | |||||
82 | """Callback for _system.""" |
|
82 | """Callback for _system.""" | |
83 | enc = DEFAULT_ENCODING |
|
83 | enc = DEFAULT_ENCODING | |
84 |
|
84 | |||
|
85 | # Dec 2024: in both of these functions, I'm not sure why we .splitlines() | |||
|
86 | # the bytes and then decode each line individually instead of just decoding | |||
|
87 | # the whole thing at once. | |||
85 | def stdout_read() -> None: |
|
88 | def stdout_read() -> None: | |
86 | try: |
|
89 | try: | |
87 | for line in read_no_interrupt(p.stdout).splitlines(): |
|
90 | assert p.stdout is not None | |
88 | line = line.decode(enc, "replace") |
|
91 | for byte_line in read_no_interrupt(p.stdout).splitlines(): | |
|
92 | line = byte_line.decode(enc, "replace") | |||
89 | print(line, file=sys.stdout) |
|
93 | print(line, file=sys.stdout) | |
90 | except Exception as e: |
|
94 | except Exception as e: | |
91 | print(f"Error reading stdout: {e}", file=sys.stderr) |
|
95 | print(f"Error reading stdout: {e}", file=sys.stderr) | |
92 |
|
96 | |||
93 | def stderr_read() -> None: |
|
97 | def stderr_read() -> None: | |
94 | try: |
|
98 | try: | |
95 | for line in read_no_interrupt(p.stderr).splitlines(): |
|
99 | assert p.stderr is not None | |
96 | line = line.decode(enc, "replace") |
|
100 | for byte_line in read_no_interrupt(p.stderr).splitlines(): | |
|
101 | line = byte_line.decode(enc, "replace") | |||
97 | print(line, file=sys.stderr) |
|
102 | print(line, file=sys.stderr) | |
98 | except Exception as e: |
|
103 | except Exception as e: | |
99 | print(f"Error reading stderr: {e}", file=sys.stderr) |
|
104 | print(f"Error reading stderr: {e}", file=sys.stderr) | |
@@ -204,7 +209,7 try: | |||||
204 | ) |
|
209 | ) | |
205 | if arg is not None |
|
210 | if arg is not None | |
206 | ] |
|
211 | ] | |
207 |
|
|
212 | LocalFree(result_pointer) | |
208 | return result |
|
213 | return result | |
209 | except AttributeError: |
|
214 | except AttributeError: | |
210 | arg_split = py_arg_split |
|
215 | arg_split = py_arg_split |
General Comments 0
You need to be logged in to leave comments.
Login now