[Python-Dev] curses: error handling and the lower right margin of the screen

Aleksejs Popovs aleksejs at mit.edu
Sun Jul 16 22:37:47 EDT 2017


Hello everyone,

My name is Aleksejs, and this is my first time posting here. I'm
working on a Python project (a client for Zephyr, MIT's instant
messaging system) that uses curses, and I believe I've found either a
bug in the Python curses bindings or a deficiency in their
documentation.

The problem has to do with ncurses' cursor advancing behavior. The
manpage addch(3x) says:

>If the advance is at the right margin:
>· The cursor automatically wraps to the beginning of the next line.
>· At the bottom of the current scrolling region, and if scrollok is 
enabled, the scrolling region is scrolled up one line.
>· If scrollok is not enabled, writing a character at the lower right 
margin succeeds. However, an error is returned because it is not
possible to wrap to a new line

Python's window.addch(y, x, ch[, attr]) function seems to be internally
calling addch or one of the related functions, and so, if scrollok is
off and (y, x) is the lower right corner of the screen, addch returns
an error, which window.addch then detects and turns into an exception.

I'd like to argue that this is not expected behavior, and does not
follow from the documentation. The documentation for window.addch makes
no mention of the fact that the cursor is advanced at all, so there's
no reason that a user should expect window.addch(height - 1, width - 1,
ch) to fail (and the exception raised, "_curses.error: add_wch()
returned ERR", is not very helpful in understanding what the deal is).
Because the documentation doesn't say anything about the cursor, this
is not even an error in any meaningful way, as the character is
successfully written to the screen, and wrapping the code in a "try: ...
except curses.error: pass" block "fixes" the error.

The same problem affects window.addstr() if the end of the string being
painted ends up in the lower right corner.

This behavior is so unintuitive that it is not even accounted for
elsewhere in the curses bindings: the implementation of
curses.panel.rectangle contains a line [1]

> win.addch(lry, lrx, curses.ACS_LRCORNER)

which raises an exception when trying to draw a rectangle spanning an
entire window (or in fact any rectangle touching the lower right
corner). I also wrote a little example script [2] demonstrating the
problem.

I believe that this is a problem, but I am not sure how it could be
resolved. It seems that there's no way to distinguish this "error" from
a legitimate ncurses error. Perhaps the documentation ought to at least
mention this behavior, and the implementation of curses.panel.rectangle
should check for the case where the rectangle touches the lower right
corner and use a try-catch block there.

Best regards,
Aleksejs Popovs

[1] https://github.com/python/cpython/blob/3.6/Lib/curses/textpad.py#L16
[2] https://gist.github.com/popoffka/e21299967f5739d18c4fa393fa5cf20b


More information about the Python-Dev mailing list