One of the lcls2 tests is failing and it looks like a real issue.
This interface is not deployed in any hutches yet.
```
=================================== FAILURES ===================================
________________________________ test_configure ________________________________
daq_lcls2 = DaqLCLS2(, name=daq)
def test_configure(daq_lcls2: DaqLCLS2):
"""
Configure must have the following behavior:
- kwargs end up in cfg signals (spot check 1 or 2)
- Returns (old_cfg, new_cfg)
- Configure transition caused if needed from conn/conf states
- Conf needed if recording gui clicked, or critical kwargs changed,
or if never done, or if someone else configured
- From the conf state, we unconf before confing
- Configure transition not caused if not needed
- Error if we're not in conn/conf states and a transition is needed
- Controls arg processed with no errors (except bad user ValueError)
- record doesn't require a configure transition, but it does
require no open run
"""
logger.debug('test_configure')
# The first configure should cause a transition
# Let's start in connected and check the basic stuff
daq_lcls2._control.sim_set_states(
transition='connect',
state='connected',
)
daq_lcls2._get_status_for(state=['connected']).wait(timeout=1)
prev_tst = daq_lcls2.read_configuration()
prev_cfg, post_cfg = daq_lcls2.configure(events=100, detname='dat')
assert daq_lcls2.events_cfg.get() == 100
assert daq_lcls2.detname_cfg.get() == 'dat'
post_tst = daq_lcls2.read_configuration()
assert (prev_cfg, post_cfg) == (prev_tst, post_tst)
# Changing controls should make us reconfigure
st_conn = daq_lcls2._get_status_for(state=['connected'], check_now=False)
st_conf = daq_lcls2._get_status_for(state=['configured'], check_now=False)
daq_lcls2.configure(controls=(Signal(name='sig'),))
st_conn.wait(timeout=1)
st_conf.wait(timeout=1)
# Changing events should not make us reconfigure
st_any = daq_lcls2._get_status_for(check_now=False)
daq_lcls2.configure(events=1000)
with pytest.raises(WaitTimeoutError):
st_any.wait(1)
st_any.set_finished()
# Any out of process configuration should make us reconfigure
daq_lcls2._control.setState('connected', {})
sig_wait_value(daq_lcls2.state_sig, daq_lcls2.state_enum.connected)
daq_lcls2._control.setState('configured', {})
sig_wait_value(daq_lcls2.state_sig, daq_lcls2.state_enum.configured)
st_conn = daq_lcls2._get_status_for(state=['connected'], check_now=False)
st_conf = daq_lcls2._get_status_for(state=['configured'], check_now=False)
assert (
daq_lcls2.configures_seen_sig.get()
> daq_lcls2.configures_requested_sig.get()
)
daq_lcls2.configure()
st_conn.wait(timeout=1)
st_conf.wait(timeout=1)
# Configure should error if transition needed from most of the states
bad_states = daq_lcls2.state_enum.exclude(['connected', 'configured'])
for state in bad_states:
logger.debug('testing %s', state)
daq_lcls2.state_sig.put(state)
with pytest.raises(RuntimeError):
daq_lcls2.configure(detname=state.name)
# Let's set up a controls arg and make sure it at least doesn't error
# Hard to check the DAQ side without making a very sophisticated sim
daq_lcls2._control.setState('connected', {})
daq_lcls2._get_status_for(state=['connected']).wait(timeout=1)
daq_lcls2._last_config = {}
daq_lcls2.configure(controls=(
Signal(name='sig'),
SoftPositioner(init_pos=0, name='pos'),
('const', 3),
))
# Again, but with at least one example of a bad controls arg
daq_lcls2._control.setState('connected', {})
daq_lcls2._get_status_for(state=['connected']).wait(timeout=1)
daq_lcls2._last_config = {}
with pytest.raises(ValueError):
daq_lcls2.configure(controls=(
Signal(name='one_good_thing'),
'some bad stuff here',
0.[232](https://github.com/pcdshub/pcdsdaq/actions/runs/4369116062/jobs/7642540901#step:17:233)323232323,
))
daq_lcls2.preconfig(controls=())
# Changing record during an open run should fail.
daq_lcls2.configure(record=True)
daq_lcls2._control.setState('running', {})
sig_wait_value(daq_lcls2.recording_sig, True)
sig_wait_value(daq_lcls2.state_sig, daq_lcls2.state_enum.running)
with pytest.raises(RuntimeError):
daq_lcls2.configure(record=False)
# Unless it's to the same recording state we already have
> daq_lcls2.configure(record=True)
tests/test_daq_lcls2.py:397:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
self = DaqLCLS2(, name=daq)
events =
duration =
record = True
controls =
motors =
begin_timeout =
begin_sleep =
group_mask =
detname =
scantype =
serial_number =
alg_name =
alg_version =
def configure(
self,
events: int | None | Sentinel = CONFIG_VAL,
duration: Real | None | Sentinel = CONFIG_VAL,
record: bool | TernaryBool | None | Sentinel = CONFIG_VAL,
controls: ControlsArg | None | Sentinel = CONFIG_VAL,
motors: ControlsArg | None | Sentinel = CONFIG_VAL,
begin_timeout: Real | None | Sentinel = CONFIG_VAL,
begin_sleep: Real | None | Sentinel = CONFIG_VAL,
group_mask: int | None | Sentinel = CONFIG_VAL,
detname: str | None | Sentinel = CONFIG_VAL,
scantype: str | None | Sentinel = CONFIG_VAL,
serial_number: str | None | Sentinel = CONFIG_VAL,
alg_name: str | None | Sentinel = CONFIG_VAL,
alg_version: list[int] | None | Sentinel = CONFIG_VAL,
):
"""
Adjusts the configuration, causing a "configure" transition if needed.
A "configure" transition will be caused in the following cases:
1. We are in the "connected" state
2. We are in the "configured" state but an important configuration
parameter has been changed. In this case, we will revert to the
"connected" state and then return to the "configured" state.
3. We are in the "configured" state but the configure was caused by
some other process, for example, the DAQ GUI or a different
Python session.
In all other states, this will raise a "RuntimeError" if it decides
that a "configure" transition is needed.
Arguments that are not provided are not changed.
Arguments that are passed as "None" will return to their
default values.
Parameters
----------
events : int or None, optional
The number of events to take per step. Incompatible with the
"duration" argument. Defaults to "None", and running without
configuring events or duration gives us an endless run (that
can be terminated manually). Supplying an argument to "events"
will reset "duration" to "None".
duration : float or None, optional
How long to acquire data at each step in seconds.
Incompatible with the "events" argument. Defaults to "None",
and running without configuring events or duration dives us
an endless run (that can be terminated manually). Supplying
an argument to "duration" will reset "events" to "None".
record : bool or None, optional
Whether or not to save data during the DAQ run. Defaults to
"None", which means that we'll keep the DAQ's recording
state at whatever it is at the start of the run.
Changing the DAQ recording state cannot be done during a run,
but it will not require a configure transition.
controls : list or tuple of valid objects, or None, optional
The objects to include per-step in the DAQ data stream.
These must implement the "name" attribute and either the
"position" attribute or the "get" method to retrieve their
current value. To enforce an alternate name, you can pass a tuple
instead of an object where the first element of the tuple is
the replacement name. The tuple syntax can also be used to send
primitive constants to the DAQ if the constant is an int, float,
or str.
If None or empty, we'll only include the default DAQ step counter,
which will always be included.
motors : list or dict of signals or positioners, or None, optional
Alias of "controls" for backwards compatibility.
begin_timeout : float or None, optional
How long to wait before marking a begin run as a failure and
raising an exception.
begin_sleep : float or None, optional
How long to wait before starting a run.
group_mask : int or None, optional
Bitmask that is used by the DAQ. This docstring writer is not
sure exactly what it does. The default is all zeroes with a
"1" bitshifted left by the platform number.
detname : str or None, optional
The name associated with the controls data in the DAQ.
Defaults to "scan".
scantype : str or None, optional
Another string associated with the runs produced by this
object in the DAQ. Defaults to "scan".
serial_number : str or None, optional
Another string associated with the runs produced by this
object in the DAQ. Defaults to "1[234](https://github.com/pcdshub/pcdsdaq/actions/runs/4369116062/jobs/7642540901#step:17:235)".
alg_name : str or None, optional
Another string associated with the runs produced by this
object in the DAQ. Defaults to "raw".
alg_version : list of int, or None, optional
The version numbers [major, minor, bugfix] associated with
alg_name. Defaults to [1, 0, 0].
Returns
-------
(old, new): tuple[dict, dict]
The configurations before and after the function was called.
This is used internally by bluesky when we include
"configure" in a plan.
"""
logger.debug("DaqLCLS2.configure, passing to super")
old, new = super().configure(
events=events,
duration=duration,
record=record,
controls=controls,
motors=motors,
begin_timeout=begin_timeout,
begin_sleep=begin_sleep,
group_mask=group_mask,
detname=detname,
scantype=scantype,
serial_number=serial_number,
alg_name=alg_name,
alg_version=alg_version,
)
other_proc_configured = (
self.configures_seen_sig.get()
!= self.configures_requested_sig.get()
)
first_configure = self.configures_requested_sig.get() == 0
# Cause a transition if we need to
if any((
self._queue_configure_transition,
other_proc_configured,
first_configure,
)):
if self.state_sig.get() < self.state_enum.connected:
raise RuntimeError('Not ready to configure.')
if self.state_sig.get() > self.state_enum.configured:
> raise RuntimeError(
'Cannot configure transition during an open run!'
)
E RuntimeError: Cannot configure transition during an open run!
```
One of the lcls2 tests is failing and it looks like a real issue. This interface is not deployed in any hutches yet.
Originally posted by @ZLLentz in https://github.com/pcdshub/pcdsdaq/issues/115#issuecomment-1462694398