[Python-ideas] Remove tty module

Andrew Barnert abarnert at yahoo.com
Fri Aug 2 06:47:24 CEST 2013


From: "random832 at fastmail.us" <random832 at fastmail.us>

Sent: Thursday, August 1, 2013 1:18 PM


> On Thu, Jul 25, 2013, at 11:58, Andrew Barnert wrote:
>>  Faking termios on Windows (and presumably faking attributes for the
>>  cmd.exe console window) would probably be almost as much work as faking
>>  curses, and a lot less useful, so I'm not sure that would be worth 
> doing.
> 
> What about faking conio on Unix? There's no rule that says
> cross-platform python APIs have to be inspired by POSIX C APIs. It's a
> very simple API and is sufficient to build a pure-python windowing
> library on top of.


That's a great idea.

The quasi-standardized core of conio is definitely not enough to write a windowing library. Although some of the old DOS implementations had gotoxy, setfg, and setbg functions, the Win32 implementations don't have those; they just have… well, the same functions as MSVCRT's console APIs, which the stdlib already wraps (see http://docs.python.org/3/library/msvcrt.html#console-i-o for details). And really, all we were looking for was a way to do raw input and a few related things in a cross-platform way (and, on Unix, an easier way than tty/termios), and those APIs seem like a good match. And they'd be pretty easy to implement on Unix.

Something like this (for Unix; the Windows implementations would just call the msvcrt functions):

    def _check_tty(f):
        if not f.isatty():
            raise RuntimeError('consoleio on non-tty')

    @contextmanager
    def _tty_context(f, raw=False, echo=True):
        fd = f.fileno()
        stash = termios.tcgetattr(fd)
        tty.setraw(fd)
        yield
        termios.tcsetattr(fd, termios.TCSAFLUSH, stash)
    

    _pushback = []

    def kbhit():
        # Not sure how to write this in a cross-platform way...

    def getwch():
        _check_tty(sys.stdin)
        if _pushback:
            return _pushback.pop(0)
        with _tty_context(sys.stdin, raw=True, echo=False):
            return sys.stdin.read(1)

    def ungetwch(wch):
        _check_tty(sys.stdin)
        _pushback.append(wch)

    def putwch(wch):
        _check_tty(sys.stdout)
        sys.stdout.write(wch)

        sys.stdout.flush()

    # For the non-"wide" versions… just use sys.stdout.buffer instead of sys.stdout?

If we can require the user to call enable(input_only=False) before using any consoleio functions, and disable() before using normal I/O (maybe "with consoleio.context(input_only=False):" to wrap it), it could be simpler (especially the kbhit part), and more efficient and reliable.

Of course it is possible to have a TTY that isn't on stdin/stdout, or even two TTYs, but I don't think there's any need for the extra complexity.

Anyway, if you're interested, I could clean this up, test it out, and put something up on PyPI, and then we could see if it gets enough traction to be worth considering stdlib-ifying.


More information about the Python-ideas mailing list