diff options
-rw-r--r-- | Doc/library/sys.rst | 6 | ||||
-rw-r--r-- | Lib/test/test_sys.py | 14 | ||||
-rw-r--r-- | Misc/NEWS | 3 | ||||
-rw-r--r-- | Python/sysmodule.c | 101 |
4 files changed, 100 insertions, 24 deletions
diff --git a/Doc/library/sys.rst b/Doc/library/sys.rst index aecef74..a00c516 100644 --- a/Doc/library/sys.rst +++ b/Doc/library/sys.rst @@ -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 diff --git a/Lib/test/test_sys.py b/Lib/test/test_sys.py index 7655fbf..fad9939 100644 --- a/Lib/test/test_sys.py +++ b/Lib/test/test_sys.py @@ -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 @@ -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. diff --git a/Python/sysmodule.c b/Python/sysmodule.c index f703e09..b47a25b 100644 --- a/Python/sysmodule.c +++ b/Python/sysmodule.c @@ -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()); |