[Q]:Generate Unique ID's

Marcus Alanen marcus at infa.abo.fi
Sat May 24 07:01:28 EDT 2003


On Fri, 23 May 2003 13:29:08 -0700, achrist at easystreet.com
<achrist at easystreet.com> wrote:
>I'd like to generate unique identifiers for database items,
>sort of like the ID's that MS uses for COM.  My purpose is 
>to have unique ID's (across multiple [distributed] installations of

I wrote the following quite some time ago. It is _very_ "unpythonic"
in many ways, so don't flame me for it, I already know that ;). If you
intend to do any serious work with it, you surely _must_ understand
how everything works, and what problems there might be. I don't take
any responsibility for its correctness.

If there's interest, I could try cleaning it up a bit, though. Any
discussion on what parts are plain wrong, or bad from a theoretical
point of view is welcome. (I found the spec a bit confusing with
respect to exact bit placement, grr. Any help here is also welcome)

Should work on Red Hat, Debian and Windows 2000.

So, just import the file and successively call getUniqueID() to
generate UUIDs.

import random
import time
import os

def __getHundredNanosecondsSinceGregorianReform__():
    """<<<The timestamp is a 60 bit value. For UUID version 1, this is
    represented by Coordinated Universal Time (UTC) as a count of
    100-nanosecond intervals since 00:00:00.00, 15 October 1582 (the
    date of Gregorian reform to the Christian calendar).>>>"""

    # Since 1.1.1970 (unix epoch time)
    # BUG probably platform-dependent
    ns = time.time() * 1000 * 1000 * 10

    # Amount of 100 nanoseconds between 15.Oct.1582 to 1.1.1970
    # Takes even leap years into account
    ns_greg = ((1970-1583) * 365 + 78 + 92) * 24 * 60 * 60 * 1000 * 1000 * 10

    # BUG can long conversion lose information?
    return long(ns) + ns_greg

#Place holder for a RNG
theRNG=None

# Our NIC's MAC
ethernet = ""
# Our clocksequence
clocksequence = None
# Latest UTC
latest_utc = 0

import thread
__uniqueid_lock__ = thread.allocate_lock()

def __generateString__(value, n_nibbles):
    """Generates nibbles, and reverses the resulting string."""
    s = []
    for i in range(n_nibbles):
        digit = value & 15
        value //= 16
        s.append(string.hexdigits[digit])

    s.reverse()
    return string.join(s, "")
    

def __generateID__():
    """This function returns a string with a unique ID for XMI objects.
    It adheres to the DCE specification of generating globally
    unique id:s. Assume there are buglets in this implementation,
    the spec isn't _that_ clean on the matter.
    http://www.opengroup.org/onlinepubs/9629399/apdxa.htm
    """
    
    global theRNG
    global ethernet
    global clocksequence
    global latest_utc

    if not theRNG:
        theRNG = random.Random(time.time())
        # Get the ethernet address
        try:
            #
            #
            # RedHat Linux, Debian GNU/Linux, SunOS 2.6
            #
            #
            f = os.popen("/sbin/ifconfig -a")
            try:
                while 1:
                    s = f.readline()
                    if not s:
                        raise Exception

                    #
                    # Linux
                    #
                    i = s.find("HWaddr")
                    if i != -1:
                        ethernet = string.join(s[i:].split()[1].split(":"), "")
                    else:
                        #
                        # SunOS
                        #
                        i = s.find("ether")
                        if i != -1:
                            e = s[i:].split()[1].split(":")
                            for i in range(len(e)):
                                if len(e[i]) == 1:
                                    e[i] = "0" + e[i]
                            ethernet = string.join(e, "")
                        else:
                            continue

                    f.close()
                    break
            except:
                f.close()
                raise
            
        except:
            #
            # Windows 2000 (perhaps also NT and XP)
            #
            try:
                f = os.popen("ipconfig /all")
                try:
                    while 1:
                        s = f.readline()
                        if not s:
                            raise Exception
                    
                        i = s.find("Physical Address")
                        if i != -1:
                            i = s.find(":")
                            if i != -1:
                                ethernet = \
      string.join(s[i:].split()[1].split("-"), "")
                            else:
                                continue
                        else:
                            continue

                        f.close()
                        break
                except:
                    f.close()
                    raise
            except:
                # BUG: We randomize
                e = []
                for eth_i in range(12):
                    e.append(string.hexdigits[theRNG.randrange(16)])
                ethernet = string.join(e, "")

        # Initialize clock sequence. 14 bits
        clocksequence = theRNG.randrange(16384)
        
    s = ""
    # the final DCE string is of the form
    # "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
    value = __getHundredNanosecondsSinceGregorianReform__()
    index = 0

    if value <= latest_utc:
        clocksequence += 1
    else:
        latest_utc = value

    # time_low
    s += __generateString__(value, 8)
    s += "-"
    
    # time_mid
    value >>= (4*8)
    s += __generateString__(value, 4)
    s += "-"
    value >>= (4*4)

    # time_hi_and_version
    value |= 1<<12 # UUID version 1
    s += __generateString__(value, 4)
    s += "-"

    value = clocksequence
    value |= 1<<15 # DCE variant
    s += __generateString__(value, 4)
    s += "-"

    s += ethernet

    return "DCE:%s" % s.upper()

def getUniqueID():
    global __uniqueid_lock__
    __uniqueid_lock__.acquire()
    try:
        s = __generateID__()
    except:
        __uniqueid_lock__.release()
        raise
    
    __uniqueid_lock__.release()
    return s




More information about the Python-list mailing list