Skip to main content

mtdt

Type-safe mapping-like data structure for arbitrary metadata annotations.

mtdt provides a MetadataStore and a Key abstraction that allows attaching typed, validated, and namespaced metadata to objects or processes. It supports strong and weak reference storage, structural or identity-based key comparison, and immutability constraints.

Features

  • Type-safe Keys: Key instances define the expected type of their values. While the type parameter acts as a phantom type for static analysis, runtime validation is supported via embedded or custom validators.
  • Strong and Weak Storage: Values can be stored strongly (default) or weakly. Weak entries are automatically evicted from the store when the value has no other strong references.
  • Identity vs Structural Keys: Keys compare by identity by default. Setting use_identity=False switches equality and hashing to a structural tuple of the key's fields.
  • Immutability: Keys can be marked immutable=True, preventing overwriting or deletion of their values once set.
  • Strict and Non-strict Modes: In strict mode (default), all keys must be Key instances. In non-strict mode, any hashable object can be used as a key.
  • Annotated Type Integration: Validators can be automatically inferred from typing.Annotated metadata using EmbeddedValidator.

Installation

pip install mtdt

Usage

Basic Storage

from mtdt import MetadataStore, Key

store = MetadataStore()

# Create identity-based keys
name_key = Key(value="name", type=str)
age_key = Key(value="age", type=int)

store[name_key] = "Alice"
store[age_key] = 30

print(store[name_key])  # Alice
print(len(store))       # 2

Structural Keys

By default, two distinct Key instances are not equal even if they have the same fields. For dictionary-like behavior where keys with the same fields collide, use use_identity=False.

from mtdt import MetadataStore, Key

store = MetadataStore()

k1 = Key(value="config", use_identity=False)
k2 = Key(value="config", use_identity=False)

store[k1] = "value"
print(store[k2])  # "value"

Key Factories and Namespacing

Key.factory is the recommended way to create keys with shared defaults. It supports extra_value for namespacing and automatic validator selection.

from mtdt import key_factory

# Create a factory for a specific namespace
AppFactory = key_factory(extra_value="my_app", use_identity=False)

# Keys produced will have value == ("my_app", "user_id")
k1 = AppFactory(value="user_id")
k2 = AppFactory(value="session_id")

Validators

Validators are callables that raise InvalidValue (or a subclass) if a value is invalid. They can be passed explicitly or inferred from Annotated types.

from typing import Annotated
from mtdt import MetadataStore, Key, EmbeddedValidator
from mtdt.exceptions import InvalidValue

def validate_positive(v: int):
    if v < 0:
        raise InvalidValue(what="age", expected="positive int", got=v)

Age = Annotated[int, EmbeddedValidator(validate_positive)]

# Using the default factory, the validator is automatically pulled from the Annotated type.
AgeKey = Key.factory()

store = MetadataStore()
k = AgeKey(value="user_age", type=Age)

store[k] = 25  # OK
# store[k] = -5  # Raises InvalidValue

Weak References

If a key is marked weakref=True, its values are held weakly. When the value is garbage collected, the entry is automatically removed from the store.

import gc
from mtdt import MetadataStore, Key

class Resource:
    pass

store = MetadataStore()
k = Key(value="res", weakref=True)

res = Resource()
store[k] = res

print(k in store)  # True

del res
gc.collect()

print(k in store)  # False

Immutable Keys

Immutable keys prevent overwriting or deletion once a value has been set.

from mtdt import MetadataStore, Key
from mtdt.exceptions import InvalidUsage

store = MetadataStore()
k = Key(value="config", immutable=True)

store[k] = {"db": "localhost"}

try:
    store[k] = {"db": "remote"}
except InvalidUsage:
    print("Cannot overwrite immutable key")

try:
    del store[k]
except InvalidUsage:
    print("Cannot delete immutable key")

Strict and Non-Strict Modes

In strict mode (default), only Key instances are accepted. In non-strict mode, any hashable object can be used as a key, bypassing validation and immutability checks.

from mtdt import MetadataStore

# Non-strict mode
store = MetadataStore(strict=False)
store["string_key"] = 100
print(store["string_key"])  # 100

Exceptions

mtdt provides a hierarchy of exceptions under the Invalid base class:

  • Invalid: Base exception.
  • InvalidValue: Raised when a value fails a validation check. Subclasses RuntimeError.
  • InvalidType: Raised when a key or value fails a type check. Subclasses TypeError.
  • InvalidUsage: Raised when the API is used incorrectly (e.g., updating an immutable key).

License

MIT License

Copyright (c) [Year] [Your Name/Organization]

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

Release files for mtdt 1.0.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for mtdt 1.0.0
File Size Uploaded
mtdt-1.0.0.tar.gz 21.0 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for mtdt 1.0.0
File Interpreter ABI Platform
mtdt-1.0.0-py3-none-any.whl Python 3 none any Details

Total release size: 32.8 kB

Release files / mtdt-1.0.0.tar.gz

Download URL mtdt-1.0.0.tar.gz
Size 21.0 kB
Tags Source
SHA-256 checksum
How to use checksums
bdaaca16a91faa6354c6ad95e7f43dc9fbbf37f8f72595a6dbbbde0e0ef62b03
BLAKE2b-256 checksum
How to use checksums
157d872be33e95f0cac08f9d6ae818abc3187d9ec76067dde69825e807616309
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via uv/0.11.28 {"installer":{"name":"uv","version":"0.11.28","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Fedora Linux","version":"44","id":"","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

Release files / mtdt-1.0.0-py3-none-any.whl

Download URL mtdt-1.0.0-py3-none-any.whl
Size 11.8 kB
Tags Python 3
SHA-256 checksum
How to use checksums
884b7c5e5158310c33ab5c4c170933f55c44e933437503f4c582cedd2c04beb6
BLAKE2b-256 checksum
How to use checksums
f3b0e76ae39a641212c0efa17218448d171942ef716a73bdc5d9530afbbfe1a4
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via uv/0.11.28 {"installer":{"name":"uv","version":"0.11.28","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Fedora Linux","version":"44","id":"","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

Release history Release notifications | RSS feed

1.1.0

2 release files

This release

1.0.0 This release

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page