Compare commits

...

4 Commits

Author SHA1 Message Date
Cheryl Sabella e40e2a2cc9
bpo-32631: IDLE: Enable zzdummy example extension module (GH-14491)
Make menu items work with formatter, add docstrings, add 100% tests.

Co-authored-by: Terry Jan Reedy <tjreedy@udel.edu>
2021-01-05 02:26:43 -05:00
Serhiy Storchaka 59f9b4e450
bpo-42681: Fix test_curses failures related to color pairs (GH-24089)
On ncurses 6.1 pair numbers are limited by SHORT_MAX-1, even
with extended color support.

Improve error reporting and tests for color functions.
2021-01-05 09:13:15 +02:00
Brandt Bucher 27f9dafc2b
bpo-40636: Remove overly-strict zip pickling tests (GH-24109) 2021-01-04 23:05:29 -08:00
Brandt Bucher cde988e893
Fix broken NEWS markup (GH-24110) 2021-01-04 22:55:14 -08:00
10 changed files with 311 additions and 108 deletions

View File

@ -3,6 +3,9 @@ Released on 2021-10-04?
====================================== ======================================
bpo-32631: Finish zzdummy example extension module: make menu entries
work; add docstrings and tests with 100% coverage.
bpo-42508: Keep IDLE running on macOS. Remove obsolete workaround bpo-42508: Keep IDLE running on macOS. Remove obsolete workaround
that prevented running files with shortcuts when using new universal2 that prevented running files with shortcuts when using new universal2
installers built on macOS 11. installers built on macOS 11.

View File

@ -2316,7 +2316,15 @@ display when Code Context is turned on for an editor window.
Shell Preferences: Auto-Squeeze Min. Lines is the minimum number of lines Shell Preferences: Auto-Squeeze Min. Lines is the minimum number of lines
of output to automatically "squeeze". of output to automatically "squeeze".
''' ''',
'Extensions': '''
ZzDummy: This extension is provided as an example for how to create and
use an extension. Enable indicates whether the extension is active or
not; likewise enable_editor and enable_shell indicate which windows it
will be active on. For this extension, z-text is the text that will be
inserted at or removed from the beginning of the lines of selected text,
or the current line if no selection.
''',
} }

View File

