/src/cpython/Objects/namespaceobject.c
Line | Count | Source |
1 | | // namespace object implementation |
2 | | |
3 | | #include "Python.h" |
4 | | #include "pycore_modsupport.h" // _PyArg_NoPositional() |
5 | | #include "pycore_namespace.h" // _PyNamespace_Type |
6 | | |
7 | | #include <stddef.h> // offsetof() |
8 | | |
9 | | |
10 | | typedef struct { |
11 | | PyObject_HEAD |
12 | | PyObject *ns_dict; |
13 | | } _PyNamespaceObject; |
14 | | |
15 | 24.1k | #define _PyNamespace_CAST(op) _Py_CAST(_PyNamespaceObject*, (op)) |
16 | 0 | #define _PyNamespace_Check(op) PyObject_TypeCheck((op), &_PyNamespace_Type) |
17 | | |
18 | | |
19 | | static PyMemberDef namespace_members[] = { |
20 | | {"__dict__", _Py_T_OBJECT, offsetof(_PyNamespaceObject, ns_dict), Py_READONLY}, |
21 | | {NULL} |
22 | | }; |
23 | | |
24 | | |
25 | | // Methods |
26 | | |
27 | | static PyObject * |
28 | | namespace_new(PyTypeObject *type, PyObject *args, PyObject *kwds) |
29 | 641 | { |
30 | 641 | PyObject *self; |
31 | | |
32 | 641 | assert(type != NULL && type->tp_alloc != NULL); |
33 | 641 | self = type->tp_alloc(type, 0); |
34 | 641 | if (self != NULL) { |
35 | 641 | _PyNamespaceObject *ns = (_PyNamespaceObject *)self; |
36 | 641 | ns->ns_dict = PyDict_New(); |
37 | 641 | if (ns->ns_dict == NULL) { |
38 | 0 | Py_DECREF(ns); |
39 | 0 | return NULL; |
40 | 0 | } |
41 | 641 | } |
42 | 641 | return self; |
43 | 641 | } |
44 | | |
45 | | |
46 | | static int |
47 | | namespace_init(PyObject *op, PyObject *args, PyObject *kwds) |
48 | 497 | { |
49 | 497 | _PyNamespaceObject *ns = _PyNamespace_CAST(op); |
50 | 497 | PyObject *arg = NULL; |
51 | 497 | if (!PyArg_UnpackTuple(args, _PyType_Name(Py_TYPE(ns)), 0, 1, &arg)) { |
52 | 0 | return -1; |
53 | 0 | } |
54 | 497 | if (arg != NULL) { |
55 | 0 | PyObject *dict; |
56 | 0 | if (PyDict_CheckExact(arg)) { |
57 | 0 | dict = Py_NewRef(arg); |
58 | 0 | } |
59 | 0 | else { |
60 | 0 | dict = PyObject_CallOneArg((PyObject *)&PyDict_Type, arg); |
61 | 0 | if (dict == NULL) { |
62 | 0 | return -1; |
63 | 0 | } |
64 | 0 | } |
65 | 0 | int err = (!PyArg_ValidateKeywordArguments(dict) || |
66 | 0 | PyDict_Update(ns->ns_dict, dict) < 0); |
67 | 0 | Py_DECREF(dict); |
68 | 0 | if (err) { |
69 | 0 | return -1; |
70 | 0 | } |
71 | 0 | } |
72 | 497 | if (kwds == NULL) { |
73 | 0 | return 0; |
74 | 0 | } |
75 | 497 | if (!PyArg_ValidateKeywordArguments(kwds)) { |
76 | 0 | return -1; |
77 | 0 | } |
78 | 497 | return PyDict_Update(ns->ns_dict, kwds); |
79 | 497 | } |
80 | | |
81 | | |
82 | | static void |
83 | | namespace_dealloc(PyObject *op) |
84 | 52 | { |
85 | 52 | _PyNamespaceObject *ns = _PyNamespace_CAST(op); |
86 | 52 | PyObject_GC_UnTrack(ns); |
87 | 52 | Py_CLEAR(ns->ns_dict); |
88 | 52 | Py_TYPE(ns)->tp_free((PyObject *)ns); |
89 | 52 | } |
90 | | |
91 | | |
92 | | static PyObject * |
93 | | namespace_repr(PyObject *ns) |
94 | 0 | { |
95 | 0 | int i, loop_error = 0; |
96 | 0 | PyObject *pairs = NULL, *d = NULL, *keys = NULL, *keys_iter = NULL; |
97 | 0 | PyObject *key; |
98 | 0 | PyObject *separator, *pairsrepr, *repr = NULL; |
99 | 0 | const char * name; |
100 | |
|
101 | 0 | name = Py_IS_TYPE(ns, &_PyNamespace_Type) ? "namespace" |
102 | 0 | : Py_TYPE(ns)->tp_name; |
103 | |
|
104 | 0 | i = Py_ReprEnter(ns); |
105 | 0 | if (i != 0) { |
106 | 0 | return i > 0 ? PyUnicode_FromFormat("%s(...)", name) : NULL; |
107 | 0 | } |
108 | | |
109 | 0 | pairs = PyList_New(0); |
110 | 0 | if (pairs == NULL) |
111 | 0 | goto error; |
112 | | |
113 | 0 | assert(((_PyNamespaceObject *)ns)->ns_dict != NULL); |
114 | 0 | d = Py_NewRef(((_PyNamespaceObject *)ns)->ns_dict); |
115 | |
|
116 | 0 | keys = PyDict_Keys(d); |
117 | 0 | if (keys == NULL) |
118 | 0 | goto error; |
119 | | |
120 | 0 | keys_iter = PyObject_GetIter(keys); |
121 | 0 | if (keys_iter == NULL) |
122 | 0 | goto error; |
123 | | |
124 | 0 | while ((key = PyIter_Next(keys_iter)) != NULL) { |
125 | 0 | if (PyUnicode_Check(key) && PyUnicode_GET_LENGTH(key) > 0) { |
126 | 0 | PyObject *value, *item; |
127 | |
|
128 | 0 | int has_key = PyDict_GetItemRef(d, key, &value); |
129 | 0 | if (has_key == 1) { |
130 | 0 | item = PyUnicode_FromFormat("%U=%R", key, value); |
131 | 0 | Py_DECREF(value); |
132 | 0 | if (item == NULL) { |
133 | 0 | loop_error = 1; |
134 | 0 | } |
135 | 0 | else { |
136 | 0 | loop_error = PyList_Append(pairs, item); |
137 | 0 | Py_DECREF(item); |
138 | 0 | } |
139 | 0 | } |
140 | 0 | else if (has_key < 0) { |
141 | 0 | loop_error = 1; |
142 | 0 | } |
143 | 0 | } |
144 | |
|
145 | 0 | Py_DECREF(key); |
146 | 0 | if (loop_error) |
147 | 0 | goto error; |
148 | 0 | } |
149 | | |
150 | 0 | if (PyErr_Occurred()) { |
151 | 0 | goto error; |
152 | 0 | } |
153 | | |
154 | 0 | separator = PyUnicode_FromString(", "); |
155 | 0 | if (separator == NULL) |
156 | 0 | goto error; |
157 | | |
158 | 0 | pairsrepr = PyUnicode_Join(separator, pairs); |
159 | 0 | Py_DECREF(separator); |
160 | 0 | if (pairsrepr == NULL) |
161 | 0 | goto error; |
162 | | |
163 | 0 | repr = PyUnicode_FromFormat("%s(%S)", name, pairsrepr); |
164 | 0 | Py_DECREF(pairsrepr); |
165 | |
|
166 | 0 | error: |
167 | 0 | Py_XDECREF(pairs); |
168 | 0 | Py_XDECREF(d); |
169 | 0 | Py_XDECREF(keys); |
170 | 0 | Py_XDECREF(keys_iter); |
171 | 0 | Py_ReprLeave(ns); |
172 | |
|
173 | 0 | return repr; |
174 | 0 | } |
175 | | |
176 | | |
177 | | static int |
178 | | namespace_traverse(PyObject *op, visitproc visit, void *arg) |
179 | 23.6k | { |
180 | 23.6k | _PyNamespaceObject *ns = _PyNamespace_CAST(op); |
181 | 23.6k | Py_VISIT(ns->ns_dict); |
182 | 23.6k | return 0; |
183 | 23.6k | } |
184 | | |
185 | | |
186 | | static int |
187 | | namespace_clear(PyObject *op) |
188 | 0 | { |
189 | 0 | _PyNamespaceObject *ns = _PyNamespace_CAST(op); |
190 | 0 | Py_CLEAR(ns->ns_dict); |
191 | 0 | return 0; |
192 | 0 | } |
193 | | |
194 | | |
195 | | static PyObject * |
196 | | namespace_richcompare(PyObject *self, PyObject *other, int op) |
197 | 0 | { |
198 | 0 | if ( |
199 | 0 | (op == Py_EQ || op == Py_NE) && |
200 | 0 | PyObject_TypeCheck(self, &_PyNamespace_Type) && |
201 | 0 | PyObject_TypeCheck(other, &_PyNamespace_Type) |
202 | 0 | ) { |
203 | 0 | return PyObject_RichCompare(((_PyNamespaceObject *)self)->ns_dict, |
204 | 0 | ((_PyNamespaceObject *)other)->ns_dict, op); |
205 | 0 | } |
206 | 0 | Py_RETURN_NOTIMPLEMENTED; |
207 | 0 | } |
208 | | |
209 | | |
210 | | PyDoc_STRVAR(namespace_reduce__doc__, "Return state information for pickling"); |
211 | | |
212 | | static PyObject * |
213 | | namespace_reduce(PyObject *op, PyObject *Py_UNUSED(ignored)) |
214 | 0 | { |
215 | 0 | _PyNamespaceObject *ns = (_PyNamespaceObject*)op; |
216 | 0 | PyObject *result, *args = PyTuple_New(0); |
217 | |
|
218 | 0 | if (!args) |
219 | 0 | return NULL; |
220 | | |
221 | 0 | result = PyTuple_Pack(3, (PyObject *)Py_TYPE(ns), args, ns->ns_dict); |
222 | 0 | Py_DECREF(args); |
223 | 0 | return result; |
224 | 0 | } |
225 | | |
226 | | |
227 | | static PyObject * |
228 | | namespace_replace(PyObject *self, PyObject *args, PyObject *kwargs) |
229 | 0 | { |
230 | 0 | if (!_PyArg_NoPositional("__replace__", args)) { |
231 | 0 | return NULL; |
232 | 0 | } |
233 | | |
234 | 0 | PyObject *result = PyObject_CallNoArgs((PyObject *)Py_TYPE(self)); |
235 | 0 | if (!result) { |
236 | 0 | return NULL; |
237 | 0 | } |
238 | 0 | if (!_PyNamespace_Check(result)) { |
239 | 0 | PyErr_Format(PyExc_TypeError, |
240 | 0 | "expect %N type, but %T() returned '%T' object", |
241 | 0 | &_PyNamespace_Type, self, result); |
242 | 0 | Py_DECREF(result); |
243 | 0 | return NULL; |
244 | 0 | } |
245 | | |
246 | 0 | if (PyDict_Update(((_PyNamespaceObject*)result)->ns_dict, |
247 | 0 | ((_PyNamespaceObject*)self)->ns_dict) < 0) |
248 | 0 | { |
249 | 0 | Py_DECREF(result); |
250 | 0 | return NULL; |
251 | 0 | } |
252 | 0 | if (kwargs) { |
253 | 0 | if (PyDict_Update(((_PyNamespaceObject*)result)->ns_dict, kwargs) < 0) { |
254 | 0 | Py_DECREF(result); |
255 | 0 | return NULL; |
256 | 0 | } |
257 | 0 | } |
258 | 0 | return result; |
259 | 0 | } |
260 | | |
261 | | |
262 | | static PyMethodDef namespace_methods[] = { |
263 | | {"__reduce__", namespace_reduce, METH_NOARGS, |
264 | | namespace_reduce__doc__}, |
265 | | {"__replace__", _PyCFunction_CAST(namespace_replace), METH_VARARGS|METH_KEYWORDS, |
266 | | PyDoc_STR("__replace__($self, /, **changes)\n--\n\n" |
267 | | "Return a copy of the namespace object with new values for the specified attributes.")}, |
268 | | {NULL, NULL} // sentinel |
269 | | }; |
270 | | |
271 | | |
272 | | PyDoc_STRVAR(namespace_doc, |
273 | | "SimpleNamespace(mapping_or_iterable=(), /, **kwargs)\n\ |
274 | | --\n\n\ |
275 | | A simple attribute-based namespace."); |
276 | | |
277 | | PyTypeObject _PyNamespace_Type = { |
278 | | PyVarObject_HEAD_INIT(&PyType_Type, 0) |
279 | | "types.SimpleNamespace", /* tp_name */ |
280 | | sizeof(_PyNamespaceObject), /* tp_basicsize */ |
281 | | 0, /* tp_itemsize */ |
282 | | namespace_dealloc, /* tp_dealloc */ |
283 | | 0, /* tp_vectorcall_offset */ |
284 | | 0, /* tp_getattr */ |
285 | | 0, /* tp_setattr */ |
286 | | 0, /* tp_as_async */ |
287 | | namespace_repr, /* tp_repr */ |
288 | | 0, /* tp_as_number */ |
289 | | 0, /* tp_as_sequence */ |
290 | | 0, /* tp_as_mapping */ |
291 | | 0, /* tp_hash */ |
292 | | 0, /* tp_call */ |
293 | | 0, /* tp_str */ |
294 | | PyObject_GenericGetAttr, /* tp_getattro */ |
295 | | PyObject_GenericSetAttr, /* tp_setattro */ |
296 | | 0, /* tp_as_buffer */ |
297 | | Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | |
298 | | Py_TPFLAGS_BASETYPE, /* tp_flags */ |
299 | | namespace_doc, /* tp_doc */ |
300 | | namespace_traverse, /* tp_traverse */ |
301 | | namespace_clear, /* tp_clear */ |
302 | | namespace_richcompare, /* tp_richcompare */ |
303 | | 0, /* tp_weaklistoffset */ |
304 | | 0, /* tp_iter */ |
305 | | 0, /* tp_iternext */ |
306 | | namespace_methods, /* tp_methods */ |
307 | | namespace_members, /* tp_members */ |
308 | | 0, /* tp_getset */ |
309 | | 0, /* tp_base */ |
310 | | 0, /* tp_dict */ |
311 | | 0, /* tp_descr_get */ |
312 | | 0, /* tp_descr_set */ |
313 | | offsetof(_PyNamespaceObject, ns_dict), /* tp_dictoffset */ |
314 | | namespace_init, /* tp_init */ |
315 | | PyType_GenericAlloc, /* tp_alloc */ |
316 | | namespace_new, /* tp_new */ |
317 | | PyObject_GC_Del, /* tp_free */ |
318 | | }; |
319 | | |
320 | | |
321 | | PyObject * |
322 | | _PyNamespace_New(PyObject *kwds) |
323 | 144 | { |
324 | 144 | PyObject *ns = namespace_new(&_PyNamespace_Type, NULL, NULL); |
325 | 144 | if (ns == NULL) |
326 | 0 | return NULL; |
327 | | |
328 | 144 | if (kwds == NULL) |
329 | 36 | return ns; |
330 | 108 | if (PyDict_Update(((_PyNamespaceObject *)ns)->ns_dict, kwds) != 0) { |
331 | 0 | Py_DECREF(ns); |
332 | 0 | return NULL; |
333 | 0 | } |
334 | | |
335 | 108 | return (PyObject *)ns; |
336 | 108 | } |