[Python-checkins] bpo-31680: Add curses.ncurses_version. (GH-4217)

Serhiy Storchaka webhook-mailer at python.org
Tue Oct 30 07:22:47 EDT 2018


https://github.com/python/cpython/commit/b232df9197a19e78d0e2a751e56e0e62547354ec
commit: b232df9197a19e78d0e2a751e56e0e62547354ec
branch: master
author: Serhiy Storchaka <storchaka at gmail.com>
committer: GitHub <noreply at github.com>
date: 2018-10-30T13:22:42+02:00
summary:

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

Use curses.ncurses_version for conditionally skipping a test.

files:
A Misc/NEWS.d/next/Library/2017-11-01-15-44-48.bpo-31680.yO6oSC.rst
M Doc/library/curses.rst
M Doc/whatsnew/3.8.rst
M Lib/test/test_curses.py
M Modules/_cursesmodule.c

diff --git a/Doc/library/curses.rst b/Doc/library/curses.rst
index 2a2ee2be84af..2a4d9ce8a35a 100644
--- a/Doc/library/curses.rst
+++ b/Doc/library/curses.rst
@@ -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
    :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.
 The exact constants available are system dependent.
 
diff --git a/Doc/whatsnew/3.8.rst b/Doc/whatsnew/3.8.rst
index 758d32e6e55a..02391de0dbc0 100644
--- a/Doc/whatsnew/3.8.rst
+++ b/Doc/whatsnew/3.8.rst
@@ -152,6 +152,15 @@ now return ``False`` instead of raising :exc:`ValueError` or its subclasses
 characters or bytes unrepresentable at the OS level.
 (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
 -------
 
diff --git a/Lib/test/test_curses.py b/Lib/test/test_curses.py
index 3b442fe6a4b7..09738c8a41c9 100644
--- a/Lib/test/test_curses.py
+++ b/Lib/test/test_curses.py
@@ -368,9 +368,8 @@ def test_issue6243(self):
         self.stdscr.getkey()
 
     @requires_curses_func('unget_wch')
-    # XXX Remove the decorator when ncurses on OpenBSD be updated
-    @unittest.skipIf(sys.platform.startswith("openbsd"),
-                     "OpenBSD's curses (v.5.7) has bugs")
+    @unittest.skipIf(getattr(curses, 'ncurses_version', (99,)) < (5, 8),
+                     "unget_wch is broken in ncurses 5.7 and earlier")
     def test_unget_wch(self):
         stdscr = self.stdscr
         encoding = stdscr.encoding
@@ -456,6 +455,23 @@ def test_update_lines_cols(self):
         # can be called.
         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):
 
diff --git a/Misc/NEWS.d/next/Library/2017-11-01-15-44-48.bpo-31680.yO6oSC.rst b/Misc/NEWS.d/next/Library/2017-11-01-15-44-48.bpo-31680.yO6oSC.rst
new file mode 100644
index 000000000000..3cf33ac9bd63
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2017-11-01-15-44-48.bpo-31680.yO6oSC.rst
@@ -0,0 +1 @@
+Added :data:`curses.ncurses_version`.
diff --git a/Modules/_cursesmodule.c b/Modules/_cursesmodule.c
index a728a24f6cae..c8f564a31dbd 100644
--- a/Modules/_cursesmodule.c
+++ b/Modules/_cursesmodule.c
@@ -4289,6 +4289,59 @@ _curses_use_default_colors_impl(PyObject *module)
 }
 #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 */
 
 static PyMethodDef PyCurses_methods[] = {
@@ -4426,6 +4479,30 @@ PyInit__curses(void)
     PyDict_SetItemString(d, "__version__", 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("OK", OK);
 



More information about the Python-checkins mailing list