How to pipe input to urwid?

49 Views Asked by At

I'd like to make a program in Python that works a bit like fzf - you pipe input, manipulate it, and it's piped to something else.

I have tried making a program like this in Python using urwid. If I set up a fake input within the program, it works the way I want it to, but if I pipe input (cat foo.txt | python myprog.py) I get an error. How can I make this work?

In particular, I would like to be able to start the UI before closing stdin, the same as fzf.


To give a simple example of the issue I ran into, given this program:

import urwid

txt = urwid.Text("blah")
filler = urwid.Filler(txt)

def quitter(key):
    if key == "q":
        raise urwid.ExitMainLoop()

loop = urwid.MainLoop(filler, unhandled_input=quitter)
loop.run()

This command line:

ls | python script.py

Gives this error:

TypeError: ord() expected a character, but string of length 0 found

It wasn't obvious to me why this would happen, but looking at this issue for example, it does seem to be related to piping input.

1

There are 1 best solutions below

0
polm23 On

It looks like the way to do this is to create a Screen that uses the tty, rather than stdin, as input. This screen object must then be passed to the main loop. Example:

import urwid

txt = urwid.Text("blah")
filler = urwid.Filler(txt)

def quitter(key):
    if key == "q":
        raise urwid.ExitMainLoop()

tty_in = open('/dev/tty', 'r')
screen = urwid.raw_display.Screen(input=tty_in)
loop = urwid.MainLoop(filler, screen=screen, unhandled_input=quitter)
loop.run()

This old mailing list post got me partway there.