comparing with /home/esnow/projects/.cpython searching for changes changeset: 77148:288fe0687c59 tag: issue14673_as_type.diff tag: qbase tag: qtip tag: tip user: Eric Snow date: Fri May 25 19:45:24 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,99 @@ return version_info; } +static PyObject * +make_impl_info(PyObject *version_info) +{ + int res; + PyObject *impl_info, *name, *value, *args; + PyInterpreterState *interp = PyThreadState_GET()->interp; + PyObject *modules = interp->modules; + PyObject *builtins, *type; + + _Py_IDENTIFIER(type); + + builtins = PyDict_GetItemString(modules, "builtins"); + if (builtins == NULL) + { + PyErr_SetString(PyExc_RuntimeError, "lost builtins module"); + goto error; + } + + type = _PyObject_GetAttrId(builtins, &PyId_type); + Py_DECREF(builtins); + if (type == NULL) + goto error; + + impl_info = PyDict_New(); + if (impl_info == NULL) + return NULL; + + /* populate the dict */ + +#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; + res = PyDict_SetItemString(impl_info, "name", value); + Py_DECREF(value); + if (res < 0) + goto error; + + value = PyUnicode_FromString(TAG); + if (value == NULL) + goto error; + res = PyDict_SetItemString(impl_info, "cache_tag", value); + Py_DECREF(value); + if (res < 0) + goto error; +#undef NAME +#undef QUOTE +#undef STRIFY +#undef MAJOR +#undef MINOR +#undef TAG + + res = PyDict_SetItemString(impl_info, "version", version_info); + if (res < 0) + goto error; + + value = PyLong_FromLong(PY_VERSION_HEX); + if (value == NULL) + goto error; + res = PyDict_SetItemString(impl_info, "hexversion", value); + Py_DECREF(value); + if (res < 0) + goto error; + + /* dict ready */ + + name = PyUnicode_FromString("sys.implementation"); + if (name == NULL) + goto error; + + args = PyTuple_Pack(3, name, PyTuple_New(0), impl_info); + Py_DECREF(name); + if (args == NULL) + goto error; + + type = PyObject_CallObject(type, args); + Py_DECREF(args); + if (type == NULL) + goto error; + + Py_DECREF(impl_info); + return type; + +error: + Py_CLEAR(impl_info); + return NULL; +} + static struct PyModuleDef sysmodule = { PyModuleDef_HEAD_INIT, "sys", @@ -1469,7 +1563,7 @@ PyObject * _PySys_Init(void) { - PyObject *m, *v, *sysdict; + PyObject *m, *v, *sysdict, *version_info; char *s; m = PyModule_Create(&sysmodule); @@ -1585,11 +1679,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);