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