gabriel / muse public
record_helpers.py python
76 lines 2.2 KB
Raw
1 """muse.core.record_helpers — typed accessor helpers for deserialized storage dicts.
2
3 Used by CommitRecord, SnapshotRecord, TagRecord, and ReleaseRecord to safely
4 extract typed values from raw JSON/msgpack mappings without raising on missing
5 or wrong-typed fields.
6 """
7 from __future__ import annotations
8
9 from muse.core.types import MsgpackDict, Manifest
10
11
12 def _str_val(
13 d: MsgpackDict, key: str, default: str = ""
14 ) -> str:
15 """Return ``d[key]`` as ``str``, or *default* if absent or wrong type."""
16 val = d.get(key, default)
17 return val if isinstance(val, str) else default
18
19
20 def _int_val(
21 d: MsgpackDict, key: str, default: int = 0
22 ) -> int:
23 """Return ``d[key]`` as ``int``, or *default* if absent or wrong type.
24
25 Excludes ``bool`` (which is a subclass of ``int`` in Python) to prevent
26 accidental coercion.
27 """
28 val = d.get(key, default)
29 return val if isinstance(val, int) and not isinstance(val, bool) else default
30
31
32 def _str_or_none(
33 d: MsgpackDict, key: str
34 ) -> str | None:
35 """Return ``d[key]`` as ``str | None``."""
36 val = d.get(key)
37 return val if isinstance(val, str) else None
38
39
40 def _str_list(
41 d: MsgpackDict, key: str
42 ) -> list[str]:
43 """Return ``d[key]`` as ``list[str]``, filtering non-string elements."""
44 val = d.get(key)
45 if not isinstance(val, list):
46 return []
47 return [x for x in val if isinstance(x, str)]
48
49
50 def _str_dict(
51 d: MsgpackDict, key: str
52 ) -> Manifest:
53 """Return ``d[key]`` as ``dict[str, str]``, filtering non-string values."""
54 val = d.get(key)
55 if not isinstance(val, dict):
56 return {}
57 return {k: v for k, v in val.items() if isinstance(v, str)}
58
59
60 def _float_val(
61 d: MsgpackDict, key: str, default: float | None = None
62 ) -> float | None:
63 """Return ``d[key]`` as ``float | None``, or *default* if absent or wrong type.
64
65 Accepts ``int`` values (coerced to float) since stored JSON may encode a round
66 float like ``1.0`` as an integer. Excludes ``bool`` to prevent accidental
67 coercion from boolean-typed fields.
68 """
69 val = d.get(key, default)
70 if val is None:
71 return None
72 if isinstance(val, bool):
73 return default
74 if isinstance(val, (int, float)):
75 return float(val)
76 return default
File History 1 commit