A Python module for controlling interactive programs in a pseudo-terminal

Overview
Build status

Pexpect is a Pure Python Expect-like module

Pexpect makes Python a better tool for controlling other applications.

Pexpect is a pure Python module for spawning child applications; controlling them; and responding to expected patterns in their output. Pexpect works like Don Libes' Expect. Pexpect allows your script to spawn a child application and control it as if a human were typing commands.

Pexpect can be used for automating interactive applications such as ssh, ftp, passwd, telnet, etc. It can be used to automate setup scripts for duplicating software package installations on different servers. It can be used for automated software testing. Pexpect is in the spirit of Don Libes' Expect, but Pexpect is pure Python.

The main features of Pexpect require the pty module in the Python standard library, which is only available on Unix-like systems. Some features—waiting for patterns from file descriptors or subprocesses—are also available on Windows.

If you want to work with the development version of the source code then please read the DEVELOPERS.rst document in the root of the source code tree.

Free, open source, and all that good stuff.

You can install Pexpect using pip:

pip install pexpect

Docs on ReadTheDocs

PEXPECT LICENSE:

http://opensource.org/licenses/isc-license.txt

Copyright (c) 2013-2016, Pexpect development team
Copyright (c) 2012, Noah Spurrier <[email protected]>

PERMISSION TO USE, COPY, MODIFY, AND/OR DISTRIBUTE THIS SOFTWARE FOR ANY
PURPOSE WITH OR WITHOUT FEE IS HEREBY GRANTED, PROVIDED THAT THE ABOVE
COPYRIGHT NOTICE AND THIS PERMISSION NOTICE APPEAR IN ALL COPIES.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.

This license is approved by the OSI and FSF as GPL-compatible.

