Eric Snow's implementation of PEP 421.
Issue 14673: Add sys.implementation
This commit is contained in:
parent
82ffabdfa4
commit
409da157d7
|
@ -616,6 +616,44 @@ always available.
|
||||||
|
|
||||||
Thus ``2.1.0a3`` is hexversion ``0x020100a3``.
|
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 identifier, like ``'cpython'``.
|
||||||
|
|
||||||
|
*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)``. 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
|
.. data:: int_info
|
||||||
|
|
||||||
A :term:`struct sequence` that holds information about Python's internal
|
A :term:`struct sequence` that holds information about Python's internal
|
||||||
|
|
|
@ -194,3 +194,27 @@ Standard names are defined for the following types:
|
||||||
Return a new view of the underlying mapping's values.
|
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`
|
||||||
|
instead.
|
||||||
|
|
||||||
|
.. versionadded:: 3.3
|
||||||
|
|
|
@ -101,6 +101,7 @@
|
||||||
#include "warnings.h"
|
#include "warnings.h"
|
||||||
#include "weakrefobject.h"
|
#include "weakrefobject.h"
|
||||||
#include "structseq.h"
|
#include "structseq.h"
|
||||||
|
#include "namespaceobject.h"
|
||||||
|
|
||||||
#include "codecs.h"
|
#include "codecs.h"
|
||||||
#include "pyerrors.h"
|
#include "pyerrors.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 */
|
|
@ -581,6 +581,24 @@ class SysModuleTest(unittest.TestCase):
|
||||||
expected = None
|
expected = None
|
||||||
self.check_fsencoding(fs_encoding, expected)
|
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):
|
class SizeofTest(unittest.TestCase):
|
||||||
|
|
||||||
|
|
|
@ -996,8 +996,149 @@ class ClassCreationTests(unittest.TestCase):
|
||||||
X = types.new_class("X", (int(), C))
|
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():
|
def test_main():
|
||||||
run_unittest(TypesTests, MappingProxyTests, ClassCreationTests)
|
run_unittest(TypesTests, MappingProxyTests, ClassCreationTests,
|
||||||
|
SimpleNamespaceTests)
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
test_main()
|
test_main()
|
||||||
|
|
|
@ -13,6 +13,7 @@ FunctionType = type(_f)
|
||||||
LambdaType = type(lambda: None) # Same as FunctionType
|
LambdaType = type(lambda: None) # Same as FunctionType
|
||||||
CodeType = type(_f.__code__)
|
CodeType = type(_f.__code__)
|
||||||
MappingProxyType = type(type.__dict__)
|
MappingProxyType = type(type.__dict__)
|
||||||
|
SimpleNamespace = type(sys.implementation)
|
||||||
|
|
||||||
def _g():
|
def _g():
|
||||||
yield 1
|
yield 1
|
||||||
|
|
|
@ -392,6 +392,7 @@ OBJECT_OBJS= \
|
||||||
Objects/memoryobject.o \
|
Objects/memoryobject.o \
|
||||||
Objects/methodobject.o \
|
Objects/methodobject.o \
|
||||||
Objects/moduleobject.o \
|
Objects/moduleobject.o \
|
||||||
|
Objects/namespaceobject.o \
|
||||||
Objects/object.o \
|
Objects/object.o \
|
||||||
Objects/obmalloc.o \
|
Objects/obmalloc.o \
|
||||||
Objects/capsule.o \
|
Objects/capsule.o \
|
||||||
|
@ -766,6 +767,7 @@ PYTHON_HEADERS= \
|
||||||
$(srcdir)/Include/methodobject.h \
|
$(srcdir)/Include/methodobject.h \
|
||||||
$(srcdir)/Include/modsupport.h \
|
$(srcdir)/Include/modsupport.h \
|
||||||
$(srcdir)/Include/moduleobject.h \
|
$(srcdir)/Include/moduleobject.h \
|
||||||
|
$(srcdir)/Include/namespaceobject.h \
|
||||||
$(srcdir)/Include/node.h \
|
$(srcdir)/Include/node.h \
|
||||||
$(srcdir)/Include/object.h \
|
$(srcdir)/Include/object.h \
|
||||||
$(srcdir)/Include/objimpl.h \
|
$(srcdir)/Include/objimpl.h \
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
|
@ -1707,6 +1707,9 @@ _Py_ReadyTypes(void)
|
||||||
|
|
||||||
if (PyType_Ready(&PyZip_Type) < 0)
|
if (PyType_Ready(&PyZip_Type) < 0)
|
||||||
Py_FatalError("Can't initialize zip type");
|
Py_FatalError("Can't initialize zip type");
|
||||||
|
|
||||||
|
if (PyType_Ready(&_PyNamespace_Type) < 0)
|
||||||
|
Py_FatalError("Can't initialize namespace type");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1261,6 +1261,7 @@ executable -- absolute path of the executable binary of the Python interpreter\n
|
||||||
float_info -- a struct sequence with information about the float implementation.\n\
|
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\
|
float_repr_style -- string indicating the style of repr() output for floats\n\
|
||||||
hexversion -- version information encoded as a single integer\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\
|
int_info -- a struct sequence with information about the int implementation.\n\
|
||||||
maxsize -- the largest supported length of containers.\n\
|
maxsize -- the largest supported length of containers.\n\
|
||||||
maxunicode -- the value of the largest Unicode codepoint\n\
|
maxunicode -- the value of the largest Unicode codepoint\n\
|
||||||
|
@ -1454,6 +1455,69 @@ make_version_info(void)
|
||||||
return version_info;
|
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 = {
|
static struct PyModuleDef sysmodule = {
|
||||||
PyModuleDef_HEAD_INIT,
|
PyModuleDef_HEAD_INIT,
|
||||||
"sys",
|
"sys",
|
||||||
|
@ -1469,7 +1533,7 @@ static struct PyModuleDef sysmodule = {
|
||||||
PyObject *
|
PyObject *
|
||||||
_PySys_Init(void)
|
_PySys_Init(void)
|
||||||
{
|
{
|
||||||
PyObject *m, *v, *sysdict;
|
PyObject *m, *v, *sysdict, *version_info;
|
||||||
char *s;
|
char *s;
|
||||||
|
|
||||||
m = PyModule_Create(&sysmodule);
|
m = PyModule_Create(&sysmodule);
|
||||||
|
@ -1589,11 +1653,15 @@ _PySys_Init(void)
|
||||||
/* version_info */
|
/* version_info */
|
||||||
if (VersionInfoType.tp_name == 0)
|
if (VersionInfoType.tp_name == 0)
|
||||||
PyStructSequence_InitType(&VersionInfoType, &version_info_desc);
|
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 */
|
/* prevent user from creating new instances */
|
||||||
VersionInfoType.tp_init = NULL;
|
VersionInfoType.tp_init = NULL;
|
||||||
VersionInfoType.tp_new = NULL;
|
VersionInfoType.tp_new = NULL;
|
||||||
|
|
||||||
|
/* implementation */
|
||||||
|
SET_SYS_FROM_STRING("implementation", make_impl_info(version_info));
|
||||||
|
|
||||||
/* flags */
|
/* flags */
|
||||||
if (FlagsType.tp_name == 0)
|
if (FlagsType.tp_name == 0)
|
||||||
PyStructSequence_InitType(&FlagsType, &flags_desc);
|
PyStructSequence_InitType(&FlagsType, &flags_desc);
|
||||||
|
|
Loading…
Reference in New Issue