Philip Kilner wrote:
Andy McKay wrote:
http://www.zope.org/Members/andym/GUID "Ever had to generate unique ids? If you are running on Windows one simple answer is the GUID generation system from Microsoft" You're a star!
There's also a none Windows GUID Python class at ActiveState (that might be useful if you ever consider other plattforms): http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/163604 which I have made a Zope GUIDGenerator for: #!/usr/bin/python # A globally unique identifier made up of time and ip # Copyright (C) 2002 Dr. Conan C. Albrecht <conan_albrecht@byu.edu> # # This library is free software; you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public # License as published by the Free Software Foundation; either # version 2.1 of the License, or (at your option) any later version. # # This library is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public # License along with this library; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA import random import socket import time from Persistence import Persistent class GUID: """\ A globally-unique identifier made up of time and ip and the server (client) port or 4 random digits: 36 characters wide A globally unique identifier that combines ip, time, and random bits. Since the time is listed first, you can sort records by guid. You can also extract the time and ip if needed. GUIDs make wonderful database keys. They require no access to the database (to get the max index number), they are extremely unique, and they sort automatically by time. GUIDs prevent key clashes when merging two databases together, combining data, or generating keys in distributed systems. """ rand = random.Random() ip = '' hexip = '' lastguid = '' def __init__(self, guid=None, port=None): """\ Constructor. Use no args if you want the guid generated (this is the normal method) or send a string-typed guid to generate it from the string """ if guid == None: ip = '' hexip = '' try: ip = socket.gethostbyname(socket.gethostname()) except (socket.gaierror): # if we don't have an ip, default to someting in the 10.x.x.x private range ip = '10' for i in range(3): ip += '.' + str(self.rand.randrange(1, 254)) hexip = ''.join(["%04x" % long(i) for i in ip.split('.')]) # leave space for ip v6 (65K in each sub) ip_tuple=tuple(ip.split('.')) if port is None or port>65535: port=self.rand.randrange(1, 65535) hexport=("%04x" % port) guid = self.__class__.lastguid while guid == self.__class__.lastguid: timestamp = long(time.time() * 1000) hextimestamp = "%016x" % timestamp guid = hextimestamp + hexip + hexport self.__class__.lastguid=self.__guid=guid elif type(guid) == type(self): self.update(guid) else: self.__guid=guid def parse_guid(self, guid): if type(guid)!=StringType or len(guid)!=36: raise "InvalidGUID", "'%s' isn't a valid GUID." % str(guid) hextimestamp=guid[0:16] hexip=guid[16:32] hexport=guid[32:36] timestamp=long(guid[0:16], 16) ip_tuple=() for sub in (hexip[0:4], hexip[4:8], hexip[8:12], hexip[12:16]): sub=eval('0x'+sub, {}, {}) ip_tuple=ip_tuple+(sub,) ip='.'.join(ip_tuple) port=eval('0x'+hexport, {}, {}) return timestamp, ip, ip_tuple, port,hextimestamp, hexip, hexport def update(self, guid): if type(guid) != type(self): raise "InvalidGUID", "The value passed was not of the type GUID." self.__guid=self.getGUID() def __str__(self): """Returns the string value of this guid""" return self.__guid def __repr__(self): """Returns the string value of this guid""" return "<GUID %s />" % self.__guid def getGUID(self): return self.__guid def getHexTimestamp(self): return self.__guid[0:16] def getHexIP(self): return self.__guid[16:32] def getHexPort(self): return self.__guid[-4:] def getTimestamp(self): """Extracts the time portion out of the guid and returns the number of milliseconds since the epoch""" return long(self.__guid[0:16], 16) def getIP(self): """Extracts the ip portion out of the guid and returns it as a string like 10.10.10.10""" # there's probably a more elegant way to do this ip = '' index = 16 while index < 32: if ip != '': ip += "." ip += str(int(self.__guid[index: index + 4], 16)) index += 4 return ip def getIP_tuple(self): ip_tuple=() for sub in (self.__guid[16:20], self.__guid[20:24], self.__guid[24:28], self.__guid[28:32]): ip_tuple=ip_tuple+(int(sub, 16),) return ip_tuple def getPort(self): """Extracts the random bits from the guid. I have no idea how this would be useful, but I've included it for completeness""" return int(self.__guid[-4:], 16) class GUIDGenerator(Persistent): """\ This GUIDGenerator does provide a unique ID. If two threads collide this the same GUID new none equal GUIDs will be created and returned. GUIDs are based on time and ip-adress and a random number. The only time as GUID could be same is if the machines have the same ip-address and/or on machine has two server instances on different ports (this needs to be fixed). """ _value=None def createGUID(self): self._value=GUID() return self._value def _p_resolveConflict(self, oldState, savedState, newState): if savedState['_value'] == oldState['_value'] or savedState['_value'] == newState['_value']: oldState['_value'] = GUID() return oldState # XXX What if _p_resolveConflict _thinks_ it resolved the # conflict, but did something wrong? if __name__ == "__main__": # just print out a for testing guid = GUID() print "GUID: " + str(guid) millis = guid.time() print "Time: " + str(millis) + " millis (" + time.asctime(time.gmtime(millis / 1000)) + " UTC)" print "IP: " + guid.ip() print "Rand: " + str(guid.random()) -- Johan Carlsson Tel: + 46 8 31 24 94 Colliberty Mob: + 46 70 558 25 24 Torsgatan 72 Email: johanc@easypublisher.com SE-113 37 STOCKHOLM