1 // namespace object implementation 2 3 #include "Python.h" 4 #include "structmember.h" 5 6 7 typedef struct { 8 PyObject_HEAD 9 PyObject *ns_dict; 10 } _PyNamespaceObject; 11 12 13 static PyMemberDef namespace_members[] = { 14 {"__dict__", T_OBJECT, offsetof(_PyNamespaceObject, ns_dict), READONLY}, 15 {NULL} 16 }; 17 18 19 // Methods 20 21 static PyObject * 22 namespace_new(PyTypeObject *type, PyObject *args, PyObject *kwds) 23 { 24 PyObject *self; 25 26 assert(type != NULL && type->tp_alloc != NULL); 27 self = type->tp_alloc(type, 0); 28 if (self != NULL) { 29 _PyNamespaceObject *ns = (_PyNamespaceObject *)self; 30 ns->ns_dict = PyDict_New(); 31 if (ns->ns_dict == NULL) { 32 Py_DECREF(ns); 33 return NULL; 34 } 35 } 36 return self; 37 } 38 39 40 static int 41 namespace_init(_PyNamespaceObject *ns, PyObject *args, PyObject *kwds) 42 { 43 // ignore args if it's NULL or empty 44 if (args != NULL) { 45 Py_ssize_t argcount = PyObject_Size(args); 46 if (argcount < 0) 47 return -1; 48 else if (argcount > 0) { 49 PyErr_Format(PyExc_TypeError, "no positional arguments expected"); 50 return -1; 51 } 52 } 53 if (kwds == NULL) 54 return 0; 55 return PyDict_Update(ns->ns_dict, kwds); 56 } 57 58 59 static void 60 namespace_dealloc(_PyNamespaceObject *ns) 61 { 62 PyObject_GC_UnTrack(ns); 63 Py_CLEAR(ns->ns_dict); 64 Py_TYPE(ns)->tp_free((PyObject *)ns); 65 } 66 67 68 static PyObject * 69 namespace_repr(PyObject *ns) 70 { 71 int i, loop_error = 0; 72 PyObject *pairs = NULL, *d = NULL, *keys = NULL, *keys_iter = NULL; 73 PyObject *key; 74 PyObject *separator, *pairsrepr, *repr = NULL; 75 const char * name; 76 77 name = (Py_TYPE(ns) == &_PyNamespace_Type) ? "namespace" 78 : ns->ob_type->tp_name; 79 80 i = Py_ReprEnter(ns); 81 if (i != 0) { 82 return i > 0 ? PyUnicode_FromFormat("%s(...)", name) : NULL; 83 } 84 85 pairs = PyList_New(0); 86 if (pairs == NULL) 87 goto error; 88 89 d = ((_PyNamespaceObject *)ns)->ns_dict; 90 assert(d != NULL); 91 Py_INCREF(d); 92 93 keys = PyDict_Keys(d); 94 if (keys == NULL) 95 goto error; 96 if (PyList_Sort(keys) != 0) 97 goto error; 98 99 keys_iter = PyObject_GetIter(keys); 100 if (keys_iter == NULL) 101 goto error; 102 103 while ((key = PyIter_Next(keys_iter)) != NULL) { 104 if (PyUnicode_Check(key) && PyUnicode_GET_LENGTH(key) > 0) { 105 PyObject *value, *item; 106 107 value = PyDict_GetItem(d, key); 108 assert(value != NULL); 109 110 item = PyUnicode_FromFormat("%S=%R", key, value); 111 if (item == NULL) { 112 loop_error = 1; 113 } 114 else { 115 loop_error = PyList_Append(pairs, item); 116 Py_DECREF(item); 117 } 118 } 119 120 Py_DECREF(key); 121 if (loop_error) 122 goto error; 123 } 124 125 separator = PyUnicode_FromString(", "); 126 if (separator == NULL) 127 goto error; 128 129 pairsrepr = PyUnicode_Join(separator, pairs); 130 Py_DECREF(separator); 131 if (pairsrepr == NULL) 132 goto error; 133 134 repr = PyUnicode_FromFormat("%s(%S)", name, pairsrepr); 135 Py_DECREF(pairsrepr); 136 137 error: 138 Py_XDECREF(pairs); 139 Py_XDECREF(d); 140 Py_XDECREF(keys); 141 Py_XDECREF(keys_iter); 142 Py_ReprLeave(ns); 143 144 return repr; 145 } 146 147 148 static int 149 namespace_traverse(_PyNamespaceObject *ns, visitproc visit, void *arg) 150 { 151 Py_VISIT(ns->ns_dict); 152 return 0; 153 } 154 155 156 static int 157 namespace_clear(_PyNamespaceObject *ns) 158 { 159 Py_CLEAR(ns->ns_dict); 160 return 0; 161 } 162 163 164 static PyObject * 165 namespace_richcompare(PyObject *self, PyObject *other, int op) 166 { 167 if (PyObject_TypeCheck(self, &_PyNamespace_Type) && 168 PyObject_TypeCheck(other, &_PyNamespace_Type)) 169 return PyObject_RichCompare(((_PyNamespaceObject *)self)->ns_dict, 170 ((_PyNamespaceObject *)other)->ns_dict, op); 171 Py_RETURN_NOTIMPLEMENTED; 172 } 173 174 175 PyDoc_STRVAR(namespace_reduce__doc__, "Return state information for pickling"); 176 177 static PyObject * 178 namespace_reduce(_PyNamespaceObject *ns) 179 { 180 PyObject *result, *args = PyTuple_New(0); 181 182 if (!args) 183 return NULL; 184 185 result = PyTuple_Pack(3, (PyObject *)Py_TYPE(ns), args, ns->ns_dict); 186 Py_DECREF(args); 187 return result; 188 } 189 190 191 static PyMethodDef namespace_methods[] = { 192 {"__reduce__", (PyCFunction)namespace_reduce, METH_NOARGS, 193 namespace_reduce__doc__}, 194 {NULL, NULL} // sentinel 195 }; 196 197 198 PyDoc_STRVAR(namespace_doc, 199 "A simple attribute-based namespace.\n\ 200 \n\ 201 SimpleNamespace(**kwargs)"); 202 203 PyTypeObject _PyNamespace_Type = { 204 PyVarObject_HEAD_INIT(&PyType_Type, 0) 205 "types.SimpleNamespace", /* tp_name */ 206 sizeof(_PyNamespaceObject), /* tp_size */ 207 0, /* tp_itemsize */ 208 (destructor)namespace_dealloc, /* tp_dealloc */ 209 0, /* tp_print */ 210 0, /* tp_getattr */ 211 0, /* tp_setattr */ 212 0, /* tp_reserved */ 213 (reprfunc)namespace_repr, /* tp_repr */ 214 0, /* tp_as_number */ 215 0, /* tp_as_sequence */ 216 0, /* tp_as_mapping */ 217 0, /* tp_hash */ 218 0, /* tp_call */ 219 0, /* tp_str */ 220 PyObject_GenericGetAttr, /* tp_getattro */ 221 PyObject_GenericSetAttr, /* tp_setattro */ 222 0, /* tp_as_buffer */ 223 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | 224 Py_TPFLAGS_BASETYPE, /* tp_flags */ 225 namespace_doc, /* tp_doc */ 226 (traverseproc)namespace_traverse, /* tp_traverse */ 227 (inquiry)namespace_clear, /* tp_clear */ 228 namespace_richcompare, /* tp_richcompare */ 229 0, /* tp_weaklistoffset */ 230 0, /* tp_iter */ 231 0, /* tp_iternext */ 232 namespace_methods, /* tp_methods */ 233 namespace_members, /* tp_members */ 234 0, /* tp_getset */ 235 0, /* tp_base */ 236 0, /* tp_dict */ 237 0, /* tp_descr_get */ 238 0, /* tp_descr_set */ 239 offsetof(_PyNamespaceObject, ns_dict), /* tp_dictoffset */ 240 (initproc)namespace_init, /* tp_init */ 241 PyType_GenericAlloc, /* tp_alloc */ 242 (newfunc)namespace_new, /* tp_new */ 243 PyObject_GC_Del, /* tp_free */ 244 }; 245 246 247 PyObject * 248 _PyNamespace_New(PyObject *kwds) 249 { 250 PyObject *ns = namespace_new(&_PyNamespace_Type, NULL, NULL); 251 if (ns == NULL) 252 return NULL; 253 254 if (kwds == NULL) 255 return ns; 256 if (PyDict_Update(((_PyNamespaceObject *)ns)->ns_dict, kwds) != 0) { 257 Py_DECREF(ns); 258 return NULL; 259 } 260 261 return (PyObject *)ns; 262 } 263