Branch data 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 : 55116 : namespace_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
24 : : {
25 : : PyObject *self;
26 : :
27 : : assert(type != NULL && type->tp_alloc != NULL);
28 : 55116 : self = type->tp_alloc(type, 0);
29 [ + - ]: 55116 : if (self != NULL) {
30 : 55116 : _PyNamespaceObject *ns = (_PyNamespaceObject *)self;
31 : 55116 : ns->ns_dict = PyDict_New();
32 [ - + ]: 55116 : if (ns->ns_dict == NULL) {
33 : 0 : Py_DECREF(ns);
34 : 0 : return NULL;
35 : : }
36 : : }
37 : 55116 : return self;
38 : : }
39 : :
40 : :
41 : : static int
42 : 45826 : namespace_init(_PyNamespaceObject *ns, PyObject *args, PyObject *kwds)
43 : : {
44 [ + + ]: 45826 : if (PyTuple_GET_SIZE(args) != 0) {
45 : 1 : PyErr_Format(PyExc_TypeError, "no positional arguments expected");
46 : 1 : return -1;
47 : : }
48 [ + + ]: 45825 : if (kwds == NULL) {
49 : 83 : return 0;
50 : : }
51 [ + + ]: 45742 : if (!PyArg_ValidateKeywordArguments(kwds)) {
52 : 1 : return -1;
53 : : }
54 : 45741 : return PyDict_Update(ns->ns_dict, kwds);
55 : : }
56 : :
57 : :
58 : : static void
59 : 54909 : namespace_dealloc(_PyNamespaceObject *ns)
60 : : {
61 : 54909 : PyObject_GC_UnTrack(ns);
62 [ + + ]: 54909 : Py_CLEAR(ns->ns_dict);
63 : 54909 : Py_TYPE(ns)->tp_free((PyObject *)ns);
64 : 54909 : }
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 : : 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 : 863268 : namespace_traverse(_PyNamespaceObject *ns, visitproc visit, void *arg)
150 : : {
151 [ + - - + ]: 863268 : Py_VISIT(ns->ns_dict);
152 : 863268 : 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 : 9290 : _PyNamespace_New(PyObject *kwds)
249 : : {
250 : 9290 : PyObject *ns = namespace_new(&_PyNamespace_Type, NULL, NULL);
251 [ - + ]: 9290 : if (ns == NULL)
252 : 0 : return NULL;
253 : :
254 [ - + ]: 9290 : if (kwds == NULL)
255 : 0 : return ns;
256 [ - + ]: 9290 : if (PyDict_Update(((_PyNamespaceObject *)ns)->ns_dict, kwds) != 0) {
257 : 0 : Py_DECREF(ns);
258 : 0 : return NULL;
259 : : }
260 : :
261 : 9290 : return (PyObject *)ns;
262 : : }
|