Skip to content

Commit 286b512

Browse files
gh-152470: Make wide-character curses functions work on a narrow build (GH-152476)
curses.window.get_wch, curses.window.get_wstr, curses.unget_wch, curses.erasewchar, curses.killwchar and curses.wunctrl now also work when Python is built against a non-wide curses library, on an 8-bit locale, where each character is a single byte in the relevant encoding. curses.ungetch now also accepts a one-character string, like curses.unget_wch. Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
1 parent 95bfaff commit 286b512

7 files changed

Lines changed: 317 additions & 197 deletions

File tree

Doc/library/curses.rst

Lines changed: 61 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -206,17 +206,15 @@ The module :mod:`!curses` defines the following functions:
206206

207207
.. function:: erasechar()
208208

209-
Return the user's current erase character as a one-byte bytes object. Under Unix operating systems this
210-
is a property of the controlling tty of the curses program, and is not set by
211-
the curses library itself.
209+
Return the user's current erase character as a raw byte, a :class:`bytes`
210+
object of length 1. See also :func:`erasewchar`.
212211

213212

214213
.. function:: erasewchar()
215214

216-
Return the user's current erase character as a one-character string.
217-
This is the wide-character variant of :func:`erasechar`. Availability
218-
depends on building Python against a wide-character-aware version of the
219-
underlying curses library.
215+
Return the user's current erase character as a one-character :class:`str`.
216+
Under Unix operating systems this is a property of the controlling tty of the
217+
curses program, and is not set by the curses library itself.
220218

221219
.. versionadded:: next
222220

@@ -493,17 +491,15 @@ The module :mod:`!curses` defines the following functions:
493491

494492
.. function:: killchar()
495493

496-
Return the user's current line kill character as a one-byte bytes object. Under Unix operating systems
497-
this is a property of the controlling tty of the curses program, and is not set
498-
by the curses library itself.
494+
Return the user's current line kill character as a raw byte, a :class:`bytes`
495+
object of length 1. See also :func:`killwchar`.
499496

500497

501498
.. function:: killwchar()
502499

503-
Return the user's current line kill character as a one-character string.
504-
This is the wide-character variant of :func:`killchar`. Availability
505-
depends on building Python against a wide-character-aware version of the
506-
underlying curses library.
500+
Return the user's current line kill character as a one-character :class:`str`.
501+
Under Unix operating systems this is a property of the controlling tty of the
502+
curses program, and is not set by the curses library itself.
507503

508504
.. versionadded:: next
509505

@@ -910,30 +906,39 @@ The module :mod:`!curses` defines the following functions:
910906
.. function:: unctrl(ch)
911907

912908
Return a bytes object which is a printable representation of the character *ch*.
913-
Control characters are represented as a caret followed by the character, for
914-
example as ``b'^C'``. Printing characters are left as they are.
909+
*ch* cannot be a character that does not fit in a single byte; use
910+
:func:`wunctrl` for those.
915911

916912

917913
.. function:: wunctrl(ch)
918914

919-
Return a string which is a printable representation of the wide character *ch*.
920-
Control characters are represented as a caret followed by the character, for
921-
example as ``'^C'``. Printing characters are left as they are. This is the
922-
wide-character variant of :func:`unctrl`, returning a :class:`str` rather than
923-
:class:`bytes`. Availability depends on building Python against a
924-
wide-character-aware version of the underlying curses library.
915+
Return a string which is a printable representation of the character *ch*;
916+
any attributes and color pair are ignored.
917+
ASCII control characters are represented as a caret followed by a character,
918+
for example as ``'^C'``. Printing characters, including non-ASCII characters
919+
printable in the locale, are left as they are. The representation of other
920+
characters is defined by the underlying curses library.
925921

926922
.. versionadded:: next
927923

928924

929925
.. function:: ungetch(ch)
930926

931-
Push *ch* so the next :meth:`~window.getch` will return it.
927+
Push *ch* so the next :meth:`~window.getch` or :meth:`~window.get_wch` will
928+
return it.
929+
930+
*ch* may be an integer (a key code or character code), a byte, or a string of
931+
length 1. A one-character string is pushed like :func:`unget_wch`; on a
932+
narrow build it must encode to a single byte.
932933

