~ubuntu-branches/ubuntu/precise/emesene/precise-201203200543

« back to all changes in this revision

Viewing changes to emesenelib/uuid.py

  • Committer: Bazaar Package Importer
  • Author(s): Emilio Pozuelo Monfort
  • Date: 2009-10-20 16:48:42 UTC
  • mfrom: (1.1.4 upstream) (5.2.4 sid)
  • Revision ID: james.westby@ubuntu.com-20091020164842-p6r1w6wr9x6gkk08
Tags: 1.5.1-1
* New upstream release.
  - debian/rules,
    debian/copyright:
    + uuid.py is not shipped upstream anymore, don't remove it it rules
      and don't mention it in copyright.
* debian/bin/emesene,
  debian/rules,
  debian/links:
  - Don't install a wrapper script in /usr/bin, install the upstream
    script together with the python modules and symlink it to /usr/bin
    instead.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# -*- coding: utf-8 -*-
2
 
 
3
 
r"""UUID objects (universally unique identifiers) according to RFC 4122.
4
 
 
5
 
This module provides immutable UUID objects (class UUID) and the functions
6
 
uuid1(), uuid3(), uuid4(), uuid5() for generating version 1, 3, 4, and 5
7
 
UUIDs as specified in RFC 4122.
8
 
 
9
 
If all you want is a unique ID, you should probably call uuid1() or uuid4().
10
 
Note that uuid1() may compromise privacy since it creates a UUID containing
11
 
the computer's network address.  uuid4() creates a random UUID.
12
 
 
13
 
Typical usage:
14
 
 
15
 
    >>> import uuid
16
 
 
17
 
    # make a UUID based on the host ID and current time
18
 
    >>> uuid.uuid1()
19
 
    UUID('a8098c1a-f86e-11da-bd1a-00112444be1e')
20
 
 
21
 
    # make a UUID using an MD5 hash of a namespace UUID and a name
22
 
    >>> uuid.uuid3(uuid.NAMESPACE_DNS, 'python.org')
23
 
    UUID('6fa459ea-ee8a-3ca4-894e-db77e160355e')
24
 
 
25
 
    # make a random UUID
26
 
    >>> uuid.uuid4()
27
 
    UUID('16fd2706-8baf-433b-82eb-8c7fada847da')
28
 
 
29
 
    # make a UUID using a SHA-1 hash of a namespace UUID and a name
30
 
    >>> uuid.uuid5(uuid.NAMESPACE_DNS, 'python.org')
31
 
    UUID('886313e1-3b8a-5372-9b90-0c9aee199e5d')
32
 
 
33
 
    # make a UUID from a string of hex digits (braces and hyphens ignored)
34
 
    >>> x = uuid.UUID('{00010203-0405-0607-0809-0a0b0c0d0e0f}')
35
 
 
36
 
    # convert a UUID to a string of hex digits in standard form
37
 
    >>> str(x)
38
 
    '00010203-0405-0607-0809-0a0b0c0d0e0f'
39
 
 
40
 
    # get the raw 16 bytes of the UUID
41
 
    >>> x.bytes
42
 
    '\x00\x01\x02\x03\x04\x05\x06\x07\x08\t\n\x0b\x0c\r\x0e\x0f'
43
 
 
44
 
    # make a UUID from a 16-byte string
45
 
    >>> uuid.UUID(bytes=x.bytes)
46
 
    UUID('00010203-0405-0607-0809-0a0b0c0d0e0f')
47
 
 
48
 
This module works with Python 2.3 or higher."""
49
 
 
50
 
__author__ = 'Ka-Ping Yee <ping@zesty.ca>'
51
 
__date__ = '$Date: 2006/06/12 23:15:40 $'.split()[1].replace('/', '-')
52
 
__version__ = '$Revision: 1.30 $'.split()[1]
53
 
 
54
 
RESERVED_NCS, RFC_4122, RESERVED_MICROSOFT, RESERVED_FUTURE = [
55
 
    'reserved for NCS compatibility', 'specified in RFC 4122',
56
 
    'reserved for Microsoft compatibility', 'reserved for future definition']
57
 
 
58
 
