I am trying to get a simple curses script to run using Python (with PyCharm 2.0).
This is my script:
import curses
stdscr = curses.initscr()
curses.noecho()
curses.cbreak()
stdscr.keypad(1)
while 1:
c = stdscr.getch()
if c == ord('p'): print("I pressed p")
elif c == ord('q'): break
curses.nocbreak(); stdscr.keypad(0); curses.echo()
curses.endwin()
When I run this from my IDE (PyCharm 2) I get the following error:
_curses.error: setupterm: could not find terminal
Process finished with exit code 1
If I run the script from bash it will simply be stuck in the while loop not reacting to either pressing p or q.
Any help would be appreciated.
You must set enviroment variables TERM and TERMINFO, like this:
export TERM=linux
export TERMINFO=/etc/terminfo
And, if you device have no this dir (/etc/terminfo), make it, and copy terminfo database.
For "linux", and "pcansi" terminals you can download database:
http://forum.xda-developers.com/attachment.php?attachmentid=2134052&d=1374459598
http://forum.xda-developers.com/showthread.php?t=552287&page=4
Go to run/debug configuration(the one next to Pycharm run button). Sticking on Emulate Terminal In Output Console. Then you will be able to run your program with the run button.
You'll see this error if you're using Idle. It's because of Idle's default redirection of input/output. Try running your program from the command line. python3 <filename>.py
I found this question when searching for examples because I am also learning to use curses so I don't know much about it. I know this works though:
import curses
try:
stdscr = curses.initscr()
curses.noecho()
curses.cbreak()
stdscr.keypad(1)
while 1:
c = stdscr.getch()
if c == ord('p'):
stdscr.addstr("I pressed p")
elif c == ord('q'): break
finally:
curses.nocbreak(); stdscr.keypad(0); curses.echo()
curses.endwin()
I also added the try: finally: to make sure I get the terminal to it's original appearance even if something simple goes wrong inside the loop.
You have to use the addstr to make sure the text is going to be displayed inside the window.
I was having the same problem. See Curses Programming with Python - Starting and ending a curses application.
There's a curses.wrapper() function that simplifies the process of starting/ending a curses application.
Here's the example from the Python doc:
from curses import wrapper
def main(stdscr):
# Clear screen
stdscr.clear()
# This raises ZeroDivisionError when i == 10.
for i in range(0, 11):
v = i-10
stdscr.addstr(i, 0, '10 divided by {} is {}'.format(v, 10/v))
stdscr.refresh()
stdscr.getkey()
wrapper(main)
If you are using macOS and running PyCharm you will have to set environment variables from the IDE itself, for execution scope.
Edit Configurations -> Environment variables
then add the below name-value pairs
TERM linux
TERMINFO /etc/zsh
The above is equivalent to exporting environment variable from the console which is done like this
$ export TERM=linux
$ export TERMINFO=/bin/zsh
the default for TERM is xterm, other values are [konsole, rxvt]
rxvt for example is often built with support for 16 colors. You can try to set TERM to rxvt-16color.
/bin/zsh is path of the terminal application that I use in mac.
It's like telling your program that you will be logging into linux(TERM) like terminal which can be found at /bin/zsh. For using bash shell it could be something like /bin/bash .
Related
In a program I am writing in python I need to completely restart the program if a variable becomes true, looking for a while I found this command:
while True:
if reboot == True:
os.execv(sys.argv[0], sys.argv)
When executed it returns the error [Errno 8] Exec format error. I searched for further documentation on os.execv, but didn't find anything relevant, so my question is if anyone knows what I did wrong or knows a better way to restart a script (by restarting I mean completely re-running the script, as if it were been opened for the first time, so with all unassigned variables and no thread running).
There are multiple ways to achieve the same thing. Start by modifying the program to exit whenever the flag turns True. Then there are various options, each one with its advantages and disadvantages.
Wrap it using a bash script.
The script should handle exits and restart your program. A really basic version could be:
#!/bin/bash
while :
do
python program.py
sleep 1
done
Start the program as a sub-process of another program.
Start by wrapping your program's code to a function. Then your __main__ could look like this:
def program():
### Here is the code of your program
...
while True:
from multiprocessing import Process
process = Process(target=program)
process.start()
process.join()
print("Restarting...")
This code is relatively basic, and it requires error handling to be implemented.
Use a process manager
There are a lot of tools available that can monitor the process, run multiple processes in parallel and automatically restart stopped processes. It's worth having a look at PM2 or similar.
IMHO the third option (process manager) looks like the safest approach. The other approaches will have edge cases and require implementation from your side to handle edge cases.
This has worked for me. Please add the shebang at the top of your code and os.execv() as shown below
#!/usr/bin/env python3
import os
import sys
if __name__ == '__main__':
while True:
reboot = input('Enter:')
if reboot == '1':
sys.stdout.flush()
os.execv(sys.executable, [sys.executable, __file__] + [sys.argv[0]])
else:
print('OLD')
I got the same "Exec Format Error", and I believe it is basically the same error you get when you simply type a python script name at the command prompt and expect it to execute. On linux it won't work because a path is required, and the execv method is basically encountering the same error.
You could add the pathname of your python compiler, and that error goes away, except that the name of your script then becomes a parameter and must be added to the argv list. To avoid that, make your script independently executable by adding "#!/usr/bin/python3" to the top of the script AND chmod 755.
This works for me:
#!/usr/bin/python3
# this script is called foo.py
import os
import sys
import time
if (len(sys.argv) >= 2):
Arg1 = int(sys.argv[1])
else:
sys.argv.append(None)
Arg1 = 1
print(f"Arg1: {Arg1}")
sys.argv[1] = str(Arg1 + 1)
time.sleep(3)
os.execv("./foo.py", sys.argv)
Output:
Arg1: 1
Arg1: 2
Arg1: 3
.
.
.
I've tried to read one char from the console in PyCharm (without pressing enter), but to no avail.
The functions msvcrt.getch() stops the code, but does not react to key presses (even enter), and msvcrt.kbhit() always returns 0. For example this code prints nothing:
import msvcrt
while 1:
if msvcrt.kbhit():
print 'reading'
print 'done'
I am using Windows 7, PyCharm 3.4 (the same heppens in idle).
What is wrong? Is there any other way to just read input without enter?
It's possible in a special mode of the Run window.
Check the Emulate terminal in output console setting checkbox in Run/Debug Configurations
You are trying to compare <Class 'Bytes'> to <Class 'string'>.
Cast the key to a string and then compare:
import msvcrt
while True:
if msvcrt.kbhit():
key = str(msvcrt.getch())
if key == "b'w'":
print(key)
To run the program in the Command Line go to: edit Configurations > Execution > enable "Emulate terminal in output console".
This code will fix. So use key.lower()
while True:
key = msvcrt.getch()
if key == "b'w'":
print("Pressed: W without lower()")
#It won't work.
if key.lower() == "b'w'":
print("Pressed: W with lower()")
#This one will work.
#I don't know why but key.lower() works.
I want to display a long list interactively in a python command line program.
Basically, think git log, with the scrolling and the q to quit.
How would I do this in python?
The interactive view that git has is called a pager. Git just uses the pager less, or a different one if you configure it.
Basically you need to run less in a subprocess and pipe your output to it.
There are more details on how to do that in this question: Paging output from python
There is also a python helper library: https://pypi.python.org/pypi/pager (I've not used it)
Create a while loop and ask inputs from the prompt.
Eg:
import msvcrt
my_lis = range(1,78)
limit = 25
my_inp = None
while my_lis:
if my_inp != 'q':
print my_lis[:limit]
my_lis = my_lis[limit:]
else:
break
print "Press any key to continue or (q) to Quit :"
my_inp = msvcrt.getch()
# Exit
I'm playing around a little with Python and curses.
When I run
import time
import curses
def main():
curses.initscr()
curses.cbreak()
for i in range(3):
time.sleep(1)
curses.flash()
pass
print( "Hello World" )
curses.endwin()
if __name__ == '__main__':
main()
if I wait all the way through, curses.endwin() gets called so everything works out fine.
However, if I cut it short with Ctrl-C, curses.endwin() never gets called so it screws up my terminal session.
What is the proper way to handle this situation? How can I make sure that no matter how I try to end/interrupt the program (e.g. Ctrl-C, Ctrl-Z), it doesn't mess up the terminal?
I believe you are looking for curses.wrapper
See http://docs.python.org/dev/library/curses.html#curses.wrapper
It will do curses.cbreak(), curses.noecho() and curses_screen.keypad(1) on init and reverse them on exit, even if the exit was an exception.
Your program goes as a function to the wrapper, example:
def main(screen):
"""screen is a curses screen passed from the wrapper"""
...
if __name__ == '__main__':
curses.wrapper(main)
You could do this:
def main():
curses.initscr()
try:
curses.cbreak()
for i in range(3):
time.sleep(1)
curses.flash()
pass
print( "Hello World" )
finally:
curses.endwin()
Or more nicely, make a context wrapper:
class CursesWindow(object):
def __enter__(self):
curses.initscr()
def __exit__(self):
curses.endwin()
def main():
with CursesWindow():
curses.cbreak()
for i in range(3):
time.sleep(1)
curses.flash()
pass
print( "Hello World" )
My advice: For testing purposes, call your script using a simple wrapper shell script; have the shell script perform a reset command to bring your terminal settings back into a usable state:
#!/bin/sh
eval "$#"
stty -sane
reset
... call that as run.sh and be happy. This should run your command almost exactly as your shell would if you entered the arguments as a command (more exactly if you wrap the arguments in hard quotes).
To ensure that your program will leave the terminal in a robust state, in the the face of uncaught exceptions and abnormal terminations ... either use the curses.wrapper() method to call your top level entry point (probably main() or whatever main_curses_ui() you choose to implement) or wrap your code in your own sequence of curses.* methods to restore cursor visibility, restore "cbreak" (canonical/cooked input) mode, restore the normal "echo" settings and whatever else you may have mucked with.
You can also use the Python: atexit Handlers to register all your clean-up actions. But there might still be cases where your code doesn't get called --- some sorts of non-catchable signals and any situation where os._exit() is invoked.
My little shell script wrapper should be fairly robust even in those cases.
You can:
wrap your code in a try/finally block that calls curses.endwin()
capture the interrupt signal specifically via the signal library
use the atexit library.
The first option is probably the simplest for a basic case (if you're not running much code).
The second option is the most specific, if you want to do something special for Ctrl+C.
The last option is the most robust if you always want to do certain shutdown actions, no matter how your program is ending.
You need to capture the signal and run endwin() during the capture.
For info on this, look at this SO answer: How do I capture SIGINT in Python?
I have inadvertently created Frankenstein.
Everything runs fine in the interpreter, but after running python pyinstaller.py --onefile myFile.py to make an .exe, upon running it starts behaving oddly. It seems to call its main() function seemingly randomly -- even after a keyboard interrupt to break out, it resurrects itself.
The code looks like this:
def main():
print 'DO NOT CLOSE!'
count = 0
lastTime = ((time.localtime()[4])*60) + (time.localtime()[5])
sShot = ImageGrab.grab()
saveSnap(count, lastTime)
currentScreen = grab()
while True:
if currentScreen == grab():
pass
else:
count += 1
saveSnap(count, lastTime)
currentScreen = grab()
lastTime = ((time.localtime()[4])*60) + (time.localtime()[5])
if __name__ == '__main__':
main()
Pretty simple stuff, and like I said, it works fine in the interpreter. All it does it search for changes on screen and then timeStamps a snapshot.
What would be causing to randomly fire main()? It sometimes does it even before keyboard interrupt.
My guess is that the ImageGrab module uses the multiprocessing module to launch a subprocess that collects the image, and that subprocess causes problems with a single-file PyInstaller executable. The problem is that Windows doesn't have a spawn command, and it just reruns the executable. You have to tweak some environment variables to avoid the random rerunning of your program.