def test_console_starts(): """test that `ipython console` starts a terminal""" from IPython.external import pexpect args = ['console', '--colors=NoColor'] # FIXME: remove workaround for 2.6 support if sys.version_info[:2] > (2,6): args = ['-m', 'IPython'] + args cmd = sys.executable else: cmd = 'ipython' try: p = pexpect.spawn(cmd, args=args) except IOError: raise SkipTest("Couldn't find command %s" % cmd) idx = p.expect([r'In \[\d+\]', pexpect.EOF], timeout=15) nt.assert_equal(idx, 0, "expected in prompt") p.sendline('5') idx = p.expect([r'Out\[\d+\]: 5', pexpect.EOF], timeout=5) nt.assert_equal(idx, 0, "expected out prompt") idx = p.expect([r'In \[\d+\]', pexpect.EOF], timeout=5) nt.assert_equal(idx, 0, "expected second in prompt") # send ctrl-D;ctrl-D to exit p.sendeof() p.sendeof() p.expect([pexpect.EOF, pexpect.TIMEOUT], timeout=5) if p.isalive(): p.terminate()
def test_console_starts(): """test that `ipython console` starts a terminal""" from IPython.external import pexpect # weird IOErrors prevent this from firing sometimes: ipython_cmd = None for i in range(5): try: ipython_cmd = find_cmd('ipython3' if py3compat.PY3 else 'ipython') except IOError: time.sleep(0.1) else: break if ipython_cmd is None: raise SkipTest("Could not determine ipython command") p = pexpect.spawn(ipython_cmd, args=['console', '--colors=NoColor']) idx = p.expect([r'In \[\d+\]', pexpect.EOF], timeout=15) nt.assert_equals(idx, 0, "expected in prompt") p.sendline('5') idx = p.expect([r'Out\[\d+\]: 5', pexpect.EOF], timeout=5) nt.assert_equals(idx, 0, "expected out prompt") idx = p.expect([r'In \[\d+\]', pexpect.EOF], timeout=5) nt.assert_equals(idx, 0, "expected second in prompt") # send ctrl-D;ctrl-D to exit p.sendeof() p.sendeof() p.expect([pexpect.EOF, pexpect.TIMEOUT], timeout=5) if p.isalive(): p.terminate()
def test_console_starts(): """test that `ipython console` starts a terminal""" from IPython.external import pexpect args = ['console', '--colors=NoColor'] # FIXME: remove workaround for 2.6 support if sys.version_info[:2] > (2, 6): args = ['-m', 'IPython'] + args cmd = sys.executable else: cmd = 'ipython' try: p = pexpect.spawn(cmd, args=args) except IOError: raise SkipTest("Couldn't find command %s" % cmd) # timeout after one minute t = 60 idx = p.expect([r'In \[\d+\]', pexpect.EOF], timeout=t) p.sendline('5') idx = p.expect([r'Out\[\d+\]: 5', pexpect.EOF], timeout=t) idx = p.expect([r'In \[\d+\]', pexpect.EOF], timeout=t) # send ctrl-D;ctrl-D to exit p.sendeof() p.sendeof() p.expect([pexpect.EOF, pexpect.TIMEOUT], timeout=t) if p.isalive(): p.terminate()
def test_console_starts(): """test that `ipython console` starts a terminal""" from IPython.external import pexpect # weird IOErrors prevent this from firing sometimes: ipython_cmd = None for i in range(5): try: ipython_cmd = find_cmd('ipython3' if py3compat.PY3 else 'ipython') except IOError: time.sleep(0.1) else: break if ipython_cmd is None: raise SkipTest("Could not determine ipython command") p = pexpect.spawn(ipython_cmd, args=['console', '--colors=NoColor']) idx = p.expect([r'In \[\d+\]', pexpect.EOF], timeout=15) nt.assert_equal(idx, 0, "expected in prompt") p.sendline('5') idx = p.expect([r'Out\[\d+\]: 5', pexpect.EOF], timeout=5) nt.assert_equal(idx, 0, "expected out prompt") idx = p.expect([r'In \[\d+\]', pexpect.EOF], timeout=5) nt.assert_equal(idx, 0, "expected second in prompt") # send ctrl-D;ctrl-D to exit p.sendeof() p.sendeof() p.expect([pexpect.EOF, pexpect.TIMEOUT], timeout=5) if p.isalive(): p.terminate()
def __init__(self, program, prompts, args=None, out=sys.stdout, echo=True): """Construct a runner. Inputs: - program: command to execute the given program. - prompts: a list of patterns to match as valid prompts, in the format used by pexpect. This basically means that it can be either a string (to be compiled as a regular expression) or a list of such (it must be a true list, as pexpect does type checks). If more than one prompt is given, the first is treated as the main program prompt and the others as 'continuation' prompts, like python's. This means that blank lines in the input source are ommitted when the first prompt is matched, but are NOT ommitted when the continuation one matches, since this is how python signals the end of multiline input interactively. Optional inputs: - args(None): optional list of strings to pass as arguments to the child program. - out(sys.stdout): if given, an output stream to be used when writing output. The only requirement is that it must have a .write() method. Public members not parameterized in the constructor: - delaybeforesend(0): Newer versions of pexpect have a delay before sending each new input. For our purposes here, it's typically best to just set this to zero, but if you encounter reliability problems or want an interactive run to pause briefly at each prompt, just increase this value (it is measured in seconds). Note that this variable is not honored at all by older versions of pexpect. """ self.program = program self.prompts = prompts if args is None: args = [] self.args = args self.out = out self.echo = echo # Other public members which we don't make as parameters, but which # users may occasionally want to tweak self.delaybeforesend = 0 # Create child process and hold on to it so we don't have to re-create # for every single execution call c = self.child = pexpect.spawn(self.program, self.args, timeout=None) c.delaybeforesend = self.delaybeforesend # pexpect hard-codes the terminal size as (24,80) (rows,columns). # This causes problems because any line longer than 80 characters gets # completely overwrapped on the printed outptut (even though # internally the code runs fine). We reset this to 99 rows X 200 # columns (arbitrarily chosen), which should avoid problems in all # reasonable cases. c.setwinsize(99, 200)
def start_console(): "Start `ipython console` using pexpect" from IPython.external import pexpect args = ['-m', 'IPython', 'console', '--colors=NoColor'] cmd = sys.executable try: p = pexpect.spawn(cmd, args=args) except IOError: raise SkipTest("Couldn't find command %s" % cmd) # timeout after one minute t = 60 idx = p.expect([r'In \[\d+\]', pexpect.EOF], timeout=t) return p, pexpect, t
def _try_passwordless_openssh(server, keyfile): """Try passwordless login with shell ssh command.""" if pexpect is None: raise ImportError("pexpect unavailable, use paramiko") cmd = 'ssh -f '+ server if keyfile: cmd += ' -i ' + keyfile cmd += ' exit' p = pexpect.spawn(cmd) while True: try: p.expect('[Pp]assword:', timeout=.1) except pexpect.TIMEOUT: continue except pexpect.EOF: return True else: return False
def _try_passwordless_openssh(server, keyfile): """Try passwordless login with shell ssh command.""" if pexpect is None: raise ImportError("pexpect unavailable, use paramiko") cmd = 'ssh -f '+ server if keyfile: cmd += ' -i ' + keyfile cmd += ' exit' p = pexpect.spawn(cmd) while True: try: p.expect('[Ppassword]:', timeout=.1) except pexpect.TIMEOUT: continue except pexpect.EOF: return True else: return False
def start_console(): "Start `ipython console` using pexpect" from IPython.external import pexpect args = ['console', '--colors=NoColor'] # FIXME: remove workaround for 2.6 support if sys.version_info[:2] > (2, 6): args = ['-m', 'IPython'] + args cmd = sys.executable else: cmd = 'ipython' try: p = pexpect.spawn(cmd, args=args) except IOError: raise SkipTest("Couldn't find command %s" % cmd) # timeout after one minute t = 60 idx = p.expect([r'In \[\d+\]', pexpect.EOF], timeout=t) return p, pexpect, t
def test_autoindent_recovery_after_EOF(self): ip = get_ipython() args = ['console', '--colors=NoColor'] # FIXME: remove workaround for 2.6 support if sys.version_info[:2] > (2,6): args = ['-m', 'IPython'] + args cmd = sys.executable else: cmd = 'ipython' t = 20 p = pexpect.spawn(cmd, args=args) p.expect([r'In \[\d+\]', pexpect.EOF], timeout=t) p.sendeof() # say 'no' at the quit prompt p.sendline('n') p.expect([r'In \[\d+\]', pexpect.EOF], timeout=t) p.sendline('for x in range(2):') p.sendline('print(x)') p.sendline('') # check that the code executed and not an indent error p.expect([r'0\s+1'], timeout=t) if p.isalive(): p.terminate()
def openssh_tunnel(self, lport, rport, server, remoteip='127.0.0.1', keyfile=None, password=None, timeout=0.4): if pexpect is None: raise ImportError("pexpect unavailable, use paramiko_tunnel") ssh="ssh " if keyfile: ssh += "-i " + keyfile if ':' in server: server, port = server.split(':') ssh += " -p %s" % port cmd = "%s -O check %s" % (ssh, server) (output, exitstatus) = pexpect.run(cmd, withexitstatus=True) if not exitstatus: pid = int(output[output.find("(pid=")+5:output.find(")")]) cmd = "%s -O forward -L 127.0.0.1:%i:%s:%i %s" % ( ssh, lport, remoteip, rport, server) (output, exitstatus) = pexpect.run(cmd, withexitstatus=True) if not exitstatus: atexit.register(_stop_tunnel, cmd.replace("-O forward", "-O cancel", 1)) return pid cmd = "%s -f -S none -L 127.0.0.1:%i:%s:%i %s sleep %i" % ( ssh, lport, remoteip, rport, server, timeout) # pop SSH_ASKPASS from env env = os.environ.copy() env.pop('SSH_ASKPASS', None) ssh_newkey = 'Are you sure you want to continue connecting' tunnel = pexpect.spawn(cmd, env=env) failed = False while True: try: i = tunnel.expect([ssh_newkey, '[Pp]assword:'], timeout=.1) if i==0: host = server.split('@')[-1] question = ("The authenticity of host <b>%s</b> can't be " "established. Are you sure you want to continue " "connecting?") % host reply = _gui.QMessageBox.question(self, 'Warning', question, _gui.QMessageBox.Yes | _gui.QMessageBox.No, _gui.QMessageBox.No) if reply == _gui.QMessageBox.Yes: tunnel.sendline('yes') continue else: tunnel.sendline('no') raise RuntimeError("The authenticity of the host can't be established") if i==1 and password is not None: tunnel.sendline(password) except pexpect.TIMEOUT: continue except pexpect.EOF: if tunnel.exitstatus: raise RuntimeError("Tunnel '%s' failed to start"%cmd) else: return tunnel.pid else: if failed or password is None: raise RuntimeError("Could not connect to remote host") # TODO: Use this block when pyzmq bug #620 is fixed # # Prompt a passphrase dialog to the user for a second attempt # password, ok = QInputDialog.getText(self, _('Password'), # _('Enter password for: ') + server, # echo=QLineEdit.Password) # if ok is False: # raise RuntimeError('Could not connect to remote host.') tunnel.sendline(password) failed = True
def openssh_tunnel(lport, rport, server, remoteip='127.0.0.1', keyfile=None, password=None, timeout=60): """Create an ssh tunnel using command-line ssh that connects port lport on this machine to localhost:rport on server. The tunnel will automatically close when not in use, remaining open for a minimum of timeout seconds for an initial connection. This creates a tunnel redirecting `localhost:lport` to `remoteip:rport`, as seen from `server`. keyfile and password may be specified, but ssh config is checked for defaults. Parameters ---------- lport : int local port for connecting to the tunnel from this machine. rport : int port on the remote machine to connect to. server : str The ssh server to connect to. The full ssh server string will be parsed. user@server:port remoteip : str [Default: 127.0.0.1] The remote ip, specifying the destination of the tunnel. Default is localhost, which means that the tunnel would redirect localhost:lport on this machine to localhost:rport on the *server*. keyfile : str; path to public key file This specifies a key to be used in ssh login, default None. Regular default ssh keys will be used without specifying this argument. password : str; Your ssh password to the ssh server. Note that if this is left None, you will be prompted for it if passwordless key based login is unavailable. timeout : int [default: 60] The time (in seconds) after which no activity will result in the tunnel closing. This prevents orphaned tunnels from running forever. """ if pexpect is None: raise ImportError("pexpect unavailable, use paramiko_tunnel") ssh="ssh " if keyfile: ssh += "-i " + keyfile if ':' in server: server, port = server.split(':') ssh += " -p %s" % port cmd = "%s -f -S none -L 127.0.0.1:%i:%s:%i %s sleep %i" % ( ssh, lport, remoteip, rport, server, timeout) tunnel = pexpect.spawn(cmd) failed = False while True: try: tunnel.expect('[Pp]assword:', timeout=.1) except pexpect.TIMEOUT: continue except pexpect.EOF: if tunnel.exitstatus: print (tunnel.exitstatus) print (tunnel.before) print (tunnel.after) raise RuntimeError("tunnel '%s' failed to start" % cmd) else: return tunnel.pid else: if failed: print("Password rejected, try again") password=None if password is None: password = getpass("%s's password: " % server) tunnel.sendline(password) failed = True
def system(self, cmd): """Execute a command in a subshell. Parameters ---------- cmd : str A command to be executed in the system shell. Returns ------- int : child's exitstatus """ # Get likely encoding for the output. enc = DEFAULT_ENCODING # Patterns to match on the output, for pexpect. We read input and # allow either a short timeout or EOF patterns = [pexpect.TIMEOUT, pexpect.EOF] # the index of the EOF pattern in the list. # even though we know it's 1, this call means we don't have to worry if # we change the above list, and forget to change this value: EOF_index = patterns.index(pexpect.EOF) # The size of the output stored so far in the process output buffer. # Since pexpect only appends to this buffer, each time we print we # record how far we've printed, so that next time we only print *new* # content from the buffer. out_size = 0 try: # Since we're not really searching the buffer for text patterns, we # can set pexpect's search window to be tiny and it won't matter. # We only search for the 'patterns' timeout or EOF, which aren't in # the text itself. #child = pexpect.spawn(pcmd, searchwindowsize=1) if hasattr(pexpect, 'spawnb'): child = pexpect.spawnb(self.sh, args=['-c', cmd]) # Pexpect-U else: child = pexpect.spawn(self.sh, args=['-c', cmd]) # Vanilla Pexpect flush = sys.stdout.flush while True: # res is the index of the pattern that caused the match, so we # know whether we've finished (if we matched EOF) or not res_idx = child.expect_list(patterns, self.read_timeout) print(child.before[out_size:].decode(enc, 'replace'), end='') flush() if res_idx==EOF_index: break # Update the pointer to what we've already printed out_size = len(child.before) except KeyboardInterrupt: # We need to send ^C to the process. The ascii code for '^C' is 3 # (the character is known as ETX for 'End of Text', see # curses.ascii.ETX). child.sendline(chr(3)) # Read and print any more output the program might produce on its # way out. try: out_size = len(child.before) child.expect_list(patterns, self.terminate_timeout) print(child.before[out_size:].decode(enc, 'replace'), end='') sys.stdout.flush() except KeyboardInterrupt: # Impatient users tend to type it multiple times pass finally: # Ensure the subprocess really is terminated child.terminate(force=True) # add isalive check, to ensure exitstatus is set: child.isalive() return child.exitstatus
def test_nest_embed(): """test that `IPython.embed()` is nestable""" from IPython.external import pexpect ipy_prompt = r']:' #ansi color codes give problems matching beyond this child = pexpect.spawn('%s -m IPython'%(sys.executable, )) child.expect(ipy_prompt) child.sendline("from __future__ import print_function") child.expect(ipy_prompt) child.sendline("import IPython") child.expect(ipy_prompt) child.sendline("ip0 = get_ipython()") #enter first nested embed child.sendline("IPython.embed()") #skip the banner until we get to a prompt try: prompted = -1 while prompted != 0: prompted = child.expect([ipy_prompt, '\r\n']) except pexpect.TIMEOUT as e: print(e) #child.interact() child.sendline("embed1 = get_ipython()"); child.expect(ipy_prompt) child.sendline("print('true' if embed1 is not ip0 else 'false')") assert(child.expect(['true\r\n', 'false\r\n']) == 0) child.expect(ipy_prompt) child.sendline("print('true' if IPython.get_ipython() is embed1 else 'false')") assert(child.expect(['true\r\n', 'false\r\n']) == 0) child.expect(ipy_prompt) #enter second nested embed child.sendline("IPython.embed()") #skip the banner until we get to a prompt try: prompted = -1 while prompted != 0: prompted = child.expect([ipy_prompt, '\r\n']) except pexpect.TIMEOUT as e: print(e) #child.interact() child.sendline("embed2 = get_ipython()"); child.expect(ipy_prompt) child.sendline("print('true' if embed2 is not embed1 else 'false')") assert(child.expect(['true\r\n', 'false\r\n']) == 0) child.expect(ipy_prompt) child.sendline("print('true' if embed2 is IPython.get_ipython() else 'false')") assert(child.expect(['true\r\n', 'false\r\n']) == 0) child.expect(ipy_prompt) child.sendline('exit') #back at first embed child.expect(ipy_prompt) child.sendline("print('true' if get_ipython() is embed1 else 'false')") assert(child.expect(['true\r\n', 'false\r\n']) == 0) child.expect(ipy_prompt) child.sendline("print('true' if IPython.get_ipython() is embed1 else 'false')") assert(child.expect(['true\r\n', 'false\r\n']) == 0) child.expect(ipy_prompt) child.sendline('exit') #back at launching scope child.expect(ipy_prompt) child.sendline("print('true' if get_ipython() is ip0 else 'false')") assert(child.expect(['true\r\n', 'false\r\n']) == 0) child.expect(ipy_prompt) child.sendline("print('true' if IPython.get_ipython() is ip0 else 'false')") assert(child.expect(['true\r\n', 'false\r\n']) == 0) child.expect(ipy_prompt)
def openssh_tunnel(lport, rport, server, remoteip='127.0.0.1', keyfile=None, password=None, timeout=15): """Create an ssh tunnel using command-line ssh that connects port lport on this machine to localhost:rport on server. The tunnel will automatically close when not in use, remaining open for a minimum of timeout seconds for an initial connection. This creates a tunnel redirecting `localhost:lport` to `remoteip:rport`, as seen from `server`. keyfile and password may be specified, but ssh config is checked for defaults. Parameters ---------- lport : int local port for connecting to the tunnel from this machine. rport : int port on the remote machine to connect to. server : str The ssh server to connect to. The full ssh server string will be parsed. user@server:port remoteip : str [Default: 127.0.0.1] The remote ip, specifying the destination of the tunnel. Default is localhost, which means that the tunnel would redirect localhost:lport on this machine to localhost:rport on the *server*. keyfile : str; path to public key file This specifies a key to be used in ssh login, default None. Regular default ssh keys will be used without specifying this argument. password : str; Your ssh password to the ssh server. Note that if this is left None, you will be prompted for it if passwordless key based login is unavailable. """ if pexpect is None: raise ImportError("pexpect unavailable, use paramiko_tunnel") ssh="ssh " if keyfile: ssh += "-i " + keyfile cmd = ssh + " -f -L 127.0.0.1:%i:%s:%i %s sleep %i"%(lport, remoteip, rport, server, timeout) tunnel = pexpect.spawn(cmd) failed = False while True: try: tunnel.expect('[Pp]assword:', timeout=.1) except pexpect.TIMEOUT: continue except pexpect.EOF: if tunnel.exitstatus: print (tunnel.exitstatus) print (tunnel.before) print (tunnel.after) raise RuntimeError("tunnel '%s' failed to start"%(cmd)) else: return tunnel.pid else: if failed: print("Password rejected, try again") password=None if password is None: password = getpass("%s's password: "%(server)) tunnel.sendline(password) failed = True
def system(self, cmd): """Execute a command in a subshell. Parameters ---------- cmd : str A command to be executed in the system shell. Returns ------- int : child's exitstatus """ # Get likely encoding for the output. enc = text.getdefaultencoding() pcmd = self._make_cmd(cmd) # Patterns to match on the output, for pexpect. We read input and # allow either a short timeout or EOF patterns = [pexpect.TIMEOUT, pexpect.EOF] # the index of the EOF pattern in the list. EOF_index = 1 # Fix this index if you change the list!! # The size of the output stored so far in the process output buffer. # Since pexpect only appends to this buffer, each time we print we # record how far we've printed, so that next time we only print *new* # content from the buffer. out_size = 0 try: # Since we're not really searching the buffer for text patterns, we # can set pexpect's search window to be tiny and it won't matter. # We only search for the 'patterns' timeout or EOF, which aren't in # the text itself. #child = pexpect.spawn(pcmd, searchwindowsize=1) child = pexpect.spawn(pcmd) flush = sys.stdout.flush while True: # res is the index of the pattern that caused the match, so we # know whether we've finished (if we matched EOF) or not res_idx = child.expect_list(patterns, self.read_timeout) print(child.before[out_size:].decode(enc, 'replace'), end='') flush() if res_idx==EOF_index: break # Update the pointer to what we've already printed out_size = len(child.before) except KeyboardInterrupt: # We need to send ^C to the process. The ascii code for '^C' is 3 # (the character is known as ETX for 'End of Text', see # curses.ascii.ETX). child.sendline(chr(3)) # Read and print any more output the program might produce on its # way out. try: out_size = len(child.before) child.expect_list(patterns, self.terminate_timeout) print(child.before[out_size:].decode(enc, 'replace'), end='') sys.stdout.flush() except KeyboardInterrupt: # Impatient users tend to type it multiple times pass finally: # Ensure the subprocess really is terminated child.terminate(force=True) return child.exitstatus
def system(self, cmd): """Execute a command in a subshell. Parameters ---------- cmd : str A command to be executed in the system shell. Returns ------- int : child's exitstatus """ # Get likely encoding for the output. enc = text.getdefaultencoding() pcmd = self._make_cmd(cmd) # Patterns to match on the output, for pexpect. We read input and # allow either a short timeout or EOF patterns = [pexpect.TIMEOUT, pexpect.EOF] # the index of the EOF pattern in the list. EOF_index = 1 # Fix this index if you change the list!! # The size of the output stored so far in the process output buffer. # Since pexpect only appends to this buffer, each time we print we # record how far we've printed, so that next time we only print *new* # content from the buffer. out_size = 0 try: # Since we're not really searching the buffer for text patterns, we # can set pexpect's search window to be tiny and it won't matter. # We only search for the 'patterns' timeout or EOF, which aren't in # the text itself. #child = pexpect.spawn(pcmd, searchwindowsize=1) child = pexpect.spawn(pcmd) flush = sys.stdout.flush while True: # res is the index of the pattern that caused the match, so we # know whether we've finished (if we matched EOF) or not res_idx = child.expect_list(patterns, self.read_timeout) print(child.before[out_size:].decode(enc, 'replace'), end='') flush() if res_idx == EOF_index: break # Update the pointer to what we've already printed out_size = len(child.before) except KeyboardInterrupt: # We need to send ^C to the process. The ascii code for '^C' is 3 # (the character is known as ETX for 'End of Text', see # curses.ascii.ETX). child.sendline(chr(3)) # Read and print any more output the program might produce on its # way out. try: out_size = len(child.before) child.expect_list(patterns, self.terminate_timeout) print(child.before[out_size:].decode(enc, 'replace'), end='') sys.stdout.flush() except KeyboardInterrupt: # Impatient users tend to type it multiple times pass finally: # Ensure the subprocess really is terminated child.terminate(force=True) return child.exitstatus
def system(self, cmd): """Execute a command in a subshell. Parameters ---------- cmd : str A command to be executed in the system shell. Returns ------- int : child's exitstatus """ # Get likely encoding for the output. enc = DEFAULT_ENCODING # Patterns to match on the output, for pexpect. We read input and # allow either a short timeout or EOF patterns = [pexpect.TIMEOUT, pexpect.EOF] # the index of the EOF pattern in the list. # even though we know it's 1, this call means we don't have to worry if # we change the above list, and forget to change this value: EOF_index = patterns.index(pexpect.EOF) # The size of the output stored so far in the process output buffer. # Since pexpect only appends to this buffer, each time we print we # record how far we've printed, so that next time we only print *new* # content from the buffer. out_size = 0 try: # Since we're not really searching the buffer for text patterns, we # can set pexpect's search window to be tiny and it won't matter. # We only search for the 'patterns' timeout or EOF, which aren't in # the text itself. #child = pexpect.spawn(pcmd, searchwindowsize=1) if hasattr(pexpect, 'spawnb'): child = pexpect.spawnb(self.sh, args=['-c', cmd]) # Pexpect-U else: child = pexpect.spawn(self.sh, args=['-c', cmd]) # Vanilla Pexpect flush = sys.stdout.flush while True: # res is the index of the pattern that caused the match, so we # know whether we've finished (if we matched EOF) or not res_idx = child.expect_list(patterns, self.read_timeout) print(child.before[out_size:].decode(enc, 'replace'), end='') flush() if res_idx == EOF_index: break # Update the pointer to what we've already printed out_size = len(child.before) except KeyboardInterrupt: # We need to send ^C to the process. The ascii code for '^C' is 3 # (the character is known as ETX for 'End of Text', see # curses.ascii.ETX). child.sendline(chr(3)) # Read and print any more output the program might produce on its # way out. try: out_size = len(child.before) child.expect_list(patterns, self.terminate_timeout) print(child.before[out_size:].decode(enc, 'replace'), end='') sys.stdout.flush() except KeyboardInterrupt: # Impatient users tend to type it multiple times pass finally: # Ensure the subprocess really is terminated child.terminate(force=True) # add isalive check, to ensure exitstatus is set: child.isalive() return child.exitstatus
def test_nest_embed(): """test that `IPython.embed()` is nestable""" from IPython.external import pexpect ipy_prompt = r']:' #ansi color codes give problems matching beyond this child = pexpect.spawn('%s -m IPython' % (sys.executable, )) child.expect(ipy_prompt) child.sendline("from __future__ import print_function") child.expect(ipy_prompt) child.sendline("import IPython") child.expect(ipy_prompt) child.sendline("ip0 = get_ipython()") #enter first nested embed child.sendline("IPython.embed()") #skip the banner until we get to a prompt try: prompted = -1 while prompted != 0: prompted = child.expect([ipy_prompt, '\r\n']) except pexpect.TIMEOUT as e: print(e) #child.interact() child.sendline("embed1 = get_ipython()") child.expect(ipy_prompt) child.sendline("print('true' if embed1 is not ip0 else 'false')") assert (child.expect(['true\r\n', 'false\r\n']) == 0) child.expect(ipy_prompt) child.sendline( "print('true' if IPython.get_ipython() is embed1 else 'false')") assert (child.expect(['true\r\n', 'false\r\n']) == 0) child.expect(ipy_prompt) #enter second nested embed child.sendline("IPython.embed()") #skip the banner until we get to a prompt try: prompted = -1 while prompted != 0: prompted = child.expect([ipy_prompt, '\r\n']) except pexpect.TIMEOUT as e: print(e) #child.interact() child.sendline("embed2 = get_ipython()") child.expect(ipy_prompt) child.sendline("print('true' if embed2 is not embed1 else 'false')") assert (child.expect(['true\r\n', 'false\r\n']) == 0) child.expect(ipy_prompt) child.sendline( "print('true' if embed2 is IPython.get_ipython() else 'false')") assert (child.expect(['true\r\n', 'false\r\n']) == 0) child.expect(ipy_prompt) child.sendline('exit') #back at first embed child.expect(ipy_prompt) child.sendline("print('true' if get_ipython() is embed1 else 'false')") assert (child.expect(['true\r\n', 'false\r\n']) == 0) child.expect(ipy_prompt) child.sendline( "print('true' if IPython.get_ipython() is embed1 else 'false')") assert (child.expect(['true\r\n', 'false\r\n']) == 0) child.expect(ipy_prompt) child.sendline('exit') #back at launching scope child.expect(ipy_prompt) child.sendline("print('true' if get_ipython() is ip0 else 'false')") assert (child.expect(['true\r\n', 'false\r\n']) == 0) child.expect(ipy_prompt) child.sendline( "print('true' if IPython.get_ipython() is ip0 else 'false')") assert (child.expect(['true\r\n', 'false\r\n']) == 0) child.expect(ipy_prompt)