"""Module for content hashing file contents."""from__future__importannotations# system importsimporthashlibfromtypingimportBinaryIO,Union_WritableBuffer=Union[bytes,bytearray]
[docs]classDropboxContentHasher:""" Computes a hash using the same algorithm that the Dropbox API uses for the "content_hash" metadata field. The :meth:`digest` method returns a raw binary representation of the hash. The :meth:`hexdigest` convenience method returns a hexadecimal-encoded version, which is what the "content_hash" metadata field uses. This class has the same interface as the hashers in the standard 'hashlib' package. :Example: Read a file in chunks of 1024 bytes and compute its content hash: >>> hasher = DropboxContentHasher() >>> with open('some-file', 'rb') as f: ... while True: ... chunk = f.read(1024) ... if len(chunk) == 0: ... break ... hasher.update(chunk) ... print(hasher.hexdigest()) """
def__init__(self)->None:self._overall_hasher=hashlib.sha256()self._block_hasher=hashlib.sha256()self._digested=Falseself._block_pos=0self.digest_size=self._overall_hasher.digest_sizedef_reuse_guard(self)->None:ifself._digested:raiseRuntimeError("Can't use this object anymore; ""you already called digest() or hexdigest()")
[docs]classStreamHasher:""" A wrapper around a file-like object (either for reading or writing) that hashes everything that passes through it. Can be used with DropboxContentHasher or any 'hashlib' hasher. :Example: >>> hasher = DropboxContentHasher() >>> with open('some-file', 'rb') as f: ... wrapped_f = StreamHasher(f, hasher) ... response = some_api_client.upload(wrapped_f) >>> locally_computed = hasher.hexdigest() >>> assert response.content_hash == locally_computed :param f: File-like object. :param hasher: Hasher to use. Must implement an ``update`` method. """def__init__(self,f:BinaryIO,hasher:DropboxContentHasher)->None:self._f=fself._hasher=hasher