bpo-31680: Add curses.ncurses_version. (GH-4217)

Use curses.ncurses_version for conditionally skipping a test.
This commit is contained in:
Serhiy Storchaka 2018-10-30 13:22:42 +02:00 committed by GitHub
parent 3e429dcc24
commit b232df9197
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 119 additions and 3 deletions

View File

@ -1291,6 +1291,19 @@ The :mod:`curses` module defines the following data members:
A bytes object representing the current version of the module. Also available as A bytes object representing the current version of the module. Also available as
:const:`__version__`. :const:`__version__`.
.. data:: ncurses_version
A named tuple containing the three components of the ncurses library
version: *major*, *minor*, and *patch*. All values are integers. The
components can also be accessed by name, so ``curses.ncurses_version[0]``
is equivalent to ``curses.ncurses_version.major`` and so on.
Availability: if the ncurses library is used.
.. versionadded:: 3.8
Some constants are available to specify character cell attributes. Some constants are available to specify character cell attributes.
The exact constants available are system dependent. The exact constants available are system dependent.

View File

@ -152,6 +152,15 @@ now return ``False`` instead of raising :exc:`ValueError` or its subclasses
characters or bytes unrepresentable at the OS level. characters or bytes unrepresentable at the OS level.
(Contributed by Serhiy Storchaka in :issue:`33721`.) (Contributed by Serhiy Storchaka in :issue:`33721`.)
ncurses
-------
Added a new variable holding structured version information for the
underlying ncurses library: :data:`~curses.ncurses_version`.
(Contributed by Serhiy Storchaka in :issue:`31680`.)
pathlib pathlib
------- -------

View File

@ -368,9 +368,8 @@ class TestCurses(unittest.TestCase):
self.stdscr.getkey() self.stdscr.getkey()
@requires_curses_func('unget_wch') @requires_curses_func('unget_wch')
# XXX Remove the decorator when ncurses on OpenBSD be updated @unittest.skipIf(getattr(curses, 'ncurses_version', (99,)) < (5, 8),
@unittest.skipIf(sys.platform.startswith("openbsd"), "unget_wch is broken in ncurses 5.7 and earlier")
"OpenBSD's curses (v.5.7) has bugs")
def test_unget_wch(self): def test_unget_wch(self):
stdscr = self.stdscr stdscr = self.stdscr
encoding = stdscr.encoding encoding = stdscr.encoding
@ -456,6 +455,23 @@ class MiscTests(unittest.TestCase):
# can be called. # can be called.
curses.update_lines_cols() curses.update_lines_cols()
@requires_curses_func('ncurses_version')
def test_ncurses_version(self):
v = curses.ncurses_version
self.assertIsInstance(v[:], tuple)
self.assertEqual(len(v), 3)
self.assertIsInstance(v[0], int)
self.assertIsInstance(v[1], int)
self.assertIsInstance(v[2], int)
self.assertIsInstance(v.major, int)
self.assertIsInstance(v.minor, int)
self.assertIsInstance(v.patch, int)
self.assertEqual(v[0], v.major)
self.assertEqual(v[1], v.minor)
self.assertEqual(v[2], v.patch)
self.assertGreaterEqual(v.major, 0)
self.assertGreaterEqual(v.minor, 0)
self.assertGreaterEqual(v.patch, 0)
class TestAscii(unittest.TestCase): class TestAscii(unittest.TestCase):

View File

@ -0,0 +1 @@
Added :data:`curses.ncurses_version`.

View File

@ -4289,6 +4289,59 @@ _curses_use_default_colors_impl(PyObject *module)
} }
#endif /* STRICT_SYSV_CURSES */ #endif /* STRICT_SYSV_CURSES */
#ifdef NCURSES_VERSION
PyDoc_STRVAR(ncurses_version__doc__,
"curses.ncurses_version\n\
\n\
Ncurses version information as a named tuple.");
static PyTypeObject NcursesVersionType;
static PyStructSequence_Field ncurses_version_fields[] = {
{"major", "Major release number"},
{"minor", "Minor release number"},
{"patch", "Patch release number"},
{0}
};
static PyStructSequence_Desc ncurses_version_desc = {
"curses.ncurses_version", /* name */
ncurses_version__doc__, /* doc */
ncurses_version_fields, /* fields */
3
};
static PyObject *
make_ncurses_version(void)
{
PyObject *ncurses_version;
int pos = 0;
ncurses_version = PyStructSequence_New(&NcursesVersionType);
if (ncurses_version == NULL) {
return NULL;
}
#define SetIntItem(flag) \
PyStructSequence_SET_ITEM(ncurses_version, pos++, PyLong_FromLong(flag)); \
if (PyErr_Occurred()) { \
Py_CLEAR(ncurses_version); \
return NULL; \
}
SetIntItem(NCURSES_VERSION_MAJOR)
SetIntItem(NCURSES_VERSION_MINOR)
SetIntItem(NCURSES_VERSION_PATCH)
#undef SetIntItem
return ncurses_version;
}
#endif /* NCURSES_VERSION */
/* List of functions defined in the module */ /* List of functions defined in the module */
static PyMethodDef PyCurses_methods[] = { static PyMethodDef PyCurses_methods[] = {
@ -4426,6 +4479,30 @@ PyInit__curses(void)
PyDict_SetItemString(d, "__version__", v); PyDict_SetItemString(d, "__version__", v);
Py_DECREF(v); Py_DECREF(v);
#ifdef NCURSES_VERSION
/* ncurses_version */
if (NcursesVersionType.tp_name == NULL) {
if (PyStructSequence_InitType2(&NcursesVersionType,
&ncurses_version_desc) < 0)
return NULL;
}
v = make_ncurses_version();
if (v == NULL) {
return NULL;
}
PyDict_SetItemString(d, "ncurses_version", v);
Py_DECREF(v);
/* prevent user from creating new instances */
NcursesVersionType.tp_init = NULL;
NcursesVersionType.tp_new = NULL;
if (PyDict_DelItemString(NcursesVersionType.tp_dict, "__new__") < 0 &&
PyErr_ExceptionMatches(PyExc_KeyError))
{
PyErr_Clear();
}
#endif /* NCURSES_VERSION */
SetDictInt("ERR", ERR); SetDictInt("ERR", ERR);
SetDictInt("OK", OK); SetDictInt("OK", OK);