blob: ff278d33474a2bf7c800be687a1acf058431a5f0 [file] [log] [blame]
Barry Warsaw409da152012-06-03 16:18:47 -04001/* namespace object implementation */
2
3#include "Python.h"
4#include "structmember.h"
5
6
7typedef struct {
8 PyObject_HEAD
9 PyObject *ns_dict;
10} _PyNamespaceObject;
11
12
13static PyMemberDef namespace_members[] = {
14 {"__dict__", T_OBJECT, offsetof(_PyNamespaceObject, ns_dict), READONLY},
15 {NULL}
16};
17
18
19/* Methods */
20
21static PyObject *
22namespace_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
23{
Eric Snow547298c2012-10-16 22:35:38 -070024 PyObject *self;
Barry Warsaw409da152012-06-03 16:18:47 -040025
Eric Snow547298c2012-10-16 22:35:38 -070026 assert(type != NULL && type->tp_alloc != NULL);
27 self = type->tp_alloc(type, 0);
28 if (self != NULL) {
29 _PyNamespaceObject *ns = (_PyNamespaceObject *)self;
30 ns->ns_dict = PyDict_New();
31 if (ns->ns_dict == NULL) {
32 Py_DECREF(ns);
33 return NULL;
34 }
Barry Warsaw409da152012-06-03 16:18:47 -040035 }
Eric Snow547298c2012-10-16 22:35:38 -070036 return self;
Barry Warsaw409da152012-06-03 16:18:47 -040037}
38
39
40static int
41namespace_init(_PyNamespaceObject *ns, PyObject *args, PyObject *kwds)
42{
43 /* ignore args if it's NULL or empty */
44 if (args != NULL) {
45 Py_ssize_t argcount = PyObject_Size(args);
46 if (argcount < 0)
47 return argcount;
48 else if (argcount > 0) {
49 PyErr_Format(PyExc_TypeError, "no positional arguments expected");
50 return -1;
51 }
52 }
53 if (kwds == NULL)
54 return 0;
55 return PyDict_Update(ns->ns_dict, kwds);
56}
57
58
59static void
60namespace_dealloc(_PyNamespaceObject *ns)
61{
62 PyObject_GC_UnTrack(ns);
63 Py_CLEAR(ns->ns_dict);
64 Py_TYPE(ns)->tp_free((PyObject *)ns);
65}
66
67
68static PyObject *
69namespace_repr(_PyNamespaceObject *ns)
70{
71 int i, loop_error = 0;
72 PyObject *pairs = NULL, *d = NULL, *keys = NULL, *keys_iter = NULL;
73 PyObject *key;
74 PyObject *separator, *pairsrepr, *repr = NULL;
75
76 i = Py_ReprEnter((PyObject *)ns);
77 if (i != 0) {
78 return i > 0 ? PyUnicode_FromString("namespace(...)") : NULL;
79 }
80
81 pairs = PyList_New(0);
82 if (pairs == NULL)
83 goto error;
84
85 d = ((_PyNamespaceObject *)ns)->ns_dict;
86 assert(d != NULL);
87 Py_INCREF(d);
88
89 keys = PyDict_Keys(d);
90 if (keys == NULL)
91 goto error;
92 if (PyList_Sort(keys) != 0)
93 goto error;
94
95 keys_iter = PyObject_GetIter(keys);
96 if (keys_iter == NULL)
97 goto error;
98
99 while ((key = PyIter_Next(keys_iter)) != NULL) {
100 if (PyUnicode_Check(key) && PyUnicode_GET_SIZE(key) > 0) {
101 PyObject *value, *item;
102
103 value = PyDict_GetItem(d, key);
104 assert(value != NULL);
105
106 item = PyUnicode_FromFormat("%S=%R", key, value);
107 if (item == NULL) {
108 loop_error = 1;
109 }
110 else {
111 loop_error = PyList_Append(pairs, item);
112 Py_DECREF(item);
113 }
114 }
115
116 Py_DECREF(key);
117 if (loop_error)
118 goto error;
119 }
120
121 separator = PyUnicode_FromString(", ");
122 if (separator == NULL)
123 goto error;
124
125 pairsrepr = PyUnicode_Join(separator, pairs);
126 Py_DECREF(separator);
127 if (pairsrepr == NULL)
128 goto error;
129
130 repr = PyUnicode_FromFormat("%s(%S)",
131 ((PyObject *)ns)->ob_type->tp_name, pairsrepr);
132 Py_DECREF(pairsrepr);
133
134error:
135 Py_XDECREF(pairs);
136 Py_XDECREF(d);
137 Py_XDECREF(keys);
138 Py_XDECREF(keys_iter);
139 Py_ReprLeave((PyObject *)ns);
140
141 return repr;
142}
143
144
145static int
146namespace_traverse(_PyNamespaceObject *ns, visitproc visit, void *arg)
147{
148 Py_VISIT(ns->ns_dict);
149 return 0;
150}
151
152
153static int
154namespace_clear(_PyNamespaceObject *ns)
155{
156 Py_CLEAR(ns->ns_dict);
157 return 0;
158}
159
160
161PyDoc_STRVAR(namespace_doc,
162"A simple attribute-based namespace.\n\
163\n\
164namespace(**kwargs)");
165
166PyTypeObject _PyNamespace_Type = {
167 PyVarObject_HEAD_INIT(&PyType_Type, 0)
168 "namespace", /* tp_name */
169 sizeof(_PyNamespaceObject), /* tp_size */
170 0, /* tp_itemsize */
171 (destructor)namespace_dealloc, /* tp_dealloc */
172 0, /* tp_print */
173 0, /* tp_getattr */
174 0, /* tp_setattr */
175 0, /* tp_reserved */
176 (reprfunc)namespace_repr, /* tp_repr */
177 0, /* tp_as_number */
178 0, /* tp_as_sequence */
179 0, /* tp_as_mapping */
180 0, /* tp_hash */
181 0, /* tp_call */
182 0, /* tp_str */
183 PyObject_GenericGetAttr, /* tp_getattro */
184 PyObject_GenericSetAttr, /* tp_setattro */
185 0, /* tp_as_buffer */
186 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC |
187 Py_TPFLAGS_BASETYPE, /* tp_flags */
188 namespace_doc, /* tp_doc */
189 (traverseproc)namespace_traverse, /* tp_traverse */
190 (inquiry)namespace_clear, /* tp_clear */
191 0, /* tp_richcompare */
192 0, /* tp_weaklistoffset */
193 0, /* tp_iter */
194 0, /* tp_iternext */
195 0, /* tp_methods */
196 namespace_members, /* tp_members */
197 0, /* tp_getset */
198 0, /* tp_base */
199 0, /* tp_dict */
200 0, /* tp_descr_get */
201 0, /* tp_descr_set */
202 offsetof(_PyNamespaceObject, ns_dict), /* tp_dictoffset */
203 (initproc)namespace_init, /* tp_init */
204 PyType_GenericAlloc, /* tp_alloc */
205 (newfunc)namespace_new, /* tp_new */
206 PyObject_GC_Del, /* tp_free */
207};
208
209
210PyObject *
211_PyNamespace_New(PyObject *kwds)
212{
213 PyObject *ns = namespace_new(&_PyNamespace_Type, NULL, NULL);
214 if (ns == NULL)
215 return NULL;
216
217 if (kwds == NULL)
218 return ns;
219 if (PyDict_Update(((_PyNamespaceObject *)ns)->ns_dict, kwds) != 0) {
220 Py_DECREF(ns);
221 return NULL;
222 }
223
224 return (PyObject *)ns;
225}