mirror of
				https://github.com/clearml/wexpect-venv
				synced 2025-06-26 18:15:52 +00:00 
			
		
		
		
	Fix blocking pipe connection
The console application could be run forever in case of connection errors
This commit is contained in:
		
							parent
							
								
									290ceebc2d
								
							
						
					
					
						commit
						c8977d8460
					
				@ -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 <https://pypi.org/project/wexpect/3.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.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -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):
 | 
			
		||||
 | 
			
		||||
@ -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,
 | 
			
		||||
 | 
			
		||||
		Loading…
	
		Reference in New Issue
	
	Block a user