]> granicus.if.org Git - python/commitdiff
Merged revisions 69331 via svnmerge from
authorEric Smith <eric@trueblade.com>
Fri, 6 Feb 2009 01:32:42 +0000 (01:32 +0000)
committerEric Smith <eric@trueblade.com>
Fri, 6 Feb 2009 01:32:42 +0000 (01:32 +0000)
svn+ssh://pythondev@svn.python.org/python/trunk

........
  r69331 | eric.smith | 2009-02-05 19:48:26 -0500 (Thu, 05 Feb 2009) | 2 lines

  Implement issue #4285, convert sys.version_info to a named
  tuple. Patch by Ross Light.
........

Doc/library/sys.rst
Lib/test/test_sys.py
Misc/NEWS
Python/sysmodule.c

index aecef74a669f7852de30cad07957751189f0aaa0..a00c516b71871f20fc2bdbee37f283093b0a9b3a 100644 (file)
@@ -769,8 +769,12 @@ always available.
    *micro*, *releaselevel*, and *serial*.  All values except *releaselevel* are
    integers; the release level is ``'alpha'``, ``'beta'``, ``'candidate'``, or
    ``'final'``.  The ``version_info`` value corresponding to the Python version 2.0
-   is ``(2, 0, 0, 'final', 0)``.
+   is ``(2, 0, 0, 'final', 0)``.  The components can also be accessed by name,
+   so ``sys.version_info[0]`` is equivalent to ``sys.version_info.major``
+   and so on.
 
+   .. versionchanged:: 2.7
+      Added named component attributes
 
 .. data:: warnoptions
 
index 7655fbf05fed75b7715b689b7da929689709da7b..fad99397604b51f9b98991c46de7160413d87df9 100644 (file)
@@ -298,13 +298,25 @@ class SysModuleTest(unittest.TestCase):
         self.assert_(isinstance(sys.prefix, str))
         self.assert_(isinstance(sys.version, str))
         vi = sys.version_info
-        self.assert_(isinstance(vi, tuple))
+        self.assert_(isinstance(vi[:], tuple))
         self.assertEqual(len(vi), 5)
         self.assert_(isinstance(vi[0], int))
         self.assert_(isinstance(vi[1], int))
         self.assert_(isinstance(vi[2], int))
         self.assert_(vi[3] in ("alpha", "beta", "candidate", "final"))
         self.assert_(isinstance(vi[4], int))
+        self.assert_(isinstance(vi.major, int))
+        self.assert_(isinstance(vi.minor, int))
+        self.assert_(isinstance(vi.micro, int))
+        self.assert_(vi.releaselevel in
+                     ("alpha", "beta", "candidate", "final"))
+        self.assert_(isinstance(vi.serial, int))
+        self.assertEqual(vi[0], vi.major)
+        self.assertEqual(vi[1], vi.minor)
+        self.assertEqual(vi[2], vi.micro)
+        self.assertEqual(vi[3], vi.releaselevel)
+        self.assertEqual(vi[4], vi.serial)
+        self.assert_(vi > (1,0,0))
 
     def test_43581(self):
         # Can't use sys.stdout, as this is a StringIO object when
index 98a7cefa1d5cb6495323ff70d1c3821908367bfe..b6e06d79b077e6fd39aa2c0db2d13096ffaf664d 100644 (file)
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -155,6 +155,9 @@ Core and Builtins
 Library
 -------
 
+- Issue #4285: Change sys.version_info to be a named tuple. Patch by
+  Ross Light.
+
 - Issue #1520877: Now distutils.sysconfig reads $AR from the 
   environment/Makefile. Patch by Douglas Greiman.
 
index f703e097f0f05b4e6ef7627d4a4293b12e5d4f68..b47a25bc33a4932dbbdc680633fdf27b2c3a6254 100644 (file)
@@ -1017,7 +1017,7 @@ maxunicode -- the largest supported character\n\
 builtin_module_names -- tuple of module names built into this interpreter\n\
 subversion -- subversion information of the build as tuple\n\
 version -- the version of this interpreter as a string\n\
-version_info -- version information as a tuple\n\
+version_info -- version information as a named tuple\n\
 hexversion -- version information encoded as a single integer\n\
 copyright -- copyright notice pertaining to this interpreter\n\
 platform -- platform identifier\n\
@@ -1227,6 +1227,75 @@ make_flags(void)
        return seq;
 }
 
