Index: Python/sysmodule.c =================================================================== --- Python/sysmodule.c (revision 68932) +++ Python/sysmodule.c (working copy) @@ -1279,6 +1279,75 @@ return seq; } +PyDoc_STRVAR(version_info__doc__, +"sys.version_info\n\ +\n\ +Version information as a 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 SetIntFlag(flag) \ + PyStructSequence_SET_ITEM(version_info, pos++, PyInt_FromLong(flag)) +#define SetStrFlag(flag) \ + PyStructSequence_SET_ITEM(version_info, pos++, PyString_FromString(flag)) + + SetIntFlag(PY_MAJOR_VERSION); + SetIntFlag(PY_MINOR_VERSION); + SetIntFlag(PY_MICRO_VERSION); + SetStrFlag(s); + SetIntFlag(PY_RELEASE_SERIAL); +#undef SetIntFlag +#undef SetStrFlag + + if (PyErr_Occurred()) { + Py_CLEAR(version_info); + return NULL; + } + return version_info; +} + PyObject * _PySys_Init(void) { @@ -1354,25 +1423,6 @@ 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,12 +1479,19 @@ 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()); + /* flags */ if (FlagsType.tp_name == 0) PyStructSequence_InitType(&FlagsType, &flags_desc); SET_SYS_FROM_STRING("flags", make_flags()); /* prevent user from creating new instances */ FlagsType.tp_init = NULL; FlagsType.tp_new = NULL; + VersionInfoType.tp_init = NULL; + VersionInfoType.tp_new = NULL; #undef SET_SYS_FROM_STRING if (PyErr_Occurred()) Index: Lib/test/test_sys.py =================================================================== --- Lib/test/test_sys.py (revision 68932) +++ Lib/test/test_sys.py (working copy) @@ -340,13 +340,23 @@ self.assert_(isinstance(sys.prefix, basestring)) self.assert_(isinstance(sys.version, basestring)) vi = sys.version_info - 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) def test_43581(self): # Can't use sys.stdout, as this is a cStringIO object when