Utility¶
This document describes small helper classes that are used across EDRI.
Storage¶
Storage[T] is a small in-memory key/value store (dict[str, T]) that can generate unique random keys for stored items.
Storage use cases¶
generating short-lived lookup keys (tickets, temporary IDs)
keeping in-memory objects indexed by a random token
Key generation¶
If you do not provide a key,
Storagegenerates one.Keys are generated from a configurable character set (
choices) and length.The default character set is ASCII letters + digits.
The default key length is 16.
Key generation loops until it finds a key that is not currently used.
Storage API¶
append(item, key=None) -> strstores
itemreturns the key used
raises
KeyErrorif you provide a key that already exists
Storage example¶
storage = Storage[int]()
k1 = storage.append(100) # auto-generated key
k2 = storage.append(200, key="job") # explicit key
assert storage[k1] == 100
assert storage["job"] == 200
Storage gotchas¶
Storageis an in-memory dict. It is not persistent.If you need cryptographic-strength tokens, consider using a cryptographic RNG (this implementation uses
random.choice).
Queue¶
Queue[T] extends Python’s queue.Queue by adding unget(...), which inserts an item at the front of the queue.
Queue use cases¶
re-queueing an item that should be processed again next
implementing simple reprioritization within a FIFO queue
Queue API¶
unget(item, block=True, timeout=None) -> Nonebehaves like
put(...)regarding blocking/full-queue behaviorbut inserts at the front instead of the end
Queue example¶
q = Queue[int]()
q.put(1)
q.put(2)
q.unget(0) # will be processed next
assert q.get() == 0
assert q.get() == 1
assert q.get() == 2
Queue gotchas¶
If the queue has a
maxsizeand is full,ungetcan block or raisequeue.Full, consistent withput.ungetincrementsunfinished_tasks, just likeput.
NormalizedDefaultDict¶
NormalizedDefaultDict[VT] is a defaultdict variant that normalizes keys on both set and get. Keys are always normalized to str, so the class takes a single type parameter for the value type (VT).
NormalizedDefaultDict use cases¶
storing values indexed by case-insensitive keys (e.g. event names, resource names)
preventing accidental duplicates such as
"EVENT"vs"event"
Normalization¶
Default normalization is
key.lower().You can pass a custom
normalization=...function.If you initialize from a
dict, the initial keys are normalized too.
NormalizedDefaultDict example¶
d = NormalizedDefaultDict(set) # default_factory is positional-only
d["EVENT_TYPE"].add("client-1")
d["event_type"].add("client-2")
assert d["Event_Type"] == {"client-1", "client-2"}
Custom normalization example¶
d = NormalizedDefaultDict(
list, # default_factory is positional-only
normalization=lambda x: str(x).strip().lower(),
)
d[" Hello "].append(1)
assert d["hello"] == [1]
NormalizedDefaultDict gotchas¶
The default normalization assumes the key supports
.lower().In practice, this is intended for string keys.
If you want to accept non-string keys, provide a normalization function that converts to string first.