What's New in Curses

What changed in curses — past month

python/cpython main, window ≈ 2026-06-09 → 2026-07-10 · 51 commits touching the curses module, tests, and docs.

The month was dominated by two large pieces of work — full Unicode / styled-cell support and multiple-terminal support — plus a run of correctness and portability fixes that let the module build and run across ncurses, NetBSD curses, PDCurses and windows-curses. Everything else was comparatively minor.

1. Full Unicode text and styled character cells

The biggest change. The character-cell window methods now accept a full character cell — a spacing character optionally followed by combining characters — anywhere they previously took a single integer or byte character, so the module finally handles wide and combining characters end to end (gh-151757). New wide-character read methods window.get_wstr() / window.in_wstr() and the functions erasewchar(), killwchar(), wunctrl() came with it.

On top of that, two new types make a styled cell a first-class Python object:

  • curses.complexchar (gh-152233) — one styled character cell: its text, attributes and color pair together. window.in_wch() and window.getbkgrnd() return one, and the cell methods (addch, bkgd, border, hline, …) now also accept one. So you can read a decorated cell off the screen and write it back unchanged.
  • curses.complexstr (gh-152233) — an immutable string of styled cells, the counterpart to complexchar. window.in_wchstr() returns one; addstr, addnstr, insstr and insnstr now accept one, each cell carrying its own attributes and color.

Crucially, all of this works whether or not Python was built against a wide-character-aware (ncursesw) curses library (gh-152470, gh-152233). On a narrow build a cell simply holds a single character with no combining marks, representable as one byte in the window’s encoding — the same API, degraded gracefully rather than absent. curses.textpad.Textbox was lifted onto this foundation and now edits the full Unicode range, not just Latin-1 (gh-133031).

2. Multiple terminals in one process

The second major feature: curses can now drive more than one terminal from a single process (gh-90092), which previously it could not model at all. The change adds:

  • curses.newterm() — initialize an additional terminal, returning a new screen object (documented as a first-class object with its own lifecycle).
  • curses.set_term() — switch the current terminal.
  • curses.new_prescr() and the window.use() method to bind windows to a screen.

Screen state can also be persisted: scr_dump(), scr_restore(), scr_init() and scr_set() dump the whole screen to a file and restore it (gh-152260).

3. Other newly wrapped functions

A batch of smaller X/Open gap-closers, each a straightforward binding: dynamic (extended) color-pair management (gh-151774), state-query functions such as is_cbreak / is_echo / is_raw (gh-151776), window attribute get/set methods with WA_* constants (gh-152219), key managementdefine_key(), key_defined(), keyok() (gh-152334), soft-label-key (slk_*) functions (gh-152263), term_attrs() (gh-152332), window.dupwin() (gh-152258), nofilter() (gh-151744), and the mouse helpers has_mouse() / window.mouse_trafo() (gh-152325).

4. Fixes, portability and docs

  • Correctness: use-after-free of the screen encoding (gh-151695); integer-overflow guards on the chtype / color-pair packing path (gh-152275); the public module name now appears in curses types and exceptions (gh-87904); Textbox can edit its last cell (gh-71880).
  • Build/portability: optional functions detected via configure probes (gh-152502); the mouse interface and is_* methods detected portably across ncurses / NetBSD / PDCurses / windows-curses (gh-152502); compilation fixed on platforms defining the stdscr macro (gh-153009) and a macOS build warning silenced (gh-152813); the test suite made portable to other curses implementations (gh-151693).
  • Docs: the curses documentation was reorganized into topic subsections (gh-152584), the classes documented (gh-87904), missing docstrings added (gh-151623), and results of inch() / getbkgd() documented (gh-87881).

Availability: the styled-cell types, multiple-terminal support and most new functions are 3.16+; several fixes (portability, overflow guards, Textbox 8-bit-locale support) were backported to 3.13–3.15.

10 Likes

Does this mean that the curses module will be available on the standard Windows builds of Python in future? Or is it simply that if you build your own Python, and have a curses library available, you can include curses?

2 Likes

And I should say thanks for this post (and the similar one for Tkinter). It’s nice to see focused news postings like this.

8 Likes

It is just a start of the work. The module can be built with PDCurses on Linux, and most code works, but there are some issues with running the testsuite (PDCurses only supports single terminal, some tests for new functions depend on this). The main issue – bundling. This is beyond my competence. If it was solved, I’ll try to blow the dust off mine Windows and make curses working on Windows.

4 Likes