class UUID(object):
59
 
    """Instances of the UUID class represent UUIDs as specified in RFC 4122.
60
 
    UUID objects are immutable, hashable, and usable as dictionary keys.
61
 
    Converting a UUID to a string with str() yields something in the form
62
 
    '12345678-1234-1234-1234-123456789abc'.  The UUID constructor accepts
63
 
    four possible forms: a similar string of hexadecimal digits, or a
64
 
    string of 16 raw bytes as an argument named 'bytes', or a tuple of
65
 
    six integer fields (with 32-bit, 16-bit, 16-bit, 8-bit, 8-bit, and
66
 
    48-bit values respectively) as an argument named 'fields', or a single
67
 
    128-bit integer as an argument named 'int'.
68
 
    
69
 
    UUIDs have these read-only attributes:
70
 
 
71
 
        bytes       the UUID as a 16-byte string
72
 
 
73
 
        fields      a tuple of the six integer fields of the UUID,
74
 
                    which are also available as six individual attributes
75
 
                    and two derived attributes:
76
 
 
77
 
            time_low                the first 32 bits of the UUID
78
 
            time_mid                the next 16 bits of the UUID
79
 
            time_hi_version         the next 16 bits of the UUID
80
 
            clock_seq_hi_variant    the next 8 bits of the UUID
81
 
            clock_seq_low           the next 8 bits of the UUID
82
 
            node                    the last 48 bits of the UUID
83
 
 
84
 
            time                    the 60-bit timestamp
85
 
            clock_seq               the 14-bit sequence number
86
 
 
87
 
        hex         the UUID as a 32-character hexadecimal string
88
 
 
89
 
        int         the UUID as a 128-bit integer
90
 
 
91
 
        urn         the UUID as a URN as specified in RFC 4122
92
 
 
93
 
        variant     the UUID variant (one of the constants RESERVED_NCS,
94
 
                    RFC_4122, RESERVED_MICROSOFT, or RESERVED_FUTURE)
95
 
 
96
 
        version     the UUID version number (1 through 5, meaningful only
97
 
                    when the variant is RFC_4122)
98
 
    """
99
 
 
100
 
    def __init__(self, hex=None, bytes=None, fields=None, int=None,
101
 
                       version=None):
102
 
        r"""Create a UUID from either a string of 32 hexadecimal digits,
103
 
        a string of 16 bytes as the 'bytes' argument, a tuple of six
104
 
        integers (32-bit time_low, 16-bit time_mid, 16-bit time_hi_version,
105
 
        8-bit clock_seq_hi_variant, 8-bit clock_seq_low, 48-bit node) as
106
 
        the 'fields' argument, or a single 128-bit integer as the 'int'
107
 
        argument.  When a string of hex digits is given, curly braces,
108
 
        hyphens, and a URN prefix are all optional.  For example, these
109
 
        expressions all yield the same UUID:
110
 
 
111
 
        UUID('{12345678-1234-5678-1234-567812345678}')
112
 
        UUID('12345678123456781234567812345678')
113
 
        UUID('urn:uuid:12345678-1234-5678-1234-567812345678')
114
 
        UUID(bytes='\x12\x34\x56\x78'*4)
115
 
        UUID(fields=(0x12345678, 0x1234, 0x5678, 0x12, 0x34, 0x567812345678))
116
 
        UUID(int=0x12345678123456781234567812345678)
117
 
 
118
 
        Exactly one of 'hex', 'bytes', 'fields', or 'int' must be given.
119
 
        The 'version' argument is optional; if given, the resulting UUID
120
 
        will have its variant and version number set according to RFC 4122,
121
 
        overriding bits in the given 'hex', 'bytes', 'fields', or 'int'.
122
 
        """
123
 
 
124
 
        if [hex, bytes, fields, int].count(None) != 3:
125
 
            raise TypeError('need just one of hex, bytes, fields, or int')
126
 
        if hex is not None:
127
 
            hex = hex.replace('urn:', '').replace('uuid:', '')
128
 
            hex = hex.strip('{}').replace('-', '')
129
 
            if len(hex) != 32:
130
 
                raise ValueError('badly formed hexadecimal UUID string')
