[Python-checkins] [3.7] bpo-34621: fix uuid.UUID (un)pickling compatbility with older Python versions (<3.7) (GH-9133)

Tal Einat webhook-mailer at python.org
Mon Sep 10 11:47:36 EDT 2018


https://github.com/python/cpython/commit/d53f1cabe8837697df4acb70c9c6537461b5eeda
commit: d53f1cabe8837697df4acb70c9c6537461b5eeda
branch: 3.7
author: Tal Einat <taleinat+github at gmail.com>
committer: GitHub <noreply at github.com>
date: 2018-09-10T18:47:29+03:00
summary:

[3.7] bpo-34621: fix uuid.UUID (un)pickling compatbility with older Python versions (<3.7) (GH-9133)

files:
A Misc/NEWS.d/next/Library/2018-09-10-15-54-58.bpo-34621.Uqj5x3.rst
M Lib/test/test_uuid.py
M Lib/uuid.py

diff --git a/Lib/test/test_uuid.py b/Lib/test/test_uuid.py
index 7af1d7aec797..dc502b97ca4e 100644
--- a/Lib/test/test_uuid.py
+++ b/Lib/test/test_uuid.py
@@ -2,10 +2,13 @@
 from test import support
 import builtins
 import contextlib
+import copy
 import io
 import os
+import pickle
 import shutil
 import subprocess
+import sys
 
 py_uuid = support.import_fresh_module('uuid', blocked=['_uuid'])
 c_uuid = support.import_fresh_module('uuid', fresh=['_uuid'])
@@ -311,6 +314,140 @@ def test_getnode(self):
         node2 = self.uuid.getnode()
         self.assertEqual(node1, node2, '%012x != %012x' % (node1, node2))
 
