Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit b5c8f92

Browse files
Issue #15022: Add pickle and comparison support to types.SimpleNamespace.
1 parent e924ddb commit b5c8f92

4 files changed

Lines changed: 54 additions & 15 deletions

File tree

Doc/library/types.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -212,6 +212,8 @@ Standard names are defined for the following types:
212212
keys = sorted(self.__dict__)
213213
items = ("{}={!r}".format(k, self.__dict__[k]) for k in keys)
214214
return "{}({})".format(type(self).__name__, ", ".join(items))
215+
def __eq__(self, other):
216+
return self.__dict__ == other.__dict__
215217

216218
``SimpleNamespace`` may be useful as a replacement for ``class NS: pass``.
217219
However, for a structured record type use :func:`~collections.namedtuple`

Lib/test/test_types.py

Lines changed: 26 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
from test.support import run_unittest, run_with_locale
44
import collections
5+
import pickle
56
import locale
67
import sys
78
import types
@@ -1077,9 +1078,19 @@ def test_repr(self):
10771078
ns2 = types.SimpleNamespace()
10781079
ns2.x = "spam"
10791080
ns2._y = 5
1081+
name = "namespace"
10801082

1081-
self.assertEqual(repr(ns1), "namespace(w=3, x=1, y=2)")
1082-
self.assertEqual(repr(ns2), "namespace(_y=5, x='spam')")
1083+
self.assertEqual(repr(ns1), "{name}(w=3, x=1, y=2)".format(name=name))
1084+
self.assertEqual(repr(ns2), "{name}(_y=5, x='spam')".format(name=name))
1085+
1086+
def test_equal(self):
1087+
ns1 = types.SimpleNamespace(x=1)
1088+
ns2 = types.SimpleNamespace()
1089+
ns2.x = 1
1090+
1091+
self.assertEqual(types.SimpleNamespace(), types.SimpleNamespace())
1092+
self.assertEqual(ns1, ns2)
1093+
self.assertNotEqual(ns2, types.SimpleNamespace())
10831094

10841095
def test_nested(self):
10851096
ns1 = types.SimpleNamespace(a=1, b=2)
@@ -1117,11 +1128,12 @@ def test_recursive_repr(self):
11171128
ns1.spam = ns1
11181129
ns2.spam = ns3
11191130
ns3.spam = ns2
1131+
name = "namespace"
1132+
repr1 = "{name}(c='cookie', spam={name}(...))".format(name=name)
1133+
repr2 = "{name}(spam={name}(spam={name}(...), x=1))".format(name=name)
11201134

1121-
self.assertEqual(repr(ns1),
1122-
"namespace(c='cookie', spam=namespace(...))")
1123-
self.assertEqual(repr(ns2),
1124-
"namespace(spam=namespace(spam=namespace(...), x=1))")
1135+
self.assertEqual(repr(ns1), repr1)
1136+
self.assertEqual(repr(ns2), repr2)
11251137

11261138
def test_as_dict(self):
11271139
ns = types.SimpleNamespace(spam='spamspamspam')
@@ -1144,6 +1156,14 @@ class Spam(types.SimpleNamespace):
11441156
self.assertIs(type(spam), Spam)
11451157
self.assertEqual(vars(spam), {'ham': 8, 'eggs': 9})
11461158

1159+
def test_pickle(self):
1160+
ns = types.SimpleNamespace(breakfast="spam", lunch="spam")
1161+
1162+
ns_pickled = pickle.dumps(ns)
1163+
ns_roundtrip = pickle.loads(ns_pickled)
1164+
1165+
self.assertEqual(ns, ns_roundtrip)
1166+
11471167