131
 
            int = long(hex, 16)
132
 
        if bytes is not None:
133
 
            if len(bytes) != 16:
134
 
                raise ValueError('bytes is not a 16-char string')
135
 
            int = long(('%02x'*16) % tuple(map(ord, bytes)), 16)
136
 
        if fields is not None:
137
 
            if len(fields) != 6:
138
 
                raise ValueError('fields is not a 6-tuple')
139
 
            (time_low, time_mid, time_hi_version,
140
 
             clock_seq_hi_variant, clock_seq_low, node) = fields
141
 
            if not 0 <= time_low < 1<<32L:
142
 
                raise ValueError('field 1 out of range (need a 32-bit value)')
143
 
            if not 0 <= time_mid < 1<<16L:
144
 
                raise ValueError('field 2 out of range (need a 16-bit value)')
145
 
            if not 0 <= time_hi_version < 1<<16L:
146
 
                raise ValueError('field 3 out of range (need a 16-bit value)')
147
 
            if not 0 <= clock_seq_hi_variant < 1<<8L:
148
 
                raise ValueError('field 4 out of range (need an 8-bit value)')
149
 
            if not 0 <= clock_seq_low < 1<<8L:
150
 
                raise ValueError('field 5 out of range (need an 8-bit value)')
151
 
            if not 0 <= node < 1<<48L:
152
 
                raise ValueError('field 6 out of range (need a 48-bit value)')
153
 
            clock_seq = (clock_seq_hi_variant << 8L) | clock_seq_low
154
 
            int = ((time_low << 96L) | (time_mid << 80L) |
155
 
                   (time_hi_version << 64L) | (clock_seq << 48L) | node)
156
 
        if int is not None:
157
 
            if not 0 <= int < 1<<128L:
158
 
                raise ValueError('int is out of range (need a 128-bit value)')
159
 
        if version is not None:
160
 
            if not 1 <= version <= 5:
161
 
                raise ValueError('illegal version number')
162
 
            # Set the variant to RFC 4122.
163
 
            int &= ~(0xc000 << 48L)
164
 
            int |= 0x8000 << 48L
165
 
            # Set the version number.
166
 
            int &= ~(0xf000 << 64L)
167
 
            int |= version << 76L
168
 
        self.__dict__['int'] = int
169
 
 
170
 
    def __cmp__(self, other):
171
 
        if isinstance(other, UUID):
172
 
            return cmp(self.int, other.int)
173
 
        return NotImplemented
174
 
 
175
 
    def __hash__(self):
176
 
        return hash(self.int)
177
 
 
178
 
    def __int__(self):
179
 
        return self.int
180
 
 
181
 
    def __repr__(self):
182
 
        return 'UUID(%r)' % str(self)
183
 
 
184
 
    def __setattr__(self, name, value):
185
 
        raise TypeError('UUID objects are immutable')
186
 
 
187
 
    def __str__(self):
188
 
        hex = '%032x' % self.int
189
 
        return '%s-%s-%s-%s-%s' % (
190
 
            hex[:8], hex[8:12], hex[12:16], hex[16:20], hex[20:])
191
 
 
192
 
    def get_bytes(self):
193
 
        bytes = ''
194
 
        for shift in range(0, 128, 8):
195
 
            bytes = chr((self.int >> shift) & 0xff) + bytes
196
 
        return bytes
197
 
 
198
 
    bytes = property(get_bytes)
199
 
 
200
 
    def get_fields(self):
201
 
        return (self.time_low, self.time_mid, self.time_hi_version,
202
 
                self.clock_seq_hi_variant, self.clock_seq_low, self.node)
203
 
 
204
 
    fields = property(get_fields)
205
 
 
206
 
    def get_time_low(self):
207
 
        return self.int >> 96L
208
 
   
209
 
    time_low = property(get_time_low)
210
 
 
211
 
    def get_time_mid(self):
212
 
        return (self.int >> 80L) & 0xffff
213
 
 
214
 
    time_mid = property(get_time_mid)
215
 
 
216
 
    def get_time_hi_version(self):
217
 
        return (self.int >> 64L) & 0xffff
218
 
    
219
 
    time_hi_version = property(get_time_hi_version)
