comparing with /home/esnow/projects/.cpython searching for changes changeset: 77148:e1f0a5abae9a tag: issue14673_as_structseq.diff tag: qbase tag: qtip tag: tip user: Eric Snow date: Fri May 25 19:38:21 2012 -0600 summary: [issue14673] add sys.implementation diff --git a/Doc/library/sys.rst b/Doc/library/sys.rst --- a/Doc/library/sys.rst +++ b/Doc/library/sys.rst @@ -586,6 +586,34 @@ Thus ``2.1.0a3`` is hexversion ``0x020100a3``. + +.. data:: implementation + + An object containing the information about the implementation of the + currently running Python interpreter. Its attributes are the those + that all Python implementations must implement. They are described + below. + + *name* is the implementation's identifer, like ``'cpython'``. + + *version* is a named tuple, in the format of + :data:`sys.version_info`. It represents the version of the Python + implementation, **not** the version of the Python language + specification it implements. + + *hexversion* is the implementation version in hexadecimal format. + + *cache_tag* is the tag used by the import machinery in the filenames + of cached modules, like ``'cpython-33'``. + + Regardless of its contents, :data:`sys.implementation` will not + change during a run of the interpreter, nor between implementation + versions. (It may change between Python language versions, + however.) See `PEP 421` for more information. + + .. versionadded:: 3.3 + + .. data:: int_info A :term:`struct sequence` that holds information about Python's internal diff --git a/Lib/test/test_sys.py b/Lib/test/test_sys.py --- a/Lib/test/test_sys.py +++ b/Lib/test/test_sys.py @@ -577,6 +577,16 @@ expected = None self.check_fsencoding(fs_encoding, expected) + def test_implementation(self): + # This test applies to all implementations equally. + self.assertTrue(hasattr(sys.implementation, 'name')) + self.assertTrue(hasattr(sys.implementation, 'version')) + self.assertTrue(hasattr(sys.implementation, 'hexversion')) + self.assertTrue(hasattr(sys.implementation, 'cache_tag')) + + version = sys.implementation.version + self.assertEqual(version[:2], (version.major, version.minor)) + class SizeofTest(unittest.TestCase): diff --git a/Python/sysmodule.c b/Python/sysmodule.c --- a/Python/sysmodule.c +++ b/Python/sysmodule.c @@ -1261,6 +1261,7 @@ float_info -- a struct sequence with information about the float implementation.\n\ float_repr_style -- string indicating the style of repr() output for floats\n\ hexversion -- version information encoded as a single integer\n\ +implementation -- Python implementation information.\n\ int_info -- a struct sequence with information about the int implementation.\n\ maxsize -- the largest supported length of containers.\n\ maxunicode -- the value of the largest Unicode codepoint\n\ @@ -1454,6 +1455,76 @@ return version_info; } +PyDoc_STRVAR(impl_info__doc__, +"sys.implementation\n\ +\n\ +Implementation-specific information as a named tuple."); + +static PyTypeObject ImplInfoType; + +static PyStructSequence_Field impl_info_fields[] = { + {"name", "The implementation's name"}, + {"version", "Implementation version (as opposed to the Python version)"}, + {"hexversion", "Implementation version in hexadecimal format"}, + {"cache_tag", "PEP 3147 cache tag"}, + {0} +}; + +static PyStructSequence_Desc impl_info_desc = { + "sys.implementation", /* name */ + impl_info__doc__, /* doc */ + impl_info_fields, /* fields */ + 4 +}; + +static PyObject * +make_impl_info(PyObject *version_info) +{ + int pos = 0; + PyObject *impl_info, *value; + + impl_info = PyStructSequence_New(&ImplInfoType); + if (impl_info == NULL) { + return NULL; + } + +#define NAME "cpython" +#define QUOTE(arg) #arg +#define STRIFY(name) QUOTE(name) +#define MAJOR STRIFY(PY_MAJOR_VERSION) +#define MINOR STRIFY(PY_MINOR_VERSION) +#define TAG NAME "-" MAJOR MINOR + value = PyUnicode_FromString(NAME); + if (value == NULL) + goto error; + PyStructSequence_SET_ITEM(impl_info, pos++, value); + + Py_INCREF(version_info); + PyStructSequence_SET_ITEM(impl_info, pos++, version_info); + + value = PyLong_FromLong(PY_VERSION_HEX); + if (value == NULL) + goto error; + PyStructSequence_SET_ITEM(impl_info, pos++, value); + + value = PyUnicode_FromString(TAG); + if (value == NULL) + goto error; + PyStructSequence_SET_ITEM(impl_info, pos++, value); +#undef NAME +#undef QUOTE +#undef STRIFY +#undef MAJOR +#undef MINOR +#undef TAG + + return impl_info; + +error: + Py_CLEAR(impl_info); + return NULL; +} + static struct PyModuleDef sysmodule = { PyModuleDef_HEAD_INIT, "sys", @@ -1469,7 +1540,7 @@ PyObject * _PySys_Init(void) { - PyObject *m, *v, *sysdict; + PyObject *m, *v, *sysdict, *version_info; char *s; m = PyModule_Create(&sysmodule); @@ -1585,11 +1656,20 @@ /* version_info */ if (VersionInfoType.tp_name == 0) PyStructSequence_InitType(&VersionInfoType, &version_info_desc); - SET_SYS_FROM_STRING("version_info", make_version_info()); + version_info = make_version_info(); + SET_SYS_FROM_STRING("version_info", version_info); /* prevent user from creating new instances */ VersionInfoType.tp_init = NULL; VersionInfoType.tp_new = NULL; + /* implementation */ + if (ImplInfoType.tp_name == 0) + PyStructSequence_InitType(&ImplInfoType, &impl_info_desc); + SET_SYS_FROM_STRING("implementation", make_impl_info(version_info)); + /* prevent user from creating new instances */ + ImplInfoType.tp_init = NULL; + ImplInfoType.tp_new = NULL; + /* flags */ if (FlagsType.tp_name == 0) PyStructSequence_InitType(&FlagsType, &flags_desc);