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

Skip to content

Commit 19b6fa6

Browse files
committed
Issue #6477: Added support for pickling the types of built-in singletons.
1 parent f8ceb04 commit 19b6fa6

6 files changed

Lines changed: 58 additions & 4 deletions

File tree

Include/object.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -831,6 +831,9 @@ they can have object code that is not dependent on Python compilation flags.
831831
PyAPI_FUNC(void) Py_IncRef(PyObject *);
832832
PyAPI_FUNC(void) Py_DecRef(PyObject *);
833833

834+
PyAPI_DATA(PyTypeObject) PyNone_Type;
835+
PyAPI_DATA(PyTypeObject) PyNotImplemented_Type;
836+
834837
/*
835838
_Py_NoneStruct is an object of undefined type which can be used in contexts
836839
where NULL (nil) is not suitable (since NULL often means 'error').

Lib/pickle.py

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -728,9 +728,18 @@ def save_global(self, obj, name=None, pack=struct.pack):
728728

729729
self.memoize(obj)
730730

731+
def save_type(self, obj):
732+
if obj is type(None):
733+
return self.save_reduce(type, (None,), obj=obj)
734+
elif obj is type(NotImplemented):
735+
return self.save_reduce(type, (NotImplemented,), obj=obj)
736+
elif obj is type(...):
737+
return self.save_reduce(type, (...,), obj=obj)
738+
return self.save_global(obj)
739+
731740
dispatch[FunctionType] = save_global
732741
dispatch[BuiltinFunctionType] = save_global
733-
dispatch[type] = save_global
742+
dispatch[type] = save_type
734743

735744
# Pickling helpers
736745

Lib/test/pickletester.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -768,6 +768,15 @@ def test_notimplemented(self):
768768
u = self.loads(s)
769769
self.assertEqual(NotImplemented, u)
770770

771+
def test_singleton_types(self):
772+
# Issue #6477: Test that types of built-in singletons can be pickled.
773+
singletons = [None, ..., NotImplemented]
774+
for singleton in singletons:
775+
for proto in protocols:
776+
s = self.dumps(type(singleton), proto)
777+
u = self.loads(s)
778+
self.assertIs(type(singleton), u)
779+
771780
# Tests for protocol 2
772781

773782
def test_proto(self):

Misc/NEWS

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,9 @@ Library
2424
- Fixed _pickle.Unpickler to not fail when loading empty strings as
2525
persistent IDs.
2626

27+
- Issue #6477: Added support for pickling the types of built-in singletons
28+
(i.e., Ellipsis, NotImplemented, None).
29+
2730
- Issue #11508: Fixed uuid.getnode() and uuid.uuid1() on environment with
2831
virtual interface. Original patch by Kent Frazier.
2932

Modules/_pickle.c

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2835,6 +2835,36 @@ save_notimplemented(PicklerObject *self, PyObject *obj)
28352835
return res;
28362836
}
28372837

2838+
static int
2839+
save_singleton_type(PicklerObject *self, PyObject *obj, PyObject *singleton)
2840+
{
2841+
PyObject *reduce_value;
2842+
int status;
2843+
2844+
reduce_value = Py_BuildValue("O(O)", &PyType_Type, singleton);
2845+
if (reduce_value == NULL) {
2846+
return -1;
2847+
}
2848+
status = save_reduce(self, reduce_value, obj);
2849+
Py_DECREF(reduce_value);
2850+
return status;
2851+
}
2852+
2853+
static int
2854+
save_type(PicklerObject *self, PyObject *obj)
2855+
{
2856+
if (obj == (PyObject *)&PyNone_Type) {
2857+
return save_singleton_type(self, obj, Py_None);
2858+
}
2859+
else if (obj == (PyObject *)&PyEllipsis_Type) {
2860+
return save_singleton_type(self, obj, Py_Ellipsis);
2861+
}
2862+
else if (obj == (PyObject *)&PyNotImplemented_Type) {
2863+
return save_singleton_type(self, obj, Py_NotImplemented);
2864+
}
2865+
return save_global(self, obj, NULL);
2866+
}
2867+
28382868
static int
28392869
save_pers(PicklerObject *self, PyObject *obj, PyObject *func)
28402870
{
@@ -3189,7 +3219,7 @@ save(PicklerObject *self, PyObject *obj, int pers_save)
31893219
goto done;
31903220
}
31913221
else if (type == &PyType_Type) {
3192-
status = save_global(self, obj, NULL);
3222+
status = save_type(self, obj);
31933223
goto done;
31943224
}
31953225
else if (type == &PyFunction_Type) {

Objects/object.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1459,7 +1459,7 @@ static PyNumberMethods none_as_number = {
14591459
0, /* nb_index */
14601460
};
14611461

1462-
static PyTypeObject PyNone_Type = {
1462+
PyTypeObject PyNone_Type = {
14631463
PyVarObject_HEAD_INIT(&PyType_Type, 0)
14641464
"NoneType",
14651465
0,
@@ -1524,7 +1524,7 @@ notimplemented_new(PyTypeObject *type, PyObject *args, PyObject *kwargs)
15241524
Py_RETURN_NOTIMPLEMENTED;
15251525
}
15261526

1527-
static PyTypeObject PyNotImplemented_Type = {
1527+
PyTypeObject PyNotImplemented_Type = {
15281528
PyVarObject_HEAD_INIT(&PyType_Type, 0)
15291529
"NotImplementedType",
15301530
0,

0 commit comments

Comments
 (0)