220
 
 
221
 
    def get_clock_seq_hi_variant(self):
222
 
        return (self.int >> 56L) & 0xff
223
 
 
224
 
    clock_seq_hi_variant = property(get_clock_seq_hi_variant)
225
 
    
226
 
    def get_clock_seq_low(self):
227
 
        return (self.int >> 48L) & 0xff
228
 
 
229
 
    clock_seq_low = property(get_clock_seq_low)
230
 
 
231
 
    def get_time(self):
232
 
        return (((self.time_hi_version & 0x0fffL) << 48L) |
233
 
                (self.time_mid << 32L) | self.time_low)
234
 
 
235
 
    time = property(get_time)
236
 
 
237
 
    def get_clock_seq(self):
238
 
        return (((self.clock_seq_hi_variant & 0x3fL) << 8L) |
239
 
                self.clock_seq_low)
240
 
 
241
 
    clock_seq = property(get_clock_seq)
242
 
    
243
 
    def get_node(self):
244
 
        return self.int & 0xffffffffffff
245
 
 
246
 
    node = property(get_node)
247
 
 
248
 
    def get_hex(self):
249
 
        return '%032x' % self.int
250
 
 
251
 
    hex = property(get_hex)
252
 
 
253
 
    def get_urn(self):
254
 
        return 'urn:uuid:' + str(self)
255
 
 
256
 
    urn = property(get_urn)
257
 
 
258
 
    def get_variant(self):
259
 
        if not self.int & (0x8000 << 48L):
260
 
            return RESERVED_NCS
261
 
        elif not self.int & (0x4000 << 48L):
262
 
            return RFC_4122
263
 
        elif not self.int & (0x2000 << 48L):
264
 
            return RESERVED_MICROSOFT
265
 
        else:
266
 
            return RESERVED_FUTURE
267
 
 
268
 
    variant = property(get_variant)
269
 
 
270
 
    def get_version(self):
271
 
        # The version bits are only meaningful for RFC 4122 UUIDs.
272
 
        if self.variant == RFC_4122:
273
 
            return int((self.int >> 76L) & 0xf)
274
 
 
275
 
    version = property(get_version)
276
 
 
277
 
def _ifconfig_getnode():
278
 
    """Get the hardware address on Unix by running ifconfig."""
279
 
    import os
280
 
    for dir in ['', '/sbin/', '/usr/sbin']:
281
 
        try:
282
 
            pipe = os.popen(os.path.join(dir, 'ifconfig'))
283
 
        except IOError:
284
 
            continue
285
 
        for line in pipe:
286
 
            words = line.lower().split()
287
 
            for i in range(len(words)):
288
 
                if words[i] in ['hwaddr', 'ether']:
289
 
                    return int(words[i + 1].replace(':', ''), 16)
290
 
 
291
 
def _ipconfig_getnode():
292
 
    """Get the hardware address on Windows by running ipconfig.exe."""
293
 
    import os, re
294
 
    dirs = ['', r'c:\windows\system32', r'c:\winnt\system32']
295
 
    try:
296
 
        import ctypes
297
 
        buffer = ctypes.create_string_buffer(300)
298
 
        ctypes.windll.kernel32.GetSystemDirectoryA(buffer, 300)
299
 
        dirs.insert(0, buffer.value.decode('mbcs'))
300
 
    except:
301
 
        pass
302
 
    for dir in dirs:
303
 
        try:
304
 
            pipe = os.popen(os.path.join(dir, 'ipconfig') + ' /all')
305
 
        except IOError:
306
 
            continue
307
 
        for line in pipe:
308
 
            value = line.split(':')[-1].strip().lower()
309
 
            if re.match('([0-9a-f][0-9a-f]-){5}[0-9a-f][0-9a-f]', value):
310
 
                return int(value.replace('-', ''), 16)
311
 
 
312
 
def _netbios_getnode():
313
 
    """Get the hardware address on Windows using NetBIOS calls.
314
 
    See http://support.microsoft.com/kb/118623 for details."""
315
 
    import win32wnet, netbios
316
 
    ncb = netbios.NCB()
317
 
    ncb.Command = netbios.NCBENUM
