diff --git a/ndscan/experiment/fragment.py b/ndscan/experiment/fragment.py index bd029f4f..a458d43a 100644 --- a/ndscan/experiment/fragment.py +++ b/ndscan/experiment/fragment.py @@ -370,7 +370,7 @@ def setattr_param(self, name: str, param_class: type, description: str, *args, param = param_class(fqn, description, *args, **kwargs) self._free_params[name] = param - handle = param.HandleType(self, name) + handle = param.HandleType(self, name, param) setattr(self, name, handle) return handle @@ -419,7 +419,7 @@ def setattr_param_like(self, init_params["fqn"] = self.fqn + "." + name new_param = template_param.__class__(**init_params) self._free_params[name] = new_param - new_handle = new_param.HandleType(self, name) + new_handle = new_param.HandleType(self, name, new_param) setattr(self, name, new_handle) return new_handle @@ -548,8 +548,13 @@ def bind_param(self, param_name: str, source: ParamHandle) -> Any: del self._free_params[param_name] - source.owner._rebound_subfragment_params.setdefault(source.name, []).extend( - self._get_all_handles_for_param(param_name)) + handles = self._get_all_handles_for_param(param_name) + + for handle in handles: + handle.parameter = source.parameter + + source.owner._rebound_subfragment_params.setdefault(source.name, + []).extend(handles) return param diff --git a/ndscan/experiment/parameters.py b/ndscan/experiment/parameters.py index f71bf1a4..84ee12a0 100644 --- a/ndscan/experiment/parameters.py +++ b/ndscan/experiment/parameters.py @@ -7,7 +7,6 @@ # but to hang our heads in shame and manually instantiate the parameter handling # machinery for all supported value types, in particular to handle cases where e.g. # both an int and a float parameter is scanned at the same time. - from artiq.language import host_only, portable, units from enum import Enum from numpy import int32 @@ -213,12 +212,15 @@ class ParamHandle: :param owner: The owning fragment. :param name: The name of the attribute in the owning fragment bound to this object. + :param parameter: The parameter associated with this handle. The + :attr:`~.ParamHandle.parameter` attribute points to the parameter currently + associated with this handle, tracking binding of the parameter. """ - def __init__(self, owner: Any, name: str): - # `owner` will typically be a Fragment instance; no type hint to avoid circular - # dependency. + def __init__(self, owner: "Fragment", name: str, parameter): self.owner = owner self.name = name + self.parameter = parameter + assert name.isidentifier(), ("ParamHandle name should be the identifier it is " "referred to as in the owning fragment.") diff --git a/test/test_experiment_default_analysis.py b/test/test_experiment_default_analysis.py index ab255c26..184e6995 100644 --- a/test/test_experiment_default_analysis.py +++ b/test/test_experiment_default_analysis.py @@ -6,9 +6,10 @@ class CustomAnalysisTestCase(unittest.TestCase): def test_axis_matching(self): - foo = parameters.FloatParamHandle(None, "foo") + param = parameters.FloatParam("", "", 0.) + foo = parameters.FloatParamHandle(None, "foo", param) foo.set_store(parameters.FloatParamStore(("Fragment.foo", "*"), 0.0)) - bar = parameters.FloatParamHandle(None, "bar") + bar = parameters.FloatParamHandle(None, "bar", param) bar.set_store(parameters.FloatParamStore(("Fragment.bar", "*"), 1.0)) def make_axes(*axes): diff --git a/test/test_experiment_parameters.py b/test/test_experiment_parameters.py index 5377bdd7..f4ab111d 100644 --- a/test/test_experiment_parameters.py +++ b/test/test_experiment_parameters.py @@ -62,6 +62,7 @@ def build_fragment(inner_self) -> None: fqn = next(iter(schemata.keys())) self.assertTrue(fqn.endswith("Foo.baz")) self.assertEqual(schemata[fqn], self.EXPECTED_DESCRIPTION | {"fqn": fqn}) + self.assertEqual(foo.bar.parameter, foo.baz.parameter) class FloatParamCase(GenericBase.Cases):