Skip to content

Commit a4bf572

Browse files
author
eric.smith
committed
Implement issue #4285, convert sys.version_info to a named
tuple. Patch by Ross Light. git-svn-id: http://svn.python.org/projects/python/trunk@69331 6015fed2-1504-0410-9fe1-9d1591cc4771
1 parent 7cf0ae2 commit a4bf572

File tree

4 files changed

+100
-22
lines changed

4 files changed

+100
-22
lines changed

Doc/library/sys.rst

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -853,9 +853,13 @@ always available.
853853
*micro*, *releaselevel*, and *serial*. All values except *releaselevel* are
854854
integers; the release level is ``'alpha'``, ``'beta'``, ``'candidate'``, or
855855
``'final'``. The ``version_info`` value corresponding to the Python version 2.0
856-
is ``(2, 0, 0, 'final', 0)``.
856+
is ``(2, 0, 0, 'final', 0)``. The components can also be accessed by name,
857+
so ``sys.version_info[0]`` is equivalent to ``sys.version_info.major``
858+
and so on.
857859

858860
.. versionadded:: 2.0
861+
.. versionchanged:: 2.7
862+
Added named component attributes
859863

860864

861865
.. data:: warnoptions

Lib/test/test_sys.py

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -340,13 +340,25 @@ def test_attributes(self):
340340
self.assert_(isinstance(sys.prefix, basestring))
341341
self.assert_(isinstance(sys.version, basestring))
342342
vi = sys.version_info
343-
self.assert_(isinstance(vi, tuple))
343+
self.assert_(isinstance(vi[:], tuple))
344344
self.assertEqual(len(vi), 5)
345345
self.assert_(isinstance(vi[0], int))
346346
self.assert_(isinstance(vi[1], int))
347347
self.assert_(isinstance(vi[2], int))
348348
self.assert_(vi[3] in ("alpha", "beta", "candidate", "final"))
349349
self.assert_(isinstance(vi[4], int))
350+
self.assert_(isinstance(vi.major, int))
351+
self.assert_(isinstance(vi.minor, int))
352+
self.assert_(isinstance(vi.micro, int))
353+
self.assert_(vi.releaselevel in
354+
("alpha", "beta", "candidate", "final"))
355+
self.assert_(isinstance(vi.serial, int))
356+
self.assertEqual(vi[0], vi.major)
357+
self.assertEqual(vi[1], vi.minor)
358+
self.assertEqual(vi[2], vi.micro)
359+
self.assertEqual(vi[3], vi.releaselevel)
360+
self.assertEqual(vi[4], vi.serial)
361+
self.assert_(vi > (1,0,0))
350362

351363
def test_43581(self):
352364
# Can't use sys.stdout, as this is a cStringIO object when

Misc/NEWS

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,9 @@ Core and Builtins
149149
Library
150150
-------
151151

152+
- Issue #4285: Change sys.version_info to be a named tuple. Patch by
153+
Ross Light.
154+
152155
- Issue #1276768: The verbose option was not used in the code of
153156
distutils.file_util and distutils.dir_util.
154157

Python/sysmodule.c

Lines changed: 79 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1048,7 +1048,7 @@ maxsize -- the largest supported length of containers.\n\
10481048
maxunicode -- the largest supported character\n\
10491049
builtin_module_names -- tuple of module names built into this interpreter\n\
10501050
version -- the version of this interpreter as a string\n\
1051-
version_info -- version information as a tuple\n\
1051+
version_info -- version information as a named tuple\n\
10521052
hexversion -- version information encoded as a single integer\n\
10531053
copyright -- copyright notice pertaining to this interpreter\n\
10541054
platform -- platform identifier\n\
@@ -1279,6 +1279,75 @@ make_flags(void)
12791279
return seq;
12801280
}
12811281