318
 
    ncb.Buffer = adapters = netbios.LANA_ENUM()
319
 
    adapters._pack()
320
 
    if win32wnet.Netbios(ncb) != 0:
321
 
        return
322
 
    adapters._unpack()
323
 
    for i in range(adapters.length):
324
 
        ncb.Reset()
325
 
        ncb.Command = netbios.NCBRESET
326
 
        ncb.Lana_num = ord(adapters.lana[i])
327
 
        if win32wnet.Netbios(ncb) != 0:
328
 
            continue
329
 
        ncb.Reset()
330
 
        ncb.Command = netbios.NCBASTAT
331
 
        ncb.Lana_num = ord(adapters.lana[i])
332
 
        ncb.Callname = '*'.ljust(16)
333
 
        ncb.Buffer = status = netbios.ADAPTER_STATUS()
334
 
        if win32wnet.Netbios(ncb) != 0:
335
 
            continue
336
 
        status._unpack()
337
 
        bytes = map(ord, status.adapter_address)
338
 
        return ((bytes[0]<<40L) + (bytes[1]<<32L) + (bytes[2]<<24L) +
339
 
                (bytes[3]<<16L) + (bytes[4]<<8L) + bytes[5])
340
 
 
341
 
# Thanks to Thomas Heller for ctypes and for his help with its use here.
342
 
 
343
 
# If ctypes is available, use it to find system routines for UUID generation.
344
 
_uuid_generate_random = _uuid_generate_time = _UuidCreate = None
345
 
try:
346
 
    import ctypes, ctypes.util
347
 
    _buffer = ctypes.create_string_buffer(16)
348
 
 
349
 
    # The uuid_generate_* routines are provided by libuuid on at least
350
 
    # Linux and FreeBSD, and provided by libc on Mac OS X.
351
 
    for libname in ['uuid', 'c']:
352
 
        try:
353
 
            lib = ctypes.CDLL(ctypes.util.find_library(libname))
354
 
        except:
355
 
            continue
356
 
        if hasattr(lib, 'uuid_generate_random'):
357
 
            _uuid_generate_random = lib.uuid_generate_random
358
 
        if hasattr(lib, 'uuid_generate_time'):
359
 
            _uuid_generate_time = lib.uuid_generate_time
360
 
 
361
 
    # On Windows prior to 2000, UuidCreate gives a UUID containing the
362
 
    # hardware address.  On Windows 2000 and later, UuidCreate makes a
363
 
    # random UUID and UuidCreateSequential gives a UUID containing the
364
 
    # hardware address.  These routines are provided by the RPC runtime.
365
 
    try:
366
 
        lib = ctypes.windll.rpcrt4
367
 
    except:
368
 
        lib = None
369
 
    _UuidCreate = getattr(lib, 'UuidCreateSequential',
370
 
                          getattr(lib, 'UuidCreate', None))
371
 
except:
372
 
    pass
373
 
 
374
 
def _unixdll_getnode():
375
 
    """Get the hardware address on Unix using ctypes."""
376
 
    _uuid_generate_time(_buffer)
377
 
    return UUID(bytes=_buffer.raw).node
378
 
 
379
 
def _windll_getnode():
380
 
    """Get the hardware address on Windows using ctypes."""
381
 
    if _UuidCreate(_buffer) == 0:
382
 
        return UUID(bytes=_buffer.raw).node
383
 
 
384
 
def _random_getnode():
385
 
    """Get a random node ID, with eighth bit set as suggested by RFC 4122."""
386
 
    import random
387
 
    return random.randrange(0, 1<<48L) | 0x010000000000L
388
 
 
389
 
_node = None
390
 
 
391
 
def getnode():
392
 
    """Get the hardware address as a 48-bit integer.  The first time this
393
 
    runs, it may launch a separate program, which could be quite slow.  If
394
 
    all attempts to obtain the hardware address fail, we choose a random
395
 
    48-bit number with its eighth bit set to 1 as recommended in RFC 4122."""
396
 
 
397
 
    global _node
398
 
    if _node is not None:
399
 
        return _node
400
 
 
401
 
    import sys
402
 
    if sys.platform == 'win32':
