Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 9 additions & 6 deletions Doc/library/curses.rst
Original file line number Diff line number Diff line change
Expand Up @@ -1404,26 +1404,29 @@ Reading window contents
window.instr(y, x[, n])

Read the text of the window from the current cursor position,
or from *y*, *x* if specified, to the end of the line,
or from *y*, *x* if specified, to the end of the line
or at most *n* bytes if *n* is specified,
and return it as a bytes object, in the encoding of the current locale.
Attributes and color pairs are stripped;
use :meth:`in_wchstr` to read them too.
At most *n* bytes are read; *n* defaults to and cannot exceed 2047.
A character not representable in the encoding cannot be returned;
use :meth:`in_wstr` for those.

.. versionchanged:: 3.14
The maximum value for *n* was increased from 1023 to 2047.

.. versionchanged:: next
*n* is no longer limited to 2047.

.. method:: window.in_wstr([n])
window.in_wstr(y, x[, n])

Read the text of the window from the current cursor position,
or from *y*, *x* if specified, to the end of the line,
or from *y*, *x* if specified, to the end of the line
or at most *n* characters if *n* is specified,
and return it as a :class:`str`.
Attributes and color pairs are stripped;
use :meth:`in_wchstr` to read them too.
At most *n* characters are read; *n* defaults to and cannot exceed 2047.

This is the wide-character variant of :meth:`instr`.

Expand All @@ -1433,12 +1436,12 @@ Reading window contents
window.in_wchstr(y, x[, n])

Read the styled cells of the window from the current cursor position,
or from *y*, *x* if specified, to the end of the line,
or from *y*, *x* if specified, to the end of the line
or at most *n* cells if *n* is specified,
and return them as a :class:`complexstr`.
Unlike :meth:`instr` and :meth:`in_wstr`, each cell keeps its attributes
and color pair, so the result can be written back unchanged
with :meth:`addstr`.
At most *n* cells are read; *n* defaults to and cannot exceed 2047.

.. versionadded:: next

Expand Down
34 changes: 34 additions & 0 deletions Lib/test/test_curses.py
Original file line number Diff line number Diff line change
Expand Up @@ -672,6 +672,11 @@ def test_in_wstr(self):
stdscr.addstr(0, 0, 'abz')
self.assertEqual(stdscr.in_wstr(0, 0, 0), '')
self.assertEqual(stdscr.in_wstr(0), '')
self.assertEqual(stdscr.in_wstr(0, 0, 2**31), stdscr.in_wstr(0, 0))
self.assertRaises(OverflowError, stdscr.in_wstr, 2**1000)
self.assertRaises(ValueError, stdscr.in_wstr, -2)
self.assertRaises(ValueError, stdscr.in_wstr, 0, 2, -2)
self.assertRaises(ValueError, stdscr.in_wstr, -2**1000)

def test_complexchar(self):
# A complexchar is a styled wide-character cell: str() is its text,
Expand Down Expand Up @@ -871,6 +876,11 @@ def test_in_wchstr(self):
# The count is optional and reads to the end of the line by default.
stdscr.move(0, 0)
self.assertEqual(str(stdscr.in_wchstr())[:3], 'AbC')
self.assertEqual(stdscr.in_wchstr(0, 0, 2**31), stdscr.in_wchstr(0, 0))
self.assertRaises(OverflowError, stdscr.in_wchstr, 2**1000)
self.assertRaises(ValueError, stdscr.in_wchstr, -2)
self.assertRaises(ValueError, stdscr.in_wchstr, 0, 2, -2)
self.assertRaises(ValueError, stdscr.in_wchstr, -2**1000)

def test_complexstr_in_write_methods(self):
# addstr/addnstr/insstr/insnstr also accept a complexstr, written via
Expand Down Expand Up @@ -1188,8 +1198,13 @@ def test_read_from_window(self):
self.assertEqual(stdscr.instr(3)[:6], b' AB')
self.assertEqual(stdscr.instr(0, 2)[:4], b'BCD ')
self.assertEqual(stdscr.instr(0, 2, 4), b'BCD ')
# A huge count is bounded by the line, and is not used to size the
# read buffer.
self.assertEqual(stdscr.instr(0, 0, 2**31), stdscr.instr(0, 0))
self.assertRaises(OverflowError, stdscr.instr, 2**1000)
self.assertRaises(ValueError, stdscr.instr, -2)
self.assertRaises(ValueError, stdscr.instr, 0, 2, -2)
self.assertRaises(ValueError, stdscr.instr, -2**1000)
# instr(y, x, 1) reads a single cell byte, so only a character that the
# window encoding maps to one byte is checked. inch() returns the cell
# value, which is the locale byte.
Expand All @@ -1206,6 +1221,25 @@ def test_read_from_window(self):
self.assertEqual(stdscr.instr(2, 0, 1), b)
self.assertEqual(stdscr.inch(2, 0), v)

def test_read_long_line(self):
# A pad line can be longer than a window, and a character can be
# encoded with several bytes, so instr() can read more bytes than
# there are cells. See _encodable for the character set.
width = 3000
pad = curses.newpad(1, width)
for ch in ['z', '\u00e9', '\u20ac', '\u0434', '\uff71']:
if not self._storable(ch):
continue
pad.addstr(0, 0, ch)
if pad.getyx()[1] != 1:
continue # a wide character occupies two cells
with self.subTest(ch=ch):
line = ch * (width - 1) + ' ' # the last cell is left blank
pad.addstr(0, 0, line[:-1])
self.assertEqual(pad.instr(0, 0), line.encode(pad.encoding))
self.assertEqual(pad.in_wstr(0, 0), line)
self.assertEqual(str(pad.in_wchstr(0, 0)), line)

def test_coordinate_errors(self):
# Addressing a cell outside the window raises curses.error.
win = curses.newwin(5, 10, 0, 0)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
:meth:`curses.window.instr`, :meth:`~curses.window.in_wstr` and
:meth:`~curses.window.in_wchstr` no longer limit the count to 2047, which
silently truncated a longer line.
Loading
Loading