1282+
PyDoc_STRVAR(version_info__doc__,
1283+
"sys.version_info\n\
1284+
\n\
1285+
Version information as a named tuple.");
1286+
1287+
static PyTypeObject VersionInfoType = {0, 0, 0, 0, 0, 0};
1288+
1289+
static PyStructSequence_Field version_info_fields[] = {
1290+
{"major", "Major release number"},
1291+
{"minor", "Minor release number"},
1292+
{"micro", "Patch release number"},
1293+
{"releaselevel", "'alpha', 'beta', 'candidate', or 'release'"},
1294+
{"serial", "Serial release number"},
1295+
{0}
1296+
};
1297+
1298+
static PyStructSequence_Desc version_info_desc = {
1299+
"sys.version_info", /* name */
1300+
version_info__doc__, /* doc */
1301+
version_info_fields, /* fields */
1302+
5
1303+
};
1304+
1305+
static PyObject *
1306+
make_version_info(void)
1307+
{
1308+
PyObject *version_info;
1309+
char *s;
1310+
int pos = 0;
1311+
1312+
version_info = PyStructSequence_New(&VersionInfoType);
1313+
if (version_info == NULL) {
1314+
return NULL;
1315+
}
1316+
1317+
/*
1318+
* These release level checks are mutually exclusive and cover
1319+
* the field, so don't get too fancy with the pre-processor!
1320+
*/
1321+
#if PY_RELEASE_LEVEL == PY_RELEASE_LEVEL_ALPHA
1322+
s = "alpha";
1323+
#elif PY_RELEASE_LEVEL == PY_RELEASE_LEVEL_BETA
1324+
s = "beta";
1325+
#elif PY_RELEASE_LEVEL == PY_RELEASE_LEVEL_GAMMA
1326+
s = "candidate";
1327+
#elif PY_RELEASE_LEVEL == PY_RELEASE_LEVEL_FINAL
1328+
s = "final";
1329+
#endif
1330+
1331+
#define SetIntItem(flag) \
1332+
PyStructSequence_SET_ITEM(version_info, pos++, PyInt_FromLong(flag))
1333+
#define SetStrItem(flag) \
1334+
PyStructSequence_SET_ITEM(version_info, pos++, PyString_FromString(flag))
1335+
1336+
SetIntItem(PY_MAJOR_VERSION);
1337+
SetIntItem(PY_MINOR_VERSION);
1338+
SetIntItem(PY_MICRO_VERSION);
1339+
SetStrItem(s);
1340+
SetIntItem(PY_RELEASE_SERIAL);
1341+
#undef SetIntItem
1342+
#undef SetStrItem
1343+
1344+
if (PyErr_Occurred()) {
1345+
Py_CLEAR(version_info);
1346+
return NULL;
1347+
}
1348+
return version_info;
1349+
}
1350+
12821351
PyObject *
12831352
_PySys_Init(void)
12841353
{
@@ -1354,25 +1423,6 @@ _PySys_Init(void)
13541423
svn_revision));
13551424
SET_SYS_FROM_STRING("dont_write_bytecode",
13561425
PyBool_FromLong(Py_DontWriteBytecodeFlag));
1357-
/*
1358-
* These release level checks are mutually exclusive and cover
1359-
* the field, so don't get too fancy with the pre-processor!
1360-
*/
1361-
#if PY_RELEASE_LEVEL == PY_RELEASE_LEVEL_ALPHA
1362-
s = "alpha";
1363-
#elif PY_RELEASE_LEVEL == PY_RELEASE_LEVEL_BETA
1364-
s = "beta";
1365-
#elif PY_RELEASE_LEVEL == PY_RELEASE_LEVEL_GAMMA
1366-
s = "candidate";
1367-
#elif PY_RELEASE_LEVEL == PY_RELEASE_LEVEL_FINAL
1368-
s = "final";
1369-
#endif
1370-
1371-
SET_SYS_FROM_STRING("version_info",
1372-
Py_BuildValue("iiisi", PY_MAJOR_VERSION,
1373-
PY_MINOR_VERSION,
1374-
PY_MICRO_VERSION, s,
1375-
PY_RELEASE_SERIAL));
13761426
SET_SYS_FROM_STRING("api_version",
13771427
PyInt_FromLong(PYTHON_API_VERSION));
13781428
SET_SYS_FROM_STRING("copyright",
@@ -1429,6 +1479,15 @@ _PySys_Init(void)
14291479
PyDict_SetItemString(sysdict, "warnoptions", warnoptions);
14301480
}
14311481

1482+
/* version_info */
1483+
if (VersionInfoType.tp_name == 0)
1484+
PyStructSequence_InitType(&VersionInfoType, &version_info_desc);
1485+
SET_SYS_FROM_STRING("version_info", make_version_info());
1486+
/* prevent user from creating new instances */
1487+
VersionInfoType.tp_init = NULL;
1488+
VersionInfoType.tp_new = NULL;
1489+
1490+
/* flags */
14321491
if (FlagsType.tp_name == 0)
14331492
PyStructSequence_InitType(&FlagsType, &flags_desc);
14341493
SET_SYS_FROM_STRING("flags", make_flags());

0 commit comments

Comments
 (0)