Home | History | Annotate | Download | only in howto
      1 .. _curses-howto:
      2 
      3 **********************************
      4   Curses Programming with Python
      5 **********************************
      6 
      7 :Author: A.M. Kuchling, Eric S. Raymond
      8 :Release: 2.04
      9 
     10 
     11 .. topic:: Abstract
     12 
     13    This document describes how to use the :mod:`curses` extension
     14    module to control text-mode displays.
     15 
     16 
     17 What is curses?
     18 ===============
     19 
     20 The curses library supplies a terminal-independent screen-painting and
     21 keyboard-handling facility for text-based terminals; such terminals
     22 include VT100s, the Linux console, and the simulated terminal provided
     23 by various programs.  Display terminals support various control codes
     24 to perform common operations such as moving the cursor, scrolling the
     25 screen, and erasing areas.  Different terminals use widely differing
     26 codes, and often have their own minor quirks.
     27 
     28 In a world of graphical displays, one might ask "why bother"?  It's
     29 true that character-cell display terminals are an obsolete technology,
     30 but there are niches in which being able to do fancy things with them
     31 are still valuable.  One niche is on small-footprint or embedded
     32 Unixes that don't run an X server.  Another is tools such as OS
     33 installers and kernel configurators that may have to run before any
     34 graphical support is available.
     35 
     36 The curses library provides fairly basic functionality, providing the
     37 programmer with an abstraction of a display containing multiple
     38 non-overlapping windows of text.  The contents of a window can be
     39 changed in various ways---adding text, erasing it, changing its
     40 appearance---and the curses library will figure out what control codes
     41 need to be sent to the terminal to produce the right output.  curses
     42 doesn't provide many user-interface concepts such as buttons, checkboxes,
     43 or dialogs; if you need such features, consider a user interface library such as
     44 `Urwid <https://pypi.org/project/urwid/>`_.
     45 
     46 The curses library was originally written for BSD Unix; the later System V
     47 versions of Unix from AT&T added many enhancements and new functions. BSD curses
     48 is no longer maintained, having been replaced by ncurses, which is an
     49 open-source implementation of the AT&T interface.  If you're using an
     50 open-source Unix such as Linux or FreeBSD, your system almost certainly uses
     51 ncurses.  Since most current commercial Unix versions are based on System V
     52 code, all the functions described here will probably be available.  The older
     53 versions of curses carried by some proprietary Unixes may not support
     54 everything, though.
     55 
     56 The Windows version of Python doesn't include the :mod:`curses`
     57 module.  A ported version called `UniCurses
     58 <https://pypi.org/project/UniCurses>`_ is available.  You could
     59 also try `the Console module <http://effbot.org/zone/console-index.htm>`_
     60 written by Fredrik Lundh, which doesn't
     61 use the same API as curses but provides cursor-addressable text output
     62 and full support for mouse and keyboard input.
     63 
     64 
     65 The Python curses module
     66 ------------------------
     67 
     68 The Python module is a fairly simple wrapper over the C functions provided by
     69 curses; if you're already familiar with curses programming in C, it's really
     70 easy to transfer that knowledge to Python.  The biggest difference is that the
     71 Python interface makes things simpler by merging different C functions such as
     72 :c:func:`addstr`, :c:func:`mvaddstr`, and :c:func:`mvwaddstr` into a single
     73 :meth:`~curses.window.addstr` method.  You'll see this covered in more
     74 detail later.
     75 
     76 This HOWTO is an introduction to writing text-mode programs with curses
     77 and Python. It doesn't attempt to be a complete guide to the curses API; for
     78 that, see the Python library guide's section on ncurses, and the C manual pages
     79 for ncurses.  It will, however, give you the basic ideas.
     80 
     81 
     82 Starting and ending a curses application
     83 ========================================
     84 
     85 Before doing anything, curses must be initialized.  This is done by
     86 calling the :func:`~curses.initscr` function, which will determine the
     87 terminal type, send any required setup codes to the terminal, and
     88 create various internal data structures.  If successful,
     89 :func:`initscr` returns a window object representing the entire
     90 screen; this is usually called ``stdscr`` after the name of the
     91 corresponding C variable. ::
     92 
     93    import curses
     94    stdscr = curses.initscr()
     95 
     96 Usually curses applications turn off automatic echoing of keys to the
     97 screen, in order to be able to read keys and only display them under
     98 certain circumstances.  This requires calling the
     99 :func:`~curses.noecho` function. ::
    100 
    101    curses.noecho()
    102 
    103 Applications will also commonly need to react to keys instantly,
    104 without requiring the Enter key to be pressed; this is called cbreak
    105 mode, as opposed to the usual buffered input mode. ::
    106 
    107    curses.cbreak()
    108 
    109 Terminals usually return special keys, such as the cursor keys or navigation
    110 keys such as Page Up and Home, as a multibyte escape sequence.  While you could
    111 write your application to expect such sequences and process them accordingly,
    112 curses can do it for you, returning a special value such as
    113 :const:`curses.KEY_LEFT`.  To get curses to do the job, you'll have to enable
    114 keypad mode. ::
    115 
    116    stdscr.keypad(True)
    117 
    118 Terminating a curses application is much easier than starting one. You'll need
    119 to call::
    120 
    121    curses.nocbreak()
    122    stdscr.keypad(False)
    123    curses.echo()
    124 
    125 to reverse the curses-friendly terminal settings. Then call the
    126 :func:`~curses.endwin` function to restore the terminal to its original
    127 operating mode. ::
    128 
    129    curses.endwin()
    130 
    131 A common problem when debugging a curses application is to get your terminal
    132 messed up when the application dies without restoring the terminal to its
    133 previous state.  In Python this commonly happens when your code is buggy and
    134 raises an uncaught exception.  Keys are no longer echoed to the screen when
    135 you type them, for example, which makes using the shell difficult.
    136 
    137 In Python you can avoid these complications and make debugging much easier by
    138 importing the :func:`curses.wrapper` function and using it like this::
    139 
    140    from curses import wrapper
    141 
    142    def main(stdscr):
    143        # Clear screen
    144        stdscr.clear()
    145 
    146        # This raises ZeroDivisionError when i == 10.
    147        for i in range(0, 11):
    148            v = i-10
    149            stdscr.addstr(i, 0, '10 divided by {} is {}'.format(v, 10/v))
    150 
    151        stdscr.refresh()
    152        stdscr.getkey()
    153 
    154    wrapper(main)
    155 
    156 The :func:`~curses.wrapper` function takes a callable object and does the
    157 initializations described above, also initializing colors if color
    158 support is present.  :func:`wrapper` then runs your provided callable.
    159 Once the callable returns, :func:`wrapper` will restore the original
    160 state of the terminal.  The callable is called inside a
    161 :keyword:`try`...\ :keyword:`except` that catches exceptions, restores
    162 the state of the terminal, and then re-raises the exception.  Therefore
    163 your terminal won't be left in a funny state on exception and you'll be
    164 able to read the exception's message and traceback.
    165 
    166 
    167 Windows and Pads
    168 ================
    169 
    170 Windows are the basic abstraction in curses.  A window object represents a
    171 rectangular area of the screen, and supports methods to display text,
    172 erase it, allow the user to input strings, and so forth.
    173 
    174 The ``stdscr`` object returned by the :func:`~curses.initscr` function is a
    175 window object that covers the entire screen.  Many programs may need
    176 only this single window, but you might wish to divide the screen into
    177 smaller windows, in order to redraw or clear them separately. The
    178 :func:`~curses.newwin` function creates a new window of a given size,
    179 returning the new window object. ::
    180 
    181    begin_x = 20; begin_y = 7
    182    height = 5; width = 40
    183    win = curses.newwin(height, width, begin_y, begin_x)
    184 
    185 Note that the coordinate system used in curses is unusual.
    186 Coordinates are always passed in the order *y,x*, and the top-left
    187 corner of a window is coordinate (0,0).  This breaks the normal
    188 convention for handling coordinates where the *x* coordinate comes
    189 first.  This is an unfortunate difference from most other computer
    190 applications, but it's been part of curses since it was first written,
    191 and it's too late to change things now.
    192 
    193 Your application can determine the size of the screen by using the
    194 :data:`curses.LINES` and :data:`curses.COLS` variables to obtain the *y* and
    195 *x* sizes.  Legal coordinates will then extend from ``(0,0)`` to
    196 ``(curses.LINES - 1, curses.COLS - 1)``.
    197 
    198 When you call a method to display or erase text, the effect doesn't
    199 immediately show up on the display.  Instead you must call the
    200 :meth:`~curses.window.refresh` method of window objects to update the
    201 screen.
    202 
    203 This is because curses was originally written with slow 300-baud
    204 terminal connections in mind; with these terminals, minimizing the
    205 time required to redraw the screen was very important.  Instead curses
    206 accumulates changes to the screen and displays them in the most
    207 efficient manner when you call :meth:`refresh`.  For example, if your
    208 program displays some text in a window and then clears the window,
    209 there's no need to send the original text because they're never
    210 visible.
    211 
    212 In practice, explicitly telling curses to redraw a window doesn't
    213 really complicate programming with curses much. Most programs go into a flurry
    214 of activity, and then pause waiting for a keypress or some other action on the
    215 part of the user.  All you have to do is to be sure that the screen has been
    216 redrawn before pausing to wait for user input, by first calling
    217 ``stdscr.refresh()`` or the :meth:`refresh` method of some other relevant
    218 window.
    219 
    220 A pad is a special case of a window; it can be larger than the actual display
    221 screen, and only a portion of the pad displayed at a time. Creating a pad
    222 requires the pad's height and width, while refreshing a pad requires giving the
    223 coordinates of the on-screen area where a subsection of the pad will be
    224 displayed.  ::
    225 
    226    pad = curses.newpad(100, 100)
    227    # These loops fill the pad with letters; addch() is
    228    # explained in the next section
    229    for y in range(0, 99):
    230        for x in range(0, 99):
    231            pad.addch(y,x, ord('a') + (x*x+y*y) % 26)
    232 
    233    # Displays a section of the pad in the middle of the screen.
    234    # (0,0) : coordinate of upper-left corner of pad area to display.
    235    # (5,5) : coordinate of upper-left corner of window area to be filled
    236    #         with pad content.
    237    # (20, 75) : coordinate of lower-right corner of window area to be
    238    #          : filled with pad content.
    239    pad.refresh( 0,0, 5,5, 20,75)
    240 
    241 The :meth:`refresh` call displays a section of the pad in the rectangle
    242 extending from coordinate (5,5) to coordinate (20,75) on the screen; the upper
    243 left corner of the displayed section is coordinate (0,0) on the pad.  Beyond
    244 that difference, pads are exactly like ordinary windows and support the same
    245 methods.
    246 
    247 If you have multiple windows and pads on screen there is a more
    248 efficient way to update the screen and prevent annoying screen flicker
    249 as each part of the screen gets updated.  :meth:`refresh` actually
    250 does two things:
    251 
    252 1) Calls the :meth:`~curses.window.noutrefresh` method of each window
    253    to update an underlying data structure representing the desired
    254    state of the screen.
    255 2) Calls the function :func:`~curses.doupdate` function to change the
    256    physical screen to match the desired state recorded in the data structure.
    257 
    258 Instead you can call :meth:`noutrefresh` on a number of windows to
    259 update the data structure, and then call :func:`doupdate` to update
    260 the screen.
    261 
    262 
    263 Displaying Text
    264 ===============
    265 
    266 From a C programmer's point of view, curses may sometimes look like a
    267 twisty maze of functions, all subtly different.  For example,
    268 :c:func:`addstr` displays a string at the current cursor location in
    269 the ``stdscr`` window, while :c:func:`mvaddstr` moves to a given y,x
    270 coordinate first before displaying the string. :c:func:`waddstr` is just
    271 like :c:func:`addstr`, but allows specifying a window to use instead of
    272 using ``stdscr`` by default. :c:func:`mvwaddstr` allows specifying both
    273 a window and a coordinate.
    274 
    275 Fortunately the Python interface hides all these details.  ``stdscr``
    276 is a window object like any other, and methods such as
    277 :meth:`~curses.window.addstr` accept multiple argument forms.  Usually there
    278 are four different forms.
    279 
    280 +---------------------------------+-----------------------------------------------+
    281 | Form                            | Description                                   |
    282 +=================================+===============================================+
    283 | *str* or *ch*                   | Display the string *str* or character *ch* at |
    284 |                                 | the current position                          |
    285 +---------------------------------+-----------------------------------------------+
    286 | *str* or *ch*, *attr*           | Display the string *str* or character *ch*,   |
    287 |                                 | using attribute *attr* at the current         |
    288 |                                 | position                                      |
    289 +---------------------------------+-----------------------------------------------+
    290 | *y*, *x*, *str* or *ch*         | Move to position *y,x* within the window, and |
    291 |                                 | display *str* or *ch*                         |
    292 +---------------------------------+-----------------------------------------------+
    293 | *y*, *x*, *str* or *ch*, *attr* | Move to position *y,x* within the window, and |
    294 |                                 | display *str* or *ch*, using attribute *attr* |
    295 +---------------------------------+-----------------------------------------------+
    296 
    297 Attributes allow displaying text in highlighted forms such as boldface,
    298 underline, reverse code, or in color.  They'll be explained in more detail in
    299 the next subsection.
    300 
    301 
    302 The :meth:`~curses.window.addstr` method takes a Python string or
    303 bytestring as the value to be displayed.  The contents of bytestrings
    304 are sent to the terminal as-is.  Strings are encoded to bytes using
    305 the value of the window's :attr:`encoding` attribute; this defaults to
    306 the default system encoding as returned by
    307 :func:`locale.getpreferredencoding`.
    308 
    309 The :meth:`~curses.window.addch` methods take a character, which can be
    310 either a string of length 1, a bytestring of length 1, or an integer.
    311 
    312 Constants are provided for extension characters; these constants are
    313 integers greater than 255.  For example, :const:`ACS_PLMINUS` is a +/-
    314 symbol, and :const:`ACS_ULCORNER` is the upper left corner of a box
    315 (handy for drawing borders).  You can also use the appropriate Unicode
    316 character.
    317 
    318 Windows remember where the cursor was left after the last operation, so if you
    319 leave out the *y,x* coordinates, the string or character will be displayed
    320 wherever the last operation left off.  You can also move the cursor with the
    321 ``move(y,x)`` method.  Because some terminals always display a flashing cursor,
    322 you may want to ensure that the cursor is positioned in some location where it
    323 won't be distracting; it can be confusing to have the cursor blinking at some
    324 apparently random location.
    325 
    326 If your application doesn't need a blinking cursor at all, you can
    327 call ``curs_set(False)`` to make it invisible.  For compatibility
    328 with older curses versions, there's a ``leaveok(bool)`` function
    329 that's a synonym for :func:`~curses.curs_set`.  When *bool* is true, the
    330 curses library will attempt to suppress the flashing cursor, and you
    331 won't need to worry about leaving it in odd locations.
    332 
    333 
    334 Attributes and Color
    335 --------------------
    336 
    337 Characters can be displayed in different ways.  Status lines in a text-based
    338 application are commonly shown in reverse video, or a text viewer may need to
    339 highlight certain words.  curses supports this by allowing you to specify an
    340 attribute for each cell on the screen.
    341 
    342 An attribute is an integer, each bit representing a different
    343 attribute.  You can try to display text with multiple attribute bits
    344 set, but curses doesn't guarantee that all the possible combinations
    345 are available, or that they're all visually distinct.  That depends on
    346 the ability of the terminal being used, so it's safest to stick to the
    347 most commonly available attributes, listed here.
    348 
    349 +----------------------+--------------------------------------+
    350 | Attribute            | Description                          |
    351 +======================+======================================+
    352 | :const:`A_BLINK`     | Blinking text                        |
    353 +----------------------+--------------------------------------+
    354 | :const:`A_BOLD`      | Extra bright or bold text            |
    355 +----------------------+--------------------------------------+
    356 | :const:`A_DIM`       | Half bright text                     |
    357 +----------------------+--------------------------------------+
    358 | :const:`A_REVERSE`   | Reverse-video text                   |
    359 +----------------------+--------------------------------------+
    360 | :const:`A_STANDOUT`  | The best highlighting mode available |
    361 +----------------------+--------------------------------------+
    362 | :const:`A_UNDERLINE` | Underlined text                      |
    363 +----------------------+--------------------------------------+
    364 
    365 So, to display a reverse-video status line on the top line of the screen, you
    366 could code::
    367 
    368    stdscr.addstr(0, 0, "Current mode: Typing mode",
    369                  curses.A_REVERSE)
    370    stdscr.refresh()
    371 
    372 The curses library also supports color on those terminals that provide it. The
    373 most common such terminal is probably the Linux console, followed by color
    374 xterms.
    375 
    376 To use color, you must call the :func:`~curses.start_color` function soon
    377 after calling :func:`~curses.initscr`, to initialize the default color set
    378 (the :func:`curses.wrapper` function does this automatically).  Once that's
    379 done, the :func:`~curses.has_colors` function returns TRUE if the terminal
    380 in use can
    381 actually display color.  (Note: curses uses the American spelling 'color',
    382 instead of the Canadian/British spelling 'colour'.  If you're used to the
    383 British spelling, you'll have to resign yourself to misspelling it for the sake
    384 of these functions.)
    385 
    386 The curses library maintains a finite number of color pairs, containing a
    387 foreground (or text) color and a background color.  You can get the attribute
    388 value corresponding to a color pair with the :func:`~curses.color_pair`
    389 function; this can be bitwise-OR'ed with other attributes such as
    390 :const:`A_REVERSE`, but again, such combinations are not guaranteed to work
    391 on all terminals.
    392 
    393 An example, which displays a line of text using color pair 1::
    394 
    395    stdscr.addstr("Pretty text", curses.color_pair(1))
    396    stdscr.refresh()
    397 
    398 As I said before, a color pair consists of a foreground and background color.
    399 The ``init_pair(n, f, b)`` function changes the definition of color pair *n*, to
    400 foreground color f and background color b.  Color pair 0 is hard-wired to white
    401 on black, and cannot be changed.
    402 
    403 Colors are numbered, and :func:`start_color` initializes 8 basic
    404 colors when it activates color mode.  They are: 0:black, 1:red,
    405 2:green, 3:yellow, 4:blue, 5:magenta, 6:cyan, and 7:white.  The :mod:`curses`
    406 module defines named constants for each of these colors:
    407 :const:`curses.COLOR_BLACK`, :const:`curses.COLOR_RED`, and so forth.
    408 
    409 Let's put all this together. To change color 1 to red text on a white
    410 background, you would call::
    411 
    412    curses.init_pair(1, curses.COLOR_RED, curses.COLOR_WHITE)
    413 
    414 When you change a color pair, any text already displayed using that color pair
    415 will change to the new colors.  You can also display new text in this color
    416 with::
    417 
    418    stdscr.addstr(0,0, "RED ALERT!", curses.color_pair(1))
    419 
    420 Very fancy terminals can change the definitions of the actual colors to a given
    421 RGB value.  This lets you change color 1, which is usually red, to purple or
    422 blue or any other color you like.  Unfortunately, the Linux console doesn't
    423 support this, so I'm unable to try it out, and can't provide any examples.  You
    424 can check if your terminal can do this by calling
    425 :func:`~curses.can_change_color`, which returns ``True`` if the capability is
    426 there.  If you're lucky enough to have such a talented terminal, consult your
    427 system's man pages for more information.
    428 
    429 
    430 User Input
    431 ==========
    432 
    433 The C curses library offers only very simple input mechanisms. Python's
    434 :mod:`curses` module adds a basic text-input widget.  (Other libraries
    435 such as `Urwid <https://pypi.org/project/urwid/>`_ have more extensive
    436 collections of widgets.)
    437 
    438 There are two methods for getting input from a window:
    439 
    440 * :meth:`~curses.window.getch` refreshes the screen and then waits for
    441   the user to hit a key, displaying the key if :func:`~curses.echo` has been
    442   called earlier.  You can optionally specify a coordinate to which
    443   the cursor should be moved before pausing.
    444 
    445 * :meth:`~curses.window.getkey` does the same thing but converts the
    446   integer to a string.  Individual characters are returned as
    447   1-character strings, and special keys such as function keys return
    448   longer strings containing a key name such as ``KEY_UP`` or ``^G``.
    449 
    450 It's possible to not wait for the user using the
    451 :meth:`~curses.window.nodelay` window method. After ``nodelay(True)``,
    452 :meth:`getch` and :meth:`getkey` for the window become
    453 non-blocking. To signal that no input is ready, :meth:`getch` returns
    454 ``curses.ERR`` (a value of -1) and :meth:`getkey` raises an exception.
    455 There's also a :func:`~curses.halfdelay` function, which can be used to (in
    456 effect) set a timer on each :meth:`getch`; if no input becomes
    457 available within a specified delay (measured in tenths of a second),
    458 curses raises an exception.
    459 
    460 The :meth:`getch` method returns an integer; if it's between 0 and 255, it
    461 represents the ASCII code of the key pressed.  Values greater than 255 are
    462 special keys such as Page Up, Home, or the cursor keys. You can compare the
    463 value returned to constants such as :const:`curses.KEY_PPAGE`,
    464 :const:`curses.KEY_HOME`, or :const:`curses.KEY_LEFT`.  The main loop of
    465 your program may look something like this::
    466 
    467    while True:
    468        c = stdscr.getch()
    469        if c == ord('p'):
    470            PrintDocument()
    471        elif c == ord('q'):
    472            break  # Exit the while loop
    473        elif c == curses.KEY_HOME:
    474            x = y = 0
    475 
    476 The :mod:`curses.ascii` module supplies ASCII class membership functions that
    477 take either integer or 1-character string arguments; these may be useful in
    478 writing more readable tests for such loops.  It also supplies
    479 conversion functions  that take either integer or 1-character-string arguments
    480 and return the same type.  For example, :func:`curses.ascii.ctrl` returns the
    481 control character corresponding to its argument.
    482 
    483 There's also a method to retrieve an entire string,
    484 :meth:`~curses.window.getstr`.  It isn't used very often, because its
    485 functionality is quite limited; the only editing keys available are
    486 the backspace key and the Enter key, which terminates the string.  It
    487 can optionally be limited to a fixed number of characters. ::
    488 
    489    curses.echo()            # Enable echoing of characters
    490 
    491    # Get a 15-character string, with the cursor on the top line
    492    s = stdscr.getstr(0,0, 15)
    493 
    494 The :mod:`curses.textpad` module supplies a text box that supports an
    495 Emacs-like set of keybindings.  Various methods of the
    496 :class:`~curses.textpad.Textbox` class support editing with input
    497 validation and gathering the edit results either with or without
    498 trailing spaces.  Here's an example::
    499 
    500    import curses
    501    from curses.textpad import Textbox, rectangle
    502 
    503    def main(stdscr):
    504        stdscr.addstr(0, 0, "Enter IM message: (hit Ctrl-G to send)")
    505 
    506        editwin = curses.newwin(5,30, 2,1)
    507        rectangle(stdscr, 1,0, 1+5+1, 1+30+1)
    508        stdscr.refresh()
    509 
    510        box = Textbox(editwin)
    511 
    512        # Let the user edit until Ctrl-G is struck.
    513        box.edit()
    514 
    515        # Get resulting contents
    516        message = box.gather()
    517 
    518 See the library documentation on :mod:`curses.textpad` for more details.
    519 
    520 
    521 For More Information
    522 ====================
    523 
    524 This HOWTO doesn't cover some advanced topics, such as reading the
    525 contents of the screen or capturing mouse events from an xterm
    526 instance, but the Python library page for the :mod:`curses` module is now
    527 reasonably complete.  You should browse it next.
    528 
    529 If you're in doubt about the detailed behavior of the curses
    530 functions, consult the manual pages for your curses implementation,
    531 whether it's ncurses or a proprietary Unix vendor's.  The manual pages
    532 will document any quirks, and provide complete lists of all the
    533 functions, attributes, and :const:`ACS_\*` characters available to
    534 you.
    535 
    536 Because the curses API is so large, some functions aren't supported in
    537 the Python interface.  Often this isn't because they're difficult to
    538 implement, but because no one has needed them yet.  Also, Python
    539 doesn't yet support the menu library associated with ncurses.
    540 Patches adding support for these would be welcome; see
    541 `the Python Developer's Guide <https://devguide.python.org/>`_ to
    542 learn more about submitting patches to Python.
    543 
    544 * `Writing Programs with NCURSES <http://invisible-island.net/ncurses/ncurses-intro.html>`_:
    545   a lengthy tutorial for C programmers.
    546 * `The ncurses man page <https://linux.die.net/man/3/ncurses>`_
    547 * `The ncurses FAQ <http://invisible-island.net/ncurses/ncurses.faq.html>`_
    548 * `"Use curses... don't swear" <https://www.youtube.com/watch?v=eN1eZtjLEnU>`_:
    549   video of a PyCon 2013 talk on controlling terminals using curses or Urwid.
    550 * `"Console Applications with Urwid" <http://www.pyvideo.org/video/1568/console-applications-with-urwid>`_:
    551   video of a PyCon CA 2012 talk demonstrating some applications written using
    552   Urwid.
    553