933934
.. note::
934935

935936
Only one *ch* can be pushed before :meth:`!getch` is called.
936937

938+
.. versionchanged:: next
939+
A one-character string argument is no longer required to encode to a single
940+
byte, except on a narrow build.
941+
937942

938943
.. function:: update_lines_cols()
939944

@@ -953,6 +958,10 @@ The module :mod:`!curses` defines the following functions:
953958

954959
.. versionadded:: 3.3
955960

961+
.. versionchanged:: next
962+
Also available on a narrow build, where *ch* must encode to a single byte
963+
(an 8-bit locale).
964+
956965

957966
.. function:: ungetmouse(id, x, y, z, bstate)
958967

@@ -1323,15 +1332,16 @@ Window objects
13231332
.. method:: window.getbkgd()
13241333

13251334
Return the given window's current background character/attribute pair.
1335+
It cannot represent a background set with a wide character or with a color
1336+
pair outside the :func:`color_pair` range; use :meth:`getbkgrnd` for those.
13261337

13271338

13281339
.. method:: window.getbkgrnd()
13291340

13301341
Return the given window's current background as a :class:`complexchar`.
1331-
This is the wide-character variant of :meth:`getbkgd`: the returned object
1332-
carries the background character together with its attributes and color pair,
1333-
and the color pair is not limited to the value that fits in a
1334-
:func:`color_pair`.
1342+
Unlike :meth:`getbkgd`, the returned object carries the background character
1343+
together with its attributes and color pair, and the color pair is not limited
1344+
to the value that fits in a :func:`color_pair`.
13351345

13361346
.. versionadded:: next
13371347

@@ -1342,16 +1352,23 @@ Window objects
13421352
range: function keys, keypad keys and so on are represented by numbers higher
13431353
than 255. In no-delay mode, return ``-1`` if there is no input, otherwise
13441354
wait until a key is pressed.
1355+
A multibyte character is returned as its encoded bytes one at a time; use
1356+
:meth:`get_wch` to read it as a single character.
13451357

13461358

13471359
.. method:: window.get_wch([y, x])
13481360

13491361
Get a wide character. Return a character for most keys, or an integer for
1350-
function keys, keypad keys, and other special keys.
1362+
function keys, keypad keys, and other special keys. Unlike :meth:`getch`, an
1363+
ordinary key is returned as a one-character :class:`str`.
13511364
In no-delay mode, raise an exception if there is no input.
13521365

13531366
.. versionadded:: 3.3
13541367

1368+
.. versionchanged:: next
1369+
Also available on a narrow build, where only a character representable as a
1370+
single byte (an 8-bit locale) can be returned.
1371+
13551372

13561373
.. method:: window.getdelay()
13571374

@@ -1407,6 +1424,8 @@ Window objects
14071424
Read a bytes object from the user, with primitive line editing capacity.
14081425
At most *n* characters are read;
14091426
*n* defaults to and cannot exceed 2047.
1427+
A multibyte character is returned as its encoded bytes; use :meth:`get_wstr`
1428+
to read the input as a :class:`str`.
14101429

14111430
.. versionchanged:: 3.14
14121431
The maximum value for *n* was increased from 1023 to 2047.
@@ -1418,9 +1437,8 @@ Window objects
14181437
window.get_wstr(y, x, n)
14191438

14201439
Read a string from the user, with primitive line editing capacity.
1421-
This is the wide-character variant of :meth:`getstr`: it returns a
1422-
:class:`str` rather than a :class:`bytes` object, so it can return
1423-
characters that are not representable in the window's encoding.
1440+
Unlike :meth:`getstr`, it can return characters that are not representable in
1441+
the window's encoding.
14241442
At most *n* characters are read; *n* defaults to and cannot exceed 2047.
14251443

14261444
.. versionadded:: next
@@ -1470,15 +1488,17 @@ Window objects
14701488

