[Python-checkins] cpython: Eric Snow's implementation of PEP 421.
Brett Cannon
brett at python.org
Mon Jun 4 16:16:24 CEST 2012
On Mon, Jun 4, 2012 at 9:52 AM, barry.warsaw <python-checkins at python.org>wrote:
> http://hg.python.org/cpython/rev/9c445f4695c1
> changeset: 77339:9c445f4695c1
> parent: 77328:0808cb8c60fd
> user: Barry Warsaw <barry at python.org>
> date: Sun Jun 03 16:18:47 2012 -0400
> summary:
> Eric Snow's implementation of PEP 421.
>
> Issue 14673: Add sys.implementation
>
> files:
> Doc/library/sys.rst | 38 ++++
> Doc/library/types.rst | 24 ++
> Include/Python.h | 1 +
> Include/namespaceobject.h | 17 +
> Lib/test/test_sys.py | 18 ++
> Lib/test/test_types.py | 143 ++++++++++++++++-
> Lib/types.py | 1 +
> Makefile.pre.in | 2 +
> Objects/namespaceobject.c | 225 ++++++++++++++++++++++++++
> Objects/object.c | 3 +
> Python/sysmodule.c | 72 ++++++++-
> 11 files changed, 541 insertions(+), 3 deletions(-)
>
>
> diff --git a/Doc/library/sys.rst b/Doc/library/sys.rst
> --- a/Doc/library/sys.rst
> +++ b/Doc/library/sys.rst
> @@ -616,6 +616,44 @@
>
> 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
>
"the those" -> "those"
> + that all Python implementations must implement.
Should you mention that VMs are allowed to add their own attributes that
are not listed?
> They are described
> + below.
> +
> + *name* is the implementation's identifier, like ``'cpython'``.
>
Is this guaranteed to be lowercase, or does it simply happen to be
lowercase in this instance?
> +
> + *version* is a named tuple, in the same format as
> + :data:`sys.version_info`. It represents the version of the Python
> + *implementation*. This has a distinct meaning from the specific
> + version of the Python *language* to which the currently running
> + interpreter conforms, which ``sys.version_info`` represents. For
> + example, for PyPy 1.8 ``sys.implementation.version`` might be
> + ``sys.version_info(1, 8, 0, 'final', 0)``, whereas ``sys.version_info``
> + would be ``sys.version_info(1, 8, 0, 'final', 0)``.
I think you meant to say ``sys.version_info(2, 7, 2, 'final', 0)``.
> For CPython they
> + are the same value, since it is the reference implementation.
> +
> + *hexversion* is the implementation version in hexadecimal format, like
> + :data:`sys.hexversion`.
> +
> + *cache_tag* is the tag used by the import machinery in the filenames of
> + cached modules. By convention, it would be a composite of the
> + implementation's name and version, like ``'cpython-33'``. However, a
> + Python implementation may use some other value if appropriate. If
> + ``cache_tag`` is set to ``None``, it indicates that module caching
> should
> + be disabled.
> +
> + 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/Doc/library/types.rst b/Doc/library/types.rst
> --- a/Doc/library/types.rst
> +++ b/Doc/library/types.rst
> @@ -194,3 +194,27 @@
> Return a new view of the underlying mapping's values.
>
>
> +.. class:: SimpleNamespace
> +
> + A simple :class:`object` subclass that provides attribute access to its
> + namespace, as well as a meaningful repr.
> +
> + Unlike :class:`object`, with ``SimpleNamespace`` you can add and remove
> + attributes. If a ``SimpleNamespace`` object is initialized with
> keyword
> + arguments, those are directly added to the underlying namespace.
> +
> + The type is roughly equivalent to the following code::
> +
> + class SimpleNamespace:
> + def __init__(self, **kwargs):
> + self.__dict__.update(kwargs)
> + def __repr__(self):
> + keys = sorted(self.__dict__)
> + items = ("{}={!r}".format(k, self.__dict__[k]) for k in
> keys)
> + return "{}({})".format(type(self).__name__, ",
> ".join(items))
> +
> + ``SimpleNamespace`` may be useful as a replacement for ``class NS:
> pass``.
> + However, for a structured record type use
> :func:`~collections.namedtuple`
>
What's with the ~?
-Brett
> + instead.
> +
> + .. versionadded:: 3.3
> diff --git a/Include/Python.h b/Include/Python.h
> --- a/Include/Python.h
> +++ b/Include/Python.h
> @@ -101,6 +101,7 @@
> #include "warnings.h"
> #include "weakrefobject.h"
> #include "structseq.h"
> +#include "namespaceobject.h"
>
> #include "codecs.h"
> #include "pyerrors.h"
> diff --git a/Include/namespaceobject.h b/Include/namespaceobject.h
> new file mode 100644
> --- /dev/null
> +++ b/Include/namespaceobject.h
> @@ -0,0 +1,17 @@
> +
> +/* simple namespace object interface */
> +
> +#ifndef NAMESPACEOBJECT_H
> +#define NAMESPACEOBJECT_H
> +#ifdef __cplusplus
> +extern "C" {
> +#endif
> +
> +PyAPI_DATA(PyTypeObject) _PyNamespace_Type;
> +
> +PyAPI_FUNC(PyObject *) _PyNamespace_New(PyObject *kwds);
> +
> +#ifdef __cplusplus
> +}
> +#endif
> +#endif /* !NAMESPACEOBJECT_H */
> 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
> @@ -581,6 +581,24 @@
> expected = None
> self.check_fsencoding(fs_encoding, expected)
>
> + def test_implementation(self):
> + # This test applies to all implementations equally.
> +
> + levels = {'alpha': 0xA, 'beta': 0xB, 'candidate': 0xC, 'release':
> 0xF}
> +
> + 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))
> +
> + hexversion = (version.major << 24 | version.minor << 16 |
> + version.micro << 8 | levels[version.releaselevel]
> << 4 |
> + version.serial << 0)
> + self.assertEqual(sys.implementation.hexversion, hexversion)
> +
>
> class SizeofTest(unittest.TestCase):
>
> diff --git a/Lib/test/test_types.py b/Lib/test/test_types.py
> --- a/Lib/test/test_types.py
> +++ b/Lib/test/test_types.py
> @@ -996,8 +996,149 @@
> X = types.new_class("X", (int(), C))
>
>
> +class SimpleNamespaceTests(unittest.TestCase):
> +
> + def test_constructor(self):
> + ns1 = types.SimpleNamespace()
> + ns2 = types.SimpleNamespace(x=1, y=2)
> + ns3 = types.SimpleNamespace(**dict(x=1, y=2))
> +
> + with self.assertRaises(TypeError):
> + types.SimpleNamespace(1, 2, 3)
> +
> + self.assertEqual(len(ns1.__dict__), 0)
> + self.assertEqual(vars(ns1), {})
> + self.assertEqual(len(ns2.__dict__), 2)
> + self.assertEqual(vars(ns2), {'y': 2, 'x': 1})
> + self.assertEqual(len(ns3.__dict__), 2)
> + self.assertEqual(vars(ns3), {'y': 2, 'x': 1})
> +
> + def test_unbound(self):
> + ns1 = vars(types.SimpleNamespace())
> + ns2 = vars(types.SimpleNamespace(x=1, y=2))
> +
> + self.assertEqual(ns1, {})
> + self.assertEqual(ns2, {'y': 2, 'x': 1})
> +
> + def test_underlying_dict(self):
> + ns1 = types.SimpleNamespace()
> + ns2 = types.SimpleNamespace(x=1, y=2)
> + ns3 = types.SimpleNamespace(a=True, b=False)
> + mapping = ns3.__dict__
> + del ns3
> +
> + self.assertEqual(ns1.__dict__, {})
> + self.assertEqual(ns2.__dict__, {'y': 2, 'x': 1})
> + self.assertEqual(mapping, dict(a=True, b=False))
> +
> + def test_attrget(self):
> + ns = types.SimpleNamespace(x=1, y=2, w=3)
> +
> + self.assertEqual(ns.x, 1)
> + self.assertEqual(ns.y, 2)
> + self.assertEqual(ns.w, 3)
> + with self.assertRaises(AttributeError):
> + ns.z
> +
> + def test_attrset(self):
> + ns1 = types.SimpleNamespace()
> + ns2 = types.SimpleNamespace(x=1, y=2, w=3)
> + ns1.a = 'spam'
> + ns1.b = 'ham'
> + ns2.z = 4
> + ns2.theta = None
> +
> + self.assertEqual(ns1.__dict__, dict(a='spam', b='ham'))
> + self.assertEqual(ns2.__dict__, dict(x=1, y=2, w=3, z=4,
> theta=None))
> +
> + def test_attrdel(self):
> + ns1 = types.SimpleNamespace()
> + ns2 = types.SimpleNamespace(x=1, y=2, w=3)
> +
> + with self.assertRaises(AttributeError):
> + del ns1.spam
> + with self.assertRaises(AttributeError):
> + del ns2.spam
> +
> + del ns2.y
> + self.assertEqual(vars(ns2), dict(w=3, x=1))
> + ns2.y = 'spam'
> + self.assertEqual(vars(ns2), dict(w=3, x=1, y='spam'))
> + del ns2.y
> + self.assertEqual(vars(ns2), dict(w=3, x=1))
> +
> + ns1.spam = 5
> + self.assertEqual(vars(ns1), dict(spam=5))
> + del ns1.spam
> + self.assertEqual(vars(ns1), {})
> +
> + def test_repr(self):
> + ns1 = types.SimpleNamespace(x=1, y=2, w=3)
> + ns2 = types.SimpleNamespace()
> + ns2.x = "spam"
> + ns2._y = 5
> +
> + self.assertEqual(repr(ns1), "namespace(w=3, x=1, y=2)")
> + self.assertEqual(repr(ns2), "namespace(_y=5, x='spam')")
> +
> + def test_nested(self):
> + ns1 = types.SimpleNamespace(a=1, b=2)
> + ns2 = types.SimpleNamespace()
> + ns3 = types.SimpleNamespace(x=ns1)
> + ns2.spam = ns1
> + ns2.ham = '?'
> + ns2.spam = ns3
> +
> + self.assertEqual(vars(ns1), dict(a=1, b=2))
> + self.assertEqual(vars(ns2), dict(spam=ns3, ham='?'))
> + self.assertEqual(ns2.spam, ns3)
> + self.assertEqual(vars(ns3), dict(x=ns1))
> + self.assertEqual(ns3.x.a, 1)
> +
> + def test_recursive(self):
> + ns1 = types.SimpleNamespace(c='cookie')
> + ns2 = types.SimpleNamespace()
> + ns3 = types.SimpleNamespace(x=1)
> + ns1.spam = ns1
> + ns2.spam = ns3
> + ns3.spam = ns2
> +
> + self.assertEqual(ns1.spam, ns1)
> + self.assertEqual(ns1.spam.spam, ns1)
> + self.assertEqual(ns1.spam.spam, ns1.spam)
> + self.assertEqual(ns2.spam, ns3)
> + self.assertEqual(ns3.spam, ns2)
> + self.assertEqual(ns2.spam.spam, ns2)
> +
> + def test_recursive_repr(self):
> + ns1 = types.SimpleNamespace(c='cookie')
> + ns2 = types.SimpleNamespace()
> + ns3 = types.SimpleNamespace(x=1)
> + ns1.spam = ns1
> + ns2.spam = ns3
> + ns3.spam = ns2
> +
> + self.assertEqual(repr(ns1),
> + "namespace(c='cookie', spam=namespace(...))")
> + self.assertEqual(repr(ns2),
> + "namespace(spam=namespace(spam=namespace(...),
> x=1))")
> +
> + def test_as_dict(self):
> + ns = types.SimpleNamespace(spam='spamspamspam')
> +
> + with self.assertRaises(TypeError):
> + len(ns)
> + with self.assertRaises(TypeError):
> + iter(ns)
> + with self.assertRaises(TypeError):
> + 'spam' in ns
> + with self.assertRaises(TypeError):
> + ns['spam']
> +
> +
> def test_main():
> - run_unittest(TypesTests, MappingProxyTests, ClassCreationTests)
> + run_unittest(TypesTests, MappingProxyTests, ClassCreationTests,
> + SimpleNamespaceTests)
>
> if __name__ == '__main__':
> test_main()
> diff --git a/Lib/types.py b/Lib/types.py
> --- a/Lib/types.py
> +++ b/Lib/types.py
> @@ -13,6 +13,7 @@
> LambdaType = type(lambda: None) # Same as FunctionType
> CodeType = type(_f.__code__)
> MappingProxyType = type(type.__dict__)
> +SimpleNamespace = type(sys.implementation)
>
> def _g():
> yield 1
> diff --git a/Makefile.pre.in b/Makefile.pre.in
> --- a/Makefile.pre.in
> +++ b/Makefile.pre.in
> @@ -392,6 +392,7 @@
> Objects/memoryobject.o \
> Objects/methodobject.o \
> Objects/moduleobject.o \
> + Objects/namespaceobject.o \
> Objects/object.o \
> Objects/obmalloc.o \
> Objects/capsule.o \
> @@ -766,6 +767,7 @@
> $(srcdir)/Include/methodobject.h \
> $(srcdir)/Include/modsupport.h \
> $(srcdir)/Include/moduleobject.h \
> + $(srcdir)/Include/namespaceobject.h \
> $(srcdir)/Include/node.h \
> $(srcdir)/Include/object.h \
> $(srcdir)/Include/objimpl.h \
> diff --git a/Objects/namespaceobject.c b/Objects/namespaceobject.c
> new file mode 100644
> --- /dev/null
> +++ b/Objects/namespaceobject.c
> @@ -0,0 +1,225 @@
> +/* namespace object implementation */
> +
> +#include "Python.h"
> +#include "structmember.h"
> +
> +
> +typedef struct {
> + PyObject_HEAD
> + PyObject *ns_dict;
> +} _PyNamespaceObject;
> +
> +
> +static PyMemberDef namespace_members[] = {
> + {"__dict__", T_OBJECT, offsetof(_PyNamespaceObject, ns_dict),
> READONLY},
> + {NULL}
> +};
> +
> +
> +/* Methods */
> +
> +static PyObject *
> +namespace_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
> +{
> + _PyNamespaceObject *ns;
> + ns = PyObject_GC_New(_PyNamespaceObject, &_PyNamespace_Type);
> + if (ns == NULL)
> + return NULL;
> +
> + ns->ns_dict = PyDict_New();
> + if (ns->ns_dict == NULL) {
> + Py_DECREF(ns);
> + return NULL;
> + }
> +
> + PyObject_GC_Track(ns);
> + return (PyObject *)ns;
> +}
> +
> +
> +static int
> +namespace_init(_PyNamespaceObject *ns, PyObject *args, PyObject *kwds)
> +{
> + /* ignore args if it's NULL or empty */
> + if (args != NULL) {
> + Py_ssize_t argcount = PyObject_Size(args);
> + if (argcount < 0)
> + return argcount;
> + else if (argcount > 0) {
> + PyErr_Format(PyExc_TypeError, "no positional arguments
> expected");
> + return -1;
> + }
> + }
> + if (kwds == NULL)
> + return 0;
> + return PyDict_Update(ns->ns_dict, kwds);
> +}
> +
> +
> +static void
> +namespace_dealloc(_PyNamespaceObject *ns)
> +{
> + PyObject_GC_UnTrack(ns);
> + Py_CLEAR(ns->ns_dict);
> + Py_TYPE(ns)->tp_free((PyObject *)ns);
> +}
> +
> +
> +static PyObject *
> +namespace_repr(_PyNamespaceObject *ns)
> +{
> + int i, loop_error = 0;
> + PyObject *pairs = NULL, *d = NULL, *keys = NULL, *keys_iter = NULL;
> + PyObject *key;
> + PyObject *separator, *pairsrepr, *repr = NULL;
> +
> + i = Py_ReprEnter((PyObject *)ns);
> + if (i != 0) {
> + return i > 0 ? PyUnicode_FromString("namespace(...)") : NULL;
> + }
> +
> + pairs = PyList_New(0);
> + if (pairs == NULL)
> + goto error;
> +
> + d = ((_PyNamespaceObject *)ns)->ns_dict;
> + assert(d != NULL);
> + Py_INCREF(d);
> +
> + keys = PyDict_Keys(d);
> + if (keys == NULL)
> + goto error;
> + if (PyList_Sort(keys) != 0)
> + goto error;
> +
> + keys_iter = PyObject_GetIter(keys);
> + if (keys_iter == NULL)
> + goto error;
> +
> + while ((key = PyIter_Next(keys_iter)) != NULL) {
> + if (PyUnicode_Check(key) && PyUnicode_GET_SIZE(key) > 0) {
> + PyObject *value, *item;
> +
> + value = PyDict_GetItem(d, key);
> + assert(value != NULL);
> +
> + item = PyUnicode_FromFormat("%S=%R", key, value);
> + if (item == NULL) {
> + loop_error = 1;
> + }
> + else {
> + loop_error = PyList_Append(pairs, item);
> + Py_DECREF(item);
> + }
> + }
> +
> + Py_DECREF(key);
> + if (loop_error)
> + goto error;
> + }
> +
> + separator = PyUnicode_FromString(", ");
> + if (separator == NULL)
> + goto error;
> +
> + pairsrepr = PyUnicode_Join(separator, pairs);
> + Py_DECREF(separator);
> + if (pairsrepr == NULL)
> + goto error;
> +
> + repr = PyUnicode_FromFormat("%s(%S)",
> + ((PyObject *)ns)->ob_type->tp_name,
> pairsrepr);
> + Py_DECREF(pairsrepr);
> +
> +error:
> + Py_XDECREF(pairs);
> + Py_XDECREF(d);
> + Py_XDECREF(keys);
> + Py_XDECREF(keys_iter);
> + Py_ReprLeave((PyObject *)ns);
> +
> + return repr;
> +}
> +
> +
> +static int
> +namespace_traverse(_PyNamespaceObject *ns, visitproc visit, void *arg)
> +{
> + Py_VISIT(ns->ns_dict);
> + return 0;
> +}
> +
> +
> +static int
> +namespace_clear(_PyNamespaceObject *ns)
> +{
> + Py_CLEAR(ns->ns_dict);
> + return 0;
> +}
> +
> +
> +PyDoc_STRVAR(namespace_doc,
> +"A simple attribute-based namespace.\n\
> +\n\
> +namespace(**kwargs)");
> +
> +PyTypeObject _PyNamespace_Type = {
> + PyVarObject_HEAD_INIT(&PyType_Type, 0)
> + "namespace", /* tp_name */
> + sizeof(_PyNamespaceObject), /* tp_size */
> + 0, /* tp_itemsize */
> + (destructor)namespace_dealloc, /* tp_dealloc */
> + 0, /* tp_print */
> + 0, /* tp_getattr */
> + 0, /* tp_setattr */
> + 0, /* tp_reserved */
> + (reprfunc)namespace_repr, /* tp_repr */
> + 0, /* tp_as_number */
> + 0, /* tp_as_sequence */
> + 0, /* tp_as_mapping */
> + 0, /* tp_hash */
> + 0, /* tp_call */
> + 0, /* tp_str */
> + PyObject_GenericGetAttr, /* tp_getattro */
> + PyObject_GenericSetAttr, /* tp_setattro */
> + 0, /* tp_as_buffer */
> + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC |
> + Py_TPFLAGS_BASETYPE, /* tp_flags */
> + namespace_doc, /* tp_doc */
> + (traverseproc)namespace_traverse, /* tp_traverse */
> + (inquiry)namespace_clear, /* tp_clear */
> + 0, /* tp_richcompare */
> + 0, /* tp_weaklistoffset */
> + 0, /* tp_iter */
> + 0, /* tp_iternext */
> + 0, /* tp_methods */
> + namespace_members, /* tp_members */
> + 0, /* tp_getset */
> + 0, /* tp_base */
> + 0, /* tp_dict */
> + 0, /* tp_descr_get */
> + 0, /* tp_descr_set */
> + offsetof(_PyNamespaceObject, ns_dict), /* tp_dictoffset */
> + (initproc)namespace_init, /* tp_init */
> + PyType_GenericAlloc, /* tp_alloc */
> + (newfunc)namespace_new, /* tp_new */
> + PyObject_GC_Del, /* tp_free */
> +};
> +
> +
> +PyObject *
> +_PyNamespace_New(PyObject *kwds)
> +{
> + PyObject *ns = namespace_new(&_PyNamespace_Type, NULL, NULL);
> + if (ns == NULL)
> + return NULL;
> +
> + if (kwds == NULL)
> + return ns;
> + if (PyDict_Update(((_PyNamespaceObject *)ns)->ns_dict, kwds) != 0) {
> + Py_DECREF(ns);
> + return NULL;
> + }
> +
> + return (PyObject *)ns;
> +}
> diff --git a/Objects/object.c b/Objects/object.c
> --- a/Objects/object.c
> +++ b/Objects/object.c
> @@ -1707,6 +1707,9 @@
>
> if (PyType_Ready(&PyZip_Type) < 0)
> Py_FatalError("Can't initialize zip type");
> +
> + if (PyType_Ready(&_PyNamespace_Type) < 0)
> + Py_FatalError("Can't initialize namespace type");
> }
>
>
> 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,69 @@
> return version_info;
> }
>
> +static PyObject *
> +make_impl_info(PyObject *version_info)
> +{
> + int res;
> + PyObject *impl_info, *value, *ns;
> +
> + 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 */
> +
> + ns = _PyNamespace_New(impl_info);
> + Py_DECREF(impl_info);
> + return ns;
> +
> +error:
> + Py_CLEAR(impl_info);
> + return NULL;
> +}
> +
> static struct PyModuleDef sysmodule = {
> PyModuleDef_HEAD_INIT,
> "sys",
> @@ -1469,7 +1533,7 @@
> PyObject *
> _PySys_Init(void)
> {
> - PyObject *m, *v, *sysdict;
> + PyObject *m, *v, *sysdict, *version_info;
> char *s;
>
> m = PyModule_Create(&sysmodule);
> @@ -1589,11 +1653,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);
>
> --
> Repository URL: http://hg.python.org/cpython
>
> _______________________________________________
> Python-checkins mailing list
> Python-checkins at python.org
> http://mail.python.org/mailman/listinfo/python-checkins
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.python.org/pipermail/python-checkins/attachments/20120604/0560d296/attachment-0001.html>
More information about the Python-checkins
mailing list