ef.hashing¶
Content-hashing primitives shared across ef’s layers.
Content addressing is the backbone of ef’s identity and change-detection
model: a segment’s id (L2, ef.segments.segment_id()), a source’s content
hash (L0, ef.corpus.content_hash()) and — from the ArtifactGraph on —
every artifact id are all SHA-256 over normalized content.
Normalizing before hashing is the point. Cosmetically-different encodings of
the same content — NFD vs NFC, a stray BOM, CRLF vs LF line endings, JSON with
keys in a different order — must hash identically, so that re-ingesting
unchanged data is a no-op rather than a spurious “change” that re-runs the
expensive downstream pipeline. This module is the single source of truth
for that normalization; every other ef module hashes through it.
>>> sha256_hex(normalize_text('a\r\nb')) == sha256_hex(normalize_text('a\nb'))
True
Functions
|
Normalize |
|
Serialize |
|
Return the |
- ef.hashing.canonical_json(obj)[source]¶
Serialize
objto deterministic JSON: sorted keys, compact separators.Two mappings that are equal but were built in a different key order produce the same string — so they hash identically. Non-JSON values fall back to their
strform, so the function never raises on exotic input (at the cost of those values not round-tripping).- Return type:
>>> canonical_json({'b': 1, 'a': 2}) '{"a":2,"b":1}' >>> canonical_json({'a': 2, 'b': 1}) == canonical_json({'b': 1, 'a': 2}) True
- ef.hashing.normalize_text(text)[source]¶
Normalize
textfor hashing: Unicode NFC, no BOM,\nline endings.The normalization makes hashing robust to differences that carry no meaning: a composed vs decomposed accent, a leading byte-order mark, or Windows vs Unix line endings. Only the hash input is normalized — callers keep the original
textverbatim.- Return type:
>>> normalize_text('a\r\nb\rc') == 'a\nb\nc' True >>> normalize_text('\ufeffhi') == 'hi' True >>> normalize_text('café') == normalize_text('cafe\u0301') # NFC vs NFD True