def fingerprint(blob): """Compute the fingerprint of its input. This blob can contain an integer, a string, a dict or an object with a fingerprint method. """ # is it an integer? try: mpz_value = mpz(blob) except (TypeError, ValueError): pass else: string = utils.mpztob64(mpz_value) return b64encode(crypthash(string).digest()) # is it a string? if isinstance(blob, str): return b64encode(crypthash(blob).digest()) # is it a list? if isinstance(blob, (list, tuple)): list_of_fingerprints = [fingerprint(i) for i in blob] string = json.dumps(list_of_fingerprints, separators=(',', ':')) return b64encode(crypthash(string).digest()) # is it a dict? if isinstance(blob, dict): # is this dict already a hash of something? if "#" in blob: return blob["#"] # otherwise, transform dict into array and fingerprint it keys = sorted(blob) list_of_fingerprints = [fingerprint([k, blob[k]]) \ for k in keys] string = json.dumps(list_of_fingerprints, separators=(',', ':')) return b64encode(crypthash(string).digest()) # is it None if blob is None: return fingerprint('None') # is it an object? try: # is it a class for which we can compute a fingerprint? return blob.fingerprint() except AttributeError: pass assert False, "fingerprint cannot parse object"
def fingerprint(self): """Compute the fingerprint of the object, as a base64 string. It tries to not recompute the same hash many times by implementing some tracking. However, this tracking only works for attributes. As a result, it will for instance not detect changes in lists or dicts. """ # check whether the hash of this object is already known if self.attr_fingerprint["#"] is not None: return self.attr_fingerprint["#"] list_to_hash = [] # Going through all fields that need to be taken into account for key in sorted(self.to_fingerprint): # Computing missing hashes if self.attr_fingerprint[key] is None: self.attr_fingerprint[key] = \ fingerprint([key, getattr(self, key)]) # Building final string list_to_hash.append(self.attr_fingerprint[key]) string = json.dumps(list_to_hash, separators=(',', ':')) result = b64encode(crypthash(string).digest()) self.attr_fingerprint["#"] = result return result