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