From d7a441559921804a5a6141c3ec42f896f8f3b010 Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Thu, 12 Nov 2015 11:23:04 +0200 Subject: [PATCH] Issue #22995: Default implementation of __reduce__ and __reduce_ex__ now rejects builtin types with not defined __new__. Added tests for non-pickleable types. --- Lib/test/test_dictviews.py | 18 ++++++++++++++++++ Lib/test/test_generators.py | 20 ++++++++++++++++++++ Lib/test/test_xml_etree.py | 14 ++++++++++++++ Lib/test/test_zlib.py | 11 +++++++++++ Misc/NEWS | 3 +++ Objects/typeobject.c | 12 ++++++++++++ 6 files changed, 78 insertions(+) diff --git a/Lib/test/test_dictviews.py b/Lib/test/test_dictviews.py index 7b02ea9eba3..c7714cf790c 100644 --- a/Lib/test/test_dictviews.py +++ b/Lib/test/test_dictviews.py @@ -1,3 +1,5 @@ +import copy +import pickle import unittest from test import support @@ -198,6 +200,22 @@ class DictSetTest(unittest.TestCase): d[42] = d.values() self.assertRaises(RuntimeError, repr, d) + def test_copy(self): + d = {1: 10, "a": "ABC"} + self.assertRaises(TypeError, copy.copy, d.keys()) + self.assertRaises(TypeError, copy.copy, d.values()) + self.assertRaises(TypeError, copy.copy, d.items()) + + def test_pickle(self): + d = {1: 10, "a": "ABC"} + for proto in range(pickle.HIGHEST_PROTOCOL + 1): + self.assertRaises((TypeError, pickle.PicklingError), + pickle.dumps, d.keys(), proto) + self.assertRaises((TypeError, pickle.PicklingError), + pickle.dumps, d.values(), proto) + self.assertRaises((TypeError, pickle.PicklingError), + pickle.dumps, d.items(), proto) + def test_main(): support.run_unittest(DictSetTest) diff --git a/Lib/test/test_generators.py b/Lib/test/test_generators.py index 5c455cdd816..604e12d92e1 100644 --- a/Lib/test/test_generators.py +++ b/Lib/test/test_generators.py @@ -1,4 +1,6 @@ +import copy import gc +import pickle import sys import unittest import weakref @@ -70,6 +72,24 @@ class FinalizationTest(unittest.TestCase): self.assertEqual(cm.exception.value, 2) +class GeneratorTest(unittest.TestCase): + + def test_copy(self): + def f(): + yield 1 + g = f() + with self.assertRaises(TypeError): + copy.copy(g) + + def test_pickle(self): + def f(): + yield 1 + g = f() + for proto in range(pickle.HIGHEST_PROTOCOL + 1): + with self.assertRaises((TypeError, pickle.PicklingError)): + pickle.dumps(g, proto) + + class ExceptionTest(unittest.TestCase): # Tests for the issue #23353: check that the currently handled exception # is correctly saved/restored in PyEval_EvalFrameEx(). diff --git a/Lib/test/test_xml_etree.py b/Lib/test/test_xml_etree.py index b87b09832d1..d87924513cf 100644 --- a/Lib/test/test_xml_etree.py +++ b/Lib/test/test_xml_etree.py @@ -5,6 +5,7 @@ # For this purpose, the module-level "ET" symbol is temporarily # monkey-patched when running the "test_xml_etree_c" test suite. +import copy import html import io import operator @@ -2082,6 +2083,19 @@ class ElementIterTest(unittest.TestCase): self.assertEqual(self._ilist(doc), all_tags) self.assertEqual(self._ilist(doc, '*'), all_tags) + def test_copy(self): + a = ET.Element('a') + it = a.iter() + with self.assertRaises(TypeError): + copy.copy(it) + + def test_pickle(self): + a = ET.Element('a') + it = a.iter() + for proto in range(pickle.HIGHEST_PROTOCOL + 1): + with self.assertRaises((TypeError, pickle.PicklingError)): + pickle.dumps(it, proto) + class TreeBuilderTest(unittest.TestCase): sample1 = ('tp_new == NULL) { + PyErr_Format(PyExc_TypeError, + "can't pickle %s objects", + Py_TYPE(obj)->tp_name); + return NULL; + } if (_PyObject_GetNewArguments(obj, &args, &kwargs) < 0) { return NULL; } @@ -4046,6 +4052,12 @@ reduce_2(PyObject *obj) Py_ssize_t i, n; _Py_IDENTIFIER(__newobj__); + if (Py_TYPE(obj)->tp_new == NULL) { + PyErr_Format(PyExc_TypeError, + "can't pickle %s objects", + Py_TYPE(obj)->tp_name); + return NULL; + } if (_PyObject_GetNewArguments(obj, &args, &kwargs) < 0) { return NULL; }