fixed calibration data not loading due to path
This commit is contained in:
@@ -2,11 +2,13 @@
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import json
|
||||
|
||||
import numpy as np
|
||||
import pytest
|
||||
from scipy.signal import butter, filtfilt
|
||||
|
||||
from orisys import Sensor
|
||||
from orisys import Sensor, configs
|
||||
from orisys.signal_processing import (
|
||||
NORMAL_FORCE_CAL_OFFSET,
|
||||
NORMAL_FORCE_CAL_SLOPE,
|
||||
@@ -263,3 +265,156 @@ def test_configure_hhd_downsample_invalidates_solver_cache():
|
||||
sensor.configure(hhd_downsample="nope")
|
||||
finally:
|
||||
sensor.disconnect()
|
||||
|
||||
|
||||
# ------------------------------------------------- bundle resolution anchors
|
||||
#
|
||||
# The bundle is chosen by the *running* root's folder layout, not by the root's
|
||||
# name and not by whichever checkout happens to be importable. These build small
|
||||
# real trees, because ``_runtime_roots`` asks the filesystem whether a directory
|
||||
# carries ``examples/`` beside ``sensors/``.
|
||||
_CAL_DOC = {
|
||||
"schema_version": 2,
|
||||
"unit": "N",
|
||||
"channels": {
|
||||
"normal": {"method": "piecewise_linear", "points": [[0.0, 0.0], [1000.0, 1.0]]},
|
||||
"shear_x": {
|
||||
"method": "piecewise_linear",
|
||||
"signed": True,
|
||||
"points": [[0.0, 0.0], [500.0, 2.0]],
|
||||
},
|
||||
"shear_y": {
|
||||
"method": "piecewise_linear",
|
||||
"signed": True,
|
||||
"points": [[0.0, 0.0], [500.0, 3.0]],
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
def _make_root(base, *, name="anything", sensor_json=True, calibration=True):
|
||||
"""A runnable SDK root: ``examples/`` beside ``sensors/<name>/``."""
|
||||
root = base / name
|
||||
(root / "examples").mkdir(parents=True, exist_ok=True)
|
||||
if sensor_json:
|
||||
(root / "examples" / "basic_pipeline.py").write_text("# demo\n", encoding="utf-8")
|
||||
bundle = root / "sensors" / "mini"
|
||||
bundle.mkdir(parents=True, exist_ok=True)
|
||||
if sensor_json:
|
||||
(bundle / "sensor.json").write_text(
|
||||
json.dumps({"name": "prototype"}), encoding="utf-8"
|
||||
)
|
||||
if calibration:
|
||||
(bundle / "force_calibration.json").write_text(
|
||||
json.dumps(_CAL_DOC), encoding="utf-8"
|
||||
)
|
||||
return root
|
||||
|
||||
|
||||
def test_runtime_root_anchor_keys_on_layout_not_on_the_folder_name(tmp_path):
|
||||
named = _make_root(tmp_path, name="some-random-name")
|
||||
assert configs._is_sdk_runtime_root(named) is True
|
||||
|
||||
no_examples = tmp_path / "dist-like"
|
||||
(no_examples / "sensors" / "mini").mkdir(parents=True)
|
||||
assert configs._is_sdk_runtime_root(no_examples) is False
|
||||
|
||||
neither = tmp_path / "plain"
|
||||
neither.mkdir()
|
||||
assert configs._is_sdk_runtime_root(neither) is False
|
||||
|
||||
|
||||
def test_runtime_roots_walk_up_from_a_subdirectory(tmp_path, monkeypatch):
|
||||
root = _make_root(tmp_path, name="renamed-release")
|
||||
subdir = root / "examples"
|
||||
monkeypatch.setattr(configs.Path, "cwd", classmethod(lambda cls: subdir))
|
||||
roots = [str(path) for path in configs._runtime_roots()]
|
||||
assert str(root) in roots
|
||||
|
||||
|
||||
def test_the_running_root_bundle_beats_a_calibration_less_checkout(
|
||||
tmp_path, monkeypatch
|
||||
):
|
||||
"""The reported bug: a nearer bundle without coefficients must not win."""
|
||||
running = _make_root(tmp_path, name="running-root")
|
||||
checkout = _make_root(tmp_path, name="importable-checkout", calibration=False)
|
||||
monkeypatch.setattr(configs, "_runtime_roots", lambda: [running, checkout])
|
||||
|
||||
bundle = configs.resolve_sensor_bundle("mini")
|
||||
assert bundle is not None
|
||||
assert bundle.root == (running / "sensors" / "mini").resolve()
|
||||
assert bundle.force_calibration_json == (
|
||||
running / "sensors" / "mini" / "force_calibration.json"
|
||||
).resolve()
|
||||
|
||||
# The whole point: the running root's document is the one that reaches the
|
||||
# sensor, split shear and all.
|
||||
sensor = Sensor("external", config_name="mini", verbose=False, backend="cpu")
|
||||
try:
|
||||
assert sensor.force_calibrated is True
|
||||
assert sensor.force_unit == "N"
|
||||
assert sensor.calibration.source_path == (
|
||||
running / "sensors" / "mini" / "force_calibration.json"
|
||||
).resolve()
|
||||
finally:
|
||||
sensor.disconnect()
|
||||
|
||||
|
||||
def test_a_nearer_bundle_wins_even_without_coefficients(tmp_path, monkeypatch):
|
||||
"""Nearest bundle wins, so a calibration-less nearer one hides a farther one.
|
||||
|
||||
That is the chosen precedence (the running root is authoritative), and the
|
||||
diagnostic exists precisely so this stops being silent: this is the shape of
|
||||
the original report, where a checkout's ``mini`` has only ``sensor.json``.
|
||||
"""
|
||||
checkout = _make_root(tmp_path, name="checkout", calibration=False)
|
||||
running = _make_root(tmp_path, name="run-root")
|
||||
monkeypatch.setattr(configs, "_runtime_roots", lambda: [checkout, running])
|
||||
bundle = configs.resolve_sensor_bundle("mini")
|
||||
assert bundle is not None
|
||||
assert bundle.root == (checkout / "sensors" / "mini").resolve()
|
||||
assert bundle.force_calibration_json is None
|
||||
info = configs.describe_bundle_resolution("mini")
|
||||
assert info["found_root"] == (checkout / "sensors" / "mini").resolve()
|
||||
assert info["force_calibration_json"] is False
|
||||
|
||||
|
||||
def test_describe_bundle_resolution_names_the_bundle_and_the_searched_roots(
|
||||
tmp_path, monkeypatch
|
||||
):
|
||||
checkout = _make_root(tmp_path, name="checkout", calibration=False)
|
||||
running = _make_root(tmp_path, name="run-root")
|
||||
roots = [checkout / "sensors", running / "sensors"]
|
||||
# Patched at the root list, so no real bundle on this machine can satisfy
|
||||
# the lookup while the "nothing found" case is being asserted.
|
||||
monkeypatch.setattr(configs, "_candidate_sensor_roots", lambda: list(roots))
|
||||
|
||||
info = configs.describe_bundle_resolution("mini")
|
||||
assert info["found_root"] == (checkout / "sensors" / "mini").resolve()
|
||||
assert info["force_calibration_json"] is False
|
||||
assert [str(path) for path in info["searched"]] == [str(p) for p in roots]
|
||||
|
||||
(checkout / "sensors" / "mini" / "sensor.json").unlink()
|
||||
(running / "sensors" / "mini" / "sensor.json").unlink()
|
||||
missing = configs.describe_bundle_resolution("mini")
|
||||
assert missing["found_root"] is None
|
||||
assert missing["sensor_json"] is None
|
||||
assert missing["force_calibration_json"] is False
|
||||
|
||||
|
||||
def test_the_calibration_note_names_the_bundle_that_was_found(
|
||||
tmp_path, monkeypatch
|
||||
):
|
||||
checkout = _make_root(tmp_path, name="checkout", calibration=False)
|
||||
monkeypatch.setattr(configs, "_runtime_roots", lambda: [checkout])
|
||||
sensor = Sensor("external", config_name="mini", verbose=False, backend="cpu")
|
||||
try:
|
||||
assert sensor.calibration is None
|
||||
# Still None: callers read a non-None value here as "calibrated".
|
||||
assert sensor._force_cal_sensor_name is None
|
||||
note = sensor._force_calibration_note()
|
||||
assert "has no force_calibration.json" in note
|
||||
assert str((checkout / "sensors" / "mini").resolve()) in note
|
||||
assert "roots searched" in note
|
||||
finally:
|
||||
sensor.disconnect()
|
||||
|
||||
Reference in New Issue
Block a user