0

Here is an example code of a slow application. (Imagine the boot of a Linux) This is the DUT, which should be controlled.

#linux.py

import time

print('Loading kernel ......')
time.sleep(0.5)
print('Loading foo  [  OK  ]')
time.sleep(0.5)
print('Loading bar  [  OK  ]')
time.sleep(0.5)
input('login> ')

I want to control via pexpect python script like the following.

# controller.py

import pexpect
import sys

pybin = sys.executable

command = pybin + ' linux.py' 

p = pexpect.spawn(command)
p.expect('> ', timeout = 5)
print(p.before.decode(), end='')
print(p.match.group(0).decode())
p.sendline('')

It is OK, but I cannot get the console's output of the "Linux.py's" boot before total boot-up. I mean, I didn't get feedback before the login prompt. Imagine, there is an error during the boot-up. The script above will fail with timeout exception.

My GOAL

To monitor the child process and print it's output while waiting to prompt. How can it be done?

betontalpfa
  • 3,454
  • 1
  • 33
  • 65

1 Answers1

0

Solution 1

I found an easy way based on this question

# controller.py

import pexpect
import sys

pybin = sys.executable

command = pybin + ' linux.py' 

p = pexpect.spawn(command)
while True:
    # The return value is the index of the matched string
    i=p.expect(['> ', '\n'], timeout = 5)
    print(p.before.decode(), end='')
    print(p.match.group(0).decode(), end='')
    if i==0:
        break
print()
p.sendline('')

The key is to wait on multiple "expected string". Then decide which is the real prompt and which is the line end. This solution works if the error is terminated with a newline character.

Solution 2

Other way is to use small timeout and print the proper chunk of the before string:

# controller.py

import pexpect
import sys

pybin = sys.executable

command = pybin + ' linux.py' 

p = pexpect.spawn(command)
timeout_cnt = 0
print_idx = 0
while True:
    try:
        i=p.expect('> ', timeout = 1)
        # prompt has arrived
        break
    except pexpect.TIMEOUT:
        timeout_cnt += 1
        if timeout_cnt>30:
            # A real timeout has occured
            raise
    finally:        
        print(p.before.decode()[print_idx:], end='')
        print_idx = len(p.before.decode())
print(p.match.group(0).decode(), end='')
print()
p.sendline('')
betontalpfa
  • 3,454
  • 1
  • 33
  • 65