+    def test_pickle_roundtrip(self):
+        def check(actual, expected):
+            self.assertEqual(actual, expected)
+            self.assertEqual(actual.is_safe, expected.is_safe)
+
+        with support.swap_item(sys.modules, 'uuid', self.uuid):
+            for is_safe in self.uuid.SafeUUID:
+                u = self.uuid.UUID('d82579ce6642a0de7ddf490a7aec7aa5',
+                                   is_safe=is_safe)
+                check(copy.copy(u), u)
+                check(copy.deepcopy(u), u)
+                for proto in range(pickle.HIGHEST_PROTOCOL + 1):
+                    with self.subTest(protocol=proto):
+                        check(pickle.loads(pickle.dumps(u, proto)), u)
+
+    def test_unpickle_previous_python_versions(self):
+        def check(actual, expected):
+            self.assertEqual(actual, expected)
+            self.assertEqual(actual.is_safe, expected.is_safe)
+
+        pickled_uuids = [
+            # Python 2.7, protocol 0
+            b'ccopy_reg\n_reconstructor\n(cuuid\nUUID\nc__builtin__\nobject\nN'
+            b'tR(dS\'int\'\nL287307832597519156748809049798316161701L\nsb.',
+            # Python 2.7, protocol 1
+            b'ccopy_reg\n_reconstructor\n(cuuid\nUUID\nc__builtin__\nobject\nN'
+            b'tR}U\x03intL287307832597519156748809049798316161701L\nsb.',
+            # Python 2.7, protocol 2
+            b'\x80\x02cuuid\nUUID\n)\x81}U\x03int\x8a\x11\xa5z\xecz\nI\xdf}'
+            b'\xde\xa0Bf\xcey%\xd8\x00sb.',
+            # Python 3.6, protocol 0
+            b'ccopy_reg\n_reconstructor\n(cuuid\nUUID\nc__builtin__\nobject\nN'
+            b'tR(dVint\nL287307832597519156748809049798316161701L\nsb.',
+            # Python 3.6, protocol 1
+            b'ccopy_reg\n_reconstructor\n(cuuid\nUUID\nc__builtin__\nobject\nN'
+            b'tR}X\x03\x00\x00\x00intL287307832597519156748809049798316161701L'
+            b'\nsb.',
+            # Python 3.6, protocol 2
+            b'\x80\x02cuuid\nUUID\n)\x81}X\x03\x00\x00\x00int\x8a\x11\xa5z\xec'
+            b'z\nI\xdf}\xde\xa0Bf\xcey%\xd8\x00sb.',
+            # Python 3.6, protocol 3
+            b'\x80\x03cuuid\nUUID\n)\x81}X\x03\x00\x00\x00int\x8a\x11\xa5z\xec'
+            b'z\nI\xdf}\xde\xa0Bf\xcey%\xd8\x00sb.',
+            # Python 3.6, protocol 4
+            b'\x80\x04\x95+\x00\x00\x00\x00\x00\x00\x00\x8c\x04uuid\x8c\x04UUI'
+            b'D\x93)\x81}\x8c\x03int\x8a\x11\xa5z\xecz\nI\xdf}\xde\xa0Bf\xcey%'
+            b'\xd8\x00sb.',
+            # Python 3.7, protocol 0
+            b'ccopy_reg\n_reconstructor\n(cuuid\nUUID\nc__builtin__\nobject\nN'
+            b'tR(dVint\nL287307832597519156748809049798316161701L\nsVis_safe\n'
+            b'cuuid\nSafeUUID\n(NtRsb.',
+            # Python 3.7, protocol 1
+            b'ccopy_reg\n_reconstructor\n(cuuid\nUUID\nc__builtin__\nobject\nN'
+            b'tR}(X\x03\x00\x00\x00intL287307832597519156748809049798316161701'
+            b'L\nX\x07\x00\x00\x00is_safecuuid\nSafeUUID\n(NtRub.',
+            # Python 3.7, protocol 2
+            b'\x80\x02cuuid\nUUID\n)\x81}(X\x03\x00\x00\x00int\x8a\x11\xa5z'
+            b'\xecz\nI\xdf}\xde\xa0Bf\xcey%\xd8\x00X\x07\x00\x00\x00is_safecuu'
+            b'id\nSafeUUID\nN\x85Rub.',
+            # Python 3.7, protocol 3
+            b'\x80\x03cuuid\nUUID\n)\x81}(X\x03\x00\x00\x00int\x8a\x11\xa5z'
+            b'\xecz\nI\xdf}\xde\xa0Bf\xcey%\xd8\x00X\x07\x00\x00\x00is_safecuu'
+            b'id\nSafeUUID\nN\x85Rub.',
+            # Python 3.7, protocol 4
+            b'\x80\x04\x95F\x00\x00\x00\x00\x00\x00\x00\x8c\x04uuid\x94\x8c'
+            b'\x04UUID\x93)\x81}(\x8c\x03int\x8a\x11\xa5z\xecz\nI\xdf}\xde\xa0'
+            b'Bf\xcey%\xd8\x00\x8c\x07is_safeh\x00\x8c\x08SafeUUID\x93N\x85Rub'
+            b'.',
+        ]
+        pickled_uuids_safe = [
+            # Python 3.7, protocol 0
+            b'ccopy_reg\n_reconstructor\n(cuuid\nUUID\nc__builtin__\nobject\nN'
+            b'tR(dVint\nL287307832597519156748809049798316161701L\nsVis_safe\n'
+            b'cuuid\nSafeUUID\n(I0\ntRsb.',
+            # Python 3.7, protocol 1
+            b'ccopy_reg\n_reconstructor\n(cuuid\nUUID\nc__builtin__\nobject\nN'
+            b'tR}(X\x03\x00\x00\x00intL287307832597519156748809049798316161701'
+            b'L\nX\x07\x00\x00\x00is_safecuuid\nSafeUUID\n(K\x00tRub.',
+            # Python 3.7, protocol 2
+            b'\x80\x02cuuid\nUUID\n)\x81}(X\x03\x00\x00\x00int\x8a\x11\xa5z'
+            b'\xecz\nI\xdf}\xde\xa0Bf\xcey%\xd8\x00X\x07\x00\x00\x00is_safecuu'
+            b'id\nSafeUUID\nK\x00\x85Rub.',
+            # Python 3.7, protocol 3
+            b'\x80\x03cuuid\nUUID\n)\x81}(X\x03\x00\x00\x00int\x8a\x11\xa5z'
+            b'\xecz\nI\xdf}\xde\xa0Bf\xcey%\xd8\x00X\x07\x00\x00\x00is_safecuu'
+            b'id\nSafeUUID\nK\x00\x85Rub.',
+            # Python 3.7, protocol 4
+            b'\x80\x04\x95G\x00\x00\x00\x00\x00\x00\x00\x8c\x04uuid\x94\x8c'
+            b'\x04UUID\x93)\x81}(\x8c\x03int\x8a\x11\xa5z\xecz\nI\xdf}\xde\xa0'
+            b'Bf\xcey%\xd8\x00\x8c\x07is_safeh\x00\x8c\x08SafeUUID\x93K\x00'
+            b'\x85Rub.',
+        ]
+        pickled_uuids_unsafe = [
+            # Python 3.7, protocol 0
+            b'ccopy_reg\n_reconstructor\n(cuuid\nUUID\nc__builtin__\nobject\nN'
+            b'tR(dVint\nL287307832597519156748809049798316161701L\nsVis_safe\n'
+            b'cuuid\nSafeUUID\n(I-1\ntRsb.',
+            # Python 3.7, protocol 1
+            b'ccopy_reg\n_reconstructor\n(cuuid\nUUID\nc__builtin__\nobject\nN'
+            b'tR}(X\x03\x00\x00\x00intL287307832597519156748809049798316161701'
+            b'L\nX\x07\x00\x00\x00is_safecuuid\nSafeUUID\n(J\xff\xff\xff\xfftR'
+            b'ub.',
+            # Python 3.7, protocol 2
+            b'\x80\x02cuuid\nUUID\n)\x81}(X\x03\x00\x00\x00int\x8a\x11\xa5z'
+            b'\xecz\nI\xdf}\xde\xa0Bf\xcey%\xd8\x00X\x07\x00\x00\x00is_safecuu'
+            b'id\nSafeUUID\nJ\xff\xff\xff\xff\x85Rub.',
+            # Python 3.7, protocol 3
+            b'\x80\x03cuuid\nUUID\n)\x81}(X\x03\x00\x00\x00int\x8a\x11\xa5z'
+            b'\xecz\nI\xdf}\xde\xa0Bf\xcey%\xd8\x00X\x07\x00\x00\x00is_safecuu'
+            b'id\nSafeUUID\nJ\xff\xff\xff\xff\x85Rub.',
+            # Python 3.7, protocol 4
+            b'\x80\x04\x95J\x00\x00\x00\x00\x00\x00\x00\x8c\x04uuid\x94\x8c'
+            b'\x04UUID\x93)\x81}(\x8c\x03int\x8a\x11\xa5z\xecz\nI\xdf}\xde\xa0'
+            b'Bf\xcey%\xd8\x00\x8c\x07is_safeh\x00\x8c\x08SafeUUID\x93J\xff'
+            b'\xff\xff\xff\x85Rub.',
+        ]
+
+        u = self.uuid.UUID('d82579ce6642a0de7ddf490a7aec7aa5')
+        u_safe = self.uuid.UUID('d82579ce6642a0de7ddf490a7aec7aa5',
+                                is_safe=self.uuid.SafeUUID.safe)
+        u_unsafe = self.uuid.UUID('d82579ce6642a0de7ddf490a7aec7aa5',
+                                  is_safe=self.uuid.SafeUUID.unsafe)
+
+        with support.swap_item(sys.modules, 'uuid', self.uuid):
+            for pickled in pickled_uuids:
+                # is_safe was added in 3.7.  When unpickling values from older
+                # versions, is_safe will be missing, so it should be set to
+                # SafeUUID.unknown.
+                check(pickle.loads(pickled), u)
+            for pickled in pickled_uuids_safe:
+                check(pickle.loads(pickled), u_safe)
+            for pickled in pickled_uuids_unsafe:
+                check(pickle.loads(pickled), u_unsafe)
+
     # bpo-32502: UUID1 requires a 48-bit identifier, but hardware identifiers
     # need not necessarily be 48 bits (e.g., EUI-64).
     def test_uuid1_eui64(self):
