Coverage for event_normalizer/serializers/flat_dict.py: 100%
24 statements
« prev ^ index » next coverage.py v7.15.4, created at 2026-08-21 20:04 +0000
« prev ^ index » next coverage.py v7.15.4, created at 2026-08-21 20:04 +0000
1"""Flat dictionary serialization for normalized events."""
3from typing import Any
5from ..models import NormalizedEvent
7SUPPORTED_INSTRUMENTS = ("H1", "L1", "V1", "K1")
10def to_flat_dict(
11 event: NormalizedEvent,
12 *,
13 exclude_none: bool = True,
14) -> dict[str, Any]:
15 """
16 Convert a normalized event into a one-level dictionary.
18 Nested models already use prefixed fields:
19 - coinc.coinc_mass -> coinc_mass
20 - burst.burst_snr -> burst_snr
21 - mly.mly_SNR -> mly_SNR
22 - single_H1.single_snr -> single_H1_single_snr
23 - labels.label_MOCK -> label_MOCK
25 Detector lists become numeric metric fields:
26 - ["H1", "L1"] ->
27 instruments_H1 = 1
28 instruments_L1 = 1
29 instruments_V1 = 0
30 instruments_K1 = 0
31 """
32 raw = event.model_dump(
33 exclude_none=exclude_none,
34 mode="json",
35 )
37 result: dict[str, Any] = {}
39 nested_keys = {
40 "coinc",
41 "burst",
42 "mly",
43 "single_H1",
44 "single_L1",
45 "single_V1",
46 "single_K1",
47 "labels",
48 "p_astro",
49 "em_bright",
50 "links",
51 }
53 for key, value in raw.items():
54 if key in nested_keys:
55 continue
57 if key == "instruments":
58 actual_instruments = set(value or [])
60 for instrument in SUPPORTED_INSTRUMENTS:
61 result[f"instruments_{instrument}"] = int(
62 instrument in actual_instruments
63 )
65 continue
67 result[key] = value
69 for nested_key in nested_keys:
70 nested_value = raw.get(nested_key)
72 if isinstance(nested_value, dict):
73 # For single_H1, single_L1, etc., prefix with the IFO name
74 if nested_key.startswith("single_"):
75 for sub_key, sub_value in nested_value.items():
76 result[f"{nested_key}_{sub_key}"] = sub_value
77 else:
78 result.update(nested_value)
80 return result