Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

nodelay() causes python curses program to exit

I've written a curses program in python. It runs fine. However, when I use nodelay(), the program exits straight away after starting in the terminal, with nothing shown at all (just a new prompt).

EDIT

This code will reproduce the bug:

sc = curses.initscr()

sc.nodelay(1) # But removing this line allows the program to run properly

for angry in range(20):
        sc.addstr(angry, 1, "hi")

Here's my full code

import curses, time, sys, random

def paint(x, y, i):
        #...
def string(s, y):
        #...

def feed():
        #...

sc = curses.initscr()
curses.start_color()
curses.curs_set(0)
sc.nodelay(1) #########################################

 # vars + colors inited

for angry in range(20):
        try:
                dir = chr(sc.getch())

                sc.clear()

                feed()

                #lots of ifs

                body.append([x, y])
                body.pop(0)

                for point in body:
                        paint(*point, i=2)

                sc.move(height-1, 1)
                sc.refresh()
                time.sleep(wait)

        except Exception as e:
                print sys.exc_info()[0], e

sc.getch()
curses.beep()

curses.endwin()

Why is this happenning, and how can I use nodelay() safely?

like image 802
ACarter Avatar asked Dec 22 '12 17:12

ACarter


1 Answers

I've rewritten your minified demo to get the basic functionality working. It's got a nonblocking getch(). If you're holding the Q key when getch() is called, the program ends, otherwise the loop keeps going.

import curses, time

def main(sc):
    sc.nodelay(1)

    for angry in range(20):
        sc.addstr(angry, 1, "hi")
        sc.refresh()

        if sc.getch() == ord('q'):
            break

        time.sleep(1)

if __name__=='__main__':
    curses.wrapper(main)

The most significant change I made is using curses.wrapper to get a screen context instead of using curses.initscr(). The benefit is that if that if your program hits an uncaught exception (hitting ^C for example) it undos all the changes you did to the terminal like disabling the cursor before exiting. It helps a lot when you're debugging.

From here I'd recommend adding your program's features back in in very small steps. Curses is kind of a pain to work with and if you make a lot of changes at once it's hard to figure out which one caused things to break. Good luck!

like image 51
Philip Avatar answered Oct 05 '22 00:10

Philip