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


openrtm_aist
Author(s): Noriaki Ando
autogenerated on Thu Aug 27 2015 14:16:39