Repository: bluesky/bluesky
Pull request #1902 (2025-05-06 05:06:51)

FIX: regenerate the configuration cache before the descriptors
Doing it in the opposite order results in the old configuration value going in the new descriptor.

<!--- Provide a general summary of your changes in the Title above -->

## Description
<!--- Describe your changes in detail -->

I broke this in f1b3179329f7af91acc3846b805a47f3403308f0 .  It would have been caught by tests in databroker (which the new test is a modified version of), but it was xfailed due to other the temorary too-strict rules for pre-declare and it was never un-xfailed.

## Motivation and Context
<!--- Why is this change required? What problem does it solve? -->
<!--- If it fixes an open issue, please link to the issue here. -->

Found a bluesky regression while working on tiled/databroker support

## How Has This Been Tested?
<!--- Please describe in detail how you tested your changes. -->
<!--- Include details of your testing environment, and the tests you ran to -->
<!--- see how your change affects other areas of the code, etc. -->

Added a test adapted from databroker tests.

<!--
## Screenshots (if appropriate):
-->



Patch:
diff --git a/src/bluesky/bundlers.py b/src/bluesky/bundlers.py
index 0eb10b15..e970708b 100644
--- a/src/bluesky/bundlers.py
+++ b/src/bluesky/bundlers.py
@@ -1172,6 +1172,7 @@ class RunBundler:
             object.configure(*args, **kwargs)
         """
         obj = msg.obj
+        await self._cache_read_config(obj)
         # Invalidate any event descriptors that include this object.
         # New event descriptors, with this new configuration, will
         # be created for any future event documents.
@@ -1181,5 +1182,3 @@ class RunBundler:
                 del self._descriptors[name]
                 await self._prepare_stream(name, obj_set)
                 continue
-
-        await self._cache_read_config(obj)


Test patch:
diff --git a/src/bluesky/tests/test_run_engine.py b/src/bluesky/tests/test_run_engine.py
index bfcc76af..d004108a 100644
--- a/src/bluesky/tests/test_run_engine.py
+++ b/src/bluesky/tests/test_run_engine.py
@@ -12,7 +12,16 @@ import pytest
 from event_model import DocumentNames
 
 from bluesky import Msg, RunEngine
-from bluesky.plan_stubs import abs_set, checkpoint, declare_stream, pause, trigger_and_read, wait, wait_for
+from bluesky.plan_stubs import (
+    abs_set,
+    checkpoint,
+    configure,
+    declare_stream,
+    pause,
+    trigger_and_read,
+    wait,
+    wait_for,
+)
 from bluesky.plans import count, grid_scan
 from bluesky.preprocessors import (
     SupplementalData,
@@ -2073,3 +2082,49 @@ def test_1event_rewind(RE, hw):
         "save",
         "close_run",
     ]
+
+
+@requires_ophyd
+def test_configure_multiple_descritpors(RE):
+    from ophyd import Component as C
+    from ophyd import Device, sim
+
+    class SynWithConfig(Device):
+        x = C(sim.Signal, value=0)
+        y = C(sim.Signal, value=2)
+        z = C(sim.Signal, value=3)
+
+    det = SynWithConfig(name="det")
+    det.x.name = "x"
+    det.y.name = "y"
+    det.z.name = "z"
+    det.read_attrs = ["x"]
+    det.configuration_attrs = ["y", "z"]
+
+    @run_decorator()
+    def plan(det):
+        # run without an exciting descriptor
+        yield from configure(det, {"z": 3})
+        # force a descriptor to be created
+        yield from declare_stream(det, name="primary")
+        # and an event
+        yield from trigger_and_read([det], name="primary")
+        # update the config which will re-generate the descriptor
+        yield from configure(det, {"z": 4})
+        # and a second event
+        yield from trigger_and_read([det], name="primary")
+
+    d = DocCollector()
+    RE(plan(det), d.insert)
+
+    (start,) = d.start
+    descA, descB = d.descriptor[start["uid"]]
+    stop = d.stop[start["uid"]]
+
+    assert descA["configuration"]["det"]["data"]["z"] == 3
+    assert descB["configuration"]["det"]["data"]["z"] == 4
+
+    for desc in (descA, descB):
+        assert len(d.event[desc["uid"]]) == 1
+
+    assert stop["num_events"]["primary"] == 2