+PyDoc_STRVAR(version_info__doc__,
+"sys.version_info\n\
+\n\
+Version information as a named tuple.");
+
+static PyTypeObject VersionInfoType;
+
+static PyStructSequence_Field version_info_fields[] = {
+       {"major", "Major release number"},
+       {"minor", "Minor release number"},
+       {"micro", "Patch release number"},
+       {"releaselevel", "'alpha', 'beta', 'candidate', or 'release'"},
+       {"serial", "Serial release number"},
+       {0}
+};
+
+static PyStructSequence_Desc version_info_desc = {
+       "sys.version_info",     /* name */
+       version_info__doc__,    /* doc */
+       version_info_fields,    /* fields */
+       5
+};
+
+static PyObject *
+make_version_info(void)
+{
+       PyObject *version_info;
+       char *s;
+       int pos = 0;
+
+       version_info = PyStructSequence_New(&VersionInfoType);
+       if (version_info == NULL) {
+               return NULL;
+       }
+
+       /*
+        * These release level checks are mutually exclusive and cover
+        * the field, so don't get too fancy with the pre-processor!
+        */
+#if PY_RELEASE_LEVEL == PY_RELEASE_LEVEL_ALPHA
+       s = "alpha";
+#elif PY_RELEASE_LEVEL == PY_RELEASE_LEVEL_BETA
+       s = "beta";
+#elif PY_RELEASE_LEVEL == PY_RELEASE_LEVEL_GAMMA
+       s = "candidate";
+#elif PY_RELEASE_LEVEL == PY_RELEASE_LEVEL_FINAL
+       s = "final";
+#endif
+
+#define SetIntItem(flag) \
+       PyStructSequence_SET_ITEM(version_info, pos++, PyLong_FromLong(flag))
+#define SetStrItem(flag) \
+       PyStructSequence_SET_ITEM(version_info, pos++, PyUnicode_FromString(flag))
+
+       SetIntItem(PY_MAJOR_VERSION);
+       SetIntItem(PY_MINOR_VERSION);
+       SetIntItem(PY_MICRO_VERSION);
+       SetStrItem(s);
+       SetIntItem(PY_RELEASE_SERIAL);
+#undef SetIntItem
+#undef SetStrItem
+
+       if (PyErr_Occurred()) {
+               Py_CLEAR(version_info);
+               return NULL;
+       }
+       return version_info;
+}
+
 static struct PyModuleDef sysmodule = {
        PyModuleDef_HEAD_INIT,
        "sys",
@@ -1239,8 +1308,6 @@ static struct PyModuleDef sysmodule = {
        NULL
 };
 
-
-
 PyObject *
 _PySys_Init(void)
 {
@@ -1291,25 +1358,6 @@ _PySys_Init(void)
                                          svn_revision));
        SET_SYS_FROM_STRING("dont_write_bytecode",
                             PyBool_FromLong(Py_DontWriteBytecodeFlag));
-       /*
-        * These release level checks are mutually exclusive and cover
-        * the field, so don't get too fancy with the pre-processor!
-        */
-#if PY_RELEASE_LEVEL == PY_RELEASE_LEVEL_ALPHA
-       s = "alpha";
-#elif PY_RELEASE_LEVEL == PY_RELEASE_LEVEL_BETA
-       s = "beta";
-#elif PY_RELEASE_LEVEL == PY_RELEASE_LEVEL_GAMMA
-       s = "candidate";
-#elif PY_RELEASE_LEVEL == PY_RELEASE_LEVEL_FINAL
-       s = "final";
-#endif
-
-       SET_SYS_FROM_STRING("version_info",
-                           Py_BuildValue("iiiUi", PY_MAJOR_VERSION,
-                                              PY_MINOR_VERSION,
-                                              PY_MICRO_VERSION, s,
-                                              PY_RELEASE_SERIAL));
        SET_SYS_FROM_STRING("api_version",
                            PyLong_FromLong(PYTHON_API_VERSION));
        SET_SYS_FROM_STRING("copyright",
@@ -1361,6 +1409,15 @@ _PySys_Init(void)
                PyDict_SetItemString(sysdict, "warnoptions", warnoptions);
        }
 
+       /* version_info */
+       if (VersionInfoType.tp_name == 0)
+               PyStructSequence_InitType(&VersionInfoType, &version_info_desc);
+       SET_SYS_FROM_STRING("version_info", make_version_info());
+       /* prevent user from creating new instances */
+       VersionInfoType.tp_init = NULL;
+       VersionInfoType.tp_new = NULL;
+
+       /* flags */
        if (FlagsType.tp_name == 0)
                PyStructSequence_InitType(&FlagsType, &flags_desc);
        SET_SYS_FROM_STRING("flags", make_flags());