0

I would like to convert a program I wrote from expect to pexpect, but the api is radically different and a lot of the features I know and love from expect I haven't figured out how to use in python.

I wondered if anyone has a way of interacting purely with a user. In expect I use send_user paired with expect_user, this type of sequence is usually triggered by a pattern observed in a spawned process or from special key codes used in an interaction with a spawned process.

I saw this example for send_user, and tried to print a prompt for input followed by the python input() function, but my program locks up.

Here is a code snippet:

import pexpect
import sys

def input_filter(s):
    if s == b'\004': # ctrl-d
        sys.stdout.write(f'\n\rYou pressed ctrl-d, press y to quit.\r\n')
        sys.stdout.flush()
        i = input()
        if i == 'y':
            return b'\r: ok, bye; exit\r'
        else:
            return b''
    else:
        return s

proc = pexpect.spawn('bash --norc')
proc.interact(input_filter=input_filter)
shortcipher3
  • 1,292
  • 9
  • 22
  • whats your real requirement? – pynexj Dec 23 '19 at 02:50
  • While the user is having an interactive session with a process, the user should be about to enter a key code to have an interactive session with my program, eg choose from a menu what they would like the program to do for them. This most likely would trigger a sequence of send/expect with one or more processes. When the command completed they should be returned to the interact of the original process. – shortcipher3 Dec 23 '19 at 03:09
  • If I can get my minimal example to receive the input and make a decision (as in the if statement) then I imagine I can get the rest of my requirement working. – shortcipher3 Dec 23 '19 at 03:13

1 Answers1

2

Calling input() from within the input_filter() does not work. You need to make interact() return and re-enter it as needed.

See the following example:

[STEP 104] # cat interact.py
#!/usr/bin/env python3

import pexpect, sys

got_ctrl_d = False
def input_filter(s):
    global got_ctrl_d

    if s == b'\x04':
        got_ctrl_d = True
        # \x1d (CTRL-]) is the default escape char
        return b'\x1d'
    else:
        return s

proc = pexpect.spawn('bash --norc')

while True:
    got_ctrl_d = False
    proc.interact(input_filter=input_filter)
    if got_ctrl_d:
        sys.stdout.write('\nAre you sure to exit? [y/n] ')
        inp = input()

        if inp == 'y':
            proc.sendline('exit')
            break
        else:
            # press ENTER so we can see the next prompt
            proc.send('\r')
    else:
        break

proc.expect(pexpect.EOF)

Try it:

[STEP 105] # python3 interact.py
bash-5.0#                         <-- press CTRL-D
Are you sure to exit? [y/n] n     <-- input 'n' and press ENTER

bash-5.0#                         <-- press CTRL-D
Are you sure to exit? [y/n] y     <-- input 'y' and press ENTER
[STEP 106] #
pynexj
  • 19,215
  • 5
  • 38
  • 56