Implement issue #4285, convert sys.version_info to a named

tuple. Patch by Ross Light.
This commit is contained in:
Eric Smith 2009-02-06 00:48:26 +00:00
parent 5dde357c9e
commit 81fe09344c
4 changed files with 100 additions and 22 deletions

View File

@ -853,9 +853,13 @@ 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.
.. versionadded:: 2.0
.. versionchanged:: 2.7
Added named component attributes
.. data:: warnoptions

View File

@ -340,13 +340,25 @@ class SysModuleTest(unittest.TestCase):
self.assert_(isinstance(sys.prefix, basestring))
self.assert_(isinstance(sys.version, basestring))
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 cStringIO object when

View File

@ -149,6 +149,9 @@ Core and Builtins
Library
-------
- Issue #4285: Change sys.version_info to be a named tuple. Patch by
Ross Light.
- Issue #1276768: The verbose option was not used in the code of
distutils.file_util and distutils.dir_util.

View File

@ -1048,7 +1048,7 @@ maxsize -- the largest supported length of containers.\n\
maxunicode -- the largest supported character\n\
builtin_module_names -- tuple of module names built into this interpreter\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\
@ -1279,6 +1279,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 = {0, 0, 0, 0, 0, 0};
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++, PyInt_FromLong(flag))
#define SetStrItem(flag) \
PyStructSequence_SET_ITEM(version_info, pos++, PyString_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;
}
PyObject *
_PySys_Init(void)
{
@ -1354,25 +1423,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("iiisi", PY_MAJOR_VERSION,
PY_MINOR_VERSION,
PY_MICRO_VERSION, s,
PY_RELEASE_SERIAL));
SET_SYS_FROM_STRING("api_version",
PyInt_FromLong(PYTHON_API_VERSION));
SET_SYS_FROM_STRING("copyright",
@ -1429,6 +1479,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());