Coverage Report

Created: 2026-10-17 06:15

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