Deterministic hashing of Python dicts, lists, and JSON/YAML strings
Reason this release was yanked:
intellisense not working properly
Project description
individu8
Deterministic hashing of Python dicts, lists, and JSON/YAML strings.
import individu8
individu8({"id": 1, "name": "Alice"})
# "FszF+jYmhYS17K"
individu8([{"id": 1}, {"id": 2}])
# ["GICezwtC7+vhEA", "DxgzKROIe5u0sQ"]
Why
- Stable across runs — same data always produces the same hash, regardless of key insertion order
- Flexible filtering — exclude volatile fields (timestamps, system columns) before hashing
- Multiple input formats — pass a dict, list, JSON string, or YAML string
- Multiple output formats — base64 (default), hex, or UUID v8
- Multiple hash algorithms — blake2b (default), blake2s, sha256, md5, shake128
- Predictable length —
hash_lengthcontrols the exact number of characters returned - Fast — uses orjson for serialisation by default (5-10x faster than stdlib json)
Install
pip install individu8
# or
uv add individu8
Usage
Basic
from individu8 import individu8
# hash a dict — returns exactly hash_length characters (default 14)
individu8({"id": 1, "name": "Alice"})
# "FszF+jYmhYS17K"
# hash a list — returns a list of hashes in the same order
individu8([{"id": 1}, {"id": 2}])
# ["GICezwtC7+vhEA", "DxgzKROIe5u0sQ"]
# hash a JSON string — identical to dict input
individu8('{"id": 1, "name": "Alice"}')
# "FszF+jYmhYS17K"
# hash a YAML string — identical to dict input
individu8("id: 1\nname: Alice")
# "FszF+jYmhYS17K"
Filtering
Filtering is applied as a pipeline in this order:
exclude_all_keys_starting_with/ending_with/containing— removes matching keys recursively at any depthexclude— removes specific keys or jsonpath paths from the full documentinclude— narrows to only the specified keys or paths
# exclude system/metadata keys at any depth
individu8(data, exclude_all_keys_starting_with=["_meta", "_dlt"])
individu8(data, exclude_all_keys_ending_with=["_at", "_id"])
individu8(data, exclude_all_keys_containing=["temp"])
# exclude specific top-level keys
individu8(data, exclude=["updated_at", "created_at"])
# exclude a nested key using jsonpath — only removes "code" inside this specific path,
# not other keys named "code" elsewhere in the document
individu8(data, exclude=["person.address[*].street.number.code"])
# hash only specific fields
individu8(data, include=["id", "name"])
# combine: hash only street data, excluding volatile subfields
individu8(
data,
exclude=["person.address[*].street.updated_at"],
include=["person.address[*].street"],
)
Hash length
hash_length controls the exact number of characters in the returned string.
The library computes as many bytes as needed internally and truncates to exactly
hash_length characters — you always get exactly what you asked for.
individu8(data, hash_length=8) # 8 chars
individu8(data, hash_length=14) # 14 chars (default)
individu8(data, hash_length=20) # 20 chars
individu8(data, hash_length=32) # 32 chars
For clean alignment with base64 encoding use multiples of 4 (12, 16, 20, 24) — other values work fine but the last 1–3 characters of entropy are discarded by truncation.
For expert control over digest size in bytes, use hash_bytes instead:
individu8(data, hash_bytes=16) # 16-byte digest → 22 base64 chars
individu8(data, hash_bytes=32) # 32-byte digest → 43 base64 chars
Hash format
# base64 (default) — URL-safe ASCII, no padding
individu8(data)
# "FszF+jYmhYS17K"
# hex — lowercase hexadecimal, hash_bytes * 2 characters
individu8(data, hash_format="hex")
# "19ccbe8d3d2f6b"
# UUID v8 — deterministic, RFC 9562 compliant, always 36 characters
# 122 bits of entropy (128 minus 6 version/variant bits)
# accepted anywhere a UUID is expected
individu8(data, hash_format="uuid")
# "6b5dc393-b52a-8ea0-a003-4f6986d2db77"
UUID v8 is the RFC 9562 "custom" variant — designed for exactly this use case where you want deterministic, content-based UUIDs using your own hash algorithm.
Hash algorithms
individu8(data, hash_algorithm="blake2b") # default — fast, modern, recommended
individu8(data, hash_algorithm="blake2s") # 32-bit optimised, max hash_bytes=32
individu8(data, hash_algorithm="sha256") # widely compatible, matches git/AWS
individu8(data, hash_algorithm="md5") # legacy, used for ETags/checksums
individu8(data, hash_algorithm="shake128") # SHA-3, matches dlt _dlt_id format
Output structure
Controls what wraps the hash string(s) — separate from hash_format which
controls how each individual hash is encoded.
individu8(data, output="same_as_input") # default — matches input type
individu8(data, output="python") # always str or list[str]
individu8(data, output="json") # always a JSON string
individu8(data, output="yaml") # always a YAML string
JSON backend
individu8(data, json_backend="orjson") # default — 5-10x faster
individu8(data, json_backend="stdlib") # stdlib json, no extra dependencies
Both backends produce identical hashes for the same input.
Supported input types
The following Python types are handled automatically when they appear as values in the data being hashed:
| Type | Serialised as |
|---|---|
Decimal |
string (avoids float precision loss) |
datetime / date / time |
ISO 8601 string |
UUID |
string |
bytes |
base64 string |
namedtuple |
dict via _asdict() |
@dataclass |
dict via dataclasses.asdict() |
Enum |
.value |
pydantic BaseModel |
dict via .model_dump() |
objects with .asdict() |
dict via .asdict() |
Development
git clone https://github.com/niklasskoldmark/individu8
cd individu8
uv sync
uv run pytest
uv run ruff check src/ tests/
Changelog
See CHANGELOG.md.
Powered by
- jsonpath-ng — jsonpath filtering
- orjson — fast JSON serialisation
- pyyaml — YAML parsing
License
MIT — see LICENSE.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file individu8-0.1.1.tar.gz.
File metadata
- Download URL: individu8-0.1.1.tar.gz
- Upload date:
- Size: 16.9 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
fb7526806c363802692269cdd26a2bddb7ac2ebe9cf21bdc408c7cccb60ef352
|
|
| MD5 |
e68d892ec87ba8f942d0081e3e9be570
|
|
| BLAKE2b-256 |
6a1872a7c8d0f79a2390631fd9da7f09e64c4676156c3a39c7e193223adef2c7
|
Provenance
The following attestation bundles were made for individu8-0.1.1.tar.gz:
Publisher:
publish.yml on niklasskoldmark/individu8
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
individu8-0.1.1.tar.gz -
Subject digest:
fb7526806c363802692269cdd26a2bddb7ac2ebe9cf21bdc408c7cccb60ef352 - Sigstore transparency entry: 1901758823
- Sigstore integration time:
-
Permalink:
niklasskoldmark/individu8@aadc8a30267f38ecbb561315ce10e21e14c6245f -
Branch / Tag:
refs/tags/v0.1.1 - Owner: https://github.com/niklasskoldmark
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@aadc8a30267f38ecbb561315ce10e21e14c6245f -
Trigger Event:
release
-
Statement type:
File details
Details for the file individu8-0.1.1-py3-none-any.whl.
File metadata
- Download URL: individu8-0.1.1-py3-none-any.whl
- Upload date:
- Size: 12.5 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
6384aca3c91ca88196de6f366d0c40f5b2b62ddd402d44ff94204a0aa0f0ff29
|
|
| MD5 |
606caacc919d5631cb2814b5998e9320
|
|
| BLAKE2b-256 |
9cf744fe9ddbdea8a8038f60a4330007a0ba99eb7b91fc0cb7f96e3414f3763a
|
Provenance
The following attestation bundles were made for individu8-0.1.1-py3-none-any.whl:
Publisher:
publish.yml on niklasskoldmark/individu8
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
individu8-0.1.1-py3-none-any.whl -
Subject digest:
6384aca3c91ca88196de6f366d0c40f5b2b62ddd402d44ff94204a0aa0f0ff29 - Sigstore transparency entry: 1901758956
- Sigstore integration time:
-
Permalink:
niklasskoldmark/individu8@aadc8a30267f38ecbb561315ce10e21e14c6245f -
Branch / Tag:
refs/tags/v0.1.1 - Owner: https://github.com/niklasskoldmark
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@aadc8a30267f38ecbb561315ce10e21e14c6245f -
Trigger Event:
release
-
Statement type: