class Crc32cCalculator: """The Google Python client doesn't provide a way to stream a file being written, so we can wrap the file object in an additional class to do custom handling. This is so we don't need to download the file and then stream read it again to calculate the hash. """ def __init__(self, fileobj): self._fileobj = fileobj self.checksum = Checksum() def write(self, chunk): self._fileobj.write(chunk) self._update(chunk) def _update(self, chunk): """Given a chunk from the read in file, update the hexdigest""" self.checksum.update(chunk) def hexdigest(self): """Return the hexdigest of the hasher. The Base64 encoded CRC32c is in big-endian byte order. See https://cloud.google.com/storage/docs/hashes-etags """ return base64.b64encode(self.checksum.digest()).decode("utf-8")
def _compute_crc32c_checksum(self, string_or_bytes): """Compute the CRC32 checksum of the string. :param str|bytes string_or_bytes: :return str: """ if isinstance(string_or_bytes, str): string_or_bytes = string_or_bytes.encode() checksum = Checksum(string_or_bytes) return base64.b64encode(checksum.digest()).decode("utf-8")
def _calculate_hash(self, hash_=None): """Calculate the hash of the sorted attributes in self._ATTRIBUTES_TO_HASH. If `hash_` is not `None` and is a hasher object, its in-progress hash will be updated, rather than starting from scratch. :param google_crc32c.Checksum hash_: :return str: """ hash_ = hash_ or Checksum() for attribute_name in sorted(self._ATTRIBUTES_TO_HASH): attribute = getattr(self, attribute_name) try: items_to_hash = _HASH_PREPARATION_FUNCTIONS[type(attribute)]( attribute) except KeyError: if isinstance(attribute, dict): items_to_hash = self._prepare_dictionary_for_hashing( attribute_name, attribute) elif isinstance(attribute, collections.abc.Iterable): items_to_hash = self._prepare_iterable_for_hashing( attribute_name, attribute) else: raise TypeError( f"Attribute <{attribute_name!r}: {attribute!r}> cannot be hashed." ) hash_.update(items_to_hash.encode()) return base64.b64encode(hash_.digest()).decode("utf-8")
def __init__(self, fileobj): self._fileobj = fileobj self.checksum = Checksum()