14711489
Return the character at the given position in the window. The bottom 8 bits are
14721490
the character proper, and upper bits are the attributes.
1491+
It cannot represent a cell holding combining characters, a character that does
1492+
not fit in a single byte, or a color pair outside the :func:`color_pair`
1493+
range; use :meth:`in_wch` for those.
14731494

14741495

14751496
.. method:: window.in_wch([y, x])
14761497

14771498
Return the complex character at the given position in the window as a
1478-
:class:`complexchar`. This is the wide-character variant of :meth:`inch`:
1479-
the returned object carries the cell's text (a spacing character optionally
1480-
followed by combining characters) together with its attributes and color
1481-
pair, none of which :meth:`inch` can represent.
1499+
:class:`complexchar`. Unlike :meth:`inch`, the returned object carries the
1500+
cell's text (a spacing character optionally followed by combining characters)
1501+
together with its attributes and color pair.
14821502

14831503
.. versionadded:: next
14841504

@@ -1548,6 +1568,8 @@ Window objects
15481568
from the characters. If *n* is specified, :meth:`instr` returns a string
15491569
at most *n* characters long (exclusive of the trailing NUL).
15501570
The maximum value for *n* is 2047.
1571+
A character not representable in the window's encoding cannot be returned;
1572+
use :meth:`in_wstr` for those.
15511573

15521574
.. versionchanged:: 3.14
15531575
The maximum value for *n* was increased from 1023 to 2047.
@@ -1557,11 +1579,10 @@ Window objects
15571579
window.in_wstr(y, x[, n])
15581580

15591581
Return a string of characters, extracted from the window starting at the
1560-
current cursor position, or at *y*, *x* if specified. This is the
1561-
wide-character variant of :meth:`instr`: it returns a :class:`str` rather
1562-
than a :class:`bytes` object, so it can return characters that are not
1563-
representable in the window's encoding. Attributes and color information
1564-
are stripped from the characters. The maximum value for *n* is 2047.
1582+
current cursor position, or at *y*, *x* if specified. Unlike :meth:`instr`,
1583+
it can return characters that are not representable in the window's encoding.
1584+
Attributes and color information are stripped from the characters. The
1585+
maximum value for *n* is 2047.
15651586

15661587
.. versionadded:: next
15671588

Doc/whatsnew/3.16.rst

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -113,12 +113,20 @@ curses
113113
:func:`curses.erasechar`, :func:`curses.killchar` and :func:`curses.unctrl`.
114114
On a narrow (non-ncursesw) build the character cell holds a single character
115115
without combining marks, representable as one byte in the window's encoding,
116-
and :meth:`~curses.window.in_wstr` returns its decoded text;
117-
:meth:`~curses.window.get_wstr` and the :func:`curses.erasewchar`,
118-
:func:`curses.killwchar` and :func:`curses.wunctrl` functions require the
119-
wide-character ncursesw library.
116+
and :meth:`~curses.window.in_wstr` returns its decoded text.
120117
(Contributed by Serhiy Storchaka in :gh:`151757`.)
121118

119+
* The wide-character :mod:`curses` functions and methods
120+
:meth:`~curses.window.get_wch`, :meth:`~curses.window.get_wstr`,
121+
:func:`curses.unget_wch`, :func:`curses.erasewchar`,
122+
:func:`curses.killwchar` and :func:`curses.wunctrl` now also work when Python
123+
is not built against a wide-character-aware curses library, on an 8-bit
124+
locale, where each character is a single byte in the relevant encoding.
125+
:func:`curses.ungetch` now also accepts a one-character string, like
126+
:func:`curses.unget_wch`; on a wide-character build it can be any character
127+
(previously a multibyte character raised :exc:`OverflowError`).
128+
(Contributed by Serhiy Storchaka in :gh:`152470`.)
129+
122130
* Add :func:`curses.nofilter`, which undoes the effect of :func:`curses.filter`.
123131
(Contributed by Serhiy Storchaka in :gh:`151744`.)
124132

0 commit comments

Comments
 (0)