bpo-11063, bpo-20519: avoid ctypes and improve import time for uuid (#3796)

bpo-11063, bpo-20519: avoid ctypes and improve import time for uuid.
This commit is contained in:
Antoine Pitrou 2017-09-28 23:03:06 +02:00 committed by GitHub
parent 8d59aca4a9
commit a106aec2ed
5 changed files with 330 additions and 201 deletions

View File

@ -1,11 +1,15 @@
import unittest.mock import unittest.mock
from test import support from test import support
import builtins import builtins
import contextlib
import io import io
import os import os
import shutil import shutil
import subprocess import subprocess
import uuid
py_uuid = support.import_fresh_module('uuid', blocked=['_uuid'])
c_uuid = support.import_fresh_module('uuid', fresh=['_uuid'])
def importable(name): def importable(name):
try: try:
@ -14,7 +18,10 @@ def importable(name):
except: except:
return False return False
class TestUUID(unittest.TestCase):
class BaseTestUUID:
uuid = None
def test_UUID(self): def test_UUID(self):
equal = self.assertEqual equal = self.assertEqual
ascending = [] ascending = []
@ -28,7 +35,7 @@ class TestUUID(unittest.TestCase):
(0, 0, 0, 0, 0, 0), (0, 0, 0, 0, 0, 0),
0, 0,
'urn:uuid:00000000-0000-0000-0000-000000000000', 'urn:uuid:00000000-0000-0000-0000-000000000000',
0, 0, uuid.RESERVED_NCS, None), 0, 0, self.uuid.RESERVED_NCS, None),
('00010203-0405-0607-0809-0a0b0c0d0e0f', ('00010203-0405-0607-0809-0a0b0c0d0e0f',
'{00010203-0405-0607-0809-0a0b0c0d0e0f}', '{00010203-0405-0607-0809-0a0b0c0d0e0f}',
'000102030405060708090a0b0c0d0e0f', '000102030405060708090a0b0c0d0e0f',
@ -37,7 +44,7 @@ class TestUUID(unittest.TestCase):
(0x00010203, 0x0405, 0x0607, 8, 9, 0x0a0b0c0d0e0f), (0x00010203, 0x0405, 0x0607, 8, 9, 0x0a0b0c0d0e0f),
0x000102030405060708090a0b0c0d0e0f, 0x000102030405060708090a0b0c0d0e0f,
'urn:uuid:00010203-0405-0607-0809-0a0b0c0d0e0f', 'urn:uuid:00010203-0405-0607-0809-0a0b0c0d0e0f',
0x607040500010203, 0x809, uuid.RESERVED_NCS, None), 0x607040500010203, 0x809, self.uuid.RESERVED_NCS, None),
('02d9e6d5-9467-382e-8f9b-9300a64ac3cd', ('02d9e6d5-9467-382e-8f9b-9300a64ac3cd',
'{02d9e6d5-9467-382e-8f9b-9300a64ac3cd}', '{02d9e6d5-9467-382e-8f9b-9300a64ac3cd}',
'02d9e6d59467382e8f9b9300a64ac3cd', '02d9e6d59467382e8f9b9300a64ac3cd',
@ -46,7 +53,7 @@ class TestUUID(unittest.TestCase):
(0x02d9e6d5, 0x9467, 0x382e, 0x8f, 0x9b, 0x9300a64ac3cd), (0x02d9e6d5, 0x9467, 0x382e, 0x8f, 0x9b, 0x9300a64ac3cd),
0x02d9e6d59467382e8f9b9300a64ac3cd, 0x02d9e6d59467382e8f9b9300a64ac3cd,
'urn:uuid:02d9e6d5-9467-382e-8f9b-9300a64ac3cd', 'urn:uuid:02d9e6d5-9467-382e-8f9b-9300a64ac3cd',
0x82e946702d9e6d5, 0xf9b, uuid.RFC_4122, 3), 0x82e946702d9e6d5, 0xf9b, self.uuid.RFC_4122, 3),
('12345678-1234-5678-1234-567812345678', ('12345678-1234-5678-1234-567812345678',
'{12345678-1234-5678-1234-567812345678}', '{12345678-1234-5678-1234-567812345678}',
'12345678123456781234567812345678', '12345678123456781234567812345678',
@ -55,7 +62,7 @@ class TestUUID(unittest.TestCase):
(0x12345678, 0x1234, 0x5678, 0x12, 0x34, 0x567812345678), (0x12345678, 0x1234, 0x5678, 0x12, 0x34, 0x567812345678),
0x12345678123456781234567812345678, 0x12345678123456781234567812345678,
'urn:uuid:12345678-1234-5678-1234-567812345678', 'urn:uuid:12345678-1234-5678-1234-567812345678',
0x678123412345678, 0x1234, uuid.RESERVED_NCS, None), 0x678123412345678, 0x1234, self.uuid.RESERVED_NCS, None),
('6ba7b810-9dad-11d1-80b4-00c04fd430c8', ('6ba7b810-9dad-11d1-80b4-00c04fd430c8',
'{6ba7b810-9dad-11d1-80b4-00c04fd430c8}', '{6ba7b810-9dad-11d1-80b4-00c04fd430c8}',
'6ba7b8109dad11d180b400c04fd430c8', '6ba7b8109dad11d180b400c04fd430c8',
@ -64,7 +71,7 @@ class TestUUID(unittest.TestCase):
(0x6ba7b810, 0x9dad, 0x11d1, 0x80, 0xb4, 0x00c04fd430c8), (0x6ba7b810, 0x9dad, 0x11d1, 0x80, 0xb4, 0x00c04fd430c8),
0x6ba7b8109dad11d180b400c04fd430c8, 0x6ba7b8109dad11d180b400c04fd430c8,
'urn:uuid:6ba7b810-9dad-11d1-80b4-00c04fd430c8', 'urn:uuid:6ba7b810-9dad-11d1-80b4-00c04fd430c8',
0x1d19dad6ba7b810, 0xb4, uuid.RFC_4122, 1), 0x1d19dad6ba7b810, 0xb4, self.uuid.RFC_4122, 1),
('6ba7b811-9dad-11d1-80b4-00c04fd430c8', ('6ba7b811-9dad-11d1-80b4-00c04fd430c8',
'{6ba7b811-9dad-11d1-80b4-00c04fd430c8}', '{6ba7b811-9dad-11d1-80b4-00c04fd430c8}',
'6ba7b8119dad11d180b400c04fd430c8', '6ba7b8119dad11d180b400c04fd430c8',
@ -73,7 +80,7 @@ class TestUUID(unittest.TestCase):
(0x6ba7b811, 0x9dad, 0x11d1, 0x80, 0xb4, 0x00c04fd430c8), (0x6ba7b811, 0x9dad, 0x11d1, 0x80, 0xb4, 0x00c04fd430c8),
0x6ba7b8119dad11d180b400c04fd430c8, 0x6ba7b8119dad11d180b400c04fd430c8,
'urn:uuid:6ba7b811-9dad-11d1-80b4-00c04fd430c8', 'urn:uuid:6ba7b811-9dad-11d1-80b4-00c04fd430c8',
0x1d19dad6ba7b811, 0xb4, uuid.RFC_4122, 1), 0x1d19dad6ba7b811, 0xb4, self.uuid.RFC_4122, 1),
('6ba7b812-9dad-11d1-80b4-00c04fd430c8', ('6ba7b812-9dad-11d1-80b4-00c04fd430c8',
'{6ba7b812-9dad-11d1-80b4-00c04fd430c8}', '{6ba7b812-9dad-11d1-80b4-00c04fd430c8}',
'6ba7b8129dad11d180b400c04fd430c8', '6ba7b8129dad11d180b400c04fd430c8',
@ -82,7 +89,7 @@ class TestUUID(unittest.TestCase):
(0x6ba7b812, 0x9dad, 0x11d1, 0x80, 0xb4, 0x00c04fd430c8), (0x6ba7b812, 0x9dad, 0x11d1, 0x80, 0xb4, 0x00c04fd430c8),
0x6ba7b8129dad11d180b400c04fd430c8, 0x6ba7b8129dad11d180b400c04fd430c8,
'urn:uuid:6ba7b812-9dad-11d1-80b4-00c04fd430c8', 'urn:uuid:6ba7b812-9dad-11d1-80b4-00c04fd430c8',
0x1d19dad6ba7b812, 0xb4, uuid.RFC_4122, 1), 0x1d19dad6ba7b812, 0xb4, self.uuid.RFC_4122, 1),
('6ba7b814-9dad-11d1-80b4-00c04fd430c8', ('6ba7b814-9dad-11d1-80b4-00c04fd430c8',
'{6ba7b814-9dad-11d1-80b4-00c04fd430c8}', '{6ba7b814-9dad-11d1-80b4-00c04fd430c8}',
'6ba7b8149dad11d180b400c04fd430c8', '6ba7b8149dad11d180b400c04fd430c8',
@ -91,7 +98,7 @@ class TestUUID(unittest.TestCase):
(0x6ba7b814, 0x9dad, 0x11d1, 0x80, 0xb4, 0x00c04fd430c8), (0x6ba7b814, 0x9dad, 0x11d1, 0x80, 0xb4, 0x00c04fd430c8),
0x6ba7b8149dad11d180b400c04fd430c8, 0x6ba7b8149dad11d180b400c04fd430c8,
'urn:uuid:6ba7b814-9dad-11d1-80b4-00c04fd430c8', 'urn:uuid:6ba7b814-9dad-11d1-80b4-00c04fd430c8',
0x1d19dad6ba7b814, 0xb4, uuid.RFC_4122, 1), 0x1d19dad6ba7b814, 0xb4, self.uuid.RFC_4122, 1),
('7d444840-9dc0-11d1-b245-5ffdce74fad2', ('7d444840-9dc0-11d1-b245-5ffdce74fad2',
'{7d444840-9dc0-11d1-b245-5ffdce74fad2}', '{7d444840-9dc0-11d1-b245-5ffdce74fad2}',
'7d4448409dc011d1b2455ffdce74fad2', '7d4448409dc011d1b2455ffdce74fad2',
@ -100,7 +107,7 @@ class TestUUID(unittest.TestCase):
(0x7d444840, 0x9dc0, 0x11d1, 0xb2, 0x45, 0x5ffdce74fad2), (0x7d444840, 0x9dc0, 0x11d1, 0xb2, 0x45, 0x5ffdce74fad2),
0x7d4448409dc011d1b2455ffdce74fad2, 0x7d4448409dc011d1b2455ffdce74fad2,
'urn:uuid:7d444840-9dc0-11d1-b245-5ffdce74fad2', 'urn:uuid:7d444840-9dc0-11d1-b245-5ffdce74fad2',
0x1d19dc07d444840, 0x3245, uuid.RFC_4122, 1), 0x1d19dc07d444840, 0x3245, self.uuid.RFC_4122, 1),
('e902893a-9d22-3c7e-a7b8-d6e313b71d9f', ('e902893a-9d22-3c7e-a7b8-d6e313b71d9f',
'{e902893a-9d22-3c7e-a7b8-d6e313b71d9f}', '{e902893a-9d22-3c7e-a7b8-d6e313b71d9f}',
'e902893a9d223c7ea7b8d6e313b71d9f', 'e902893a9d223c7ea7b8d6e313b71d9f',
@ -109,7 +116,7 @@ class TestUUID(unittest.TestCase):
(0xe902893a, 0x9d22, 0x3c7e, 0xa7, 0xb8, 0xd6e313b71d9f), (0xe902893a, 0x9d22, 0x3c7e, 0xa7, 0xb8, 0xd6e313b71d9f),
0xe902893a9d223c7ea7b8d6e313b71d9f, 0xe902893a9d223c7ea7b8d6e313b71d9f,
'urn:uuid:e902893a-9d22-3c7e-a7b8-d6e313b71d9f', 'urn:uuid:e902893a-9d22-3c7e-a7b8-d6e313b71d9f',
0xc7e9d22e902893a, 0x27b8, uuid.RFC_4122, 3), 0xc7e9d22e902893a, 0x27b8, self.uuid.RFC_4122, 3),
('eb424026-6f54-4ef8-a4d0-bb658a1fc6cf', ('eb424026-6f54-4ef8-a4d0-bb658a1fc6cf',
'{eb424026-6f54-4ef8-a4d0-bb658a1fc6cf}', '{eb424026-6f54-4ef8-a4d0-bb658a1fc6cf}',
'eb4240266f544ef8a4d0bb658a1fc6cf', 'eb4240266f544ef8a4d0bb658a1fc6cf',
@ -118,7 +125,7 @@ class TestUUID(unittest.TestCase):
(0xeb424026, 0x6f54, 0x4ef8, 0xa4, 0xd0, 0xbb658a1fc6cf), (0xeb424026, 0x6f54, 0x4ef8, 0xa4, 0xd0, 0xbb658a1fc6cf),
0xeb4240266f544ef8a4d0bb658a1fc6cf, 0xeb4240266f544ef8a4d0bb658a1fc6cf,
'urn:uuid:eb424026-6f54-4ef8-a4d0-bb658a1fc6cf', 'urn:uuid:eb424026-6f54-4ef8-a4d0-bb658a1fc6cf',
0xef86f54eb424026, 0x24d0, uuid.RFC_4122, 4), 0xef86f54eb424026, 0x24d0, self.uuid.RFC_4122, 4),
('f81d4fae-7dec-11d0-a765-00a0c91e6bf6', ('f81d4fae-7dec-11d0-a765-00a0c91e6bf6',
'{f81d4fae-7dec-11d0-a765-00a0c91e6bf6}', '{f81d4fae-7dec-11d0-a765-00a0c91e6bf6}',
'f81d4fae7dec11d0a76500a0c91e6bf6', 'f81d4fae7dec11d0a76500a0c91e6bf6',
@ -127,7 +134,7 @@ class TestUUID(unittest.TestCase):
(0xf81d4fae, 0x7dec, 0x11d0, 0xa7, 0x65, 0x00a0c91e6bf6), (0xf81d4fae, 0x7dec, 0x11d0, 0xa7, 0x65, 0x00a0c91e6bf6),
0xf81d4fae7dec11d0a76500a0c91e6bf6, 0xf81d4fae7dec11d0a76500a0c91e6bf6,
'urn:uuid:f81d4fae-7dec-11d0-a765-00a0c91e6bf6', 'urn:uuid:f81d4fae-7dec-11d0-a765-00a0c91e6bf6',
0x1d07decf81d4fae, 0x2765, uuid.RFC_4122, 1), 0x1d07decf81d4fae, 0x2765, self.uuid.RFC_4122, 1),
('fffefdfc-fffe-fffe-fffe-fffefdfcfbfa', ('fffefdfc-fffe-fffe-fffe-fffefdfcfbfa',
'{fffefdfc-fffe-fffe-fffe-fffefdfcfbfa}', '{fffefdfc-fffe-fffe-fffe-fffefdfcfbfa}',
'fffefdfcfffefffefffefffefdfcfbfa', 'fffefdfcfffefffefffefffefdfcfbfa',
@ -136,7 +143,7 @@ class TestUUID(unittest.TestCase):
(0xfffefdfc, 0xfffe, 0xfffe, 0xff, 0xfe, 0xfffefdfcfbfa), (0xfffefdfc, 0xfffe, 0xfffe, 0xff, 0xfe, 0xfffefdfcfbfa),
0xfffefdfcfffefffefffefffefdfcfbfa, 0xfffefdfcfffefffefffefffefdfcfbfa,
'urn:uuid:fffefdfc-fffe-fffe-fffe-fffefdfcfbfa', 'urn:uuid:fffefdfc-fffe-fffe-fffe-fffefdfcfbfa',
0xffefffefffefdfc, 0x3ffe, uuid.RESERVED_FUTURE, None), 0xffefffefffefdfc, 0x3ffe, self.uuid.RESERVED_FUTURE, None),
('ffffffff-ffff-ffff-ffff-ffffffffffff', ('ffffffff-ffff-ffff-ffff-ffffffffffff',
'{ffffffff-ffff-ffff-ffff-ffffffffffff}', '{ffffffff-ffff-ffff-ffff-ffffffffffff}',
'ffffffffffffffffffffffffffffffff', 'ffffffffffffffffffffffffffffffff',
@ -145,14 +152,14 @@ class TestUUID(unittest.TestCase):
(0xffffffff, 0xffff, 0xffff, 0xff, 0xff, 0xffffffffffff), (0xffffffff, 0xffff, 0xffff, 0xff, 0xff, 0xffffffffffff),
0xffffffffffffffffffffffffffffffff, 0xffffffffffffffffffffffffffffffff,
'urn:uuid:ffffffff-ffff-ffff-ffff-ffffffffffff', 'urn:uuid:ffffffff-ffff-ffff-ffff-ffffffffffff',
0xfffffffffffffff, 0x3fff, uuid.RESERVED_FUTURE, None), 0xfffffffffffffff, 0x3fff, self.uuid.RESERVED_FUTURE, None),
]: ]:
equivalents = [] equivalents = []
# Construct each UUID in several different ways. # Construct each UUID in several different ways.
for u in [uuid.UUID(string), uuid.UUID(curly), uuid.UUID(hex), for u in [self.uuid.UUID(string), self.uuid.UUID(curly), self.uuid.UUID(hex),
uuid.UUID(bytes=bytes), uuid.UUID(bytes_le=bytes_le), self.uuid.UUID(bytes=bytes), self.uuid.UUID(bytes_le=bytes_le),
uuid.UUID(fields=fields), uuid.UUID(int=integer), self.uuid.UUID(fields=fields), self.uuid.UUID(int=integer),
uuid.UUID(urn)]: self.uuid.UUID(urn)]:
# Test all conversions and properties of the UUID object. # Test all conversions and properties of the UUID object.
equal(str(u), string) equal(str(u), string)
equal(int(u), integer) equal(int(u), integer)
@ -206,64 +213,64 @@ class TestUUID(unittest.TestCase):
badtype = lambda f: self.assertRaises(TypeError, f) badtype = lambda f: self.assertRaises(TypeError, f)
# Badly formed hex strings. # Badly formed hex strings.
badvalue(lambda: uuid.UUID('')) badvalue(lambda: self.uuid.UUID(''))
badvalue(lambda: uuid.UUID('abc')) badvalue(lambda: self.uuid.UUID('abc'))
badvalue(lambda: uuid.UUID('1234567812345678123456781234567')) badvalue(lambda: self.uuid.UUID('1234567812345678123456781234567'))
badvalue(lambda: uuid.UUID('123456781234567812345678123456789')) badvalue(lambda: self.uuid.UUID('123456781234567812345678123456789'))
badvalue(lambda: uuid.UUID('123456781234567812345678z2345678')) badvalue(lambda: self.uuid.UUID('123456781234567812345678z2345678'))
# Badly formed bytes. # Badly formed bytes.
badvalue(lambda: uuid.UUID(bytes='abc')) badvalue(lambda: self.uuid.UUID(bytes='abc'))
badvalue(lambda: uuid.UUID(bytes='\0'*15)) badvalue(lambda: self.uuid.UUID(bytes='\0'*15))
badvalue(lambda: uuid.UUID(bytes='\0'*17)) badvalue(lambda: self.uuid.UUID(bytes='\0'*17))
# Badly formed bytes_le. # Badly formed bytes_le.
badvalue(lambda: uuid.UUID(bytes_le='abc')) badvalue(lambda: self.uuid.UUID(bytes_le='abc'))
badvalue(lambda: uuid.UUID(bytes_le='\0'*15)) badvalue(lambda: self.uuid.UUID(bytes_le='\0'*15))
badvalue(lambda: uuid.UUID(bytes_le='\0'*17)) badvalue(lambda: self.uuid.UUID(bytes_le='\0'*17))
# Badly formed fields. # Badly formed fields.
badvalue(lambda: uuid.UUID(fields=(1,))) badvalue(lambda: self.uuid.UUID(fields=(1,)))
badvalue(lambda: uuid.UUID(fields=(1, 2, 3, 4, 5))) badvalue(lambda: self.uuid.UUID(fields=(1, 2, 3, 4, 5)))
badvalue(lambda: uuid.UUID(fields=(1, 2, 3, 4, 5, 6, 7))) badvalue(lambda: self.uuid.UUID(fields=(1, 2, 3, 4, 5, 6, 7)))
# Field values out of range. # Field values out of range.
badvalue(lambda: uuid.UUID(fields=(-1, 0, 0, 0, 0, 0))) badvalue(lambda: self.uuid.UUID(fields=(-1, 0, 0, 0, 0, 0)))
badvalue(lambda: uuid.UUID(fields=(0x100000000, 0, 0, 0, 0, 0))) badvalue(lambda: self.uuid.UUID(fields=(0x100000000, 0, 0, 0, 0, 0)))
badvalue(lambda: uuid.UUID(fields=(0, -1, 0, 0, 0, 0))) badvalue(lambda: self.uuid.UUID(fields=(0, -1, 0, 0, 0, 0)))
badvalue(lambda: uuid.UUID(fields=(0, 0x10000, 0, 0, 0, 0))) badvalue(lambda: self.uuid.UUID(fields=(0, 0x10000, 0, 0, 0, 0)))
badvalue(lambda: uuid.UUID(fields=(0, 0, -1, 0, 0, 0))) badvalue(lambda: self.uuid.UUID(fields=(0, 0, -1, 0, 0, 0)))
badvalue(lambda: uuid.UUID(fields=(0, 0, 0x10000, 0, 0, 0))) badvalue(lambda: self.uuid.UUID(fields=(0, 0, 0x10000, 0, 0, 0)))
badvalue(lambda: uuid.UUID(fields=(0, 0, 0, -1, 0, 0))) badvalue(lambda: self.uuid.UUID(fields=(0, 0, 0, -1, 0, 0)))
badvalue(lambda: uuid.UUID(fields=(0, 0, 0, 0x100, 0, 0))) badvalue(lambda: self.uuid.UUID(fields=(0, 0, 0, 0x100, 0, 0)))
badvalue(lambda: uuid.UUID(fields=(0, 0, 0, 0, -1, 0))) badvalue(lambda: self.uuid.UUID(fields=(0, 0, 0, 0, -1, 0)))
badvalue(lambda: uuid.UUID(fields=(0, 0, 0, 0, 0x100, 0))) badvalue(lambda: self.uuid.UUID(fields=(0, 0, 0, 0, 0x100, 0)))
badvalue(lambda: uuid.UUID(fields=(0, 0, 0, 0, 0, -1))) badvalue(lambda: self.uuid.UUID(fields=(0, 0, 0, 0, 0, -1)))
badvalue(lambda: uuid.UUID(fields=(0, 0, 0, 0, 0, 0x1000000000000))) badvalue(lambda: self.uuid.UUID(fields=(0, 0, 0, 0, 0, 0x1000000000000)))
# Version number out of range. # Version number out of range.
badvalue(lambda: uuid.UUID('00'*16, version=0)) badvalue(lambda: self.uuid.UUID('00'*16, version=0))
badvalue(lambda: uuid.UUID('00'*16, version=6)) badvalue(lambda: self.uuid.UUID('00'*16, version=6))
# Integer value out of range. # Integer value out of range.
badvalue(lambda: uuid.UUID(int=-1)) badvalue(lambda: self.uuid.UUID(int=-1))
badvalue(lambda: uuid.UUID(int=1<<128)) badvalue(lambda: self.uuid.UUID(int=1<<128))
# Must supply exactly one of hex, bytes, fields, int. # Must supply exactly one of hex, bytes, fields, int.
h, b, f, i = '00'*16, b'\0'*16, (0, 0, 0, 0, 0, 0), 0 h, b, f, i = '00'*16, b'\0'*16, (0, 0, 0, 0, 0, 0), 0
uuid.UUID(h) self.uuid.UUID(h)
uuid.UUID(hex=h) self.uuid.UUID(hex=h)
uuid.UUID(bytes=b) self.uuid.UUID(bytes=b)
uuid.UUID(bytes_le=b) self.uuid.UUID(bytes_le=b)
uuid.UUID(fields=f) self.uuid.UUID(fields=f)
uuid.UUID(int=i) self.uuid.UUID(int=i)
# Wrong number of arguments (positional). # Wrong number of arguments (positional).
badtype(lambda: uuid.UUID()) badtype(lambda: self.uuid.UUID())
badtype(lambda: uuid.UUID(h, b)) badtype(lambda: self.uuid.UUID(h, b))
badtype(lambda: uuid.UUID(h, b, b)) badtype(lambda: self.uuid.UUID(h, b, b))
badtype(lambda: uuid.UUID(h, b, b, f)) badtype(lambda: self.uuid.UUID(h, b, b, f))
badtype(lambda: uuid.UUID(h, b, b, f, i)) badtype(lambda: self.uuid.UUID(h, b, b, f, i))
# Duplicate arguments. # Duplicate arguments.
for hh in [[], [('hex', h)]]: for hh in [[], [('hex', h)]]:
@ -273,12 +280,12 @@ class TestUUID(unittest.TestCase):
for ff in [[], [('fields', f)]]: for ff in [[], [('fields', f)]]:
args = dict(hh + bb + bble + ii + ff) args = dict(hh + bb + bble + ii + ff)
if len(args) != 0: if len(args) != 0:
badtype(lambda: uuid.UUID(h, **args)) badtype(lambda: self.uuid.UUID(h, **args))
if len(args) != 1: if len(args) != 1:
badtype(lambda: uuid.UUID(**args)) badtype(lambda: self.uuid.UUID(**args))
# Immutability. # Immutability.
u = uuid.UUID(h) u = self.uuid.UUID(h)
badtype(lambda: setattr(u, 'hex', h)) badtype(lambda: setattr(u, 'hex', h))
badtype(lambda: setattr(u, 'bytes', b)) badtype(lambda: setattr(u, 'bytes', b))
badtype(lambda: setattr(u, 'bytes_le', b)) badtype(lambda: setattr(u, 'bytes_le', b))
@ -297,122 +304,135 @@ class TestUUID(unittest.TestCase):
badtype(lambda: u > object()) badtype(lambda: u > object())
def test_getnode(self): def test_getnode(self):
node1 = uuid.getnode() node1 = self.uuid.getnode()
self.assertTrue(0 < node1 < (1 << 48), '%012x' % node1) self.assertTrue(0 < node1 < (1 << 48), '%012x' % node1)
# Test it again to ensure consistency. # Test it again to ensure consistency.
node2 = uuid.getnode() node2 = self.uuid.getnode()
self.assertEqual(node1, node2, '%012x != %012x' % (node1, node2)) self.assertEqual(node1, node2, '%012x != %012x' % (node1, node2))
@unittest.skipUnless(importable('ctypes'), 'requires ctypes')
def test_uuid1(self): def test_uuid1(self):
equal = self.assertEqual equal = self.assertEqual
# Make sure uuid1() generates UUIDs that are actually version 1. # Make sure uuid1() generates UUIDs that are actually version 1.
for u in [uuid.uuid1() for i in range(10)]: for u in [self.uuid.uuid1() for i in range(10)]:
equal(u.variant, uuid.RFC_4122) equal(u.variant, self.uuid.RFC_4122)
equal(u.version, 1) equal(u.version, 1)
self.assertIn(u.is_safe, {self.uuid.SafeUUID.safe,
self.uuid.SafeUUID.unsafe,
self.uuid.SafeUUID.unknown})
# Make sure the generated UUIDs are actually unique. # Make sure the generated UUIDs are actually unique.
uuids = {} uuids = {}
for u in [uuid.uuid1() for i in range(1000)]: for u in [self.uuid.uuid1() for i in range(1000)]:
uuids[u] = 1 uuids[u] = 1
equal(len(uuids.keys()), 1000) equal(len(uuids.keys()), 1000)
# Make sure the supplied node ID appears in the UUID. # Make sure the supplied node ID appears in the UUID.
u = uuid.uuid1(0) u = self.uuid.uuid1(0)
equal(u.node, 0) equal(u.node, 0)
u = uuid.uuid1(0x123456789abc) u = self.uuid.uuid1(0x123456789abc)
equal(u.node, 0x123456789abc) equal(u.node, 0x123456789abc)
u = uuid.uuid1(0xffffffffffff) u = self.uuid.uuid1(0xffffffffffff)
equal(u.node, 0xffffffffffff) equal(u.node, 0xffffffffffff)
# Make sure the supplied clock sequence appears in the UUID. # Make sure the supplied clock sequence appears in the UUID.
u = uuid.uuid1(0x123456789abc, 0) u = self.uuid.uuid1(0x123456789abc, 0)
equal(u.node, 0x123456789abc) equal(u.node, 0x123456789abc)
equal(((u.clock_seq_hi_variant & 0x3f) << 8) | u.clock_seq_low, 0) equal(((u.clock_seq_hi_variant & 0x3f) << 8) | u.clock_seq_low, 0)
u = uuid.uuid1(0x123456789abc, 0x1234) u = self.uuid.uuid1(0x123456789abc, 0x1234)
equal(u.node, 0x123456789abc) equal(u.node, 0x123456789abc)
equal(((u.clock_seq_hi_variant & 0x3f) << 8) | equal(((u.clock_seq_hi_variant & 0x3f) << 8) |
u.clock_seq_low, 0x1234) u.clock_seq_low, 0x1234)
u = uuid.uuid1(0x123456789abc, 0x3fff) u = self.uuid.uuid1(0x123456789abc, 0x3fff)
equal(u.node, 0x123456789abc) equal(u.node, 0x123456789abc)
equal(((u.clock_seq_hi_variant & 0x3f) << 8) | equal(((u.clock_seq_hi_variant & 0x3f) << 8) |
u.clock_seq_low, 0x3fff) u.clock_seq_low, 0x3fff)
requires_ugt = unittest.skipUnless(uuid._uuid_generate_time is not None, # bpo-29925: On Mac OS X Tiger, self.uuid.uuid1().is_safe returns
'requires uuid_generate_time_safe(3)') # self.uuid.SafeUUID.unknown
@requires_ugt
# bpo-29925: On Mac OS X Tiger, uuid.uuid1().is_safe returns
# uuid.SafeUUID.unknown
@support.requires_mac_ver(10, 5) @support.requires_mac_ver(10, 5)
@unittest.skipUnless(os.name == 'posix', 'POSIX-only test')
def test_uuid1_safe(self): def test_uuid1_safe(self):
u = uuid.uuid1() if not self.uuid._has_uuid_generate_time_safe:
self.skipTest('requires uuid_generate_time_safe(3)')
u = self.uuid.uuid1()
# uuid_generate_time_safe() may return 0 or -1 but what it returns is # uuid_generate_time_safe() may return 0 or -1 but what it returns is
# dependent on the underlying platform support. At least it cannot be # dependent on the underlying platform support. At least it cannot be
# unknown (unless I suppose the platform is buggy). # unknown (unless I suppose the platform is buggy).
self.assertNotEqual(u.is_safe, uuid.SafeUUID.unknown) self.assertNotEqual(u.is_safe, self.uuid.SafeUUID.unknown)
@requires_ugt @contextlib.contextmanager
def mock_generate_time_safe(self, safe_value):
"""
Mock uuid._generate_time_safe() to return a given *safe_value*.
"""
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')
with unittest.mock.patch.object(self.uuid, '_generate_time_safe',
lambda: (f()[0], safe_value)):
yield
@unittest.skipUnless(os.name == 'posix', 'POSIX-only test')
def test_uuid1_unknown(self): def test_uuid1_unknown(self):
# Even if the platform has uuid_generate_time_safe(), let's mock it to # Even if the platform has uuid_generate_time_safe(), let's mock it to
# be uuid_generate_time() and ensure the safety is unknown. # be uuid_generate_time() and ensure the safety is unknown.
with unittest.mock.patch.object(uuid._uuid_generate_time, with self.mock_generate_time_safe(None):
'restype', None): u = self.uuid.uuid1()
u = uuid.uuid1() self.assertEqual(u.is_safe, self.uuid.SafeUUID.unknown)
self.assertEqual(u.is_safe, uuid.SafeUUID.unknown)
@requires_ugt @unittest.skipUnless(os.name == 'posix', 'POSIX-only test')
def test_uuid1_is_safe(self): def test_uuid1_is_safe(self):
with unittest.mock.patch.object(uuid._uuid_generate_time, with self.mock_generate_time_safe(0):
'restype', lambda x: 0): u = self.uuid.uuid1()
u = uuid.uuid1() self.assertEqual(u.is_safe, self.uuid.SafeUUID.safe)
self.assertEqual(u.is_safe, uuid.SafeUUID.safe)
@requires_ugt @unittest.skipUnless(os.name == 'posix', 'POSIX-only test')
def test_uuid1_is_unsafe(self): def test_uuid1_is_unsafe(self):
with unittest.mock.patch.object(uuid._uuid_generate_time, with self.mock_generate_time_safe(-1):
'restype', lambda x: -1): u = self.uuid.uuid1()
u = uuid.uuid1() self.assertEqual(u.is_safe, self.uuid.SafeUUID.unsafe)
self.assertEqual(u.is_safe, uuid.SafeUUID.unsafe)
@requires_ugt @unittest.skipUnless(os.name == 'posix', 'POSIX-only test')
def test_uuid1_bogus_return_value(self): def test_uuid1_bogus_return_value(self):
with unittest.mock.patch.object(uuid._uuid_generate_time, with self.mock_generate_time_safe(3):
'restype', lambda x: 3): u = self.uuid.uuid1()
u = uuid.uuid1() self.assertEqual(u.is_safe, self.uuid.SafeUUID.unknown)
self.assertEqual(u.is_safe, uuid.SafeUUID.unknown)
def test_uuid3(self): def test_uuid3(self):
equal = self.assertEqual equal = self.assertEqual
# Test some known version-3 UUIDs. # Test some known version-3 UUIDs.
for u, v in [(uuid.uuid3(uuid.NAMESPACE_DNS, 'python.org'), for u, v in [(self.uuid.uuid3(self.uuid.NAMESPACE_DNS, 'python.org'),
'6fa459ea-ee8a-3ca4-894e-db77e160355e'), '6fa459ea-ee8a-3ca4-894e-db77e160355e'),
(uuid.uuid3(uuid.NAMESPACE_URL, 'http://python.org/'), (self.uuid.uuid3(self.uuid.NAMESPACE_URL, 'http://python.org/'),
'9fe8e8c4-aaa8-32a9-a55c-4535a88b748d'), '9fe8e8c4-aaa8-32a9-a55c-4535a88b748d'),
(uuid.uuid3(uuid.NAMESPACE_OID, '1.3.6.1'), (self.uuid.uuid3(self.uuid.NAMESPACE_OID, '1.3.6.1'),
'dd1a1cef-13d5-368a-ad82-eca71acd4cd1'), 'dd1a1cef-13d5-368a-ad82-eca71acd4cd1'),
(uuid.uuid3(uuid.NAMESPACE_X500, 'c=ca'), (self.uuid.uuid3(self.uuid.NAMESPACE_X500, 'c=ca'),
'658d3002-db6b-3040-a1d1-8ddd7d189a4d'), '658d3002-db6b-3040-a1d1-8ddd7d189a4d'),
]: ]:
equal(u.variant, uuid.RFC_4122) equal(u.variant, self.uuid.RFC_4122)
equal(u.version, 3) equal(u.version, 3)
equal(u, uuid.UUID(v)) equal(u, self.uuid.UUID(v))
equal(str(u), v) equal(str(u), v)
def test_uuid4(self): def test_uuid4(self):
equal = self.assertEqual equal = self.assertEqual
# Make sure uuid4() generates UUIDs that are actually version 4. # Make sure uuid4() generates UUIDs that are actually version 4.
for u in [uuid.uuid4() for i in range(10)]: for u in [self.uuid.uuid4() for i in range(10)]:
equal(u.variant, uuid.RFC_4122) equal(u.variant, self.uuid.RFC_4122)
equal(u.version, 4) equal(u.version, 4)
# Make sure the generated UUIDs are actually unique. # Make sure the generated UUIDs are actually unique.
uuids = {} uuids = {}
for u in [uuid.uuid4() for i in range(1000)]: for u in [self.uuid.uuid4() for i in range(1000)]:
uuids[u] = 1 uuids[u] = 1
equal(len(uuids.keys()), 1000) equal(len(uuids.keys()), 1000)
@ -420,44 +440,54 @@ class TestUUID(unittest.TestCase):
equal = self.assertEqual equal = self.assertEqual
# Test some known version-5 UUIDs. # Test some known version-5 UUIDs.
for u, v in [(uuid.uuid5(uuid.NAMESPACE_DNS, 'python.org'), for u, v in [(self.uuid.uuid5(self.uuid.NAMESPACE_DNS, 'python.org'),
'886313e1-3b8a-5372-9b90-0c9aee199e5d'), '886313e1-3b8a-5372-9b90-0c9aee199e5d'),
(uuid.uuid5(uuid.NAMESPACE_URL, 'http://python.org/'), (self.uuid.uuid5(self.uuid.NAMESPACE_URL, 'http://python.org/'),
'4c565f0d-3f5a-5890-b41b-20cf47701c5e'), '4c565f0d-3f5a-5890-b41b-20cf47701c5e'),
(uuid.uuid5(uuid.NAMESPACE_OID, '1.3.6.1'), (self.uuid.uuid5(self.uuid.NAMESPACE_OID, '1.3.6.1'),
'1447fa61-5277-5fef-a9b3-fbc6e44f4af3'), '1447fa61-5277-5fef-a9b3-fbc6e44f4af3'),
(uuid.uuid5(uuid.NAMESPACE_X500, 'c=ca'), (self.uuid.uuid5(self.uuid.NAMESPACE_X500, 'c=ca'),
'cc957dd1-a972-5349-98cd-874190002798'), 'cc957dd1-a972-5349-98cd-874190002798'),
]: ]:
equal(u.variant, uuid.RFC_4122) equal(u.variant, self.uuid.RFC_4122)
equal(u.version, 5) equal(u.version, 5)
equal(u, uuid.UUID(v)) equal(u, self.uuid.UUID(v))
equal(str(u), v) equal(str(u), v)
@unittest.skipUnless(os.name == 'posix', 'requires Posix') @unittest.skipUnless(os.name == 'posix', 'requires Posix')
def testIssue8621(self): def testIssue8621(self):
# On at least some versions of OSX uuid.uuid4 generates # On at least some versions of OSX self.uuid.uuid4 generates
# the same sequence of UUIDs in the parent and any # the same sequence of UUIDs in the parent and any
# children started using fork. # children started using fork.
fds = os.pipe() fds = os.pipe()
pid = os.fork() pid = os.fork()
if pid == 0: if pid == 0:
os.close(fds[0]) os.close(fds[0])
value = uuid.uuid4() value = self.uuid.uuid4()
os.write(fds[1], value.hex.encode('latin-1')) os.write(fds[1], value.hex.encode('latin-1'))
os._exit(0) os._exit(0)
else: else:
os.close(fds[1]) os.close(fds[1])
self.addCleanup(os.close, fds[0]) self.addCleanup(os.close, fds[0])
parent_value = uuid.uuid4().hex parent_value = self.uuid.uuid4().hex
os.waitpid(pid, 0) os.waitpid(pid, 0)
child_value = os.read(fds[0], 100).decode('latin-1') child_value = os.read(fds[0], 100).decode('latin-1')
self.assertNotEqual(parent_value, child_value) self.assertNotEqual(parent_value, child_value)
class TestInternals(unittest.TestCase): class TestUUIDWithoutExtModule(BaseTestUUID, unittest.TestCase):
uuid = py_uuid
@unittest.skipUnless(c_uuid, 'requires the C _uuid module')
class TestUUIDWithExtModule(BaseTestUUID, unittest.TestCase):
uuid = c_uuid
class BaseTestInternals:
uuid = None
@unittest.skipUnless(os.name == 'posix', 'requires Posix') @unittest.skipUnless(os.name == 'posix', 'requires Posix')
def test_find_mac(self): def test_find_mac(self):
data = ''' data = '''
@ -473,7 +503,7 @@ eth0 Link encap:Ethernet HWaddr 12:34:56:78:90:ab
return_value='/sbin/ifconfig'): return_value='/sbin/ifconfig'):
with unittest.mock.patch.object(subprocess, 'Popen', with unittest.mock.patch.object(subprocess, 'Popen',
return_value=popen): return_value=popen):
mac = uuid._find_mac( mac = self.uuid._find_mac(
command='ifconfig', command='ifconfig',
args='', args='',
hw_identifiers=[b'hwaddr'], hw_identifiers=[b'hwaddr'],
@ -497,61 +527,70 @@ eth0 Link encap:Ethernet HWaddr 12:34:56:78:90:ab
@unittest.skipUnless(os.name == 'posix', 'requires Posix') @unittest.skipUnless(os.name == 'posix', 'requires Posix')
def test_ifconfig_getnode(self): def test_ifconfig_getnode(self):
node = uuid._ifconfig_getnode() node = self.uuid._ifconfig_getnode()
self.check_node(node, 'ifconfig', True) self.check_node(node, 'ifconfig', True)
@unittest.skipUnless(os.name == 'posix', 'requires Posix') @unittest.skipUnless(os.name == 'posix', 'requires Posix')
def test_ip_getnode(self): def test_ip_getnode(self):
node = uuid._ip_getnode() node = self.uuid._ip_getnode()
self.check_node(node, 'ip', True) self.check_node(node, 'ip', True)
@unittest.skipUnless(os.name == 'posix', 'requires Posix') @unittest.skipUnless(os.name == 'posix', 'requires Posix')
def test_arp_getnode(self): def test_arp_getnode(self):
node = uuid._arp_getnode() node = self.uuid._arp_getnode()
self.check_node(node, 'arp', True) self.check_node(node, 'arp', True)
@unittest.skipUnless(os.name == 'posix', 'requires Posix') @unittest.skipUnless(os.name == 'posix', 'requires Posix')
def test_lanscan_getnode(self): def test_lanscan_getnode(self):
node = uuid._lanscan_getnode() node = self.uuid._lanscan_getnode()
self.check_node(node, 'lanscan', True) self.check_node(node, 'lanscan', True)
@unittest.skipUnless(os.name == 'posix', 'requires Posix') @unittest.skipUnless(os.name == 'posix', 'requires Posix')
def test_netstat_getnode(self): def test_netstat_getnode(self):
node = uuid._netstat_getnode() node = self.uuid._netstat_getnode()
self.check_node(node, 'netstat', True) self.check_node(node, 'netstat', True)
@unittest.skipUnless(os.name == 'nt', 'requires Windows') @unittest.skipUnless(os.name == 'nt', 'requires Windows')
def test_ipconfig_getnode(self): def test_ipconfig_getnode(self):
node = uuid._ipconfig_getnode() node = self.uuid._ipconfig_getnode()
self.check_node(node, 'ipconfig', True) self.check_node(node, 'ipconfig', True)
@unittest.skipUnless(importable('win32wnet'), 'requires win32wnet') @unittest.skipUnless(importable('win32wnet'), 'requires win32wnet')
@unittest.skipUnless(importable('netbios'), 'requires netbios') @unittest.skipUnless(importable('netbios'), 'requires netbios')
def test_netbios_getnode(self): def test_netbios_getnode(self):
node = uuid._netbios_getnode() node = self.uuid._netbios_getnode()
self.check_node(node, network=True) self.check_node(node, network=True)
def test_random_getnode(self): def test_random_getnode(self):
node = uuid._random_getnode() node = self.uuid._random_getnode()
# Least significant bit of first octet must be set. # Least significant bit of first octet must be set.
self.assertTrue(node & 0x010000000000, '%012x' % node) self.assertTrue(node & 0x010000000000, '%012x' % node)
self.check_node(node) self.check_node(node)
@unittest.skipUnless(os.name == 'posix', 'requires Posix') @unittest.skipUnless(os.name == 'posix', 'requires Posix')
@unittest.skipUnless(importable('ctypes'), 'requires ctypes') def test_unix_getnode(self):
def test_unixdll_getnode(self): if not importable('_uuid') and not importable('ctypes'):
self.skipTest("neither _uuid extension nor ctypes available")
try: # Issues 1481, 3581: _uuid_generate_time() might be None. try: # Issues 1481, 3581: _uuid_generate_time() might be None.
node = uuid._unixdll_getnode() node = self.uuid._unix_getnode()
except TypeError: except TypeError:
self.skipTest('requires uuid_generate_time') self.skipTest('requires uuid_generate_time')
self.check_node(node) self.check_node(node, 'unix')
@unittest.skipUnless(os.name == 'nt', 'requires Windows') @unittest.skipUnless(os.name == 'nt', 'requires Windows')
@unittest.skipUnless(importable('ctypes'), 'requires ctypes') @unittest.skipUnless(importable('ctypes'), 'requires ctypes')
def test_windll_getnode(self): def test_windll_getnode(self):
node = uuid._windll_getnode() node = self.uuid._windll_getnode()
self.check_node(node) self.check_node(node)
class TestInternalsWithoutExtModule(BaseTestInternals, unittest.TestCase):
uuid = py_uuid
@unittest.skipUnless(c_uuid, 'requires the C _uuid module')
class TestInternalsWithExtModule(BaseTestInternals, unittest.TestCase):
uuid = c_uuid
if __name__ == '__main__': if __name__ == '__main__':
unittest.main() unittest.main()

View File

@ -45,6 +45,7 @@ Typical usage:
""" """
import os import os
import sys
from enum import Enum from enum import Enum
@ -475,73 +476,112 @@ def _netbios_getnode():
continue continue
return int.from_bytes(bytes, 'big') return int.from_bytes(bytes, 'big')
# Thanks to Thomas Heller for ctypes and for his help with its use here.
# If ctypes is available, use it to find system routines for UUID generation. _generate_time_safe = _UuidCreate = None
# XXX This makes the module non-thread-safe! _has_uuid_generate_time_safe = None
_uuid_generate_time = _UuidCreate = None
# Import optional C extension at toplevel, to help disabling it when testing
try: try:
import ctypes, ctypes.util import _uuid
import sys except ImportError:
_uuid = None
# The uuid_generate_* routines are provided by libuuid on at least
# Linux and FreeBSD, and provided by libc on Mac OS X.
_libnames = ['uuid']
if not sys.platform.startswith('win'):
_libnames.append('c')
for libname in _libnames:
try:
lib = ctypes.CDLL(ctypes.util.find_library(libname))
except Exception: # pragma: nocover
continue
# Try to find the safe variety first.
if hasattr(lib, 'uuid_generate_time_safe'):
_uuid_generate_time = lib.uuid_generate_time_safe
# int uuid_generate_time_safe(uuid_t out);
break
elif hasattr(lib, 'uuid_generate_time'): # pragma: nocover
_uuid_generate_time = lib.uuid_generate_time
# void uuid_generate_time(uuid_t out);
_uuid_generate_time.restype = None
break
del _libnames
# The uuid_generate_* functions are broken on MacOS X 10.5, as noted def _load_system_functions():
# in issue #8621 the function generates the same sequence of values """
# in the parent process and all children created using fork (unless Try to load platform-specific functions for generating uuids.
# those children use exec as well). """
# global _generate_time_safe, _UuidCreate, _has_uuid_generate_time_safe
# Assume that the uuid_generate functions are broken from 10.5 onward,
# the test can be adjusted when a later version is fixed. if _has_uuid_generate_time_safe is not None:
if sys.platform == 'darwin': return
if int(os.uname().release.split('.')[0]) >= 9:
_uuid_generate_time = None _has_uuid_generate_time_safe = False
if sys.platform == "darwin" and int(os.uname().release.split('.')[0]) < 9:
# The uuid_generate_* functions are broken on MacOS X 10.5, as noted
# in issue #8621 the function generates the same sequence of values
# in the parent process and all children created using fork (unless
# those children use exec as well).
#
# Assume that the uuid_generate functions are broken from 10.5 onward,
# the test can be adjusted when a later version is fixed.
pass
elif _uuid is not None:
_generate_time_safe = _uuid.generate_time_safe
_has_uuid_generate_time_safe = True
return
# On Windows prior to 2000, UuidCreate gives a UUID containing the
# hardware address. On Windows 2000 and later, UuidCreate makes a
# random UUID and UuidCreateSequential gives a UUID containing the
# hardware address. These routines are provided by the RPC runtime.
# NOTE: at least on Tim's WinXP Pro SP2 desktop box, while the last
# 6 bytes returned by UuidCreateSequential are fixed, they don't appear
# to bear any relationship to the MAC address of any network device
# on the box.
try: try:
lib = ctypes.windll.rpcrt4 # If we couldn't find an extension module, try ctypes to find
except: # system routines for UUID generation.
lib = None # Thanks to Thomas Heller for ctypes and for his help with its use here.
_UuidCreate = getattr(lib, 'UuidCreateSequential', import ctypes
getattr(lib, 'UuidCreate', None)) import ctypes.util
except:
pass
def _unixdll_getnode(): # The uuid_generate_* routines are provided by libuuid on at least
"""Get the hardware address on Unix using ctypes.""" # Linux and FreeBSD, and provided by libc on Mac OS X.
_buffer = ctypes.create_string_buffer(16) _libnames = ['uuid']
_uuid_generate_time(_buffer) if not sys.platform.startswith('win'):
return UUID(bytes=bytes_(_buffer.raw)).node _libnames.append('c')
for libname in _libnames:
try:
lib = ctypes.CDLL(ctypes.util.find_library(libname))
except Exception: # pragma: nocover
continue
# Try to find the safe variety first.
if hasattr(lib, 'uuid_generate_time_safe'):
_uuid_generate_time_safe = lib.uuid_generate_time_safe
# int uuid_generate_time_safe(uuid_t out);
def _generate_time_safe():
_buffer = ctypes.create_string_buffer(16)
res = _uuid_generate_time_safe(_buffer)
return bytes(_buffer.raw), res
_has_uuid_generate_time_safe = True
break
elif hasattr(lib, 'uuid_generate_time'): # pragma: nocover
_uuid_generate_time = lib.uuid_generate_time
# void uuid_generate_time(uuid_t out);
_uuid_generate_time.restype = None
def _generate_time_safe():
_buffer = ctypes.create_string_buffer(16)
_uuid_generate_time(_buffer)
return bytes(_buffer.raw), None
break
# On Windows prior to 2000, UuidCreate gives a UUID containing the
# hardware address. On Windows 2000 and later, UuidCreate makes a
# random UUID and UuidCreateSequential gives a UUID containing the
# hardware address. These routines are provided by the RPC runtime.
# NOTE: at least on Tim's WinXP Pro SP2 desktop box, while the last
# 6 bytes returned by UuidCreateSequential are fixed, they don't appear
# to bear any relationship to the MAC address of any network device
# on the box.
try:
lib = ctypes.windll.rpcrt4
except:
lib = None
_UuidCreate = getattr(lib, 'UuidCreateSequential',
getattr(lib, 'UuidCreate', None))
except Exception as exc:
import warnings
warnings.warn(f"Could not find fallback ctypes uuid functions: {exc}",
ImportWarning)
def _unix_getnode():
"""Get the hardware address on Unix using the _uuid extension module
or ctypes."""
_load_system_functions()
uuid_time, _ = _generate_time_safe()
return UUID(bytes=uuid_time).node
def _windll_getnode(): def _windll_getnode():
"""Get the hardware address on Windows using ctypes.""" """Get the hardware address on Windows using ctypes."""
import ctypes
_load_system_functions()
_buffer = ctypes.create_string_buffer(16) _buffer = ctypes.create_string_buffer(16)
if _UuidCreate(_buffer) == 0: if _UuidCreate(_buffer) == 0:
return UUID(bytes=bytes_(_buffer.raw)).node return UUID(bytes=bytes_(_buffer.raw)).node
@ -551,6 +591,7 @@ def _random_getnode():
import random import random
return random.getrandbits(48) | 0x010000000000 return random.getrandbits(48) | 0x010000000000
_node = None _node = None
def getnode(): def getnode():
@ -561,16 +602,14 @@ def getnode():
choose a random 48-bit number with its eighth bit set to 1 as recommended choose a random 48-bit number with its eighth bit set to 1 as recommended
in RFC 4122. in RFC 4122.
""" """
global _node global _node
if _node is not None: if _node is not None:
return _node return _node
import sys
if sys.platform == 'win32': if sys.platform == 'win32':
getters = [_windll_getnode, _netbios_getnode, _ipconfig_getnode] getters = [_windll_getnode, _netbios_getnode, _ipconfig_getnode]
else: else:
getters = [_unixdll_getnode, _ifconfig_getnode, _ip_getnode, getters = [_unix_getnode, _ifconfig_getnode, _ip_getnode,
_arp_getnode, _lanscan_getnode, _netstat_getnode] _arp_getnode, _lanscan_getnode, _netstat_getnode]
for getter in getters + [_random_getnode]: for getter in getters + [_random_getnode]:
@ -581,6 +620,7 @@ def getnode():
if _node is not None: if _node is not None:
return _node return _node
_last_timestamp = None _last_timestamp = None
def uuid1(node=None, clock_seq=None): def uuid1(node=None, clock_seq=None):
@ -591,14 +631,14 @@ def uuid1(node=None, clock_seq=None):
# When the system provides a version-1 UUID generator, use it (but don't # When the system provides a version-1 UUID generator, use it (but don't
# use UuidCreate here because its UUIDs don't conform to RFC 4122). # use UuidCreate here because its UUIDs don't conform to RFC 4122).
if _uuid_generate_time and node is clock_seq is None: _load_system_functions()
_buffer = ctypes.create_string_buffer(16) if _generate_time_safe is not None and node is clock_seq is None:
safely_generated = _uuid_generate_time(_buffer) uuid_time, safely_generated = _generate_time_safe()
try: try:
is_safe = SafeUUID(safely_generated) is_safe = SafeUUID(safely_generated)
except ValueError: except ValueError:
is_safe = SafeUUID.unknown is_safe = SafeUUID.unknown
return UUID(bytes=bytes_(_buffer.raw), is_safe=is_safe) return UUID(bytes=uuid_time, is_safe=is_safe)
global _last_timestamp global _last_timestamp
import time import time

View File

@ -0,0 +1 @@
Avoid ctypes use (if possible) and improve import time for uuid.

35
Modules/_uuidmodule.c Normal file
View File

@ -0,0 +1,35 @@
#define PY_SSIZE_T_CLEAN
#include "Python.h"
#include <uuid/uuid.h>
static PyObject *
py_uuid_generate_time_safe(void)
{
uuid_t out;
int res;
res = uuid_generate_time_safe(out);
return Py_BuildValue("y#i", (const char *) out, sizeof(out), res);
}
static PyMethodDef uuid_methods[] = {
{"generate_time_safe", (PyCFunction) py_uuid_generate_time_safe, METH_NOARGS, NULL},
{NULL, NULL, 0, NULL} /* sentinel */
};
static struct PyModuleDef uuidmodule = {
PyModuleDef_HEAD_INIT,
.m_name = "_uuid",
.m_size = -1,
.m_methods = uuid_methods,
};
PyMODINIT_FUNC
PyInit__uuid(void)
{
assert(sizeof(uuid_t) == 16);
return PyModule_Create(&uuidmodule);
}

View File

@ -1668,6 +1668,20 @@ class PyBuildExt(build_ext):
if '_tkinter' not in [e.name for e in self.extensions]: if '_tkinter' not in [e.name for e in self.extensions]:
missing.append('_tkinter') missing.append('_tkinter')
# Build the _uuid module if possible
uuid_incs = find_file("uuid.h", inc_dirs, ["/usr/include/uuid"])
if uuid_incs:
if self.compiler.find_library_file(lib_dirs, 'uuid'):
uuid_libs = ['uuid']
else:
uuid_libs = []
if uuid_incs:
self.extensions.append(Extension('_uuid', ['_uuidmodule.c'],
libraries=uuid_libs,
include_dirs=uuid_incs))
else:
missing.append('_uuid')
## # Uncomment these lines if you want to play with xxmodule.c ## # Uncomment these lines if you want to play with xxmodule.c
## ext = Extension('xx', ['xxmodule.c']) ## ext = Extension('xx', ['xxmodule.c'])
## self.extensions.append(ext) ## self.extensions.append(ext)