pFad - Phone/Frame/Anonymizer/Declutterfier! Saves Data!


--- a PPN by Garber Painting Akron. With Image Size Reduction included!

URL: http://github.com/python/cpython/commit/b5c8f927829a1679c6748df84a6289fb68343e51

60c69660fa.css" /> Issue #15022: Add pickle and comparison support to types.SimpleNamesp… · python/cpython@b5c8f92 · GitHub
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)
pFad - Phonifier reborn

Pfad - The Proxy pFad © 2024 Your Company Name. All rights reserved.





Check this box to remove all script contents from the fetched content.



Check this box to remove all images from the fetched content.


Check this box to remove all CSS styles from the fetched content.


Check this box to keep images inefficiently compressed and original size.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy