|
1 | 1 | import errno
|
2 | 2 | import logging
|
3 |
| -import multiprocessing |
4 | 3 | import os
|
5 | 4 | import subprocess
|
6 |
| -import sys |
7 | 5 | import tempfile
|
8 | 6 | import textwrap
|
9 | 7 | import uuid
|
10 |
| -from multiprocessing import queues |
11 | 8 | from typing import AnyStr
|
12 | 9 |
|
13 | 10 | import pexpect.fdpexpect
|
14 | 11 | from pexpect import EOF, TIMEOUT
|
15 | 12 | from pexpect.utils import poll_ignore_interrupts, select_ignore_interrupts
|
16 | 13 |
|
17 |
| -from .utils import Meta, remove_asci_color_code, to_bytes, to_str, utcnow_str |
18 |
| - |
19 |
| -if sys.platform == 'darwin': |
20 |
| - _ctx = multiprocessing.get_context('fork') |
21 |
| -else: |
22 |
| - _ctx = multiprocessing.get_context() |
23 |
| - |
24 |
| - |
25 |
| -class MessageQueue(queues.Queue): |
26 |
| - def __init__(self, *args, **kwargs): |
27 |
| - if 'ctx' not in kwargs: |
28 |
| - kwargs['ctx'] = _ctx |
29 |
| - |
30 |
| - super().__init__(*args, **kwargs) |
31 |
| - |
32 |
| - def put(self, obj, **kwargs): |
33 |
| - if not isinstance(obj, str | bytes): |
34 |
| - super().put(obj, **kwargs) |
35 |
| - return |
36 |
| - |
37 |
| - if obj == '' or obj == b'': |
38 |
| - return |
39 |
| - |
40 |
| - _b = to_bytes(obj) |
41 |
| - try: |
42 |
| - super().put(_b, **kwargs) |
43 |
| - except: # noqa # queue might be closed |
44 |
| - pass |
45 |
| - |
46 |
| - def write(self, s: AnyStr): |
47 |
| - self.put(s) |
48 |
| - |
49 |
| - def flush(self): |
50 |
| - pass |
51 |
| - |
52 |
| - def isatty(self): |
53 |
| - return True |
| 14 | +from pytest_embedded import MP_CTX, MessageQueue |
| 15 | +from pytest_embedded.utils import Meta, remove_asci_color_code, to_bytes, to_str, utcnow_str |
54 | 16 |
|
55 | 17 |
|
56 | 18 | class PexpectProcess(pexpect.fdpexpect.fdspawn):
|
@@ -144,18 +106,18 @@ def live_print_call(*args, msg_queue: MessageQueue | None = None, expect_returnc
|
144 | 106 | raise subprocess.CalledProcessError(process.returncode, process.args)
|
145 | 107 |
|
146 | 108 |
|
147 |
| -class _PopenRedirectProcess(_ctx.Process): |
| 109 | +class _PopenRedirectProcess(MP_CTX.Process): |
148 | 110 | def __init__(self, msg_queue: MessageQueue, logfile: str):
|
149 |
| - self._q = msg_queue |
150 |
| - |
151 |
| - self.logfile = logfile |
152 |
| - |
153 |
| - super().__init__(target=self._forward_io, daemon=True) # killed by the main process |
| 111 | + super().__init__(target=self._forward_io, args=(msg_queue, logfile), daemon=True) |
154 | 112 |
|
155 |
| - def _forward_io(self) -> None: |
156 |
| - with open(self.logfile) as fr: |
| 113 | + @staticmethod |
| 114 | + def _forward_io(msg_queue, logfile) -> None: |
| 115 | + with open(logfile) as fr: |
157 | 116 | while True:
|
158 |
| - self._q.put(fr.read()) |
| 117 | + try: |
| 118 | + msg_queue.put(fr.read()) # msg_queue may be closed |
| 119 | + except Exception: |
| 120 | + break |
159 | 121 |
|
160 | 122 |
|
161 | 123 | class DuplicateStdoutPopen(subprocess.Popen):
|
|
0 commit comments