11

I'm building a python curses application.

I have two ways of printing to the curses window: print x, and windows.addstr(x) (and the other similar window.* options).

However, for debugging purposes, I'd like to be able to print to the standard console, so when I exit the curses window, I have the infomation waiting for me to be seen. I would normally just use print x, but that prints to the curses window.

sys.stout.write() also fails.

How can I do this?

After using sys.stdout after os.fdopen, this is the traceback

 curses.nocbreak()
 _curses.error: nocbreak() returned ERR
 close failed in file object destructor:
 sys.excepthook is missing
 lost sys.stderr
ACarter
  • 5,688
  • 9
  • 39
  • 56
  • 1
    Have you tried `sys.stdout.write()`? It could be that's redirected too though, in which case you have to use `open(1, 'w')` perhaps (fd 1 is stdout). – Martijn Pieters Dec 23 '12 at 10:09
  • @Martijn `sys.sdout.write()` fails too. Also, `open(1, 'w')` fails too, it wants a string as the filename. – ACarter Dec 23 '12 at 10:23
  • 1
    @ACarter Martijn probably meant [`os.fdopen`](http://docs.python.org/2/library/os.html#os.fdopen). Anyway I believe you should use the [`logging`](http://docs.python.org/2/library/logging.html) module and log to a file. – Bakuriu Dec 23 '12 at 10:45
  • @MartijnPieters If `print` prints to other than the standard output, I think `sys.stdout` is 100% redirected. – jadkik94 Dec 23 '12 at 11:00
  • @jadkik94: I suspect `sys.stdout` is redirected, indeed, hence the attempt to open fd 1. For python 2, indeed, use `os.fdopen(1, 'w'). – Martijn Pieters Dec 23 '12 at 11:02
  • @Martjin, aaaah, that kinda killed it, see my edited stacktrace – ACarter Dec 23 '12 at 11:13

2 Answers2

13

To do as you say, here is a snippet I used:

class StdOutWrapper:
    text = ""
    def write(self,txt):
        self.text += txt
        self.text = '\n'.join(self.text.split('\n')[-30:])
    def get_text(self,beg,end):
        return '\n'.join(self.text.split('\n')[beg:end])

if __name__ == "__main__":
    mystdout = StdOutWrapper()
    sys.stdout = mystdout
    sys.stderr = mystdout

    screen = curses.initscr()
    curses.noecho()
    curses.cbreak()

    # do your stuff here
    # you can also output mystdout.get_text() in a ncurses widget in runtime

    screen.keypad(0)
    curses.nocbreak()
    curses.echo()
    curses.endwin()
    sys.stdout = sys.__stdout__
    sys.stderr = sys.__stderr__
    sys.stdout.write(mystdout.get_text())

The neat thing with that trick, is that you can also output your stdout during ncurse runtime in a widget. Of course the internal representation of StdOutWrapper can be tweaked as you want, to better match your needs.

zmo
  • 24,463
  • 4
  • 54
  • 90
2

Why don't you use the standard logging module?

Combine it with curses.wrapper, and you are good to go


EDIT:

You can see example here: https://stackoverflow.com/a/28102809/26494

If you just want to log to file:

import logging
import curses

def draw(stdscr):
    logger = logging.getLogger(__file__)
    hdlr = logging.FileHandler(__file__ + ".log")
    formatter = logging.Formatter('%(asctime)s %(levelname)s %(message)s')
    hdlr.setFormatter(formatter)
    logger.addHandler(hdlr)
    logger.setLevel(logging.DEBUG)

    logger.info("begin")

    curses.init_pair(1, curses.COLOR_CYAN, curses.COLOR_BLACK)
    stdscr.addstr(0, 0, 'hello', curses.color_pair(1))
    logger.info("yeah")
    stdscr.getch()
    logger.info("end")


if __name__ == '__main__':
    curses.wrapper(draw)
Community
  • 1
  • 1
pihentagy
  • 5,975
  • 9
  • 39
  • 58