os_helper.hash_utils module

Hashing Utilities

A content hash turns any string, file, or folder into a short, fixed-length fingerprint: the same input always produces the same fingerprint, and two different inputs almost never collide. That single property answers three everyday questions: is this file the one I already downloaded (compare fingerprints instead of full bytes), have these two folders diverged (compare their folder hash), and can I use a file’s own content as its cache key (a name that never needs inventing and never goes stale).

hash_string(), hashfile(), and hashfolder() compute that fingerprint with RIPEMD-160 (BLAKE2b as a fallback where RIPEMD-160 is unavailable), always as a 40-character hex string regardless of which engine ran. This is content hashing, not password hashing: there is no salting and no key-stretching, so never use these for storing or checking passwords (see CREDENTIALS_MANAGEMENT.md).

Usage example

>>> import os_helper as osh
>>> osh.hash_string("hello")[:8]
'108f07b8'
>>> len(osh.hash_string("hello"))
40

Author

Warith HARCHAOUI, https://linkedin.com/in/warith-harchaoui

os_helper.hash_utils.hash_string(s, size=-1)[source]

Generate a hash of a given string and optionally returns a truncated version.

Parameters:
  • s (str) – The input string to hash.

  • size (int, optional) – If positive, truncates the hash to the specified length. Defaults to -1 (no truncation).

Returns:

The hashed string, optionally truncated.

Return type:

str

Example

>>> isinstance(hash_string("example"), str)
True
>>> len(hash_string("example"))
40
>>> len(hash_string("example", size=8))
8

Note

The exact digest depends on the underlying hash engine (RIPEMD-160 when available, BLAKE2b truncated to 20 bytes otherwise). The output length stays 40 hex characters either way.

os_helper.hash_utils.hashfile(path, hash_content=True, hash_path=None, date=False)[source]

Generate a hash for a file’s content and/or its last modification date.

Parameters:
  • path (str) – The path to the file to hash.

  • hash_content (bool, optional) – If True, includes the file’s content in the hash (default: True).

  • hash_path (bool or None, optional) –

    If True, includes the path string in the hash — the way to fingerprint a name rather than bytes, for a file that need not exist. Combined with hash_content=True it answers “this file, at this path”, which neither flag can express alone: two copies of the same bytes under different names share a content digest, and two different files under the same name share a path digest.

    Left unset (None, the default) it mirrors the older two-spelling behaviour — the path is hashed exactly when the content is not — so every digest produced before this parameter existed is unchanged. Pass it explicitly to control the two halves independently.

  • date (bool, optional) – If True, includes the file’s own last modification time (os.stat().st_mtime_ns) in the hash (default: False). It is the file’s mtime, never the current clock: a digest that moved on every call could not be a cache key.

Returns:

The resulting hash of the file as a 40-character hex string.

Return type:

str

Raises:
  • FileNotFoundError – If hash_content or date is True and path names nothing.

  • IsADirectoryError – If hash_content or date is True and path names a directory.

  • ValueError – If hash_content, hash_path and date are all False, which asks for a fingerprint of nothing.

Notes

Asking for content (or an mtime) that cannot be read is an error, not a fallback. This function used to answer a path digest in that case, so hashfile("/gone") returned a plausible 40-hex-char value for a file nobody had read — which made hashfile useless for noticing that a file is missing, the very reason one fingerprints a file. Callers who want a path digest ask for it with hash_path=True.

The three flags are the same three hashfolder has always taken, in the same order, so the two siblings now answer the same questions about a file and about a folder.

os_helper.hash_utils.hashfolder(path, hash_content=True, hash_path=False, date=False)[source]

Generate a hash for the contents of a folder and/or its path.

Parameters:
  • path (str) – The path to the folder to hash.

  • hash_content (bool, optional) – If True, includes the folder’s contents in the hash (default: True).

  • hash_path (bool, optional) – If True, includes the folder’s path in the hash (default: False).

  • date (bool, optional) – If True, includes the folder’s own last modification time (os.stat().st_mtime_ns) in the hash (default: False). It is the folder’s mtime, never the current clock. Note that a directory’s mtime tracks entries appearing and disappearing, not edits made inside a file it holds — that is what hash_content=True is for.

Returns:

The resulting hash of the folder and/or its contents as a 40-character hex string.

Return type:

str

Raises:
  • FileNotFoundError – If hash_content or date is True and path names nothing.

  • NotADirectoryError – If hash_content or date is True and path names a file.

  • ValueError – If hash_content, hash_path and date are all False, which asks for a fingerprint of nothing.

Notes

Asking to walk a folder that is not there is an error, not a fallback. This function used to return the digest of the empty string in that case — the same constant for every missing folder, which is also what an empty existing folder hashes to and what a file handed in by mistake hashed to. Four different situations collapsed onto one plausible 40-hex-char answer, so “have these two folders diverged” replied “no” when neither existed.