From 1040e2dfae807760562d4bc5124b4f4b6ec7b618 Mon Sep 17 00:00:00 2001 From: Thomas A Caswell Date: Mon, 25 Nov 2024 12:44:01 -0500 Subject: [PATCH 1/4] DOC: add key missing 'in' --- ophyd/device.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ophyd/device.py b/ophyd/device.py index 270e19759..0d9882a52 100644 --- a/ophyd/device.py +++ b/ophyd/device.py @@ -234,7 +234,7 @@ def maybe_add_prefix(self, instance, kw, suffix): suffix from. kw : str - The key of associated with the suffix. If this key is + The key of associated with the suffix. If this key is in self.add_prefix than prepend the prefix to the suffix and return, else just return the suffix. From 0ead9f794ffa74283df3a70d3b33264a61aa2d04 Mon Sep 17 00:00:00 2001 From: Thomas A Caswell Date: Mon, 25 Nov 2024 12:44:22 -0500 Subject: [PATCH 2/4] ENH: add ability to control component names are mangled The Python name (via attributes) of a child device is `foo.bar.baz`, however for a number of historical reasons (allowed keys in mongo and for attribute access in Pandas data frames with columns named from the data keys in an event stream) ophyd-sync has replaced '.' with '_' in the names. This leads to ambiguity when looking at the (default) name to which component on which device the data came from as there may be `_` in the attribute names. Ophyd-async used '-' which does allow for round tripping. This makes it controllable on per-instance basis in ophyd-sync so that users can either make a different set of trade offs. xref https://github.com/bluesky/ophyd-async/issues/666 --- ophyd/device.py | 7 +++++-- ophyd/tests/test_device.py | 28 ++++++++++++++++++++++++++++ 2 files changed, 33 insertions(+), 2 deletions(-) diff --git a/ophyd/device.py b/ophyd/device.py index 0d9882a52..59f579ccb 100644 --- a/ophyd/device.py +++ b/ophyd/device.py @@ -253,10 +253,12 @@ def create_component(self, instance): "Instantiate the object described by this Component for a Device" kwargs = self.kwargs.copy() kwargs.update( - name=f"{instance.name}_{self.attr}", + name=f"{instance.name}{instance._child_name_separator}{self.attr}", kind=instance._component_kinds[self.attr], attr_name=self.attr, ) + if issubclass(self.cls, Device): + kwargs.setdefault("child_name_separator", instance._child_name_separator) for kw, val in list(kwargs.items()): kwargs[kw] = self.maybe_add_prefix(instance, kw, val) @@ -839,10 +841,11 @@ def __init__( read_attrs=None, configuration_attrs=None, parent=None, + child_name_separator="_", **kwargs, ): self._destroyed = False - + self._child_name_separator = child_name_separator # Store EpicsSignal objects (only created once they are accessed) self._signals = {} diff --git a/ophyd/tests/test_device.py b/ophyd/tests/test_device.py index 926bbab53..0aec7bca3 100644 --- a/ophyd/tests/test_device.py +++ b/ophyd/tests/test_device.py @@ -969,3 +969,31 @@ class FakeTriggerableDevice(Device): d.trigger() assert d.strigger.get() == after + + +def test_child_separator(): + class Test(Device): + a = Component(Signal) + b = Component(Signal) + + t = Test(name="bob") + assert t.a.name == "bob_a" + + t = Test(name="bob", child_name_separator="-") + assert t.a.name == "bob-a" + + class Test2(Device): + c = Component(Signal) + d = Component(Signal) + t = Component(Test) + s = Component(Test, child_name_separator="?") + + t2 = Test2(name="bob", child_name_separator="!") + + assert t2.c.name == "bob!c" + assert t2.d.name == "bob!d" + + assert t2.t.a.name == "bob!t!a" + assert t2.t.b.name == "bob!t!b" + assert t2.s.a.name == "bob!s?a" + assert t2.s.b.name == "bob!s?b" From fb49ef82cd9622dd4cf2107308df16672c4efa5c Mon Sep 17 00:00:00 2001 From: Thomas A Caswell Date: Mon, 25 Nov 2024 13:36:26 -0500 Subject: [PATCH 3/4] MNT: try to avoid segfaults --- ophyd/_pyepics_shim.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/ophyd/_pyepics_shim.py b/ophyd/_pyepics_shim.py index 118ee20d8..09c83ea5f 100644 --- a/ophyd/_pyepics_shim.py +++ b/ophyd/_pyepics_shim.py @@ -7,6 +7,10 @@ from ._dispatch import EventDispatcher, _CallbackThread, wrap_callback +# suspect attempt to monkey-patch printf is causing segfaults +if hasattr(ca, "WITH_CA_MESSAGES"): + ca.WITH_CA_MESSAGES = True + _min_pyepics = "3.4.2" if parse(epics.__version__) < parse(_min_pyepics): From 38c35ef3c3fa19d7b0e7ac922ece3dcfb842a5a0 Mon Sep 17 00:00:00 2001 From: Thomas A Caswell Date: Mon, 25 Nov 2024 15:17:09 -0500 Subject: [PATCH 4/4] CI: pin back pyepics to try and avoid segfaults --- setup.cfg | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.cfg b/setup.cfg index bf835213f..6db9029ac 100644 --- a/setup.cfg +++ b/setup.cfg @@ -50,7 +50,7 @@ dev = numpydoc pre-commit pydata-sphinx-theme - pyepics>=3.4.2 + pyepics>=3.4.2,<3.5.7 pytest pytest-asyncio pytest-cov