def __init__(self, fd, args=[], timeout=30, maxread=2000, searchwindowsize=None, logfile=None): """This takes a file descriptor (an int) or an object that support the fileno() method (returning an int). All Python file-like objects support fileno(). """ # TODO: Add better handling of trying to use fdspawn in place of spawn # TODO: (overload to allow fdspawn to also handle commands as spawn does. if not isinstance(fd, int) and hasattr(fd, 'fileno'): fd = fd.fileno() if not isinstance(fd, int): raise ExceptionPexpect( "The fd argument is not an int. If this is a command string then maybe you want to use pexpect.spawn.") try: # make sure fd is a valid file descriptor os.fstat(fd) except OSError: raise ExceptionPexpect("The fd argument is not a valid file descriptor.") self.args = None self.command = None spawn.__init__(self, None, args, timeout, maxread, searchwindowsize, logfile) self.child_fd = fd self.own_fd = False self.closed = False self.name = '<file descriptor %d>' % fd
def _create_named_pipe(template, sids=None): """INTERNAL: create a named pipe.""" if sids is None: sattrs = None else: sattrs = _create_security_attributes(*sids) for i in range(100): name = template % random.randint(0, 999999) try: pipe = CreateNamedPipe(name, PIPE_ACCESS_DUPLEX, 0, 1, 1, 1, 100000, sattrs) SetHandleInformation(pipe, HANDLE_FLAG_INHERIT, 0) except WindowsError as e: if e.winerror != ERROR_PIPE_BUSY: raise else: return pipe, name raise ExceptionPexpect('Could not create pipe after 100 attempts.')
def terminate(self, force=False): # pragma: no cover raise ExceptionPexpect( 'This method is not valid for file descriptors.')
def test_picking(self): e = ExceptionPexpect("Oh noes!") clone = pickle.loads(pickle.dumps(e)) self.assertEqual(e.value, clone.value)
def kill(self, signo): """Send a signal to the child (not available on Windows).""" raise ExceptionPexpect('Signals are not availalbe on Windows')
def _spawn(self, command, args=None): """Start the child process. If args is empty, command will be parsed according to the rules of the MS C runtime, and args will be set to the parsed args.""" if args: args = args[:] # copy args.insert(0, command) else: args = split_command_line(command) command = args[0] self.command = command self.args = args command = which(self.command) if command is None: raise ExceptionPexpect('Command not found: %s' % self.command) args = join_command_line(self.args) # Create the pipes sids = [_get_current_sid()] if self.username and self.password: sids.append(_lookup_sid(self.domain, self.username)) cmd_pipe, cmd_name = _create_named_pipe(self.pipe_template, sids) stdin_pipe, stdin_name = _create_named_pipe(self.pipe_template, sids) stdout_pipe, stdout_name = _create_named_pipe(self.pipe_template, sids) stderr_pipe, stderr_name = _create_named_pipe(self.pipe_template, sids) startupinfo = STARTUPINFO() startupinfo.dwFlags |= STARTF_USESHOWWINDOW startupinfo.wShowWindow = SW_HIDE python = os.path.join(sys.exec_prefix, 'python.exe') pycmd = 'import winpexpect; winpexpect._stub(r"%s", r"%s", r"%s", r"%s")' \ % (cmd_name, stdin_name, stdout_name, stderr_name) pyargs = join_command_line([python, '-c', pycmd]) # Create a new token or run as the current process. if self.username and self.password: token = LogonUser(self.username, self.domain, self.password, LOGON32_LOGON_INTERACTIVE, LOGON32_PROVIDER_DEFAULT) res = CreateProcessAsUser(token, python, pyargs, None, None, False, CREATE_NEW_CONSOLE, self.env, self.cwd, startupinfo) else: token = None res = CreateProcess(python, pyargs, None, None, False, CREATE_NEW_CONSOLE, self.env, self.cwd, startupinfo) child_handle = res[0] res[1].Close() # don't need thread handle ConnectNamedPipe(cmd_pipe) ConnectNamedPipe(stdin_pipe) ConnectNamedPipe(stdout_pipe) ConnectNamedPipe(stderr_pipe) # Tell the stub what to do and wait for it to exit WriteFile(cmd_pipe, 'command=%s\n' % command) WriteFile(cmd_pipe, 'args=%s\n' % args) if token: parent_sid = ConvertSidToStringSid(_get_current_sid()) WriteFile(cmd_pipe, 'parent_sid=%s\n' % str(parent_sid)) WriteFile(cmd_pipe, '\n') header = _read_header(cmd_pipe) output = _parse_header(header) if output['status'] != 'ok': m = 'Child did not start up correctly. ' m += output.get('message', '') raise ExceptionPexpect(m) self.pid = int(output['pid']) self.child_handle = OpenProcess(PROCESS_ALL_ACCESS, False, self.pid) WaitForSingleObject(child_handle, INFINITE) # Start up the I/O threads self.child_fd = open_osfhandle(stdin_pipe.Detach(), 0) # for pexpect self.stdout_handle = stdout_pipe self.stdout_reader = Thread(target=self._child_reader, args=(self.stdout_handle,)) self.stdout_reader.start() self.stderr_handle = stderr_pipe self.stderr_reader = Thread(target=self._child_reader, args=(self.stderr_handle,)) self.stderr_reader.start() self.terminated = False self.closed = False