diff --git a/doc/source/history.rst b/doc/source/history.rst index 1ffeb65..be873e3 100644 --- a/doc/source/history.rst +++ b/doc/source/history.rst @@ -11,7 +11,7 @@ This project fixes these limitations, with example codes, tests, and pypi integr Refactor ^^^^^^^^ -The original wexpect was a monolite, one-file code, with several structural weaknesses. This leads +The original wexpect was a monolith, one-file code, with several structural weaknesses. This leads me to rewrite the whole code. The first variant of the new structure is delivered with `v3.2.0 `_. (The default is the old variant (:code:`legacy_wexpect`) in v3.2.0. :code:`WEXPECT_SPAWN_CLASS` environment variable can choose the @@ -26,7 +26,7 @@ Generally, wexpect (both old and new) has three processes: - *host* is our original python script/program, which want to launch the child. - *console* is a process which started by the host, and launches the child. (This is a python script) - - *child* is the process which want to be launced. + - *child* is the process which want to be launched. The child and the console has a common Windows console, distict from the host. diff --git a/wexpect/console_reader.py b/wexpect/console_reader.py index 5dea8f8..781b657 100644 --- a/wexpect/console_reader.py +++ b/wexpect/console_reader.py @@ -27,6 +27,7 @@ import socket from .wexpect_util import init_logger from .wexpect_util import EOF_CHAR from .wexpect_util import SIGNAL_CHARS +from .wexpect_util import TIMEOUT # # System-wide constants @@ -74,6 +75,8 @@ class ConsoleReaderBase: self.child_process = None self.child_pid = None self.enable_signal_chars = True + self.timeout = 30 + self.child_exitstatus = None logger.info(f'ConsoleReader started. location {os.path.abspath(__file__)}') @@ -504,17 +507,32 @@ class ConsoleReaderSocket(ConsoleReaderBase): class ConsoleReaderPipe(ConsoleReaderBase): - def create_connection(self, **kwargs): + def create_connection(self, timeout=-1, **kwargs): + if timeout == -1: + timeout = self.timeout + if timeout is None: + end_time = float('inf') + else: + end_time = time.time() + timeout + pipe_name = 'wexpect_{}'.format(self.console_pid) pipe_full_path = r'\\.\pipe\{}'.format(pipe_name) logger.info('Start pipe server: %s', pipe_full_path) self.pipe = win32pipe.CreateNamedPipe( pipe_full_path, win32pipe.PIPE_ACCESS_DUPLEX, - win32pipe.PIPE_TYPE_MESSAGE | win32pipe.PIPE_READMODE_MESSAGE | win32pipe.PIPE_WAIT, - 1, 65536, 65536, 0, None) + win32pipe.PIPE_TYPE_MESSAGE | win32pipe.PIPE_READMODE_MESSAGE | win32pipe.PIPE_NOWAIT, + 1, 65536, 65536, 10000, None) logger.info("waiting for client") - win32pipe.ConnectNamedPipe(self.pipe, None) + while True: + if end_time < time.time(): + raise TIMEOUT('Connect to child has been timed out.') + try: + win32pipe.ConnectNamedPipe(self.pipe, None) + break + except Exception as e: + logger.debug(e) + time.sleep(0.2) logger.info('got client') def close_connection(self): diff --git a/wexpect/host.py b/wexpect/host.py index 4997d5c..f512269 100644 --- a/wexpect/host.py +++ b/wexpect/host.py @@ -881,11 +881,20 @@ class SpawnPipe(SpawnBase): # seconds. self.delayafterterminate = 2 - def connect_to_child(self): + def connect_to_child(self, timeout=-1): + if timeout == -1: + timeout = self.timeout + if timeout is None: + end_time = float('inf') + else: + end_time = time.time() + timeout + pipe_name = 'wexpect_{}'.format(self.console_pid) pipe_full_path = r'\\.\pipe\{}'.format(pipe_name) logger.debug(f'Trying to connect to pipe: {pipe_full_path}') while True: + if end_time < time.time(): + raise TIMEOUT('Connect to child has been timed out.') try: self.pipe = win32file.CreateFile( pipe_full_path,