@ -28,8 +28,8 @@ variables:
(There are a few more, but they are rarely useful.) (There are a few more, but they are rarely useful.)
The extension class must not directly bind Window Manager (e.g. X) events. The extension class must not directly bind Window Manager (e.g. X) events.
Rather, it must define one or more virtual events, e.g. <<zoom-height>>, and Rather, it must define one or more virtual events, e.g. <<z-in>>, and
corresponding methods, e.g. zoom_height_event(). The virtual events will be corresponding methods, e.g. z_in_event(). The virtual events will be
bound to the corresponding methods, and Window Manager events can then be bound bound to the corresponding methods, and Window Manager events can then be bound
to the virtual events. (This indirection is done so that the key bindings can to the virtual events. (This indirection is done so that the key bindings can
easily be changed, and so that other sources of virtual events can exist, such easily be changed, and so that other sources of virtual events can exist, such
@ -54,21 +54,21 @@ Extensions are not required to define menu entries for all the events they
implement. (They are also not required to create keybindings, but in that implement. (They are also not required to create keybindings, but in that
case there must be empty bindings in cofig-extensions.def) case there must be empty bindings in cofig-extensions.def)
Here is a complete example: Here is a partial example from zzdummy.py:
class ZoomHeight: class ZzDummy:
menudefs = [ menudefs = [
('edit', [ ('format', [
None, # Separator ('Z in', '<<z-in>>'),
('_Zoom Height', '<<zoom-height>>'), ('Z out', '<<z-out>>'),
]) ] )
] ]
def __init__(self, editwin): def __init__(self, editwin):
self.editwin = editwin self.editwin = editwin
def zoom_height_event(self, event): def z_in_event(self, event=None):
"...Do what you want here..." "...Do what you want here..."
The final piece of the puzzle is the file "config-extensions.def", which is The final piece of the puzzle is the file "config-extensions.def", which is

View File

@ -0,0 +1,152 @@
"Test zzdummy, coverage 100%."
from idlelib import zzdummy
import unittest
from test.support import requires
from tkinter import Tk, Text
from unittest import mock
from idlelib import config
from idlelib import editor
from idlelib import format
usercfg = zzdummy.idleConf.userCfg
testcfg = {
'main': config.IdleUserConfParser(''),
'highlight': config.IdleUserConfParser(''),
'keys': config.IdleUserConfParser(''),
'extensions': config.IdleUserConfParser(''),
}
code_sample = """\
class C1():
# Class comment.
def __init__(self, a, b):
self.a = a
self.b = b
"""
class DummyEditwin:
get_selection_indices = editor.EditorWindow.get_selection_indices
def __init__(self, root, text):
self.root = root
self.top = root
self.text = text
self.fregion = format.FormatRegion(self)
self.text.undo_block_start = mock.Mock()
self.text.undo_block_stop = mock.Mock()
class ZZDummyTest(unittest.TestCase):
@classmethod
def setUpClass(cls):
requires('gui')
root = cls.root = Tk()
root.withdraw()
text = cls.text = Text(cls.root)
cls.editor = DummyEditwin(root, text)
zzdummy.idleConf.userCfg = testcfg
@classmethod
def tearDownClass(cls):
zzdummy.idleConf.userCfg = usercfg
del cls.editor, cls.text
cls.root.update_idletasks()
for id in cls.root.tk.call('after', 'info'):
cls.root.after_cancel(id) # Need for EditorWindow.
cls.root.destroy()
del cls.root
def setUp(self):
text = self.text
text.insert('1.0', code_sample)
text.undo_block_start.reset_mock()
text.undo_block_stop.reset_mock()
zz = self.zz = zzdummy.ZzDummy(self.editor)
zzdummy.ZzDummy.ztext = '# ignore #'
def tearDown(self):
self.text.delete('1.0', 'end')
del self.zz
def checklines(self, text, value):
# Verify that there are lines being checked.
end_line = int(float(text.index('end')))
# Check each line for the starting text.
actual = []
for line in range(1, end_line):
txt = text.get(f'{line}.0', f'{line}.end')
actual.append(txt.startswith(value))
return actual
def test_init(self):
zz = self.zz
self.assertEqual(zz.editwin, self.editor)
self.assertEqual(zz.text, self.editor.text)
def test_reload(self):
self.assertEqual(self.zz.ztext, '# ignore #')
testcfg['extensions'].SetOption('ZzDummy', 'z-text', 'spam')
zzdummy.ZzDummy.reload()
self.assertEqual(self.zz.ztext, 'spam')
def test_z_in_event(self):
eq = self.assertEqual
zz = self.zz
text = zz.text
eq(self.zz.ztext, '# ignore #')
# No lines have the leading text.
expected = [False, False, False, False, False, False, False]
actual = self.checklines(text, zz.ztext)
eq(expected, actual)
text.tag_add('sel', '2.0', '4.end')
eq(zz.z_in_event(), 'break')
expected = [False, True, True, True, False, False, False]
actual = self.checklines(text, zz.ztext)
eq(expected, actual)
text.undo_block_start.assert_called_once()
text.undo_block_stop.assert_called_once()
def test_z_out_event(self):
eq = self.assertEqual
zz = self.zz
text = zz.text
eq(self.zz.ztext, '# ignore #')
# Prepend text.
text.tag_add('sel', '2.0', '5.end')
zz.z_in_event()
text.undo_block_start.reset_mock()
text.undo_block_stop.reset_mock()
# Select a few lines to remove text.
text.tag_remove('sel', '1.0', 'end')
text.tag_add('sel', '3.0', '4.end')
eq(zz.z_out_event(), 'break')
expected = [False, True, False, False, True, False, False]
actual = self.checklines(text, zz.ztext)
eq(expected, actual)
text.undo_block_start.assert_called_once()
text.undo_block_stop.assert_called_once()
def test_roundtrip(self):
# Insert and remove to all code should give back original text.
zz = self.zz
text = zz.text
text.tag_add('sel', '1.0', 'end-1c')
zz.z_in_event()
zz.z_out_event()
self.assertEqual(text.get('1.0', 'end-1c'), code_sample)
if __name__ == '__main__':
unittest.main(verbosity=2)

View File

@ -1,42 +1,73 @@
"Example extension, also used for testing." """Example extension, also used for testing.
See extend.txt for more details on creating an extension.
See config-extension.def for configuring an extension.
"""
from idlelib.config import idleConf from idlelib.config import idleConf
from functools import wraps
ztext = idleConf.GetOption('extensions', 'ZzDummy', 'z-text')
def format_selection(format_line):
"Apply a formatting function to all of the selected lines."
@wraps(format_line)
def apply(self, event=None):
head, tail, chars, lines = self.formatter.get_region()
for pos in range(len(lines) - 1):
line = lines[pos]
lines[pos] = format_line(self, line)
self.formatter.set_region(head, tail, chars, lines)
return 'break'
return apply
class ZzDummy: class ZzDummy:
"""Prepend or remove initial text from selected lines."""
## menudefs = [ # Extend the format menu.
## ('format', [ menudefs = [
## ('Z in', '<<z-in>>'), ('format', [
## ('Z out', '<<z-out>>'), ('Z in', '<<z-in>>'),
## ] ) ('Z out', '<<z-out>>'),
## ] ] )
]
def __init__(self, editwin): def __init__(self, editwin):
"Initialize the settings for this extension."
self.editwin = editwin
self.text = editwin.text self.text = editwin.text
z_in = False self.formatter = editwin.fregion
@classmethod @classmethod
def reload(cls): def reload(cls):
"Load class variables from config."
cls.ztext = idleConf.GetOption('extensions', 'ZzDummy', 'z-text') cls.ztext = idleConf.GetOption('extensions', 'ZzDummy', 'z-text')
def z_in_event(self, event): @format_selection
""" def z_in_event(self, line):
""" """Insert text at the beginning of each selected line.
text = self.text
text.undo_block_start() This is bound to the <<z-in>> virtual event when the extensions
for line in range(1, text.index('end')): are loaded.
text.insert('%d.0', ztext) """
text.undo_block_stop() return f'{self.ztext}{line}'
return "break"
@format_selection
def z_out_event(self, line):
"""Remove specific text from the beginning of each selected line.
This is bound to the <<z-out>> virtual event when the extensions
are loaded.
"""
zlength = 0 if not line.startswith(self.ztext) else len(self.ztext)
return line[zlength:]
def z_out_event(self, event): pass
ZzDummy.reload() ZzDummy.reload()
##if __name__ == "__main__":
## import unittest if __name__ == "__main__":
## unittest.main('idlelib.idle_test.test_zzdummy', import unittest
## verbosity=2, exit=False) unittest.main('idlelib.idle_test.test_zzdummy', verbosity=2, exit=False)

View File

@ -1621,48 +1621,6 @@ class BuiltinTest(unittest.TestCase):
self.assertEqual(self.iter_error(z1, ValueError), t) self.assertEqual(self.iter_error(z1, ValueError), t)
self.assertEqual(self.iter_error(z2, ValueError), t) self.assertEqual(self.iter_error(z2, ValueError), t)
def test_zip_pickle_stability(self):
# Pickles of zip((1, 2, 3), (4, 5, 6)) dumped from 3.9:
pickles = [
b'citertools\nizip\np0\n(c__builtin__\niter\np1\n((I1\nI2\nI3\ntp2\ntp3\nRp4\nI0\nbg1\n((I4\nI5\nI6\ntp5\ntp6\nRp7\nI0\nbtp8\nRp9\n.',
b'citertools\nizip\nq\x00(c__builtin__\niter\nq\x01((K\x01K\x02K\x03tq\x02tq\x03Rq\x04K\x00bh\x01((K\x04K\x05K\x06tq\x05tq\x06Rq\x07K\x00btq\x08Rq\t.',
b'\x80\x02citertools\nizip\nq\x00c__builtin__\niter\nq\x01K\x01K\x02K\x03\x87q\x02\x85q\x03Rq\x04K\x00bh\x01K\x04K\x05K\x06\x87q\x05\x85q\x06Rq\x07K\x00b\x86q\x08Rq\t.',
b'\x80\x03cbuiltins\nzip\nq\x00cbuiltins\niter\nq\x01K\x01K\x02K\x03\x87q\x02\x85q\x03Rq\x04K\x00bh\x01K\x04K\x05K\x06\x87q\x05\x85q\x06Rq\x07K\x00b\x86q\x08Rq\t.',
b'\x80\x04\x95L\x00\x00\x00\x00\x00\x00\x00\x8c\x08builtins\x94\x8c\x03zip\x94\x93\x94\x8c\x08builtins\x94\x8c\x04iter\x94\x93\x94K\x01K\x02K\x03\x87\x94\x85\x94R\x94K\x00bh\x05K\x04K\x05K\x06\x87\x94\x85\x94R\x94K\x00b\x86\x94R\x94.',
b'\x80\x05\x95L\x00\x00\x00\x00\x00\x00\x00\x8c\x08builtins\x94\x8c\x03zip\x94\x93\x94\x8c\x08builtins\x94\x8c\x04iter\x94\x93\x94K\x01K\x02K\x03\x87\x94\x85\x94R\x94K\x00bh\x05K\x04K\x05K\x06\x87\x94\x85\x94R\x94K\x00b\x86\x94R\x94.',
]
for protocol, dump in enumerate(pickles):
z1 = zip((1, 2, 3), (4, 5, 6))
z2 = zip((1, 2, 3), (4, 5, 6), strict=False)
z3 = pickle.loads(dump)
l3 = list(z3)
self.assertEqual(type(z3), zip)
self.assertEqual(pickle.dumps(z1, protocol), dump)
self.assertEqual(pickle.dumps(z2, protocol), dump)
self.assertEqual(list(z1), l3)
self.assertEqual(list(z2), l3)
def test_zip_pickle_strict_stability(self):
# Pickles of zip((1, 2, 3), (4, 5), strict=True) dumped from 3.10:
pickles = [
b'citertools\nizip\np0\n(c__builtin__\niter\np1\n((I1\nI2\nI3\ntp2\ntp3\nRp4\nI0\nbg1\n((I4\nI5\ntp5\ntp6\nRp7\nI0\nbtp8\nRp9\nI01\nb.',
b'citertools\nizip\nq\x00(c__builtin__\niter\nq\x01((K\x01K\x02K\x03tq\x02tq\x03Rq\x04K\x00bh\x01((K\x04K\x05tq\x05tq\x06Rq\x07K\x00btq\x08Rq\tI01\nb.',
b'\x80\x02citertools\nizip\nq\x00c__builtin__\niter\nq\x01K\x01K\x02K\x03\x87q\x02\x85q\x03Rq\x04K\x00bh\x01K\x04K\x05\x86q\x05\x85q\x06Rq\x07K\x00b\x86q\x08Rq\t\x88b.',
b'\x80\x03cbuiltins\nzip\nq\x00cbuiltins\niter\nq\x01K\x01K\x02K\x03\x87q\x02\x85q\x03Rq\x04K\x00bh\x01K\x04K\x05\x86q\x05\x85q\x06Rq\x07K\x00b\x86q\x08Rq\t\x88b.',
b'\x80\x04\x95L\x00\x00\x00\x00\x00\x00\x00\x8c\x08builtins\x94\x8c\x03zip\x94\x93\x94\x8c\x08builtins\x94\x8c\x04iter\x94\x93\x94K\x01K\x02K\x03\x87\x94\x85\x94R\x94K\x00bh\x05K\x04K\x05\x86\x94\x85\x94R\x94K\x00b\x86\x94R\x94\x88b.',
b'\x80\x05\x95L\x00\x00\x00\x00\x00\x00\x00\x8c\x08builtins\x94\x8c\x03zip\x94\x93\x94\x8c\x08builtins\x94\x8c\x04iter\x94\x93\x94K\x01K\x02K\x03\x87\x94\x85\x94R\x94K\x00bh\x05K\x04K\x05\x86\x94\x85\x94R\x94K\x00b\x86\x94R\x94\x88b.',
]
a = (1, 2, 3)
b = (4, 5)
t = [(1, 4), (2, 5)]
for protocol, dump in enumerate(pickles):
z1 = zip(a, b, strict=True)
z2 = pickle.loads(dump)
self.assertEqual(pickle.dumps(z1, protocol), dump)
self.assertEqual(type(z2), zip)
self.assertEqual(self.iter_error(z1, ValueError), t)
self.assertEqual(self.iter_error(z2, ValueError), t)
def test_zip_bad_iterable(self): def test_zip_bad_iterable(self):
exception = TypeError() exception = TypeError()

View File

@ -47,6 +47,7 @@ def requires_colors(test):
return wrapped return wrapped
term = os.environ.get('TERM') term = os.environ.get('TERM')
SHORT_MAX = 0x7fff
# If newterm was supported we could use it instead of initscr and not exit # If newterm was supported we could use it instead of initscr and not exit
@unittest.skipIf(not term or term == 'unknown', @unittest.skipIf(not term or term == 'unknown',
@ -327,11 +328,20 @@ class TestCurses(unittest.TestCase):
def bad_pairs(self): def bad_pairs(self):
return (-1, -2**31 - 1, 2**31, -2**63 - 1, 2**63, 2**64) return (-1, -2**31 - 1, 2**31, -2**63 - 1, 2**63, 2**64)
def test_start_color(self):
if not curses.has_colors():
self.skipTest('requires colors support')
curses.start_color()
if verbose:
print(f'COLORS = {curses.COLORS}', file=sys.stderr)
print(f'COLOR_PAIRS = {curses.COLOR_PAIRS}', file=sys.stderr)
@requires_colors @requires_colors
def test_color_content(self): def test_color_content(self):
self.assertEqual(curses.color_content(curses.COLOR_BLACK), (0, 0, 0)) self.assertEqual(curses.color_content(curses.COLOR_BLACK), (0, 0, 0))
curses.color_content(0) curses.color_content(0)
curses.color_content(curses.COLORS - 1) maxcolor = curses.COLORS - 1
curses.color_content(maxcolor)
for color in self.bad_colors(): for color in self.bad_colors():
self.assertRaises(ValueError, curses.color_content, color) self.assertRaises(ValueError, curses.color_content, color)
@ -352,11 +362,12 @@ class TestCurses(unittest.TestCase):
curses.init_color(0, 1000, 1000, 1000) curses.init_color(0, 1000, 1000, 1000)
self.assertEqual(curses.color_content(0), (1000, 1000, 1000)) self.assertEqual(curses.color_content(0), (1000, 1000, 1000))
old = curses.color_content(curses.COLORS - 1) maxcolor = curses.COLORS - 1
curses.init_color(curses.COLORS - 1, *old) old = curses.color_content(maxcolor)
self.addCleanup(curses.init_color, curses.COLORS - 1, *old) curses.init_color(maxcolor, *old)
curses.init_color(curses.COLORS - 1, 0, 500, 1000) self.addCleanup(curses.init_color, maxcolor, *old)
self.assertEqual(curses.color_content(curses.COLORS - 1), (0, 500, 1000)) curses.init_color(maxcolor, 0, 500, 1000)
self.assertEqual(curses.color_content(maxcolor), (0, 500, 1000))
for color in self.bad_colors(): for color in self.bad_colors():
self.assertRaises(ValueError, curses.init_color, color, 0, 0, 0) self.assertRaises(ValueError, curses.init_color, color, 0, 0, 0)
@ -365,13 +376,25 @@ class TestCurses(unittest.TestCase):
self.assertRaises(ValueError, curses.init_color, 0, 0, comp, 0) self.assertRaises(ValueError, curses.init_color, 0, 0, comp, 0)
self.assertRaises(ValueError, curses.init_color, 0, 0, 0, comp) self.assertRaises(ValueError, curses.init_color, 0, 0, 0, comp)
def get_pair_limit(self):
pair_limit = curses.COLOR_PAIRS
if hasattr(curses, 'ncurses_version'):
if curses.has_extended_color_support():
pair_limit += 2*curses.COLORS + 1
if (not curses.has_extended_color_support()
or (6, 1) <= curses.ncurses_version < (6, 2)):
pair_limit = min(pair_limit, SHORT_MAX)
return pair_limit
@requires_colors @requires_colors
def test_pair_content(self): def test_pair_content(self):
if not hasattr(curses, 'use_default_colors'): if not hasattr(curses, 'use_default_colors'):
self.assertEqual(curses.pair_content(0), self.assertEqual(curses.pair_content(0),
(curses.COLOR_WHITE, curses.COLOR_BLACK)) (curses.COLOR_WHITE, curses.COLOR_BLACK))
curses.pair_content(0) curses.pair_content(0)
curses.pair_content(curses.COLOR_PAIRS - 1) maxpair = self.get_pair_limit() - 1
if maxpair > 0:
curses.pair_content(maxpair)
for pair in self.bad_pairs(): for pair in self.bad_pairs():
self.assertRaises(ValueError, curses.pair_content, pair) self.assertRaises(ValueError, curses.pair_content, pair)
@ -384,11 +407,15 @@ class TestCurses(unittest.TestCase):
curses.init_pair(1, 0, 0) curses.init_pair(1, 0, 0)
self.assertEqual(curses.pair_content(1), (0, 0)) self.assertEqual(curses.pair_content(1), (0, 0))
curses.init_pair(1, curses.COLORS - 1, curses.COLORS - 1) maxcolor = curses.COLORS - 1
self.assertEqual(curses.pair_content(1), curses.init_pair(1, maxcolor, 0)
(curses.COLORS - 1, curses.COLORS - 1)) self.assertEqual(curses.pair_content(1), (maxcolor, 0))
curses.init_pair(curses.COLOR_PAIRS - 1, 2, 3) curses.init_pair(1, 0, maxcolor)
self.assertEqual(curses.pair_content(curses.COLOR_PAIRS - 1), (2, 3)) self.assertEqual(curses.pair_content(1), (0, maxcolor))
maxpair = self.get_pair_limit() - 1
if maxpair > 1:
curses.init_pair(maxpair, 0, 0)
self.assertEqual(curses.pair_content(maxpair), (0, 0))
for pair in self.bad_pairs(): for pair in self.bad_pairs():
self.assertRaises(ValueError, curses.init_pair, pair, 0, 0) self.assertRaises(ValueError, curses.init_pair, pair, 0, 0)
@ -582,6 +609,8 @@ class MiscTests(unittest.TestCase):
@requires_curses_func('ncurses_version') @requires_curses_func('ncurses_version')
def test_ncurses_version(self): def test_ncurses_version(self):
v = curses.ncurses_version v = curses.ncurses_version
if verbose:
print(f'ncurses_version = {curses.ncurses_version}', flush=True)
self.assertIsInstance(v[:], tuple) self.assertIsInstance(v[:], tuple)
self.assertEqual(len(v), 3) self.assertEqual(len(v), 3)
self.assertIsInstance(v[0], int) self.assertIsInstance(v[0], int)

View File

@ -0,0 +1,2 @@
Finish zzdummy example extension module: make menu entries work;
add docstrings and tests with 100% coverage.

View File

@ -1 +1 @@
In :mod:`sqlite3`, fix `CheckTraceCallbackContent` for SQLite pre 3.7.15. In :mod:`sqlite3`, fix ``CheckTraceCallbackContent`` for SQLite pre 3.7.15.

View File

@ -135,29 +135,28 @@ typedef chtype attr_t; /* No attr_t type is available */
#define STRICT_SYSV_CURSES #define STRICT_SYSV_CURSES
#endif #endif
#if defined(NCURSES_EXT_COLORS) && defined(NCURSES_EXT_FUNCS) #if NCURSES_EXT_COLORS+0 && NCURSES_EXT_FUNCS+0
#define _NCURSES_EXTENDED_COLOR_FUNCS 1 #define _NCURSES_EXTENDED_COLOR_FUNCS 1
#else #else
#define _NCURSES_EXTENDED_COLOR_FUNCS 0 #define _NCURSES_EXTENDED_COLOR_FUNCS 0
#endif /* defined(NCURSES_EXT_COLORS) && defined(NCURSES_EXT_FUNCS) */ #endif /* defined(NCURSES_EXT_COLORS) && defined(NCURSES_EXT_FUNCS) */
#if _NCURSES_EXTENDED_COLOR_FUNCS #if _NCURSES_EXTENDED_COLOR_FUNCS
#define _NCURSES_COLOR_VAL_TYPE int #define _CURSES_COLOR_VAL_TYPE int
#define _CURSES_COLOR_NUM_TYPE int
#define _CURSES_INIT_COLOR_FUNC init_extended_color #define _CURSES_INIT_COLOR_FUNC init_extended_color
#define _CURSES_INIT_PAIR_FUNC init_extended_pair #define _CURSES_INIT_PAIR_FUNC init_extended_pair
#define _COLOR_CONTENT_FUNC extended_color_content #define _COLOR_CONTENT_FUNC extended_color_content
#define _CURSES_PAIR_NUMBER_FUNC extended_pair_content #define _CURSES_PAIR_CONTENT_FUNC extended_pair_content
#else #else
#define _NCURSES_COLOR_VAL_TYPE short #define _CURSES_COLOR_VAL_TYPE short
#define _CURSES_COLOR_NUM_TYPE short
#define _CURSES_INIT_COLOR_FUNC init_color #define _CURSES_INIT_COLOR_FUNC init_color
#define _CURSES_INIT_PAIR_FUNC init_pair #define _CURSES_INIT_PAIR_FUNC init_pair
#define _COLOR_CONTENT_FUNC color_content #define _COLOR_CONTENT_FUNC color_content
#define _CURSES_PAIR_NUMBER_FUNC pair_content #define _CURSES_PAIR_CONTENT_FUNC pair_content
#endif /* _NCURSES_EXTENDED_COLOR_FUNCS */ #endif /* _NCURSES_EXTENDED_COLOR_FUNCS */
#define _CURSES_INIT_COLOR_FUNC_NAME Py_STRINGIFY(_CURSES_INIT_COLOR_FUNC)
#define _CURSES_INIT_PAIR_FUNC_NAME Py_STRINGIFY(_CURSES_INIT_PAIR_FUNC)
/*[clinic input] /*[clinic input]
module _curses module _curses
class _curses.window "PyCursesWindowObject *" "&PyCursesWindow_Type" class _curses.window "PyCursesWindowObject *" "&PyCursesWindow_Type"
@ -2737,18 +2736,18 @@ static PyObject *
_curses_color_content_impl(PyObject *module, int color_number) _curses_color_content_impl(PyObject *module, int color_number)
/*[clinic end generated code: output=17b466df7054e0de input=03b5ed0472662aea]*/ /*[clinic end generated code: output=17b466df7054e0de input=03b5ed0472662aea]*/
{ {
_NCURSES_COLOR_VAL_TYPE r,g,b; _CURSES_COLOR_VAL_TYPE r,g,b;
PyCursesInitialised; PyCursesInitialised;
PyCursesInitialisedColor; PyCursesInitialisedColor;
if (_COLOR_CONTENT_FUNC(color_number, &r, &g, &b) != ERR) if (_COLOR_CONTENT_FUNC(color_number, &r, &g, &b) == ERR) {
return Py_BuildValue("(iii)", r, g, b); PyErr_Format(PyCursesError, "%s() returned ERR",
else { Py_STRINGIFY(_COLOR_CONTENT_FUNC));
PyErr_SetString(PyCursesError,
"Argument 1 was out of range. Check value of COLORS.");
return NULL; return NULL;
} }
return Py_BuildValue("(iii)", r, g, b);
} }
/*[clinic input] /*[clinic input]
@ -3190,7 +3189,8 @@ _curses_init_color_impl(PyObject *module, int color_number, short r, short g,
PyCursesInitialised; PyCursesInitialised;
PyCursesInitialisedColor; PyCursesInitialisedColor;
return PyCursesCheckERR(_CURSES_INIT_COLOR_FUNC(color_number, r, g, b), _CURSES_INIT_COLOR_FUNC_NAME); return PyCursesCheckERR(_CURSES_INIT_COLOR_FUNC(color_number, r, g, b),
Py_STRINGIFY(_CURSES_INIT_COLOR_FUNC));
} }
/*[clinic input] /*[clinic input]
@ -3217,7 +3217,20 @@ _curses_init_pair_impl(PyObject *module, int pair_number, int fg, int bg)
PyCursesInitialised; PyCursesInitialised;
PyCursesInitialisedColor; PyCursesInitialisedColor;
return PyCursesCheckERR(_CURSES_INIT_PAIR_FUNC(pair_number, fg, bg), _CURSES_INIT_PAIR_FUNC_NAME); if (_CURSES_INIT_PAIR_FUNC(pair_number, fg, bg) == ERR) {
if (pair_number >= COLOR_PAIRS) {
PyErr_Format(PyExc_ValueError,
"Color pair is greater than COLOR_PAIRS-1 (%d).",
COLOR_PAIRS - 1);
}
else {
PyErr_Format(PyCursesError, "%s() returned ERR",
Py_STRINGIFY(_CURSES_INIT_PAIR_FUNC));
}
return NULL;
}
Py_RETURN_NONE;
} }
static PyObject *ModDict; static PyObject *ModDict;
@ -3845,14 +3858,21 @@ static PyObject *
_curses_pair_content_impl(PyObject *module, int pair_number) _curses_pair_content_impl(PyObject *module, int pair_number)
/*[clinic end generated code: output=4a726dd0e6885f3f input=03970f840fc7b739]*/ /*[clinic end generated code: output=4a726dd0e6885f3f input=03970f840fc7b739]*/
{ {
_NCURSES_COLOR_VAL_TYPE f, b; _CURSES_COLOR_NUM_TYPE f, b;
PyCursesInitialised; PyCursesInitialised;
PyCursesInitialisedColor; PyCursesInitialisedColor;
if (_CURSES_PAIR_NUMBER_FUNC(pair_number, &f, &b)==ERR) { if (_CURSES_PAIR_CONTENT_FUNC(pair_number, &f, &b) == ERR) {
PyErr_SetString(PyCursesError, if (pair_number >= COLOR_PAIRS) {
"Argument 1 was out of range. (0..COLOR_PAIRS-1)"); PyErr_Format(PyExc_ValueError,
"Color pair is greater than COLOR_PAIRS-1 (%d).",
COLOR_PAIRS - 1);
}
else {
PyErr_Format(PyCursesError, "%s() returned ERR",
Py_STRINGIFY(_CURSES_PAIR_CONTENT_FUNC));
}
return NULL; return NULL;
} }