Files
2026-10-06 12:32:26 +03:00

82 lines
4.3 KiB
Python

"""Embedded preprocess metadata and compatibility with older NPZ sets."""
import json
from pathlib import Path
import tempfile
import unittest
import numpy as np
from python_app.models.dataset_model import ComboKey, SweepCollection, TraceData
from python_app.storage.npz.store import NpzStore
class SetMetadataTest(unittest.TestCase):
def setUp(self) -> None:
temporary = tempfile.TemporaryDirectory()
self.addCleanup(temporary.cleanup)
self.root = Path(temporary.name)
self.store = NpzStore(self.root)
self.kind = "s21_object_calibration"
self.collection = SweepCollection(7, 100, [TraceData(
ComboKey(2, 3), np.array([1e9, 2e9], dtype=np.float32),
np.array([1 + 2j, 3 - 4j], dtype=np.complex64),
capture_start_ns=80, capture_end_ns=90,
)], capture_start_ns=80, capture_end_ns=90)
self.metadata = {"radar_key": "radar", "geometry": [{"input_pos": 2, "x": 0.1}],
"through": {"name": "through", "hash": "abc"}, "collection_id": "user value"}
self.store.save_set(self.kind, "radar", "object", self.collection, metadata=self.metadata)
self.archive = self.root / self.kind / "radar/object.npz"
self.sidecar = self.archive.with_suffix(".json")
def test_metadata_and_collection_round_trip_through_generic_set_api(self) -> None:
loaded, metadata = self.store.load_set_with_metadata(self.kind, "radar", "object")
self.assertEqual(metadata, self.metadata)
self.assertEqual((loaded.collection_id, loaded.monotonic_ns), (7, 100))
self.assertEqual((loaded.capture_start_ns, loaded.capture_end_ns), (80, 90))
self.assertEqual((loaded.traces[0].capture_start_ns, loaded.traces[0].capture_end_ns), (80, 90))
np.testing.assert_array_equal(loaded.traces[0].s21, self.collection.traces[0].s21)
np.testing.assert_array_equal(loaded.traces[0].frequency_hz, self.collection.traces[0].frequency_hz)
self.assertEqual(self.store.load_set(self.kind, "radar", "object").collection_id, 7)
self.assertEqual(self.store.list_sets(self.kind, "radar"), ["object"])
self.assertTrue(self.store.has_combo_coverage(self.kind, "radar", "object", [ComboKey(2, 3)]))
self.assertFalse(self.store.has_combo_coverage(self.kind, "radar", "object", [ComboKey(0, 0)]))
def test_embedded_metadata_is_authoritative_when_sidecar_is_stale_or_missing(self) -> None:
for sidecar in ('{"metadata": {"radar_key": "wrong"}}', "broken JSON", None):
with self.subTest(sidecar=sidecar):
if sidecar is None:
self.sidecar.unlink()
else:
self.sidecar.write_text(sidecar, encoding="utf-8")
_, metadata = self.store.load_set_with_metadata(self.kind, "radar", "object")
self.assertEqual(metadata, self.metadata)
def test_old_sets_without_user_metadata_load_with_empty_dict(self) -> None:
with np.load(self.archive, allow_pickle=False) as stored:
arrays = {key: stored[key] for key in stored.files if key != "metadata_json"}
envelope = json.loads(self.sidecar.read_text(encoding="utf-8"))
del envelope["metadata"]
self.sidecar.write_text(json.dumps(envelope), encoding="utf-8")
for embedded in (True, False):
with self.subTest(embedded=embedded):
payload = dict(arrays)
if embedded:
payload["metadata_json"] = np.asarray(json.dumps(envelope))
np.savez(self.archive, **payload)
collection, metadata = self.store.load_set_with_metadata(self.kind, "radar", "object")
self.assertEqual(metadata, {})
np.testing.assert_array_equal(collection.traces[0].s21, self.collection.traces[0].s21)
def test_invalid_metadata_cannot_overwrite_saved_set(self) -> None:
before = (self.archive.read_bytes(), self.sidecar.read_bytes())
for metadata in ({"value": float("nan")}, {"value": [float("inf")]}, {"value": object()}):
with self.subTest(metadata=metadata), self.assertRaises((TypeError, ValueError)):
self.store.save_set(self.kind, "radar", "object", self.collection, metadata=metadata)
self.assertEqual((self.archive.read_bytes(), self.sidecar.read_bytes()), before)