uuid.py
Go to the documentation of this file.
00001 #!/usr/bin/env python
00002 
00003 r"""UUID objects (universally unique identifiers) according to RFC 4122.
00004 
00005 This module provides immutable UUID objects (class UUID) and the functions
00006 uuid1(), uuid3(), uuid4(), uuid5() for generating version 1, 3, 4, and 5
00007 UUIDs as specified in RFC 4122.
00008 
00009 If all you want is a unique ID, you should probably call uuid1() or uuid4().
00010 Note that uuid1() may compromise privacy since it creates a UUID containing
00011 the computer's network address.  uuid4() creates a random UUID.
00012 
00013 Typical usage:
00014 
00015     >>> import uuid
00016 
00017     # make a UUID based on the host ID and current time
00018     >>> uuid.uuid1()
00019     UUID('a8098c1a-f86e-11da-bd1a-00112444be1e')
00020 
00021     # make a UUID using an MD5 hash of a namespace UUID and a name
00022     >>> uuid.uuid3(uuid.NAMESPACE_DNS, 'python.org')
00023     UUID('6fa459ea-ee8a-3ca4-894e-db77e160355e')
00024 
00025     # make a random UUID
00026     >>> uuid.uuid4()
00027     UUID('16fd2706-8baf-433b-82eb-8c7fada847da')
00028 
00029     # make a UUID using a SHA-1 hash of a namespace UUID and a name
00030     >>> uuid.uuid5(uuid.NAMESPACE_DNS, 'python.org')
00031     UUID('886313e1-3b8a-5372-9b90-0c9aee199e5d')
00032 
00033     # make a UUID from a string of hex digits (braces and hyphens ignored)
00034     >>> x = uuid.UUID('{00010203-0405-0607-0809-0a0b0c0d0e0f}')
00035 
00036     # convert a UUID to a string of hex digits in standard form
00037     >>> str(x)
00038     '00010203-0405-0607-0809-0a0b0c0d0e0f'
00039 
00040     # get the raw 16 bytes of the UUID
00041     >>> x.bytes
00042     '\x00\x01\x02\x03\x04\x05\x06\x07\x08\t\n\x0b\x0c\r\x0e\x0f'
00043 
00044     # make a UUID from a 16-byte string
00045     >>> uuid.UUID(bytes=x.bytes)
00046     UUID('00010203-0405-0607-0809-0a0b0c0d0e0f')
00047 
00048 This module works with Python 2.3 or higher."""
00049 
00050 __author__ = 'Ka-Ping Yee <ping@zesty.ca>'
00051 __date__ = '$Date: 2007-07-20 15:38:13 $'.split()[1].replace('/', '-')
00052 __version__ = '$Revision: 1.1.2.1 $'.split()[1]
00053 
00054 RESERVED_NCS, RFC_4122, RESERVED_MICROSOFT, RESERVED_FUTURE = [
00055     'reserved for NCS compatibility', 'specified in RFC 4122',
00056     'reserved for Microsoft compatibility', 'reserved for future definition']
00057 
00058 class UUID(object):
00059     """Instances of the UUID class represent UUIDs as specified in RFC 4122.
00060     UUID objects are immutable, hashable, and usable as dictionary keys.
00061     Converting a UUID to a string with str() yields something in the form
00062     '12345678-1234-1234-1234-123456789abc'.  The UUID constructor accepts
00063     four possible forms: a similar string of hexadecimal digits, or a
00064     string of 16 raw bytes as an argument named 'bytes', or a tuple of
00065     six integer fields (with 32-bit, 16-bit, 16-bit, 8-bit, 8-bit, and
00066     48-bit values respectively) as an argument named 'fields', or a single
00067     128-bit integer as an argument named 'int'.
00068     
00069     UUIDs have these read-only attributes:
00070 
00071         bytes       the UUID as a 16-byte string
00072 
00073         fields      a tuple of the six integer fields of the UUID,
00074                     which are also available as six individual attributes
00075                     and two derived attributes:
00076 
00077             time_low                the first 32 bits of the UUID
00078             time_mid                the next 16 bits of the UUID
00079             time_hi_version         the next 16 bits of the UUID
00080             clock_seq_hi_variant    the next 8 bits of the UUID
00081             clock_seq_low           the next 8 bits of the UUID
00082             node                    the last 48 bits of the UUID
00083 
00084             time                    the 60-bit timestamp
00085             clock_seq               the 14-bit sequence number
00086 
00087         hex         the UUID as a 32-character hexadecimal string
00088 
00089         int         the UUID as a 128-bit integer
00090 
00091         urn         the UUID as a URN as specified in RFC 4122
00092 
00093         variant     the UUID variant (one of the constants RESERVED_NCS,
00094                     RFC_4122, RESERVED_MICROSOFT, or RESERVED_FUTURE)
00095 
00096         version     the UUID version number (1 through 5, meaningful only
00097                     when the variant is RFC_4122)
00098     """
00099 
00100     def __init__(self, hex=None, bytes=None, fields=None, int=None,
00101                        version=None):
00102         r"""Create a UUID from either a string of 32 hexadecimal digits,
00103         a string of 16 bytes as the 'bytes' argument, a tuple of six
00104         integers (32-bit time_low, 16-bit time_mid, 16-bit time_hi_version,
00105         8-bit clock_seq_hi_variant, 8-bit clock_seq_low, 48-bit node) as
00106         the 'fields' argument, or a single 128-bit integer as the 'int'
00107         argument.  When a string of hex digits is given, curly braces,
00108         hyphens, and a URN prefix are all optional.  For example, these
00109         expressions all yield the same UUID:
00110 
00111         UUID('{12345678-1234-5678-1234-567812345678}')
00112         UUID('12345678123456781234567812345678')
00113         UUID('urn:uuid:12345678-1234-5678-1234-567812345678')
00114         UUID(bytes='\x12\x34\x56\x78'*4)
00115         UUID(fields=(0x12345678, 0x1234, 0x5678, 0x12, 0x34, 0x567812345678))
00116         UUID(int=0x12345678123456781234567812345678)
00117 
00118         Exactly one of 'hex', 'bytes', 'fields', or 'int' must be given.
00119         The 'version' argument is optional; if given, the resulting UUID
00120         will have its variant and version number set according to RFC 4122,
00121         overriding bits in the given 'hex', 'bytes', 'fields', or 'int'.
00122         """
00123 
00124         if [hex, bytes, fields, int].count(None) != 3:
00125             raise TypeError('need just one of hex, bytes, fields, or int')
00126         if hex is not None:
00127             hex = hex.replace('urn:', '').replace('uuid:', '')
00128             hex = hex.strip('{}').replace('-', '')
00129             if len(hex) != 32:
00130                 raise ValueError('badly formed hexadecimal UUID string')
00131             int = long(hex, 16)
00132         if bytes is not None:
00133             if len(bytes) != 16:
00134                 raise ValueError('bytes is not a 16-char string')
00135             int = long(('%02x'*16) % tuple(map(ord, bytes)), 16)
00136         if fields is not None:
00137             if len(fields) != 6:
00138                 raise ValueError('fields is not a 6-tuple')
00139             (time_low, time_mid, time_hi_version,
00140              clock_seq_hi_variant, clock_seq_low, node) = fields
00141             if not 0 <= time_low < 1<<32L:
00142                 raise ValueError('field 1 out of range (need a 32-bit value)')
00143             if not 0 <= time_mid < 1<<16L:
00144                 raise ValueError('field 2 out of range (need a 16-bit value)')
00145             if not 0 <= time_hi_version < 1<<16L:
00146                 raise ValueError('field 3 out of range (need a 16-bit value)')
00147             if not 0 <= clock_seq_hi_variant < 1<<8L:
00148                 raise ValueError('field 4 out of range (need an 8-bit value)')
00149             if not 0 <= clock_seq_low < 1<<8L:
00150                 raise ValueError('field 5 out of range (need an 8-bit value)')
00151             if not 0 <= node < 1<<48L:
00152                 raise ValueError('field 6 out of range (need a 48-bit value)')
00153             clock_seq = (clock_seq_hi_variant << 8L) | clock_seq_low
00154             int = ((time_low << 96L) | (time_mid << 80L) |
00155                    (time_hi_version << 64L) | (clock_seq << 48L) | node)
00156         if int is not None:
00157             if not 0 <= int < 1<<128L:
00158                 raise ValueError('int is out of range (need a 128-bit value)')
00159         if version is not None:
00160             if not 1 <= version <= 5:
00161                 raise ValueError('illegal version number')
00162             # Set the variant to RFC 4122.
00163             int &= ~(0xc000 << 48L)
00164             int |= 0x8000 << 48L
00165             # Set the version number.
00166             int &= ~(0xf000 << 64L)
00167             int |= version << 76L
00168         self.__dict__['int'] = int
00169 
00170     def __cmp__(self, other):
00171         if isinstance(other, UUID):
00172             return cmp(self.int, other.int)
00173         return NotImplemented
00174 
00175     def __hash__(self):
00176         return hash(self.int)
00177 
00178     def __int__(self):
00179         return self.int
00180 
00181     def __repr__(self):
00182         return 'UUID(%r)' % str(self)
00183 
00184     def __setattr__(self, name, value):
00185         raise TypeError('UUID objects are immutable')
00186 
00187     def __str__(self):
00188         hex = '%032x' % self.int
00189         return '%s-%s-%s-%s-%s' % (
00190             hex[:8], hex[8:12], hex[12:16], hex[16:20], hex[20:])
00191 
00192     def get_bytes(self):
00193         bytes = ''
00194         for shift in range(0, 128, 8):
00195             bytes = chr((self.int >> shift) & 0xff) + bytes
00196         return bytes
00197 
00198     bytes = property(get_bytes)
00199 
00200     def get_fields(self):
00201         return (self.time_low, self.time_mid, self.time_hi_version,
00202                 self.clock_seq_hi_variant, self.clock_seq_low, self.node)
00203 
00204     fields = property(get_fields)
00205 
00206     def get_time_low(self):
00207         return self.int >> 96L
00208    
00209     time_low = property(get_time_low)
00210 
00211     def get_time_mid(self):
00212         return (self.int >> 80L) & 0xffff
00213 
00214     time_mid = property(get_time_mid)
00215 
00216     def get_time_hi_version(self):
00217         return (self.int >> 64L) & 0xffff
00218     
00219     time_hi_version = property(get_time_hi_version)
00220 
00221     def get_clock_seq_hi_variant(self):
00222         return (self.int >> 56L) & 0xff
00223 
00224     clock_seq_hi_variant = property(get_clock_seq_hi_variant)
00225     
00226     def get_clock_seq_low(self):
00227         return (self.int >> 48L) & 0xff
00228 
00229     clock_seq_low = property(get_clock_seq_low)
00230 
00231     def get_time(self):
00232         return (((self.time_hi_version & 0x0fffL) << 48L) |
00233                 (self.time_mid << 32L) | self.time_low)
00234 
00235     time = property(get_time)
00236 
00237     def get_clock_seq(self):
00238         return (((self.clock_seq_hi_variant & 0x3fL) << 8L) |
00239                 self.clock_seq_low)
00240 
00241     clock_seq = property(get_clock_seq)
00242     
00243     def get_node(self):
00244         return self.int & 0xffffffffffff
00245 
00246     node = property(get_node)
00247 
00248     def get_hex(self):
00249         return '%032x' % self.int
00250 
00251     hex = property(get_hex)
00252 
00253     def get_urn(self):
00254         return 'urn:uuid:' + str(self)
00255 
00256     urn = property(get_urn)
00257 
00258     def get_variant(self):
00259         if not self.int & (0x8000 << 48L):
00260             return RESERVED_NCS
00261         elif not self.int & (0x4000 << 48L):
00262             return RFC_4122
00263         elif not self.int & (0x2000 << 48L):
00264             return RESERVED_MICROSOFT
00265         else:
00266             return RESERVED_FUTURE
00267 
00268     variant = property(get_variant)
00269 
00270     def get_version(self):
00271         # The version bits are only meaningful for RFC 4122 UUIDs.
00272         if self.variant == RFC_4122:
00273             return int((self.int >> 76L) & 0xf)
00274 
00275     version = property(get_version)
00276 
00277 def _ifconfig_getnode():
00278     """Get the hardware address on Unix by running ifconfig."""
00279     import os
00280     for dir in ['', '/sbin/', '/usr/sbin']:
00281         try:
00282             pipe = os.popen(os.path.join(dir, 'ifconfig'))
00283         except IOError:
00284             continue
00285         for line in pipe:
00286             words = line.lower().split()
00287             for i in range(len(words)):
00288                 if words[i] in ['hwaddr', 'ether']:
00289                     return int(words[i + 1].replace(':', ''), 16)
00290 
00291 def _ipconfig_getnode():
00292     """Get the hardware address on Windows by running ipconfig.exe."""
00293     import os, re
00294     dirs = ['', r'c:\windows\system32', r'c:\winnt\system32']
00295     try:
00296         import ctypes
00297         buffer = ctypes.create_string_buffer(300)
00298         ctypes.windll.kernel32.GetSystemDirectoryA(buffer, 300)
00299         dirs.insert(0, buffer.value.decode('mbcs'))
00300     except:
00301         pass
00302     for dir in dirs:
00303         try:
00304             pipe = os.popen(os.path.join(dir, 'ipconfig') + ' /all')
00305         except IOError:
00306             continue
00307         for line in pipe:
00308             value = line.split(':')[-1].strip().lower()
00309             if re.match('([0-9a-f][0-9a-f]-){5}[0-9a-f][0-9a-f]', value):
00310                 return int(value.replace('-', ''), 16)
00311 
00312 def _netbios_getnode():
00313     """Get the hardware address on Windows using NetBIOS calls.
00314     See http://support.microsoft.com/kb/118623 for details."""
00315     import win32wnet, netbios
00316     ncb = netbios.NCB()
00317     ncb.Command = netbios.NCBENUM
00318     ncb.Buffer = adapters = netbios.LANA_ENUM()
00319     adapters._pack()
00320     if win32wnet.Netbios(ncb) != 0:
00321         return
00322     adapters._unpack()
00323     for i in range(adapters.length):
00324         ncb.Reset()
00325         ncb.Command = netbios.NCBRESET
00326         ncb.Lana_num = ord(adapters.lana[i])
00327         if win32wnet.Netbios(ncb) != 0:
00328             continue
00329         ncb.Reset()
00330         ncb.Command = netbios.NCBASTAT
00331         ncb.Lana_num = ord(adapters.lana[i])
00332         ncb.Callname = '*'.ljust(16)
00333         ncb.Buffer = status = netbios.ADAPTER_STATUS()
00334         if win32wnet.Netbios(ncb) != 0:
00335             continue
00336         status._unpack()
00337         bytes = map(ord, status.adapter_address)
00338         return ((bytes[0]<<40L) + (bytes[1]<<32L) + (bytes[2]<<24L) +
00339                 (bytes[3]<<16L) + (bytes[4]<<8L) + bytes[5])
00340 
00341 # Thanks to Thomas Heller for ctypes and for his help with its use here.
00342 
00343 # If ctypes is available, use it to find system routines for UUID generation.
00344 _uuid_generate_random = _uuid_generate_time = _UuidCreate = None
00345 try:
00346     import ctypes, ctypes.util
00347     _buffer = ctypes.create_string_buffer(16)
00348 
00349     # The uuid_generate_* routines are provided by libuuid on at least
00350     # Linux and FreeBSD, and provided by libc on Mac OS X.
00351     for libname in ['uuid', 'c']:
00352         try:
00353             lib = ctypes.CDLL(ctypes.util.find_library(libname))
00354         except:
00355             continue
00356         if hasattr(lib, 'uuid_generate_random'):
00357             _uuid_generate_random = lib.uuid_generate_random
00358         if hasattr(lib, 'uuid_generate_time'):
00359             _uuid_generate_time = lib.uuid_generate_time
00360 
00361     # On Windows prior to 2000, UuidCreate gives a UUID containing the
00362     # hardware address.  On Windows 2000 and later, UuidCreate makes a
00363     # random UUID and UuidCreateSequential gives a UUID containing the
00364     # hardware address.  These routines are provided by the RPC runtime.
00365     try:
00366         lib = ctypes.windll.rpcrt4
00367     except:
00368         lib = None
00369     _UuidCreate = getattr(lib, 'UuidCreateSequential',
00370                           getattr(lib, 'UuidCreate', None))
00371 except:
00372     pass
00373 
00374 def _unixdll_getnode():
00375     """Get the hardware address on Unix using ctypes."""
00376     _uuid_generate_time(_buffer)
00377     return UUID(bytes=_buffer.raw).node
00378 
00379 def _windll_getnode():
00380     """Get the hardware address on Windows using ctypes."""
00381     if _UuidCreate(_buffer) == 0:
00382         return UUID(bytes=_buffer.raw).node
00383 
00384 def _random_getnode():
00385     """Get a random node ID, with eighth bit set as suggested by RFC 4122."""
00386     import random
00387     return random.randrange(0, 1<<48L) | 0x010000000000L
00388 
00389 _node = None
00390 
00391 def getnode():
00392     """Get the hardware address as a 48-bit integer.  The first time this
00393     runs, it may launch a separate program, which could be quite slow.  If
00394     all attempts to obtain the hardware address fail, we choose a random
00395     48-bit number with its eighth bit set to 1 as recommended in RFC 4122."""
00396 
00397     global _node
00398     if _node is not None:
00399         return _node
00400 
00401     import sys
00402     if sys.platform == 'win32':
00403         getters = [_windll_getnode, _netbios_getnode, _ipconfig_getnode]
00404     else:
00405         getters = [_unixdll_getnode, _ifconfig_getnode]
00406 
00407     for getter in getters + [_random_getnode]:
00408         try:
00409             _node = getter()
00410         except:
00411             continue
00412         if _node is not None:
00413             return _node
00414 
00415 def uuid1(node=None, clock_seq=None):
00416     """Generate a UUID from a host ID, sequence number, and the current time.
00417     If 'node' is not given, getnode() is used to obtain the hardware
00418     address.  If 'clock_seq' is given, it is used as the sequence number;
00419     otherwise a random 14-bit sequence number is chosen."""
00420 
00421     # When the system provides a version-1 UUID generator, use it (but don't
00422     # use UuidCreate here because its UUIDs don't conform to RFC 4122).
00423     if _uuid_generate_time and node is clock_seq is None:
00424         _uuid_generate_time(_buffer)
00425         return UUID(bytes=_buffer.raw)
00426 
00427     import time
00428     nanoseconds = int(time.time() * 1e9)
00429     # 0x01b21dd213814000 is the number of 100-ns intervals between the
00430     # UUID epoch 1582-10-15 00:00:00 and the Unix epoch 1970-01-01 00:00:00.
00431     timestamp = int(nanoseconds/100) + 0x01b21dd213814000L
00432     if clock_seq is None:
00433         import random
00434         clock_seq = random.randrange(1<<14L) # instead of stable storage
00435     time_low = timestamp & 0xffffffffL
00436     time_mid = (timestamp >> 32L) & 0xffffL
00437     time_hi_version = (timestamp >> 48L) & 0x0fffL
00438     clock_seq_low = clock_seq & 0xffL
00439     clock_seq_hi_variant = (clock_seq >> 8L) & 0x3fL
00440     if node is None:
00441         node = getnode()
00442     return UUID(fields=(time_low, time_mid, time_hi_version,
00443                         clock_seq_hi_variant, clock_seq_low, node), version=1)
00444 
00445 def uuid3(namespace, name):
00446     """Generate a UUID from the MD5 hash of a namespace UUID and a name."""
00447     import md5
00448     hash = md5.md5(namespace.bytes + name).digest()
00449     return UUID(bytes=hash[:16], version=3)
00450 
00451 def uuid4():
00452     """Generate a random UUID."""
00453 
00454     # When the system provides a version-4 UUID generator, use it.
00455     if _uuid_generate_random:
00456         _uuid_generate_random(_buffer)
00457         return UUID(bytes=_buffer.raw)
00458 
00459     # Otherwise, get randomness from urandom or the 'random' module.
00460     try:
00461         import os
00462         return UUID(bytes=os.urandom(16), version=4)
00463     except:
00464         import random
00465         bytes = [chr(random.randrange(256)) for i in range(16)]
00466         return UUID(bytes=bytes, version=4)
00467 
00468 def uuid5(namespace, name):
00469     """Generate a UUID from the SHA-1 hash of a namespace UUID and a name."""
00470     import sha
00471     hash = sha.sha(namespace.bytes + name).digest()
00472     return UUID(bytes=hash[:16], version=5)
00473 
00474 # The following standard UUIDs are for use with uuid3() or uuid5().
00475 
00476 NAMESPACE_DNS = UUID('6ba7b810-9dad-11d1-80b4-00c04fd430c8')
00477 NAMESPACE_URL = UUID('6ba7b811-9dad-11d1-80b4-00c04fd430c8')
00478 NAMESPACE_OID = UUID('6ba7b812-9dad-11d1-80b4-00c04fd430c8')
00479 NAMESPACE_X500 = UUID('6ba7b814-9dad-11d1-80b4-00c04fd430c8')


openrtm_aist_python
Author(s): Shinji Kurihara
autogenerated on Thu Aug 27 2015 14:17:28