Comments
  • Windows support

    Windows support

    There are at least two ports of pexpect to Windows APIs:

    We could look at integrating this support into pexpect. Both Chris and Geert have said they'd be willing to help out with some initial work, but I think this would need someone committed to maintaining it and fixing the inevitable problems. I don't really use Windows myself, so I can't give it much support.

    enhancement needs-code 
    opened by takluyver 42
  • select.select() cannot handle more than 1024 open files

    select.select() cannot handle more than 1024 open files

    I have been using pexpect for many months with no problem. However, I recently this line:

    1680 return select.select(iwtd, owtd, ewtd, timeout)

    Has been creating a few problems. The select system call cannot handle more than 1024 file descriptors. On the other hand, the select.poll() system call does not have such limitations.

    I understand that not all platforms support poll() but it would be nice to incorporate this system call as an option.

    enhancement needs-code 
    opened by rediate 23
  • Some update broke pexpect

    Some update broke pexpect

    Up until a few weeks ago pexpect worked just fine.

    My setup: A Raspberry Pi 3B+ updated with the latest Raspbain: 4.19.66-v7+ #1253 SMP Thu Aug 15 11:49:46 BST 2019 armv7l GNU/Linux

    Latest python included with Raspbain: python3/oldstable,now 3.5.3-1 armhf [installed,automatic] Latest pexpect included with Raspbain: python3-pexpect/oldstable,now 4.2.1-1 all [installed]

    Simplified and sanitized version of my code:

    import pexpect

    child = pexpect.spawn('ssh -i /home/pi/.ssh/remote_box -o StrictHostKeyChecking=no -p 22 [email protected]_box ifconfig') child.expect("remote_box': ") child.sendline('secretpassword') child.expect(pexpect.EOF, timeout=20) print (child.before)

    What happens is it sends the ssh command, it then gets two identical prompt lines for the passphrase instead of just one. However pexpect never sends the secretpassword. It just times out.

    Tried many things including: Tried the ssh command line outside of python. - That works fine. The prompt comes back to enter the passphrase for the key. Enter that and you get the ifconfig output and it exits from the remote box. Changed timeout=None - just hangs there forever Changed the child.expect("remote_box': ") line with shorter and longer prompt strings - no change Replaced the child.expect("remote_box': ") line entirely with time.sleep(5) - no change

    What can I try next?

    opened by T-2 22
  • ANSI and screen don't support Unicode

    ANSI and screen don't support Unicode

    It would be nice if the ANSI and screen packages supported Unicode strings, or there were additional packages/classes that did. I only had to change str() to unicode() and add u in front of the quoted strings (and perhaps even some of that wasn't necessary) in screen.pretty() and put_abs() in 345eb58 to get this working quickly for me, but I didn't test all methods.

    If you could suggest your preferred solution, I might be able to implement it and submit a pull request.

    opened by dcoshea 22
  • pexpect on Solaris via cron (/dev/tty issue)

    pexpect on Solaris via cron (/dev/tty issue)

    I am using the pexpect (version 3.1, installed via pip) on OmniOS (Solaris fork), and it works fine on the interactive shell. But when I try to use it via cron it has issues with /dev/tty. I thought this was an issue for Solaris but had been fixed? Specifically, the error is:

    OSError: [Errno 6] No such device or address: '/dev/tty'
    

    Rest of the trace:

    p=pexpect.spawn('ssh -oUserKnownHostsFile=/dev/null -oStrictHostKeyChecking=no %s@%s' % ('root', host), timeout=60)
      File "/usr/lib/python2.6/site-packages/pexpect/__init__.py", line 485, in __init__
        self._spawn(command, args)
      File "/usr/lib/python2.6/site-packages/pexpect/__init__.py", line 607, in _spawn
        self.pid, self.child_fd = self.__fork_pty()
      File "/usr/lib/python2.6/site-packages/pexpect/__init__.py", line 668, in __fork_pty
        self.__pty_make_controlling_tty(child_fd)
      File "/usr/lib/python2.6/site-packages/pexpect/__init__.py", line 722, in __pty_make_controlling_tty
        fd = os.open("/dev/tty", os.O_WRONLY)
    OSError: [Errno 6] No such device or address: '/dev/tty'
    Traceback (most recent call last):
      File "/root/nologify.py", line 25, in <module>
        p.expect('\r\n.+]# ')
      File "/usr/lib/python2.6/site-packages/pexpect/__init__.py", line 1418, in expect
        timeout, searchwindowsize)
      File "/usr/lib/python2.6/site-packages/pexpect/__init__.py", line 1433, in expect_list
        timeout, searchwindowsize)
      File "/usr/lib/python2.6/site-packages/pexpect/__init__.py", line 1521, in expect_loop
        raise EOF(str(err) + '\n' + str(self))
    pexpect.EOF: End of File (EOF). Very slow platform.
    <pexpect.spawn object at 0x8181d6c>
    version: 3.1
    command: /usr/bin/ssh
    args: ['/usr/bin/ssh', '-oUserKnownHostsFile=/dev/null', '-oStrictHostKeyChecking=no', '[email protected]']
    searcher: <pexpect.searcher_re object at 0x8181dec>
    buffer (last 100 chars): ''
    
    bug 
    opened by ksalman 22
  • Restore POSIX support to fdpexpect.

    Restore POSIX support to fdpexpect.

    Factor out uninterruptible select and put the code in utils as select_ignore_interrupts. Modify fdpexpect to use select_ignore_interrupts if os.name is posix. This should restore POSIX support without affecting Windows support.

    needs-changelog 
    opened by MountainRider 19
  • Issue #84: Unicode support in screen and ANSI.

    Issue #84: Unicode support in screen and ANSI.

    Please see the commit message for details.

    I'm not sure if I'm on the right track at all, so I didn't spend a huge amount of time trying to tidy the code, get the comments exactly right, etc. I'm happy to fix that stuff up if I'm on the right track. Apologies if I'm on the completely wrong track!

    The screen and ANSI unit tests pass on Python 2.6, 2.7 and 3.3.

    Some issues I'm aware of which I think are fairly minor:

    It's not 100% clear to me which methods are meant to be public and which are only meant for internal use, so I've tried to perform decoding in all methods that accept input.

    There are some cases (e.g. screen.fill(), fill_region(), put(), insert_abs(), insert()) where decoding is performed by a method that then invokes another method that also potentially performs decoding. I thought that this was safer as it meant that future refactoring wouldn't inadvertently result in decoding not being performed in some code path.

    Use of the incremental decoder from ANSI.write_ch() and screen.put_abs() technically doesn't make sense, since those methods expect to receive exactly one character, and if the caller actually needs an incremental decoder to be used because they don't know where the character boundaries are in the byte stream, they shouldn't be calling those methods. However, I've just used the same incremental decoder in those methods as in all the other ones. I assume those methods probably wouldn't typically be called directly by outside code, and if they were, the user would have to have more of an idea of what they were doing with regards to multi-byte encodings.

    With an incremental decoder, we're meant to call it once at the end with final=True so that any incomplete byte sequence at the end of the stream can be detected. I don't know of a sensible way to do that - perhaps screen() should have a close() method added to it that does this?

    opened by dcoshea 18
  • Pxssh and expect patterns

    Pxssh and expect patterns

    We have tried pexpect, but we have found pxssh to work better is our situation, but we are hitting a wall at one part.

    I am trying to connect to multiple versions of Cisco devices. Some I have to enable, some use a '>' as a prompt and others just go to the '#' prompt. Is there a way that we can create a expect pattern with pxssh as we can with pexpect?

    I would prefer to have one script running rather than having to specify which script to use with which host.

    Thank you

    opened by 123troy 17
  • Read more bytes

    Read more bytes

    Optimize read_nonblocking() in two ways:

    1. When a lot of data is available to read, return all of it. This speeds up callers of read_nonblocking() such as expect_loop() because there are a lot less iterations in the loop.
    2. Only call is_alive() if there is no data ready to read. This avoids a lot of pointless calls to is_alive().

    Downstream: http://trac.sagemath.org/ticket/10295

    enhancement needs-changelog needs-decision 
    opened by jdemeyer 17
  • Cannot install pexpect 4.0 with python 2.7

    Cannot install pexpect 4.0 with python 2.7

    Maybe this is just an docs issue (http://pexpect.readthedocs.org/en/stable/install.html#requirements), however pexpect >=4.0 does not work with python 2.7, because it uses a python 3.3 syntax (yield from). It is not clearly stated in docs and the install fails with a syntax error.

    Installing collected packages: pexpect
      Running setup.py install for pexpect
          File "/home/smido/projects/pexeso-testing-indexer/env/lib/python2.7/site-packages/pexpect/async.py", line 16
            transport, pw = yield from asyncio.get_event_loop()\
                                     ^
        SyntaxError: invalid syntax
    

    https://github.com/pexpect/pexpect/blob/master/pexpect/async.py#L16

    question 
    opened by martinsmid 17
  • pexpect.spawn(logfile=sys.stdout) fails on python3.4, clarify documentation to use sys.stdout.buffer.

    pexpect.spawn(logfile=sys.stdout) fails on python3.4, clarify documentation to use sys.stdout.buffer.

    File "/usr/lib/python3.4/site-packages/pexpect/init.py", line 904, in _log self.logfile.write(s) TypeError: must be str, not bytes

    This contradicts the doc.

    enhancement needs-changelog needs-tests WIP 
    opened by rich-pixley 17
  • pexpect is not printing the loop!

    pexpect is not printing the loop!

    paaword.py is a script where getpass() asked the user about the password and validates it. but i want to automate the whole process and used pexpect for it (main.py). And i am using python3.10

    Problem: But the problem is it not printing loop on the terminal. it running the loop in backend because its print output after sometime.

    password.py

    import warnings
    import getpass
    import time
    
    # Suppress warnings
    warnings.filterwarnings("ignore", category=getpass.GetPassWarning)
    for x in range(10):
        print(f"curnt index {x}")
    time.sleep(5)
    password = getpass.getpass("Enter your password: ")
    if password != "test":
        print("wrong password")
    else:
        print("correct password")
    

    main.py

    import pexpect
    
    child = pexpect.spawn("python password.py")
    
    # wait for the input
    child.expect("Enter your password:")
    
    # send the password to the subprocess
    child.sendline("test")
    
    # Wait for output from the subprocess and print it
    while True:
        try:
            child.expect("\n")
            print(child.before.strip())
            child.expect(pexpect.TIMEOUT, timeout=1)
        except pexpect.EOF:
            break
    
    print(child.before.strip())
    
    

    output:

    Screenshot from 2022-12-30 20-24-07

    opened by samannazz 0
  • refactor(_async.py): introduce modern coroutine syntax

    refactor(_async.py): introduce modern coroutine syntax

    Python 3.5 introduced the await and async def keywords. This change imports the coroutines from two different places, depending on the running Python version.

    This address comments previously put in pull requests:

    • #715
    • #690
    opened by karrukola 1
  • Issues and our ability to handle them

    Issues and our ability to handle them

    @dluyer @jdemeyer @jquast @noahsquaretrade @takluyver I'd like to get the number of open issues down to <20. Can we please discuss what we're happy with to handle issues?

    I'd like to open the github discussions feature and move issues around user questions or help there so we can keep the issues only related to software problems in pexpect in the issues section. This way other users can help each other and we can keep a more clear idea about when other projects find problems or someone wishes to request features.

    I don't like stale bots that auto-close because it feels like a complete lack of responsibility and ownership on problems as you can simply wait out the timer to not answer difficult questions. I am however happy to put this in if other people would prefer to have such a process.

    opened by Red-M 5
  • Add a serial spawn interface

    Add a serial spawn interface

    First contribution to this project. I hope this code is of interest.

    Please, let me know if there is interest on this PR and any improvement I can make to get this merged.

    Thanks.

    opened by antoniovazquezblanco 0
  • when call 'interact' then keyboard input experience is very different from before

    when call 'interact' then keyboard input experience is very different from before

    example when I use bash and input long text looks like:

    [email protected]:~$ aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
    aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
    

    use pexpect run bash and called interact then input long text looks like:

    [email protected]:~$ aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
    

    There is no line wrapping, and removing characters affects the presentation

    • kubuntu 20.04
    • python 3.8.10
    • pexpect 4.6.0
    opened by fawdlstty 1
Releases(4.8.0)
  • 4.8.0(Jan 17, 2020)

    • Returned behavior of searchwindowsize to that in 4.3 and earlier (searches are only done within the search window) (#579).
    • Fixed a bug truncating before attribute after a timeout (#579).
    • Fixed a bug where a search could be less than searchwindowsize if it was increased between calls (#579).
    • Minor test cleanups to improve portability (#580) (#581) (#582) (#583) (#584) (#585).
    • Disable chaining of timeout and EOF exceptions (#606).
    • Allow traceback included snippet length to be configured via str_last_chars rather than always 100 (#598).
    • Python 3 warning added to interact.py (#537).
    • Several doc updates.
    Source code(tar.gz)
    Source code(zip)
  • 4.2(Jul 2, 2016)

    • Change: When an env parameter is specified to the spawn() or run() family of calls containing a value for PATH, its value is used to discover the target executable from a relative path, rather than the current process's environment PATH. This mirrors the behavior of subprocess.Popen in the standard library (PR #348).
    • Regression: Re-introduce capability for method read_nonblocking() in class fdspawn as previously supported in version 3.3 (PR #359).
    Source code(tar.gz)
    Source code(zip)
  • 3.2(Apr 15, 2014)

    • Fix exception handling from select.select() on Python 2 (PR #38). This was accidentally broken in the previous release when it was fixed for Python 3.
    • Removed a workaround for TIOCSWINSZ on very old systems, which was causing issues on some BSD systems (PR #40).
    • Fixed an issue with exception handling in pxssh (PR #43)

    The documentation for pxssh was improved.

    Source code(tar.gz)
    Source code(zip)
    pexpect-3.2.tar.gz(127.99 KB)
  • 3.1(Jan 22, 2014)

    • Fix an issue that prevented importing pexpect on Python 3 when sys.stdout was reassigned (#30).
    • Improve prompt synchronisation in pxssh (PR #28).
    • Fix pickling exception instances (PR #34).
    • Fix handling exceptions from select.select() on Python 3 (PR #33).

    The examples have also been cleaned up somewhat - this will continue in future releases.

    Source code(tar.gz)
    Source code(zip)
    pexpect-3.1.tar.gz(127.33 KB)
  • 3.0(Nov 11, 2013)

    The new major version number doesn't indicate any deliberate API incompatibility. We have endeavoured to avoid breaking existing APIs. However, pexpect is under new maintenance after a long dormancy, so some caution is warranted.

    • A new unicode API was introduced.
    • Python 3 is now supported, using a single codebase.
    • Pexpect now requires at least Python 2.6 or 3.2.
    • The modules other than pexpect, such as pexpect.fdpexpect and pexpect.pxssh, were moved into the pexpect package. For now, wrapper modules are installed to the old locations for backwards compatibility (e.g. import pxssh will still work), but these will be removed at some point in the future.
    • Ignoring SIGHUP is now optional - thanks to Kimmo Parviainen-Jalanko for the patch.

    We also now have docs on ReadTheDocs, and continuous integration on Travis CI.

    Source code(tar.gz)
    Source code(zip)
    pexpect-3.0.tar.gz(143.24 KB)
  • 3.0b1(Oct 2, 2013)

    The new major version number doesn’t indicate any deliberate API incompatibility. We have endeavoured to avoid breaking existing APIs. However, pexpect is under new maintenance after a long dormancy, so some caution is warranted.

    • A new unicode API was introduced.
    • Python 3 is now supported, using a single codebase.
    • Pexpect now requires at least Python 2.6 or 3.2.

    We also now have docs on ReadTheDocs, and continuous integration on Travis CI.

    Source code(tar.gz)
    Source code(zip)
    pexpect-3.0b1.tar.gz(740.67 KB)
Run a subprocess in a pseudo terminal

Launch a subprocess in a pseudo terminal (pty), and interact with both the process and its pty. Sometimes, piping stdin and stdout is not enough. Ther

184 Jan 03, 2023
A Python module for controlling interactive programs in a pseudo-terminal

Pexpect is a Pure Python Expect-like module Pexpect makes Python a better tool for controlling other applications. Pexpect is a pure Python module for

2.3k Dec 26, 2022
Jurigged lets you update your code while it runs.

jurigged Jurigged lets you update your code while it runs. Using it is trivial: python -m jurigged your_script.py Change some function or method with

Olivier Breuleux 767 Dec 28, 2022
Python process launching

sh is a full-fledged subprocess replacement for Python 2.6 - 3.8, PyPy and PyPy3 that allows you to call any program as if it were a function: from sh

Andrew Moffat 6.5k Jan 04, 2023
Supervisor process control system for UNIX

Supervisor Supervisor is a client/server system that allows its users to control a number of processes on UNIX-like operating systems. Supported Platf

Supervisor 7.6k Jan 02, 2023