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/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,240 @@ +/* namespace object implementation */ + +#include "Python.h" +#include "structmember.h" +#include "namespaceobject.h" + + +typedef struct { + PyObject_HEAD + PyObject *ns_dict; +} _PyNamespaceObject; + + +static PyMemberDef namespace_members[] = { + {"__dict__", T_OBJECT, offsetof(_PyNamespaceObject, ns_dict), READONLY}, + {0} +}; + + +/* 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 *kwds) +{ + if (kwds == NULL) + return 0; + return PyDict_Update(ns->ns_dict, kwds); +} + + +static int +namespace_init(_PyNamespaceObject *ns, PyObject *args, PyObject *kwds) +{ + assert(args == NULL || PyTuple_Check(args)); + assert(kwds == NULL || PyDict_Check(kwds)); + + if (PyObject_Size(args) > 0) + { + PyErr_Format(PyExc_TypeError, "expected no positional arguments"); + return -1; + } + return _namespace_init(ns, kwds); +} + + +static void +namespace_dealloc(_PyNamespaceObject *ns) +{ + PyObject_GC_UnTrack(ns); + if (ns->ns_dict != NULL) { + PyDict_Clear(ns->ns_dict); + Py_DECREF(ns->ns_dict); + } + Py_TYPE(ns)->tp_free((PyObject *)ns); +} + + +static PyObject * +namespace_repr(_PyNamespaceObject *ns) +{ + int result; + PyObject *key = NULL, *value = NULL, *item = NULL; + PyObject *separator, *pairs, *keys, *keys_iter = NULL; + PyObject *d, *repr = NULL; + + + separator = PyUnicode_FromString(", "); + if (separator == NULL) + { + return NULL; + } + + pairs = PyList_New(0); + if (pairs == NULL) + { + Py_DECREF(separator); + return NULL; + } + + d = ((_PyNamespaceObject *)ns)->ns_dict; + if (d == NULL) + { + Py_DECREF(separator); + Py_DECREF(pairs); + return NULL; + } + Py_INCREF(d); + + keys = PyDict_Keys(d); + if (keys == NULL) + goto error; + if (PyList_Sort(keys) != 0) + { + Py_DECREF(keys); + goto error; + } + keys_iter = PyObject_GetIter(keys); + Py_DECREF(keys); + if (keys_iter == NULL) + goto error; + + while ((key = PyIter_Next(keys_iter)) != NULL) + { + if (!PyUnicode_Check(key) || PyUnicode_GET_SIZE(key) == 0) + continue; + if (PyUnicode_AS_DATA(key)[0] != '_') { + value = PyDict_GetItem(d, key); + assert (value != NULL); + + item = PyUnicode_FromFormat("%S=%R", key, value); + Py_DECREF(key); + if (item == NULL) + goto error; + + result = PyList_Append(pairs, item); + Py_DECREF(item); + if (result < 0) + goto error; + } + } + pairs = PyUnicode_Join(separator, pairs); + if (pairs == NULL) + goto error; + repr = PyUnicode_FromFormat("%s(%S)", + ((PyObject *)ns)->ob_type->tp_name, pairs); + +error: + Py_DECREF(separator); + Py_DECREF(pairs); + Py_DECREF(d); + Py_XDECREF(keys_iter); + + 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\ +SimpleNamespace(**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) +{ + if (kwds != NULL && !PyDict_Check(kwds)) + { + PyErr_Format(PyExc_TypeError, "expected kwds to be a dict"); + return NULL; + } + + PyObject *ns = namespace_new(&_PyNamespace_Type, NULL, NULL); + if (ns == NULL) + return NULL; + + if (_namespace_init((_PyNamespaceObject *)ns, kwds) != 0) { + Py_DECREF(ns); + return NULL; + } + return (PyObject *)ns; +} diff --git a/Python/sysmodule.c b/Python/sysmodule.c --- a/Python/sysmodule.c +++ b/Python/sysmodule.c @@ -18,6 +18,7 @@ #include "code.h" #include "frameobject.h" #include "pythread.h" +#include "namespaceobject.h" #include "osdefs.h" @@ -1261,6 +1262,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 +1456,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 +1534,7 @@ PyObject * _PySys_Init(void) { - PyObject *m, *v, *sysdict; + PyObject *m, *v, *sysdict, *version_info; char *s; m = PyModule_Create(&sysmodule); @@ -1585,11 +1650,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);