Commit 3dd1ccbb authored by Serhiy Storchaka's avatar Serhiy Storchaka Committed by GitHub

bpo-29902: Emit a Py3k deprecation warning when pickling or copying (#2823)

some builtin and extension objects that don't support pickling
explicitly and are pickled incorrectly by default (like memoryview or
staticmethod).
parent 956902e5
......@@ -8,6 +8,7 @@ import copy
import pickle
import sys
import unittest
import warnings
from test import test_support
class BufferTests(unittest.TestCase):
......@@ -39,15 +40,19 @@ class BufferTests(unittest.TestCase):
def test_copy(self):
buf = buffer(b'abc')
with self.assertRaises(TypeError):
with self.assertRaises(TypeError), warnings.catch_warnings():
warnings.filterwarnings('ignore', ".*buffer", DeprecationWarning)
copy.copy(buf)
# See issue #22995
## def test_pickle(self):
## buf = buffer(b'abc')
## for proto in range(pickle.HIGHEST_PROTOCOL + 1):
## with self.assertRaises(TypeError):
## pickle.dumps(buf, proto)
@test_support.cpython_only
def test_pickle(self):
buf = buffer(b'abc')
for proto in range(2):
with self.assertRaises(TypeError):
pickle.dumps(buf, proto)
with test_support.check_py3k_warnings(
(".*buffer", DeprecationWarning)):
pickle.dumps(buf, 2)
def test_main():
......
import __builtin__
import copy
import gc
import pickle
import sys
import types
import unittest
......@@ -10,6 +12,10 @@ from copy import deepcopy
from test import test_support
def func(*args):
return args
class OperatorsTest(unittest.TestCase):
def __init__(self, *args, **kwargs):
......@@ -1415,6 +1421,21 @@ order (MRO) for bases """
else:
self.fail("classmethod shouldn't accept keyword args")
@test_support.cpython_only
def test_classmethod_copy_pickle(self):
cm = classmethod(func)
with test_support.check_py3k_warnings(
(".*classmethod", DeprecationWarning)):
copy.copy(cm)
with test_support.check_py3k_warnings(
(".*classmethod", DeprecationWarning)):
copy.deepcopy(cm)
for proto in range(2):
self.assertRaises(TypeError, pickle.dumps, cm, proto)
with test_support.check_py3k_warnings(
(".*classmethod", DeprecationWarning)):
pickle.dumps(cm, 2)
@test_support.impl_detail("the module 'xxsubtype' is internal")
def test_classmethods_in_c(self):
# Testing C-based class methods...
......@@ -1463,6 +1484,21 @@ order (MRO) for bases """
self.assertEqual(d.foo(1), (d, 1))
self.assertEqual(D.foo(d, 1), (d, 1))
@test_support.cpython_only
def test_staticmethod_copy_pickle(self):
sm = staticmethod(func)
with test_support.check_py3k_warnings(
(".*staticmethod", DeprecationWarning)):
copy.copy(sm)
with test_support.check_py3k_warnings(
(".*staticmethod", DeprecationWarning)):
copy.deepcopy(sm)
for proto in range(2):
self.assertRaises(TypeError, pickle.dumps, sm, proto)
with test_support.check_py3k_warnings(
(".*staticmethod", DeprecationWarning)):
pickle.dumps(sm, 2)
@test_support.impl_detail("the module 'xxsubtype' is internal")
def test_staticmethods_in_c(self):
# Testing C-based static methods...
......@@ -2158,6 +2194,21 @@ order (MRO) for bases """
else:
self.fail("expected ZeroDivisionError from bad property")
@test_support.cpython_only
def test_property_copy_pickle(self):
p = property(func)
with test_support.check_py3k_warnings(
(".*property", DeprecationWarning)):
copy.copy(p)
with test_support.check_py3k_warnings(
(".*property", DeprecationWarning)):
copy.deepcopy(p)
for proto in range(2):
self.assertRaises(TypeError, pickle.dumps, p, proto)
with test_support.check_py3k_warnings(
(".*property", DeprecationWarning)):
pickle.dumps(p, 2)
@unittest.skipIf(sys.flags.optimize >= 2,
"Docstrings are omitted with -O2 and above")
def test_properties_doc_attrib(self):
......
......@@ -12,6 +12,7 @@ from test import test_support
import io
import copy
import pickle
import warnings
class AbstractMemoryTests:
......@@ -359,15 +360,20 @@ class BytesMemorySliceSliceTest(unittest.TestCase,
class OtherTest(unittest.TestCase):
def test_copy(self):
m = memoryview(b'abc')
with self.assertRaises(TypeError):
with self.assertRaises(TypeError), warnings.catch_warnings():
warnings.filterwarnings('ignore', ".*memoryview", DeprecationWarning)
copy.copy(m)
# See issue #22995
## def test_pickle(self):
## m = memoryview(b'abc')
## for proto in range(pickle.HIGHEST_PROTOCOL + 1):
## with self.assertRaises(TypeError):
## pickle.dumps(m, proto)
@test_support.cpython_only
def test_pickle(self):
m = memoryview(b'abc')
for proto in range(2):
with self.assertRaises(TypeError):
pickle.dumps(m, proto)
with test_support.check_py3k_warnings(
(".*memoryview", DeprecationWarning)):
pickle.dumps(m, 2)
def test_main():
......
Py3k deprecation warning now is emitted when pickling or copying some builtin
and extension objects that don't support pickling explicitly and are pickled
incorrectly by default (like memoryview or staticmethod). This is a
TypeError in Python 3.6.
......@@ -3366,6 +3366,29 @@ reduce_2(PyObject *obj)
goto end;
assert(names == Py_None || PyList_Check(names));
if (required_state && Py_Py3kWarningFlag) {
Py_ssize_t basicsize = PyBaseObject_Type.tp_basicsize;
if (obj->ob_type->tp_dictoffset)
basicsize += sizeof(PyObject *);
if (obj->ob_type->tp_weaklistoffset)
basicsize += sizeof(PyObject *);
if (names != Py_None)
basicsize += sizeof(PyObject *) * PyList_GET_SIZE(names);
if (obj->ob_type->tp_basicsize > basicsize) {
PyObject *msg = PyString_FromFormat(
"can't pickle %.200s objects",
Py_TYPE(obj)->tp_name);
if (msg == NULL) {
goto end;
}
if (PyErr_WarnPy3k(PyString_AS_STRING(msg), 1) < 0) {
Py_DECREF(msg);
goto end;
}
Py_DECREF(msg);
}
}
if (names != Py_None) {
slots = PyDict_New();
if (slots == NULL)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment