| // namespace object implementation |
| |
| #include "Python.h" |
| #include "structmember.h" // PyMemberDef |
| |
| |
| 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) |
| { |
| PyObject *self; |
| |
| assert(type != NULL && type->tp_alloc != NULL); |
| self = type->tp_alloc(type, 0); |
| if (self != NULL) { |
| _PyNamespaceObject *ns = (_PyNamespaceObject *)self; |
| ns->ns_dict = PyDict_New(); |
| if (ns->ns_dict == NULL) { |
| Py_DECREF(ns); |
| return NULL; |
| } |
| } |
| return self; |
| } |
| |
| |
| static int |
| namespace_init(_PyNamespaceObject *ns, PyObject *args, PyObject *kwds) |
| { |
| if (PyTuple_GET_SIZE(args) != 0) { |
| PyErr_Format(PyExc_TypeError, "no positional arguments expected"); |
| return -1; |
| } |
| if (kwds == NULL) { |
| return 0; |
| } |
| if (!PyArg_ValidateKeywordArguments(kwds)) { |
| return -1; |
| } |
| 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(PyObject *ns) |
| { |
| int i, loop_error = 0; |
| PyObject *pairs = NULL, *d = NULL, *keys = NULL, *keys_iter = NULL; |
| PyObject *key; |
| PyObject *separator, *pairsrepr, *repr = NULL; |
| const char * name; |
| |
| name = Py_IS_TYPE(ns, &_PyNamespace_Type) ? "namespace" |
| : Py_TYPE(ns)->tp_name; |
| |
| i = Py_ReprEnter(ns); |
| if (i != 0) { |
| return i > 0 ? PyUnicode_FromFormat("%s(...)", name) : 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_LENGTH(key) > 0) { |
| PyObject *value, *item; |
| |
| value = PyDict_GetItemWithError(d, key); |
| if (value != NULL) { |
| item = PyUnicode_FromFormat("%U=%R", key, value); |
| if (item == NULL) { |
| loop_error = 1; |
| } |
| else { |
| loop_error = PyList_Append(pairs, item); |
| Py_DECREF(item); |
| } |
| } |
| else if (PyErr_Occurred()) { |
| loop_error = 1; |
| } |
| } |
| |
| 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)", name, pairsrepr); |
| Py_DECREF(pairsrepr); |
| |
| error: |
| Py_XDECREF(pairs); |
| Py_XDECREF(d); |
| Py_XDECREF(keys); |
| Py_XDECREF(keys_iter); |
| Py_ReprLeave(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; |
| } |
| |
| |
| static PyObject * |
| namespace_richcompare(PyObject *self, PyObject *other, int op) |
| { |
| if (PyObject_TypeCheck(self, &_PyNamespace_Type) && |
| PyObject_TypeCheck(other, &_PyNamespace_Type)) |
| return PyObject_RichCompare(((_PyNamespaceObject *)self)->ns_dict, |
| ((_PyNamespaceObject *)other)->ns_dict, op); |
| Py_RETURN_NOTIMPLEMENTED; |
| } |
| |
| |
| PyDoc_STRVAR(namespace_reduce__doc__, "Return state information for pickling"); |
| |
| static PyObject * |
| namespace_reduce(_PyNamespaceObject *ns, PyObject *Py_UNUSED(ignored)) |
| { |
| PyObject *result, *args = PyTuple_New(0); |
| |
| if (!args) |
| return NULL; |
| |
| result = PyTuple_Pack(3, (PyObject *)Py_TYPE(ns), args, ns->ns_dict); |
| Py_DECREF(args); |
| return result; |
| } |
| |
| |
| static PyMethodDef namespace_methods[] = { |
| {"__reduce__", (PyCFunction)namespace_reduce, METH_NOARGS, |
| namespace_reduce__doc__}, |
| {NULL, NULL} // sentinel |
| }; |
| |
| |
| PyDoc_STRVAR(namespace_doc, |
| "A simple attribute-based namespace.\n\ |
| \n\ |
| SimpleNamespace(**kwargs)"); |
| |
| PyTypeObject _PyNamespace_Type = { |
| PyVarObject_HEAD_INIT(&PyType_Type, 0) |
| "types.SimpleNamespace", /* tp_name */ |
| sizeof(_PyNamespaceObject), /* tp_basicsize */ |
| 0, /* tp_itemsize */ |
| (destructor)namespace_dealloc, /* tp_dealloc */ |
| 0, /* tp_vectorcall_offset */ |
| 0, /* tp_getattr */ |
| 0, /* tp_setattr */ |
| 0, /* tp_as_async */ |
| (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 */ |
| namespace_richcompare, /* tp_richcompare */ |
| 0, /* tp_weaklistoffset */ |
| 0, /* tp_iter */ |
| 0, /* tp_iternext */ |
| namespace_methods, /* 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; |
| } |