Programmatically exit the REPL

Matthew Fitzgibbons elessar at nienna.org
Tue Aug 26 22:47:45 CEST 2008


Matthew Fitzgibbons wrote:
> I've got a pretty complex interactive command line program. Instead of 
> writing my own REPL, I'm using the Python interpreter (an infinitely 
> better solution). This program has two threads, a background thread and 
> the REPL thread. When you call quit() or sys.exit() in the REPL thread, 
> everything is perfectly happy. However, the background thread does some 
> long-running jobs, and I want it to have the ability to exit the program 
> when the job is complete. When I call quit() or sys.exit() from the 
> background thread, the REPL merrily continues on its way.
> 
> This is a very frustrating problem, so I'm hoping someone can shed some 
> light on it. Am I missing something simple? Or is this just impossible? 
> I don't see anything about breaking out of interact() in the code module 
> docs.
> 
> 
> Here's a minimal example:
> 
> #!/usr/bin/env python -i
> # You get the same behavior using code.interact()
> 
> import sys
> import time
> import threading
> 
> def end_the_program():
>     # works if you call it from the REPL thread,
>     # but not the background thread
>     print "called end_the_program()"
>     sys.exit()
>     # quit() # using quit() rather than sys.exit()
>              # results in identical behavior
> 
> keep_going = True
> def runner():
>     while keep_going:
>         time.sleep(0.1)
>     end_the_program()
> threading.Thread(target=runner).start()
> 
> # end example
> 
> 
> Here's the console session (edited for clarity):
> 
> Desktop$ ./exit_repl.py
>  >>> keep_going = False
> called end_the_program()
> # notice we didn't exit here
>  >>> end_the_program()
> called end_the_program()
> # but we did exit here
> Desktop$
> 
> 
> -Matt
> 

Here's a modified example that _almost_ works:

#!/usr/bin/env python

import code
import time
import threading

keep_going = True
def runner():
     while keep_going:
         time.sleep(0.1)
     ic.push("quit()") # this will exit the InteractiveConsole loop!
threading.Thread(target=runner).start()

ic = code.InteractiveConsole(locals())
ic.interact("InteractiveConsole")

# end example


It uses code.InteractiveConsole instead of python -i. When you push 
"quit()" to the InteractiveConsole, the loop exits, but the raw_input 
call is still blocking. Argh!

Console session:

Desktop$ ./exit_repl.py && echo done
InteractiveConsole
 >>> keep_going = False
 >>> <hit enter one more time...>
done
Desktop$


Does anyone know how to make raw_input think it has gotten input?

-Matt



More information about the Python-list mailing list