11481168
def test_main():
11491169
run_unittest(TypesTests, MappingProxyTests, ClassCreationTests,

Misc/NEWS

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -252,6 +252,8 @@ Core and Builtins
252252
- Issue #15111: __import__ should propagate ImportError when raised as a
253253
side-effect of a module triggered from using fromlist.
254254

255+
- Issue #15022: Add pickle and comparison support to types.SimpleNamespace.
256+
255257
Library
256258
-------
257259

Objects/namespaceobject.c

Lines changed: 24 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -66,16 +66,20 @@ namespace_dealloc(_PyNamespaceObject *ns)
6666

6767

6868
static PyObject *
69-
namespace_repr(_PyNamespaceObject *ns)
69+
namespace_repr(PyObject *ns)
7070
{
7171
int i, loop_error = 0;
7272
PyObject *pairs = NULL, *d = NULL, *keys = NULL, *keys_iter = NULL;
7373
PyObject *key;
7474
PyObject *separator, *pairsrepr, *repr = NULL;
75+
const char * name;
7576

76-
i = Py_ReprEnter((PyObject *)ns);
77+
name = (Py_TYPE(ns) == &_PyNamespace_Type) ? "namespace"
78+
: ns->ob_type->tp_name;
79+
80+
i = Py_ReprEnter(ns);
7781
if (i != 0) {
78-
return i > 0 ? PyUnicode_FromString("namespace(...)") : NULL;
82+
return i > 0 ? PyUnicode_FromFormat("%s(...)", name) : NULL;
7983
}
8084

8185
pairs = PyList_New(0);
@@ -127,16 +131,15 @@ namespace_repr(_PyNamespaceObject *ns)
127131
if (pairsrepr == NULL)
128132
goto error;
129133

130-
repr = PyUnicode_FromFormat("%s(%S)",
131-
((PyObject *)ns)->ob_type->tp_name, pairsrepr);
134+
repr = PyUnicode_FromFormat("%s(%S)", name, pairsrepr);
132135
Py_DECREF(pairsrepr);
133136

134137
error:
135138
Py_XDECREF(pairs);
136139
Py_XDECREF(d);
137140
Py_XDECREF(keys);
138141
Py_XDECREF(keys_iter);
139-
Py_ReprLeave((PyObject *)ns);
142+
Py_ReprLeave(ns);
140143

141144
return repr;
142145
}
@@ -158,14 +161,26 @@ namespace_clear(_PyNamespaceObject *ns)
158161
}
159162

160163

164+
static PyObject *
165+
namespace_richcompare(PyObject *self, PyObject *other, int op)
166+
{
167+
if (PyObject_IsInstance(self, (PyObject *)&_PyNamespace_Type) &&
168+
PyObject_IsInstance(other, (PyObject *)&_PyNamespace_Type))
169+
return PyObject_RichCompare(((_PyNamespaceObject *)self)->ns_dict,
170+
((_PyNamespaceObject *)other)->ns_dict, op);
171+
Py_INCREF(Py_NotImplemented);
172+
return Py_NotImplemented;
173+
}
174+
175+
161176
PyDoc_STRVAR(namespace_doc,
162177
"A simple attribute-based namespace.\n\
163178
\n\
164-
namespace(**kwargs)");
179+
SimpleNamespace(**kwargs)");
165180

166181
PyTypeObject _PyNamespace_Type = {
167182
PyVarObject_HEAD_INIT(&PyType_Type, 0)
168-
"namespace", /* tp_name */
183+
"types.SimpleNamespace", /* tp_name */
169184
sizeof(_PyNamespaceObject), /* tp_size */
170185
0, /* tp_itemsize */
171186
(destructor)namespace_dealloc, /* tp_dealloc */
@@ -188,7 +203,7 @@ PyTypeObject _PyNamespace_Type = {
188203
namespace_doc, /* tp_doc */
189204
(traverseproc)namespace_traverse, /* tp_traverse */
190205
(inquiry)namespace_clear, /* tp_clear */
191-
0, /* tp_richcompare */
206+
namespace_richcompare, /* tp_richcompare */
192207
0, /* tp_weaklistoffset */
193208
0, /* tp_iter */
194209
0, /* tp_iternext */

0 commit comments

Comments
 (0)