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

This commit is contained in:
Tal Einat 2018-09-10 18:47:29 +03:00 committed by GitHub
parent e9119a5de6
commit d53f1cabe8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 156 additions and 0 deletions

View File

@ -2,10 +2,13 @@ import unittest.mock
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 @@ class BaseTestUUID:
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):

View File

@ -204,6 +204,23 @@ class UUID:
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

View File

@ -0,0 +1,2 @@
Fix un/pickling compatbility of uuid.UUID objects with older versions of
Python (<3.7).