summaryrefslogtreecommitdiffstats
path: root/Lib/test
diff options
context:
space:
mode:
authorSerhiy Storchaka <storchaka@gmail.com>2024-10-21 18:30:45 (GMT)
committerGitHub <noreply@github.com>2024-10-21 18:30:45 (GMT)
commit5ca4e34bc1aab8321911aac6d5b2b9e75ff764d8 (patch)
treed4f4dc4e80de809d695247c749a3ac50340ef78e /Lib/test
parentde5a6c7c7d00ac37d66cba9849202b374e9cdfb7 (diff)
downloadcpython-5ca4e34bc1aab8321911aac6d5b2b9e75ff764d8.zip
cpython-5ca4e34bc1aab8321911aac6d5b2b9e75ff764d8.tar.gz
cpython-5ca4e34bc1aab8321911aac6d5b2b9e75ff764d8.tar.bz2
gh-125767: Fix pickling and copying of super objects (GH-125781)
Previously, copying a super object returned a copy of the instance invoking super(). Pickling a super object could pickle the instance invoking super() or fail, depending on its type and protocol. Now deep copying returns a new super object and pickling pickles the super object. Shallow copying returns the same super object.
Diffstat (limited to 'Lib/test')
-rw-r--r--Lib/test/test_super.py70
1 files changed, 70 insertions, 0 deletions
diff --git a/Lib/test/test_super.py b/Lib/test/test_super.py
index 1222ec6..1490166 100644
--- a/Lib/test/test_super.py
+++ b/Lib/test/test_super.py
@@ -1,5 +1,7 @@
"""Unit tests for zero-argument super() & related machinery."""
+import copy
+import pickle
import textwrap
import threading
import unittest
@@ -539,6 +541,74 @@ class TestSuper(unittest.TestCase):
for thread in threads:
thread.join()
+ def test_special_methods(self):
+ for e in E(), E:
+ s = super(C, e)
+ self.assertEqual(s.__reduce__, e.__reduce__)
+ self.assertEqual(s.__reduce_ex__, e.__reduce_ex__)
+ self.assertEqual(s.__getstate__, e.__getstate__)
+ self.assertFalse(hasattr(s, '__getnewargs__'))
+ self.assertFalse(hasattr(s, '__getnewargs_ex__'))
+ self.assertFalse(hasattr(s, '__setstate__'))
+ self.assertFalse(hasattr(s, '__copy__'))
+ self.assertFalse(hasattr(s, '__deepcopy__'))
+
+ def test_pickling(self):
+ e = E()
+ e.x = 1
+ s = super(C, e)
+ for proto in range(pickle.HIGHEST_PROTOCOL + 1):
+ with self.subTest(proto=proto):
+ u = pickle.loads(pickle.dumps(s, proto))
+ self.assertEqual(u.f(), s.f())
+ self.assertIs(type(u), type(s))
+ self.assertIs(type(u.__self__), E)
+ self.assertEqual(u.__self__.x, 1)
+ self.assertIs(u.__thisclass__, C)
+ self.assertIs(u.__self_class__, E)
+
+ s = super(C, E)
+ for proto in range(pickle.HIGHEST_PROTOCOL + 1):
+ with self.subTest(proto=proto):
+ u = pickle.loads(pickle.dumps(s, proto))
+ self.assertEqual(u.cm(), s.cm())
+ self.assertEqual(u.f, s.f)
+ self.assertIs(type(u), type(s))
+ self.assertIs(u.__self__, E)
+ self.assertIs(u.__thisclass__, C)
+ self.assertIs(u.__self_class__, E)
+
+ def test_shallow_copying(self):
+ s = super(C, E())
+ self.assertIs(copy.copy(s), s)
+ s = super(C, E)
+ self.assertIs(copy.copy(s), s)
+
+ def test_deep_copying(self):
+ e = E()
+ e.x = [1]
+ s = super(C, e)
+ u = copy.deepcopy(s)
+ self.assertEqual(u.f(), s.f())
+ self.assertIs(type(u), type(s))
+ self.assertIsNot(u, s)
+ self.assertIs(type(u.__self__), E)
+ self.assertIsNot(u.__self__, e)
+ self.assertIsNot(u.__self__.x, e.x)
+ self.assertEqual(u.__self__.x, [1])
+ self.assertIs(u.__thisclass__, C)
+ self.assertIs(u.__self_class__, E)
+
+ s = super(C, E)
+ u = copy.deepcopy(s)
+ self.assertEqual(u.cm(), s.cm())
+ self.assertEqual(u.f, s.f)
+ self.assertIsNot(u, s)
+ self.assertIs(type(u), type(s))
+ self.assertIs(u.__self__, E)
+ self.assertIs(u.__thisclass__, C)
+ self.assertIs(u.__self_class__, E)
+
if __name__ == "__main__":
unittest.main()