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,27 @@ Thus ``2.1.0a3`` is hexversion ``0x020100a3``. + +.. data:: implementation + + A dictionary containing the information about the currently running + Python implementation. Depending on the implementation of Python, the + dict may contain any number of items describing the implementation. + However, it will always contain *name* and *version*. + + *name* is the implementation's common name, like ``'CPython'``. + + *version* is a version tuple, in the format of :data:`sys.version_info`, + which represents the version of the Python implementation, **not** the + version of the Python language specification it implements. + + 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.) + + .. 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,13 @@ expected = None self.check_fsencoding(fs_encoding, expected) + def test_implementation(self): + self.assertIn(sys.implementation, 'name') + self.assertIn(sys.implementation, 'version') + + 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 as a named tuple\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,29 @@ return version_info; } +static PyObject * +make_impl_info(PyObject *version_info) +{ + PyObject *impl_info; + PyObject *name = PyUnicode_FromString("CPython"); + + impl_info = PyDict_New(); + if (impl_info == NULL) { + return NULL; + } + + PyDict_SetItemString(impl_info, "name", name); + Py_DECREF(name); + + PyDict_SetItemString(impl_info, "version", version_info); + + if (PyErr_Occurred()) { + Py_CLEAR(impl_info); + return NULL; + } + return impl_info; +} + static struct PyModuleDef sysmodule = { PyModuleDef_HEAD_INIT, "sys", @@ -1469,7 +1493,7 @@ PyObject * _PySys_Init(void) { - PyObject *m, *v, *sysdict; + PyObject *m, *v, *sysdict, *version_info; char *s; m = PyModule_Create(&sysmodule); @@ -1585,11 +1609,15 @@ /* 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 */ + SET_SYS_FROM_STRING("implementation", make_impl_info(version_info)); + /* flags */ if (FlagsType.tp_name == 0) PyStructSequence_InitType(&FlagsType, &flags_desc);