Skip to content

Commit 3c23e7a

Browse files
committed
Issue python#6477: Merge with 3.3.
2 parents 9204af4 + 19b6fa6 commit 3c23e7a

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
@@ -829,6 +829,9 @@ they can have object code that is not dependent on Python compilation flags.
829829
PyAPI_FUNC(void) Py_IncRef(PyObject *);
830830
PyAPI_FUNC(void) Py_DecRef(PyObject *);
831831

832+
PyAPI_DATA(PyTypeObject) PyNone_Type;
833+
PyAPI_DATA(PyTypeObject) PyNotImplemented_Type;
834+
832835
/*
833836
_Py_NoneStruct is an object of undefined type which can be used in contexts
834837
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
@@ -954,8 +954,17 @@ def save_global(self, obj, name=None):
954954

955955
self.memoize(obj)
956956

957+
def save_type(self, obj):
958+
if obj is type(None):
959+
return self.save_reduce(type, (None,), obj=obj)
960+
elif obj is type(NotImplemented):
961+
return self.save_reduce(type, (NotImplemented,), obj=obj)
962+
elif obj is type(...):
963+
return self.save_reduce(type, (...,), obj=obj)
964+
return self.save_global(obj)
965+
957966
dispatch[FunctionType] = save_global
958-
dispatch[type] = save_global
967+
dispatch[type] = save_type
959968

960969

961970
# Unpickling machinery

Lib/test/pickletester.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -804,6 +804,15 @@ def test_notimplemented(self):
804804
u = self.loads(s)
805805
self.assertIs(NotImplemented, u)
806806

807+
def test_singleton_types(self):
808+
# Issue #6477: Test that types of built-in singletons can be pickled.
809+
singletons = [None, ..., NotImplemented]
810+
for singleton in singletons:
811+
for proto in protocols:
812+
s = self.dumps(type(singleton), proto)
813+
u = self.loads(s)
814+
self.assertIs(type(singleton), u)
815+
807816
# Tests for protocol 2
808817

809818
def test_proto(self):

Misc/NEWS

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

36+
- Issue #6477: Added support for pickling the types of built-in singletons
37+
(i.e., Ellipsis, NotImplemented, None).
38+
3639
- ssl.create_default_context() sets OP_NO_COMPRESSION to prevent CRIME.
3740

3841
- Issue #19802: Add socket.SO_PRIORITY.

Modules/_pickle.c

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3287,6 +3287,36 @@ save_global(PicklerObject *self, PyObject *obj, PyObject *name)
32873287
return status;
32883288
}
32893289

3290+
static int
3291+
save_singleton_type(PicklerObject *self, PyObject *obj, PyObject *singleton)
3292+
{
3293+
PyObject *reduce_value;
3294+
int status;
3295+
3296+
reduce_value = Py_BuildValue("O(O)", &PyType_Type, singleton);
3297+
if (reduce_value == NULL) {
3298+
return -1;
3299+
}
3300+
status = save_reduce(self, reduce_value, obj);
3301+
Py_DECREF(reduce_value);
3302+
return status;
3303+
}
3304+
3305+
static int
3306+
save_type(PicklerObject *self, PyObject *obj)
3307+
{
3308+
if (obj == (PyObject *)&PyNone_Type) {
3309+
return save_singleton_type(self, obj, Py_None);
3310+
}
3311+
else if (obj == (PyObject *)&PyEllipsis_Type) {
3312+
return save_singleton_type(self, obj, Py_Ellipsis);
3313+
}
3314+
else if (obj == (PyObject *)&PyNotImplemented_Type) {
3315+
return save_singleton_type(self, obj, Py_NotImplemented);
3316+
}
3317+
return save_global(self, obj, NULL);
3318+
}
3319+
32903320
static int
32913321
save_pers(PicklerObject *self, PyObject *obj, PyObject *func)
32923322
{
@@ -3696,7 +3726,7 @@ save(PicklerObject *self, PyObject *obj, int pers_save)
36963726
goto done;
36973727
}
36983728
else if (type == &PyType_Type) {
3699-
status = save_global(self, obj, NULL);
3729+
status = save_type(self, obj);
37003730
goto done;
37013731
}
37023732
else if (type == &PyFunction_Type) {

Objects/object.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1409,7 +1409,7 @@ static PyNumberMethods none_as_number = {
14091409
0, /* nb_index */
14101410
};
14111411

1412-
static PyTypeObject PyNone_Type = {
1412+
PyTypeObject PyNone_Type = {
14131413
PyVarObject_HEAD_INIT(&PyType_Type, 0)
14141414
"NoneType",
14151415
0,
@@ -1494,7 +1494,7 @@ notimplemented_dealloc(PyObject* ignore)
14941494
Py_FatalError("deallocating NotImplemented");
14951495
}
14961496

1497-
static PyTypeObject PyNotImplemented_Type = {
1497+
PyTypeObject PyNotImplemented_Type = {
14981498
PyVarObject_HEAD_INIT(&PyType_Type, 0)
14991499
"NotImplementedType",
15001500
0,

0 commit comments

Comments
 (0)