403
 
        getters = [_windll_getnode, _netbios_getnode, _ipconfig_getnode]
404
 
    else:
405
 
        getters = [_unixdll_getnode, _ifconfig_getnode]
406
 
 
407
 
    for getter in getters + [_random_getnode]:
408
 
        try:
409
 
            _node = getter()
410
 
        except:
411
 
            continue
412
 
        if _node is not None:
413
 
            return _node
414
 
 
415
 
def uuid1(node=None, clock_seq=None):
416
 
    """Generate a UUID from a host ID, sequence number, and the current time.
417
 
    If 'node' is not given, getnode() is used to obtain the hardware
418
 
    address.  If 'clock_seq' is given, it is used as the sequence number;
419
 
    otherwise a random 14-bit sequence number is chosen."""
420
 
 
421
 
    # When the system provides a version-1 UUID generator, use it (but don't
422
 
    # use UuidCreate here because its UUIDs don't conform to RFC 4122).
423
 
    if _uuid_generate_time and node is clock_seq is None:
424
 
        _uuid_generate_time(_buffer)
425
 
        return UUID(bytes=_buffer.raw)
426
 
 
427
 
    import time
428
 
    nanoseconds = int(time.time() * 1e9)
429
 
    # 0x01b21dd213814000 is the number of 100-ns intervals between the
430
 
    # UUID epoch 1582-10-15 00:00:00 and the Unix epoch 1970-01-01 00:00:00.
431
 
    timestamp = int(nanoseconds/100) + 0x01b21dd213814000L
432
 
    if clock_seq is None:
433
 
        import random
434
 
        clock_seq = random.randrange(1<<14L) # instead of stable storage
435
 
    time_low = timestamp & 0xffffffffL
436
 
    time_mid = (timestamp >> 32L) & 0xffffL
437
 
    time_hi_version = (timestamp >> 48L) & 0x0fffL
438
 
    clock_seq_low = clock_seq & 0xffL
439
 
    clock_seq_hi_variant = (clock_seq >> 8L) & 0x3fL
440
 
    if node is None:
441
 
        node = getnode()
442
 
    return UUID(fields=(time_low, time_mid, time_hi_version,
443
 
                        clock_seq_hi_variant, clock_seq_low, node), version=1)
444
 
 
445
 
def uuid3(namespace, name):
446
 
    """Generate a UUID from the MD5 hash of a namespace UUID and a name."""
447
 
    import md5
448
 
    hash = md5.md5(namespace.bytes + name).digest()
449
 
    return UUID(bytes=hash[:16], version=3)
450
 
 
451
 
def uuid4():
452
 
    """Generate a random UUID."""
453
 
 
454
 
    # When the system provides a version-4 UUID generator, use it.
455
 
    if _uuid_generate_random:
456
 
        _uuid_generate_random(_buffer)
457
 
        return UUID(bytes=_buffer.raw)
458
 
 
459
 
    # Otherwise, get randomness from urandom or the 'random' module.
460
 
    try:
461
 
        import os
462
 
        return UUID(bytes=os.urandom(16), version=4)
463
 
    except:
464
 
        import random
465
 
        bytes = [chr(random.randrange(256)) for i in range(16)]
466
 
        return UUID(bytes=bytes, version=4)
467
 
 
468
 
def uuid5(namespace, name):
469
 
    """Generate a UUID from the SHA-1 hash of a namespace UUID and a name."""
470
 
    import sha
471
 
    hash = sha.sha(namespace.bytes + name).digest()
472
 
    return UUID(bytes=hash[:16], version=5)
473
 
 
474
 
# The following standard UUIDs are for use with uuid3() or uuid5().
475
 
 
476
 
NAMESPACE_DNS = UUID('6ba7b810-9dad-11d1-80b4-00c04fd430c8')
477
 
NAMESPACE_URL = UUID('6ba7b811-9dad-11d1-80b4-00c04fd430c8')
478
 
NAMESPACE_OID = UUID('6ba7b812-9dad-11d1-80b4-00c04fd430c8')
479
 
NAMESPACE_X500 = UUID('6ba7b814-9dad-11d1-80b4-00c04fd430c8')