| // 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) | 
 | { | 
 |     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) | 
 | { | 
 |     // ignore args if it's NULL or empty | 
 |     if (args != NULL) { | 
 |         Py_ssize_t argcount = PyObject_Size(args); | 
 |         if (argcount < 0) | 
 |             return -1; | 
 |         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(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_TYPE(ns) == &_PyNamespace_Type) ? "namespace" | 
 |                                                : ns->ob_type->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_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)", 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 *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_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 */ | 
 |     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; | 
 | } |