Update uuid from 3.13.5 (#5901)

* Update uuid from 3.13.5

* Mark failing test
This commit is contained in:
Shahar Naveh authored and GitHub committed 2025-07-04 22:37:12 +09:00
1 parent 0a59c1cad3
commit 94a55eb479
2 files changed
+194 -39

No files matched your search

+114 -9
View File
@@ -4,6 +4,7 @@ from test.support import import_helper
import builtins
import contextlib
import copy
import enum
import io
import os
import pickle
@@ -18,7 +19,7 @@ def importable(name):
try:
__import__(name)
return True
except:
except ModuleNotFoundError:
return False
@@ -31,6 +32,15 @@ def mock_get_command_stdout(data):
class BaseTestUUID:
uuid = None
# TODO: RUSTPYTHON
@unittest.expectedFailure
def test_safe_uuid_enum(self):
class CheckedSafeUUID(enum.Enum):
safe = 0
unsafe = -1
unknown = None
enum._test_simple_enum(CheckedSafeUUID, py_uuid.SafeUUID)
def test_UUID(self):
equal = self.assertEqual
ascending = []
@@ -522,7 +532,14 @@ class BaseTestUUID:
@support.requires_mac_ver(10, 5)
@unittest.skipUnless(os.name == 'posix', 'POSIX-only test')
def test_uuid1_safe(self):
if not self.uuid._has_uuid_generate_time_safe:
try:
import _uuid
except ImportError:
has_uuid_generate_time_safe = False
else:
has_uuid_generate_time_safe = _uuid.has_uuid_generate_time_safe
if not has_uuid_generate_time_safe or not self.uuid._generate_time_safe:
self.skipTest('requires uuid_generate_time_safe(3)')
u = self.uuid.uuid1()
@@ -538,7 +555,6 @@ class BaseTestUUID:
"""
if os.name != 'posix':
self.skipTest('POSIX-only test')
self.uuid._load_system_functions()
f = self.uuid._generate_time_safe
if f is None:
self.skipTest('need uuid._generate_time_safe')
@@ -573,8 +589,7 @@ class BaseTestUUID:
self.assertEqual(u.is_safe, self.uuid.SafeUUID.unknown)
def test_uuid1_time(self):
with mock.patch.object(self.uuid, '_has_uuid_generate_time_safe', False), \
mock.patch.object(self.uuid, '_generate_time_safe', None), \
with mock.patch.object(self.uuid, '_generate_time_safe', None), \
mock.patch.object(self.uuid, '_last_timestamp', None), \
mock.patch.object(self.uuid, 'getnode', return_value=93328246233727), \
mock.patch('time.time_ns', return_value=1545052026752910643), \
@@ -582,8 +597,7 @@ class BaseTestUUID:
u = self.uuid.uuid1()
self.assertEqual(u, self.uuid.UUID('a7a55b92-01fc-11e9-94c5-54e1acf6da7f'))
with mock.patch.object(self.uuid, '_has_uuid_generate_time_safe', False), \
mock.patch.object(self.uuid, '_generate_time_safe', None), \
with mock.patch.object(self.uuid, '_generate_time_safe', None), \
mock.patch.object(self.uuid, '_last_timestamp', None), \
mock.patch('time.time_ns', return_value=1545052026752910643):
u = self.uuid.uuid1(node=93328246233727, clock_seq=5317)
@@ -592,7 +606,22 @@ class BaseTestUUID:
def test_uuid3(self):
equal = self.assertEqual
# Test some known version-3 UUIDs.
# Test some known version-3 UUIDs with name passed as a byte object
for u, v in [(self.uuid.uuid3(self.uuid.NAMESPACE_DNS, b'python.org'),
'6fa459ea-ee8a-3ca4-894e-db77e160355e'),
(self.uuid.uuid3(self.uuid.NAMESPACE_URL, b'http://python.org/'),
'9fe8e8c4-aaa8-32a9-a55c-4535a88b748d'),
(self.uuid.uuid3(self.uuid.NAMESPACE_OID, b'1.3.6.1'),
'dd1a1cef-13d5-368a-ad82-eca71acd4cd1'),
(self.uuid.uuid3(self.uuid.NAMESPACE_X500, b'c=ca'),
'658d3002-db6b-3040-a1d1-8ddd7d189a4d'),
]:
equal(u.variant, self.uuid.RFC_4122)
equal(u.version, 3)
equal(u, self.uuid.UUID(v))
equal(str(u), v)
# Test some known version-3 UUIDs with name passed as a string
for u, v in [(self.uuid.uuid3(self.uuid.NAMESPACE_DNS, 'python.org'),
'6fa459ea-ee8a-3ca4-894e-db77e160355e'),
(self.uuid.uuid3(self.uuid.NAMESPACE_URL, 'http://python.org/'),
@@ -624,7 +653,22 @@ class BaseTestUUID:
def test_uuid5(self):
equal = self.assertEqual
# Test some known version-5 UUIDs.
# Test some known version-5 UUIDs with names given as byte objects
for u, v in [(self.uuid.uuid5(self.uuid.NAMESPACE_DNS, b'python.org'),
'886313e1-3b8a-5372-9b90-0c9aee199e5d'),
(self.uuid.uuid5(self.uuid.NAMESPACE_URL, b'http://python.org/'),
'4c565f0d-3f5a-5890-b41b-20cf47701c5e'),
(self.uuid.uuid5(self.uuid.NAMESPACE_OID, b'1.3.6.1'),
'1447fa61-5277-5fef-a9b3-fbc6e44f4af3'),
(self.uuid.uuid5(self.uuid.NAMESPACE_X500, b'c=ca'),
'cc957dd1-a972-5349-98cd-874190002798'),
]:
equal(u.variant, self.uuid.RFC_4122)
equal(u.version, 5)
equal(u, self.uuid.UUID(v))
equal(str(u), v)
# Test some known version-5 UUIDs with names given as strings
for u, v in [(self.uuid.uuid5(self.uuid.NAMESPACE_DNS, 'python.org'),
'886313e1-3b8a-5372-9b90-0c9aee199e5d'),
(self.uuid.uuid5(self.uuid.NAMESPACE_URL, 'http://python.org/'),
@@ -667,6 +711,67 @@ class BaseTestUUID:
weak = weakref.ref(strong)
self.assertIs(strong, weak())
@mock.patch.object(sys, "argv", ["", "-u", "uuid3", "-n", "@dns"])
@mock.patch('sys.stderr', new_callable=io.StringIO)
def test_cli_namespace_required_for_uuid3(self, mock_err):
with self.assertRaises(SystemExit) as cm:
self.uuid.main()
# Check that exception code is the same as argparse.ArgumentParser.error
self.assertEqual(cm.exception.code, 2)
self.assertIn("error: Incorrect number of arguments", mock_err.getvalue())
@mock.patch.object(sys, "argv", ["", "-u", "uuid3", "-N", "python.org"])
@mock.patch('sys.stderr', new_callable=io.StringIO)
def test_cli_name_required_for_uuid3(self, mock_err):
with self.assertRaises(SystemExit) as cm:
self.uuid.main()
# Check that exception code is the same as argparse.ArgumentParser.error
self.assertEqual(cm.exception.code, 2)
self.assertIn("error: Incorrect number of arguments", mock_err.getvalue())
@mock.patch.object(sys, "argv", [""])
def test_cli_uuid4_outputted_with_no_args(self):
stdout = io.StringIO()
with contextlib.redirect_stdout(stdout):
self.uuid.main()
output = stdout.getvalue().strip()
uuid_output = self.uuid.UUID(output)
# Output uuid should be in the format of uuid4
self.assertEqual(output, str(uuid_output))
self.assertEqual(uuid_output.version, 4)
@mock.patch.object(sys, "argv",
["", "-u", "uuid3", "-n", "@dns", "-N", "python.org"])
def test_cli_uuid3_ouputted_with_valid_namespace_and_name(self):
stdout = io.StringIO()
with contextlib.redirect_stdout(stdout):
self.uuid.main()
output = stdout.getvalue().strip()
uuid_output = self.uuid.UUID(output)
# Output should be in the form of uuid5
self.assertEqual(output, str(uuid_output))
self.assertEqual(uuid_output.version, 3)
@mock.patch.object(sys, "argv",
["", "-u", "uuid5", "-n", "@dns", "-N", "python.org"])
def test_cli_uuid5_ouputted_with_valid_namespace_and_name(self):
stdout = io.StringIO()
with contextlib.redirect_stdout(stdout):
self.uuid.main()
output = stdout.getvalue().strip()
uuid_output = self.uuid.UUID(output)
# Output should be in the form of uuid5
self.assertEqual(output, str(uuid_output))
self.assertEqual(uuid_output.version, 5)
class TestUUIDWithoutExtModule(BaseTestUUID, unittest.TestCase):
uuid = py_uuid
Vendored
+80 -30
View File
@@ -47,21 +47,22 @@ Typical usage:
import os
import sys
from enum import Enum
from enum import Enum, _simple_enum
__author__ = 'Ka-Ping Yee <ping@zesty.ca>'
# The recognized platforms - known behaviors
if sys.platform in ('win32', 'darwin'):
_AIX = _LINUX = False
elif sys.platform in ('emscripten', 'wasi'): # XXX: RUSTPYTHON; patched to support those platforms
if sys.platform in {'win32', 'darwin', 'emscripten', 'wasi'}:
_AIX = _LINUX = False
elif sys.platform == 'linux':
_LINUX = True
_AIX = False
else:
import platform
_platform_system = platform.system()
_AIX = _platform_system == 'AIX'
_LINUX = _platform_system == 'Linux'
_LINUX = _platform_system in ('Linux', 'Android')
_MAC_DELIM = b':'
_MAC_OMITS_LEADING_ZEROES = False
@@ -77,7 +78,8 @@ int_ = int # The built-in int type
bytes_ = bytes # The built-in bytes type
class SafeUUID(Enum):
@_simple_enum(Enum)
class SafeUUID:
safe = 0
unsafe = -1
unknown = None
@@ -187,7 +189,7 @@ class UUID:
if len(bytes) != 16:
raise ValueError('bytes is not a 16-char string')
assert isinstance(bytes, bytes_), repr(bytes)
int = int_.from_bytes(bytes, byteorder='big')
int = int_.from_bytes(bytes) # big endian
if fields is not None:
if len(fields) != 6:
raise ValueError('fields is not a 6-tuple')
@@ -285,7 +287,7 @@ class UUID:
@property
def bytes(self):
return self.int.to_bytes(16, 'big')
return self.int.to_bytes(16) # big endian
@property
def bytes_le(self):
@@ -372,7 +374,12 @@ def _get_command_stdout(command, *args):
# for are actually localized, but in theory some system could do so.)
env = dict(os.environ)
env['LC_ALL'] = 'C'
proc = subprocess.Popen((executable,) + args,
# Empty strings will be quoted by popen so we should just ommit it
if args != ('',):
command = (executable, *args)
else:
command = (executable,)
proc = subprocess.Popen(command,
stdout=subprocess.PIPE,
stderr=subprocess.DEVNULL,
env=env)
@@ -397,7 +404,7 @@ def _get_command_stdout(command, *args):
# over locally administered ones since the former are globally unique, but
# we'll return the first of the latter found if that's all the machine has.
#
# See https://en.wikipedia.org/wiki/MAC_address#Universal_vs._local
# See https://en.wikipedia.org/wiki/MAC_address#Universal_vs._local_(U/L_bit)
def _is_universal(mac):
return not (mac & (1 << 41))
@@ -512,7 +519,7 @@ def _ifconfig_getnode():
mac = _find_mac_near_keyword('ifconfig', args, keywords, lambda i: i+1)
if mac:
return mac
return None
return None
def _ip_getnode():
"""Get the hardware address on Unix by running ip."""
@@ -525,6 +532,8 @@ def _ip_getnode():
def _arp_getnode():
"""Get the hardware address on Unix by running arp."""
import os, socket
if not hasattr(socket, "gethostbyname"):
return None
try:
ip_addr = socket.gethostbyname(socket.gethostname())
except OSError:
@@ -558,32 +567,16 @@ def _netstat_getnode():
# This works on AIX and might work on Tru64 UNIX.
return _find_mac_under_heading('netstat', '-ian', b'Address')
def _ipconfig_getnode():
"""[DEPRECATED] Get the hardware address on Windows."""
# bpo-40501: UuidCreateSequential() is now the only supported approach
return _windll_getnode()
def _netbios_getnode():
"""[DEPRECATED] Get the hardware address on Windows."""
# bpo-40501: UuidCreateSequential() is now the only supported approach
return _windll_getnode()
# Import optional C extension at toplevel, to help disabling it when testing
try:
import _uuid
_generate_time_safe = getattr(_uuid, "generate_time_safe", None)
_UuidCreate = getattr(_uuid, "UuidCreate", None)
_has_uuid_generate_time_safe = _uuid.has_uuid_generate_time_safe
except ImportError:
_uuid = None
_generate_time_safe = None
_UuidCreate = None
_has_uuid_generate_time_safe = None
def _load_system_functions():
"""[DEPRECATED] Platform-specific functions loaded at import time"""
def _unix_getnode():
@@ -609,7 +602,7 @@ def _random_getnode():
# significant bit of the first octet". This works out to be the 41st bit
# counting from 1 being the least significant bit, or 1<<40.
#
# See https://en.wikipedia.org/wiki/MAC_address#Unicast_vs._multicast
# See https://en.wikipedia.org/w/index.php?title=MAC_address&oldid=1128764812#Universal_vs._local_(U/L_bit)
import random
return random.getrandbits(48) | (1 << 40)
@@ -705,9 +698,11 @@ def uuid1(node=None, clock_seq=None):
def uuid3(namespace, name):
"""Generate a UUID from the MD5 hash of a namespace UUID and a name."""
if isinstance(name, str):
name = bytes(name, "utf-8")
from hashlib import md5
digest = md5(
namespace.bytes + bytes(name, "utf-8"),
namespace.bytes + name,
usedforsecurity=False
).digest()
return UUID(bytes=digest[:16], version=3)
@@ -718,13 +713,68 @@ def uuid4():
def uuid5(namespace, name):
"""Generate a UUID from the SHA-1 hash of a namespace UUID and a name."""
if isinstance(name, str):
name = bytes(name, "utf-8")
from hashlib import sha1
hash = sha1(namespace.bytes + bytes(name, "utf-8")).digest()
hash = sha1(namespace.bytes + name).digest()
return UUID(bytes=hash[:16], version=5)
def main():
"""Run the uuid command line interface."""
uuid_funcs = {
"uuid1": uuid1,
"uuid3": uuid3,
"uuid4": uuid4,
"uuid5": uuid5
}
uuid_namespace_funcs = ("uuid3", "uuid5")
namespaces = {
"@dns": NAMESPACE_DNS,
"@url": NAMESPACE_URL,
"@oid": NAMESPACE_OID,
"@x500": NAMESPACE_X500
}
import argparse
parser = argparse.ArgumentParser(
description="Generates a uuid using the selected uuid function.")
parser.add_argument("-u", "--uuid", choices=uuid_funcs.keys(), default="uuid4",
help="The function to use to generate the uuid. "
"By default uuid4 function is used.")
parser.add_argument("-n", "--namespace",
help="The namespace is a UUID, or '@ns' where 'ns' is a "
"well-known predefined UUID addressed by namespace name. "
"Such as @dns, @url, @oid, and @x500. "
"Only required for uuid3/uuid5 functions.")
parser.add_argument("-N", "--name",
help="The name used as part of generating the uuid. "
"Only required for uuid3/uuid5 functions.")
args = parser.parse_args()
uuid_func = uuid_funcs[args.uuid]
namespace = args.namespace
name = args.name
if args.uuid in uuid_namespace_funcs:
if not namespace or not name:
parser.error(
"Incorrect number of arguments. "
f"{args.uuid} requires a namespace and a name. "
"Run 'python -m uuid -h' for more information."
)
namespace = namespaces[namespace] if namespace in namespaces else UUID(namespace)
print(uuid_func(namespace, name))
else:
print(uuid_func())
# The following standard UUIDs are for use with uuid3() or uuid5().
NAMESPACE_DNS = UUID('6ba7b810-9dad-11d1-80b4-00c04fd430c8')
NAMESPACE_URL = UUID('6ba7b811-9dad-11d1-80b4-00c04fd430c8')
NAMESPACE_OID = UUID('6ba7b812-9dad-11d1-80b4-00c04fd430c8')
NAMESPACE_X500 = UUID('6ba7b814-9dad-11d1-80b4-00c04fd430c8')
if __name__ == "__main__":
main()