1

Is there a way to have a timeout when calling IPython.embed() in a python script? Say I have a script that stops for a IPython.embed() at various places, how can I let the script go on with its business when the user doesn't respond in time?

Simon Streicher
  • 2,638
  • 1
  • 26
  • 30
  • Does not seem to be a way to do that with the current APIs. But one tip that might be useful when using it for debugging is the ``%kill_embedded`` macro: if you use it in an ``IPython.embed()``, it will avoid opening another session again. – Elias Dorneles Nov 01 '14 at 22:47
  • Thanks, that is a handy trick, but not quite what I am looking for. – Simon Streicher Nov 01 '14 at 23:13
  • I think I will go with an input timeout solution (`Type 'i/I' to enter IPython mode: \n....1 \n....2 \n....3 \n....4 \n....5 \nSorry too late`) as described here http://stackoverflow.com/questions/1335507/keyboard-input-with-timeout-in-python – Simon Streicher Nov 02 '14 at 08:18

1 Answers1

1

This is not quite an answer to the question, but it is adequate for what I wanted.

I used some cross-platform keypress timeout code from

to let the user decide within a time window if a IPython.embed() should be called:

import time
import IPython

try:
    from msvcrt import kbhit
except ImportError:
    import termios, fcntl, sys, os
    def kbfunc():
        fd = sys.stdin.fileno()
        oldterm = termios.tcgetattr(fd)
        newattr = termios.tcgetattr(fd)
        newattr[3] = newattr[3] & ~termios.ICANON & ~termios.ECHO
        termios.tcsetattr(fd, termios.TCSANOW, newattr)
        oldflags = fcntl.fcntl(fd, fcntl.F_GETFL)
        fcntl.fcntl(fd, fcntl.F_SETFL, oldflags | os.O_NONBLOCK)
        try:
            while True:
                try:
                    c = sys.stdin.read(1)
                    return c.decode()
                except IOError:
                    return False
        finally:
            termios.tcsetattr(fd, termios.TCSAFLUSH, oldterm)
            fcntl.fcntl(fd, fcntl.F_SETFL, oldflags)
else:
    import msvcrt
    def kbfunc():
        #this is boolean for whether the keyboard has bene hit
        x = msvcrt.kbhit()
        if x:
            #getch acquires the character encoded in binary ASCII
            ret = msvcrt.getch()
            return ret.decode()
        else:
            return False

def wait_for_interrupt(waitstr=None, exitstr=None, countdown=True, delay=3):
    if waitstr is not None: print(waitstr)
    for i in range(delay*10):
        if   countdown and i%10 ==0    : print('%d'%(i/10 + 1), end='')
        elif countdown and (i+1)%10 ==0: print('.')
        elif countdown                 : print('.', end='')

        key = kbfunc()
        if key: return key
        time.sleep(0.1)
    if exitstr is not None: print(exitstr)
    return False

if __name__ == "__main__":
    #wait_for_interrupt example test
    if wait_for_interrupt('wait_for_interrupt() Enter something in the next 3 seconds', '... Sorry too late'):
        IPython.embed()

    #begin the counter
    number = 1

    #interrupt a loop
    while True:

        #acquire the keyboard hit if exists
        x = kbfunc() 

        #if we got a keyboard hit
        if x != False and x == 'i':
            #we got the key!
            IPython.embed()
            #break loop
            break
        else:
            #prints the number
            print(number)
            #increment, there's no ++ in python
            number += 1
            #wait half a second
            time.sleep(0.5)
Simon Streicher
  • 2,638
  • 1
  • 26
  • 30
  • I saw an error in my implementation, after the `c = sys.stdin.read(1)` line, if a key such as `F2` is pressed, there are still data left in `stdin`, which triggers any following `wait_for_interrupt()`. How to fix this without introducing unforseen bugs? – Simon Streicher Nov 02 '14 at 21:06
  • And what about the case where `stdin` already have data before `wait_for_interrupt()` is envoked? Is it unreasonable for implementations like this to assume a clean `stdin`, or should a `wait_for_interrupt()` rather be used with a `context_manager` (as a `with` statement) to prepare and clean-up after itself/`stdin`? – Simon Streicher Nov 02 '14 at 21:20
  • Sorry, I'm not much familiar with these I/O terminal handling, you'll probably have more luck opening another question and maybe making it more specific. – Elias Dorneles Nov 02 '14 at 21:31
  • Thanks, here is the new question: http://stackoverflow.com/questions/26704840/corner-cases-for-my-wait-for-user-input-interruption-implementation – Simon Streicher Nov 02 '14 at 21:50