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 ...@@ -8,6 +8,7 @@ import copy
import pickle import pickle
import sys import sys
import unittest import unittest
import warnings
from test import test_support from test import test_support
class BufferTests(unittest.TestCase): class BufferTests(unittest.TestCase):
...@@ -39,15 +40,19 @@ class BufferTests(unittest.TestCase): ...@@ -39,15 +40,19 @@ class BufferTests(unittest.TestCase):
def test_copy(self): def test_copy(self):
buf = buffer(b'abc') buf = buffer(b'abc')
with self.assertRaises(TypeError): with self.assertRaises(TypeError), warnings.catch_warnings():
warnings.filterwarnings('ignore', ".*buffer", DeprecationWarning)
copy.copy(buf) copy.copy(buf)
# See issue #22995 @test_support.cpython_only
## def test_pickle(self): def test_pickle(self):
## buf = buffer(b'abc') buf = buffer(b'abc')
## for proto in range(pickle.HIGHEST_PROTOCOL + 1): for proto in range(2):
## with self.assertRaises(TypeError): with self.assertRaises(TypeError):
## pickle.dumps(buf, proto) pickle.dumps(buf, proto)
with test_support.check_py3k_warnings(
(".*buffer", DeprecationWarning)):
pickle.dumps(buf, 2)
def test_main(): def test_main():
......
import __builtin__ import __builtin__
import copy
import gc import gc
import pickle
import sys import sys
import types import types
import unittest import unittest
...@@ -10,6 +12,10 @@ from copy import deepcopy ...@@ -10,6 +12,10 @@ from copy import deepcopy
from test import test_support from test import test_support
def func(*args):
return args
class OperatorsTest(unittest.TestCase): class OperatorsTest(unittest.TestCase):
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
...@@ -1415,6 +1421,21 @@ order (MRO) for bases """ ...@@ -1415,6 +1421,21 @@ order (MRO) for bases """
else: else:
self.fail("classmethod shouldn't accept keyword args") 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") @test_support.impl_detail("the module 'xxsubtype' is internal")
def test_classmethods_in_c(self): def test_classmethods_in_c(self):
# Testing C-based class methods... # Testing C-based class methods...
...@@ -1463,6 +1484,21 @@ order (MRO) for bases """ ...@@ -1463,6 +1484,21 @@ order (MRO) for bases """
self.assertEqual(d.foo(1), (d, 1)) self.assertEqual(d.foo(1), (d, 1))
self.assertEqual(D.foo(d, 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") @test_support.impl_detail("the module 'xxsubtype' is internal")
def test_staticmethods_in_c(self): def test_staticmethods_in_c(self):
# Testing C-based static methods... # Testing C-based static methods...
...@@ -2158,6 +2194,21 @@ order (MRO) for bases """ ...@@ -2158,6 +2194,21 @@ order (MRO) for bases """
else: else:
self.fail("expected ZeroDivisionError from bad property") 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, @unittest.skipIf(sys.flags.optimize >= 2,
"Docstrings are omitted with -O2 and above") "Docstrings are omitted with -O2 and above")
def test_properties_doc_attrib(self): def test_properties_doc_attrib(self):
......
...@@ -12,6 +12,7 @@ from test import test_support ...@@ -12,6 +12,7 @@ from test import test_support
import io import io
import copy import copy
import pickle import pickle
import warnings
class AbstractMemoryTests: class AbstractMemoryTests:
...@@ -359,15 +360,20 @@ class BytesMemorySliceSliceTest(unittest.TestCase, ...@@ -359,15 +360,20 @@ class BytesMemorySliceSliceTest(unittest.TestCase,
class OtherTest(unittest.TestCase): class OtherTest(unittest.TestCase):
def test_copy(self): def test_copy(self):
m = memoryview(b'abc') m = memoryview(b'abc')
with self.assertRaises(TypeError): with self.assertRaises(TypeError), warnings.catch_warnings():
warnings.filterwarnings('ignore', ".*memoryview", DeprecationWarning)
copy.copy(m) copy.copy(m)
# See issue #22995 @test_support.cpython_only
## def test_pickle(self): def test_pickle(self):
## m = memoryview(b'abc') m = memoryview(b'abc')
## for proto in range(pickle.HIGHEST_PROTOCOL + 1): for proto in range(2):
## with self.assertRaises(TypeError): with self.assertRaises(TypeError):
## pickle.dumps(m, proto) pickle.dumps(m, proto)
with test_support.check_py3k_warnings(
(".*memoryview", DeprecationWarning)):
pickle.dumps(m, 2)
def test_main(): 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) ...@@ -3366,6 +3366,29 @@ reduce_2(PyObject *obj)
goto end; goto end;
assert(names == Py_None || PyList_Check(names)); 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) { if (names != Py_None) {
slots = PyDict_New(); slots = PyDict_New();
if (slots == NULL) 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