from sets import Set class CitError(StandardError): """Represents an error in citlib. """ def __init__(self, code_=0): StandardError.__init__(self) if code_ in RESPONSES: self.msg = RESPONSES[code_] else: self.msg = str(code_) self.code = code_ def __str__(self): return "[%d] %s" % (self.code, self.msg) class Bucket: """A bucket for arbitrary data. """ def den2bin(n): """Props to http://www.daniweb.com/code/snippet285.html. """ bits = '' while n > 0: bits = str(n % 2) + bits n = n >> 1 return bits def bitmap(n, keys=(), size=None, bucket=False): """Given a denary number, return a mapping. The mapping's keys will be decimal representations of each bit position; the values will be boolean object representations of the value at each position. This method takes three optional arguments: keys -- a tuple of strings to use as keys instead of the decimals size -- the number of positions in the bitmap bucket -- if set to True, the return value will be a Bucket with attributes instead of a mapping If both keys and size are passed in, then ValueError is raised if size does not equal the number of keys. If only keys are passed in, then size becomes the number of keys. If keys are not passed in, then the decimal representations of the bit positions are used. If neither size nor keys are passed in, then size defaults to 32, and the default key behavior is used. """ # Validate and possibly coerce n. # =============================== if not isinstance(n, (int, long)): if isinstance(n, basestring) and n.isdigit(): n = int(n) else: raise TypeError("n must be a plain or long integer") if n < 0: raise ValueError("n must be positive") # Auto-generate keys if needed. # ============================= if keys: if size: if size != len(keys): raise ValueError("%d keys given, expected " % len(keys) + "%d" % size) else: if len(Set(keys)) != len(keys): raise ValueError("No duplicate keys allowed") size = len(keys) else: if not size: size = 32 keys = [] for i in range(size): _tmp = [0] * size _tmp[i] = 1 decimal = int(''.join([str(i) for i in _tmp]), 2) keys.append(decimal) # Convert n to a bit string. # ========================== bits = den2bin(n) if len(bits) > size: raise ValueError("%d will not fit in bitmap of size %d" % (n, size)) bits = bits.zfill(size) # Now convert to a bitmap, and if asked for, a bucket. # ==================================================== bitmap = {} for i in reversed(range(size)): if i > len(keys): continue bitmap[keys[i]] = int(bits[i]) and True or False if not bucket: return bitmap else: bucket = Bucket() bucket.__dict__.update(bitmap) return bucket def bitbucket(n, names): """Given a decimal number and list of names for each bit, return a Bucket. """ return bitmap(n, names, len(names), True) RESPONSES = { # From ipcdef.h 100 : "Listing follows." , 200 : "Ok." , 300 : "More data." , 400 : "Send listing." , 500 : "Error." , 510 : "Internal error." , 511 : "Too big." , 512 : "Illegal value." , 520 : "Not logged in." , 530 : "Command not supported." , 540 : "Password required." , 541 : "Already logged in." , 542 : "Username required." , 550 : "Higher access required." , 551 : "Max sessions exceeded." , 552 : "Resource busy." , 553 : "Resource not open." , 560 : "Not here." , 561 : "Invalid floor operation." , 570 : "No such user." , 571 : "File not found." , 572 : "Room not found." , 573 : "No such system." , 574 : "Already exists." , 575 : "Message not found." , 600 : "Binary follows." , 700 : "Send binary." , 800 : "Start chat mode." , 900 : "Asynchronous message." , 902 : "ASYNC_GEXP" }