Reputation: 241
I've been writing a small utility application using Python 3 (the below testcase also works in Python 2, however) and PyQt 4 that uses the code
module to spawn a REPL prompt allowing interaction with a Qt window.
Unfortunately I've hit a problem I've been unable to solve: When I exit()
the app while code
is inside input()
(known as raw_input()
in Python 2.x), my Linux terminal subsequently no longer echoes typed characters. I.e. the terminal appears to be left in a broken state, presumably due to some escape sequence issued by input()
.
I've tried a variety of approaches to fix this, from using the curses
module and other means to reset the terminal prior to running exit
, to trying to emulate the stdin
stream to exit by actually handing exit()
to input() (unfornunately code.InteractiveConsole.push()
does not work that way, as one might think it would), to trying to write my own non-blocking input()
using threading
, but I've been unable to pull together something working.
Here, here, here and here are discussions of similar problems.
Finally, here is a reduced testcase to demonstrate the problem:
#!/usr/bin/env python3
import code
import sys
from PyQt4.QtGui import QApplication, QWidget
app = QApplication(sys.argv)
app.lastWindowClosed.connect(exit)
widget = QWidget()
widget.show()
code.interact()
For those unfamiliar with (Py)Qt, this will open a blank window, and when it is closed, the connection from app
's lastWindowClosed
signal will cause a call to the built-in exit()
function to happen. This occurs while the code
module is executing a call to input()
to read from sys.stdin
. And here, when I close the window, typing into the terminal afterwards doesn't show any of the types characters.
I'm mainly using Python 3, and the actual app uses Python 3-specific code, but I've tried the testcase in Python 2.7 as well and it shows the same problem.
Upvotes: 24
Views: 8903
Reputation: 3579
with Doing something before program exit
import os
import sys
import atexit
import subprocess
def some_function():
# break terminal
sys.stdout.buffer.write(os.urandom(1024))
def main():
# register the exit handler only in the main function
# when some_function is called from somewhere else
# then the caller is responsible for cleanup
atexit.register(exit_handler)
some_function()
def exit_handler():
# fix terminal after binary output
# no. "stty sane" fails to reset the terminal cursor
# stty is part of coreutils
#subprocess.call(["stty", "sane"])
# tput is part of ncurses
subprocess.call(["tput", "init"])
if __name__ == "__main__":
main()
Upvotes: 0
Reputation: 1280
The answer from Quentin Engles worked for me too but as a Python neophyte I didn't understand where the stty sane
was supposed to go. After some hunting and head scratching I figured out that exit was a reference to the exit()
method so I created exiting()
and passed a reference to it:
#!/usr/bin/env python3
import code
import sys
from PyQt4.QtGui import QApplication, QWidget
def exiting():
os.system('stty sane')
exit()
app = QApplication(sys.argv)
app.lastWindowClosed.connect(exiting)
widget = QWidget()
widget.show()
code.interact()
Upvotes: 3
Reputation: 2832
Try os.system('stty sane')
. The stty sane
is supposed to reset echo, and some other things apparently.
Upvotes: 34
Reputation: 3786
I've run in to the same problem using the curses module. Using the other answer on this page, I've sidestepped the problem with import os
at the beginning of the program, and then ending the program with os.system('reset')
.
Upvotes: 0
Reputation: 211
This is no real solution to the problem, but if you type "reset" in the terminal after you've closed the app, it goes back to normal.
I had similar issues once when developing a c application that didn't close a pipe correctly. Maybe something similar is happening here aswell.
Upvotes: 21