From f7bb57875acfd86a2864b3c305d90a083fa97fef Mon Sep 17 00:00:00 2001 From: Eric Smith Date: Wed, 27 Jan 2010 00:44:57 +0000 Subject: Merged revisions 77763 via svnmerge from svn+ssh://pythondev@svn.python.org/python/trunk ........ r77763 | eric.smith | 2010-01-26 19:28:29 -0500 (Tue, 26 Jan 2010) | 1 line Issue #7766: Change sys.getwindowsversion() return value to a named tuple and add the additional members returned in an OSVERSIONINFOEX structure. The new members are service_pack_major, service_pack_minor, suite_mask, and product_type. ........ --- Doc/library/sys.rst | 35 ++++++++++++++++++++---- Lib/test/test_sys.py | 18 ++++++++++++- Misc/NEWS | 5 ++++ Python/sysmodule.c | 75 +++++++++++++++++++++++++++++++++++++++++++--------- 4 files changed, 114 insertions(+), 19 deletions(-) diff --git a/Doc/library/sys.rst b/Doc/library/sys.rst index 33910ae..1278248 100644 --- a/Doc/library/sys.rst +++ b/Doc/library/sys.rst @@ -394,9 +394,15 @@ always available. .. function:: getwindowsversion() - Return a tuple containing five components, describing the Windows version - currently running. The elements are *major*, *minor*, *build*, *platform*, and - *text*. *text* contains a string while all other values are integers. + Return a named tuple containing describing the Windows version + currently running. The named elements are *major*, *minor*, + *build*, *platform*, *service_pack*, *service_pack_minor*, + *service_pack_major*, *suite_mask*, and *product_type*. + *service_pack* contains a string while all other values are + integers. The components can also be accessed by name, so + ``sys.getwindowsversion()[0]`` is equivalent to + ``sys.getwindowsversion().major``. For compatibility with prior + versions, only the first 5 elements are retrievable by indexing. *platform* may be one of the following values: @@ -412,11 +418,30 @@ always available. | :const:`3 (VER_PLATFORM_WIN32_CE)` | Windows CE | +-----------------------------------------+-------------------------+ - This function wraps the Win32 :cfunc:`GetVersionEx` function; see the Microsoft - documentation for more information about these fields. + *product_type* may be one of the following values: + + +---------------------------------------+---------------------------------+ + | Constant | Meaning | + +=======================================+=================================+ + | :const:`1 (VER_NT_WORKSTATION)` | The system is a workstation. | + +---------------------------------------+---------------------------------+ + | :const:`2 (VER_NT_DOMAIN_CONTROLLER)` | The system is a domain | + | | controller. | + +---------------------------------------+---------------------------------+ + | :const:`3 (VER_NT_SERVER)` | The system is a server, but not | + | | a domain controller. | + +---------------------------------------+---------------------------------+ + + + This function wraps the Win32 :cfunc:`GetVersionEx` function; see the + Microsoft documentation on :cfunc:`OSVERSIONINFOEX` for more information + about these fields. Availability: Windows. + .. versionchanged:: 2.7 + Changed to a named tuple and added *service_pack_minor*, + *service_pack_major*, *suite_mask*, and *product_type*. .. data:: hexversion diff --git a/Lib/test/test_sys.py b/Lib/test/test_sys.py index a4e646f..65b4430 100644 --- a/Lib/test/test_sys.py +++ b/Lib/test/test_sys.py @@ -5,6 +5,7 @@ import struct import subprocess import textwrap import warnings +import operator # count the number of test runs, used to create unique # strings to intern in test_intern() @@ -227,13 +228,28 @@ class SysModuleTest(unittest.TestCase): def test_getwindowsversion(self): if hasattr(sys, "getwindowsversion"): v = sys.getwindowsversion() - self.assertIsInstance(v, tuple) + self.assertTrue(isinstance(v[:], tuple)) self.assertEqual(len(v), 5) self.assertIsInstance(v[0], int) self.assertIsInstance(v[1], int) self.assertIsInstance(v[2], int) self.assertIsInstance(v[3], int) self.assertIsInstance(v[4], str) + self.assertRaises(IndexError, operator.getitem, v, 5) + self.assertIsInstance(v.major, int) + self.assertIsInstance(v.minor, int) + self.assertIsInstance(v.build, int) + self.assertIsInstance(v.platform, int) + self.assertIsInstance(v.service_pack, str) + self.assertEqual(v[0], v.major) + self.assertEqual(v[1], v.minor) + self.assertEqual(v[2], v.build) + self.assertEqual(v[3], v.platform) + self.assertEqual(v[4], v.service_pack) + + # This is how platform.py calls it. Make sure tuple + # still has 5 elements + maj, min, buildno, plat, csd = sys.getwindowsversion() def test_call_tracing(self): self.assertRaises(TypeError, sys.call_tracing, type, 2) diff --git a/Misc/NEWS b/Misc/NEWS index 8318f09..2e12ffe 100644 --- a/Misc/NEWS +++ b/Misc/NEWS @@ -12,6 +12,11 @@ What's New in Python 3.2 Alpha 1? Core and Builtins ----------------- +- Issue #7766: Change sys.getwindowsversion() return value to a named + tuple and add the additional members returned in an OSVERSIONINFOEX + structure. The new members are service_pack_major, service_pack_minor, + suite_mask, and product_type. + - Issue #7561: Operations on empty bytearrays (such as `int(bytearray())`) could crash in many places because of the PyByteArray_AS_STRING() macro returning NULL. The macro now returns a statically allocated empty diff --git a/Python/sysmodule.c b/Python/sysmodule.c index 84813ba..f1cbbba 100644 --- a/Python/sysmodule.c +++ b/Python/sysmodule.c @@ -597,26 +597,65 @@ recursion from causing an overflow of the C stack and crashing Python." PyDoc_STRVAR(getwindowsversion_doc, "getwindowsversion()\n\ \n\ -Return information about the running version of Windows.\n\ -The result is a tuple of (major, minor, build, platform, text)\n\ -All elements are numbers, except text which is a string.\n\ -Platform may be 0 for win32s, 1 for Windows 9x/ME, 2 for Windows NT/2000/XP\n\ -" +Return information about the running version of Windows as a named tuple.\n\ +The members are named: major, minor, build, platform, service_pack,\n\ +service_pack_major, service_pack_minor, suite_mask, and product_type. For\n\ +backward compatibiliy, only the first 5 items are available by indexing.\n\ +All elements are numbers, except service_pack which is a string. Platform\n\ +may be 0 for win32s, 1 for Windows 9x/ME, 2 for Windows NT/2000/XP/Vista/7,\n\ +3 for Windows CE. Product_type may be 1 for a workstation, 2 for a domain\n\ +controller, 3 for a server." ); +static PyTypeObject WindowsVersionType = {0, 0, 0, 0, 0, 0}; + +static PyStructSequence_Field windows_version_fields[] = { + {"major", "Major version number"}, + {"minor", "Minor version number"}, + {"build", "Build number"}, + {"platform", "Operating system platform"}, + {"service_pack", "Latest Service Pack installed on the system"}, + {"service_pack_major", "Service Pack major version number"}, + {"service_pack_minor", "Service Pack minor version number"}, + {"suite_mask", "Bit mask identifying available product suites"}, + {"product_type", "System product type"}, + {0} +}; + +static PyStructSequence_Desc windows_version_desc = { + "sys.getwindowsversion", /* name */ + getwindowsversion_doc, /* doc */ + windows_version_fields, /* fields */ + 5 /* For backward compatibility, + only the first 5 items are accessible + via indexing, the rest are name only */ +}; + static PyObject * sys_getwindowsversion(PyObject *self) { - OSVERSIONINFO ver; + PyObject *version; + int pos = 0; + OSVERSIONINFOEX ver; ver.dwOSVersionInfoSize = sizeof(ver); - if (!GetVersionEx(&ver)) + if (!GetVersionEx((OSVERSIONINFO*) &ver)) return PyErr_SetFromWindowsErr(0); - return Py_BuildValue("HHHHs", - ver.dwMajorVersion, - ver.dwMinorVersion, - ver.dwBuildNumber, - ver.dwPlatformId, - ver.szCSDVersion); + + version = PyStructSequence_New(&WindowsVersionType); + if (version == NULL) + return NULL; + + PyStructSequence_SET_ITEM(version, pos++, PyLong_FromLong(ver.dwMajorVersion)); + PyStructSequence_SET_ITEM(version, pos++, PyLong_FromLong(ver.dwMinorVersion)); + PyStructSequence_SET_ITEM(version, pos++, PyLong_FromLong(ver.dwBuildNumber)); + PyStructSequence_SET_ITEM(version, pos++, PyLong_FromLong(ver.dwPlatformId)); + PyStructSequence_SET_ITEM(version, pos++, PyUnicode_FromString(ver.szCSDVersion)); + PyStructSequence_SET_ITEM(version, pos++, PyLong_FromLong(ver.wServicePackMajor)); + PyStructSequence_SET_ITEM(version, pos++, PyLong_FromLong(ver.wServicePackMinor)); + PyStructSequence_SET_ITEM(version, pos++, PyLong_FromLong(ver.wSuiteMask)); + PyStructSequence_SET_ITEM(version, pos++, PyLong_FromLong(ver.wProductType)); + + return version; } #endif /* MS_WINDOWS */ @@ -1488,6 +1527,16 @@ _PySys_Init(void) FlagsType.tp_init = NULL; FlagsType.tp_new = NULL; + +#if defined(MS_WINDOWS) + /* getwindowsversion */ + if (WindowsVersionType.tp_name == 0) + PyStructSequence_InitType(&WindowsVersionType, &windows_version_desc); + /* prevent user from creating new instances */ + WindowsVersionType.tp_init = NULL; + WindowsVersionType.tp_new = NULL; +#endif + /* float repr style: 0.03 (short) vs 0.029999999999999999 (legacy) */ #ifndef PY_NO_SHORT_FLOAT_REPR SET_SYS_FROM_STRING("float_repr_style", -- cgit v0.12