Line data Source code
1 : // namespace object implementation
2 :
3 : #include "Python.h"
4 : #include "pycore_namespace.h" // _PyNamespace_Type
5 : #include "structmember.h" // PyMemberDef
6 :
7 :
8 : typedef struct {
9 : PyObject_HEAD
10 : PyObject *ns_dict;
11 : } _PyNamespaceObject;
12 :
13 :
14 : static PyMemberDef namespace_members[] = {
15 : {"__dict__", T_OBJECT, offsetof(_PyNamespaceObject, ns_dict), READONLY},
16 : {NULL}
17 : };
18 :
19 :
20 : // Methods
21 :
22 : static PyObject *
23 18996 : namespace_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
24 : {
25 : PyObject *self;
26 :
27 18996 : assert(type != NULL && type->tp_alloc != NULL);
28 18996 : self = type->tp_alloc(type, 0);
29 18996 : if (self != NULL) {
30 18996 : _PyNamespaceObject *ns = (_PyNamespaceObject *)self;
31 18996 : ns->ns_dict = PyDict_New();
32 18996 : if (ns->ns_dict == NULL) {
33 0 : Py_DECREF(ns);
34 0 : return NULL;
35 : }
36 : }
37 18996 : return self;
38 : }
39 :
40 :
41 : static int
42 9716 : namespace_init(_PyNamespaceObject *ns, PyObject *args, PyObject *kwds)
43 : {
44 9716 : if (PyTuple_GET_SIZE(args) != 0) {
45 1 : PyErr_Format(PyExc_TypeError, "no positional arguments expected");
46 1 : return -1;
47 : }
48 9715 : if (kwds == NULL) {
49 83 : return 0;
50 : }
51 9632 : if (!PyArg_ValidateKeywordArguments(kwds)) {
52 1 : return -1;
53 : }
54 9631 : return PyDict_Update(ns->ns_dict, kwds);
55 : }
56 :
57 :
58 : static void
59 18951 : namespace_dealloc(_PyNamespaceObject *ns)
60 : {
61 18951 : PyObject_GC_UnTrack(ns);
62 18951 : Py_CLEAR(ns->ns_dict);
63 18951 : Py_TYPE(ns)->tp_free((PyObject *)ns);
64 18951 : }
65 :
66 :
67 : static PyObject *
68 19 : namespace_repr(PyObject *ns)
69 : {
70 19 : int i, loop_error = 0;
71 19 : PyObject *pairs = NULL, *d = NULL, *keys = NULL, *keys_iter = NULL;
72 : PyObject *key;
73 19 : PyObject *separator, *pairsrepr, *repr = NULL;
74 : const char * name;
75 :
76 19 : name = Py_IS_TYPE(ns, &_PyNamespace_Type) ? "namespace"
77 19 : : Py_TYPE(ns)->tp_name;
78 :
79 19 : i = Py_ReprEnter(ns);
80 19 : if (i != 0) {
81 2 : return i > 0 ? PyUnicode_FromFormat("%s(...)", name) : NULL;
82 : }
83 :
84 17 : pairs = PyList_New(0);
85 17 : if (pairs == NULL)
86 0 : goto error;
87 :
88 17 : d = ((_PyNamespaceObject *)ns)->ns_dict;
89 17 : assert(d != NULL);
90 17 : Py_INCREF(d);
91 :
92 17 : keys = PyDict_Keys(d);
93 17 : if (keys == NULL)
94 0 : goto error;
95 :
96 17 : keys_iter = PyObject_GetIter(keys);
97 17 : if (keys_iter == NULL)
98 0 : goto error;
99 :
100 87 : while ((key = PyIter_Next(keys_iter)) != NULL) {
101 70 : if (PyUnicode_Check(key) && PyUnicode_GET_LENGTH(key) > 0) {
102 : PyObject *value, *item;
103 :
104 70 : value = PyDict_GetItemWithError(d, key);
105 70 : if (value != NULL) {
106 70 : item = PyUnicode_FromFormat("%U=%R", key, value);
107 70 : if (item == NULL) {
108 0 : loop_error = 1;
109 : }
110 : else {
111 70 : loop_error = PyList_Append(pairs, item);
112 70 : Py_DECREF(item);
113 : }
114 : }
115 0 : else if (PyErr_Occurred()) {
116 0 : loop_error = 1;
117 : }
118 : }
119 :
120 70 : Py_DECREF(key);
121 70 : if (loop_error)
122 0 : goto error;
123 : }
124 :
125 17 : separator = PyUnicode_FromString(", ");
126 17 : if (separator == NULL)
127 0 : goto error;
128 :
129 17 : pairsrepr = PyUnicode_Join(separator, pairs);
130 17 : Py_DECREF(separator);
131 17 : if (pairsrepr == NULL)
132 0 : goto error;
133 :
134 17 : repr = PyUnicode_FromFormat("%s(%S)", name, pairsrepr);
135 17 : Py_DECREF(pairsrepr);
136 :
137 17 : error:
138 17 : Py_XDECREF(pairs);
139 17 : Py_XDECREF(d);
140 17 : Py_XDECREF(keys);
141 17 : Py_XDECREF(keys_iter);
142 17 : Py_ReprLeave(ns);
143 :
144 17 : return repr;
145 : }
146 :
147 :
148 : static int
149 221198 : namespace_traverse(_PyNamespaceObject *ns, visitproc visit, void *arg)
150 : {
151 221198 : Py_VISIT(ns->ns_dict);
152 221198 : return 0;
153 : }
154 :
155 :
156 : static int
157 16 : namespace_clear(_PyNamespaceObject *ns)
158 : {
159 16 : Py_CLEAR(ns->ns_dict);
160 16 : return 0;
161 : }
162 :
163 :
164 : static PyObject *
165 24 : namespace_richcompare(PyObject *self, PyObject *other, int op)
166 : {
167 48 : if (PyObject_TypeCheck(self, &_PyNamespace_Type) &&
168 24 : PyObject_TypeCheck(other, &_PyNamespace_Type))
169 16 : return PyObject_RichCompare(((_PyNamespaceObject *)self)->ns_dict,
170 : ((_PyNamespaceObject *)other)->ns_dict, op);
171 8 : Py_RETURN_NOTIMPLEMENTED;
172 : }
173 :
174 :
175 : PyDoc_STRVAR(namespace_reduce__doc__, "Return state information for pickling");
176 :
177 : static PyObject *
178 6 : namespace_reduce(_PyNamespaceObject *ns, PyObject *Py_UNUSED(ignored))
179 : {
180 6 : PyObject *result, *args = PyTuple_New(0);
181 :
182 6 : if (!args)
183 0 : return NULL;
184 :
185 6 : result = PyTuple_Pack(3, (PyObject *)Py_TYPE(ns), args, ns->ns_dict);
186 6 : Py_DECREF(args);
187 6 : 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_basicsize */
207 : 0, /* tp_itemsize */
208 : (destructor)namespace_dealloc, /* tp_dealloc */
209 : 0, /* tp_vectorcall_offset */
210 : 0, /* tp_getattr */
211 : 0, /* tp_setattr */
212 : 0, /* tp_as_async */
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 9280 : _PyNamespace_New(PyObject *kwds)
249 : {
250 9280 : PyObject *ns = namespace_new(&_PyNamespace_Type, NULL, NULL);
251 9280 : if (ns == NULL)
252 0 : return NULL;
253 :
254 9280 : if (kwds == NULL)
255 0 : return ns;
256 9280 : if (PyDict_Update(((_PyNamespaceObject *)ns)->ns_dict, kwds) != 0) {
257 0 : Py_DECREF(ns);
258 0 : return NULL;
259 : }
260 :
261 9280 : return (PyObject *)ns;
262 : }
|