diff --git a/Lib/uuid.py b/Lib/uuid.py
index 66383218e70c..26faa1accd09 100644
--- a/Lib/uuid.py
+++ b/Lib/uuid.py
@@ -204,6 +204,23 @@ def __init__(self, hex=None, bytes=None, bytes_le=None, fields=None,
         self.__dict__['int'] = int
         self.__dict__['is_safe'] = is_safe
 
+    def __getstate__(self):
+        state = self.__dict__
+        if self.is_safe != SafeUUID.unknown:
+            # is_safe is a SafeUUID instance.  Return just its value, so that
+            # it can be un-pickled in older Python versions without SafeUUID.
+            state = state.copy()
+            state['is_safe'] = self.is_safe.value
+        return state
+
+    def __setstate__(self, state):
+        self.__dict__.update(state)
+        # is_safe was added in 3.7; it is also omitted when it is "unknown"
+        self.__dict__['is_safe'] = (
+            SafeUUID(state['is_safe'])
+            if 'is_safe' in state else SafeUUID.unknown
+        )
+
     def __eq__(self, other):
         if isinstance(other, UUID):
             return self.int == other.int
diff --git a/Misc/NEWS.d/next/Library/2018-09-10-15-54-58.bpo-34621.Uqj5x3.rst b/Misc/NEWS.d/next/Library/2018-09-10-15-54-58.bpo-34621.Uqj5x3.rst
new file mode 100644
index 000000000000..1fd60608aea3
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2018-09-10-15-54-58.bpo-34621.Uqj5x3.rst
@@ -0,0 +1,2 @@
+Fix un/pickling compatbility of uuid.UUID objects with older versions of
+Python (<3.7).



More information about the Python-checkins mailing list