The previous commit added `logger = bec_logger.logger` at module level. The
macro loader rejects any module-level ast.Assign
(bec_lib.macro_update_handler.has_executable_code) and then refuses the whole
file, so run_cont_grid_scan_for_table_row stopped being loaded at all:
Macro file .../run_cont_grid_scan_for_table_row.py contains executable code
at module level (line 16) and will not be loaded for security reasons.
Imports, defs, classes, annotated assignments and docstrings are permitted;
plain assignments are not. The logger is now fetched inside the functions.
Adds a test that runs the real has_executable_code over every macro, so this is
caught by the suite instead of by a WARNING in the log stream. Verified to fail
when a module-level assignment is reintroduced.
Noticed only because bec-log-monitor happened to be running at the time -- a
refused macro is otherwise indistinguishable from one that was never installed.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0148tn6uK6oiTH25mzLfJcyc
The tensor-tomography branch of run_cont_grid_scan_for_table_row has never
worked. `dev` is already the device container -- bec_lib binds
dev = device_manager.devices in the client namespace -- so dev.devices[name]
asks DeviceContainer for a device literally called "devices" and its
__getattr__ raises DeviceConfigError before any motor moves.
Observed at the beamline on a tensor table using sgchi/sgphi as the rotation
axes:
--> 72 roty_motor = dev.devices[row["roty_axis"]]
DeviceConfigError: Device devices does not exist.
The failure is deterministic, so @scan_repeat(max_repeats=3, default=True)
retried it three times, and the surrounding except reported only "Error while
moving motors to starting position for sample ..." -- the traceback goes to
SciLog and nowhere else, which is why this survived undetected.
Adds tests/tests_macros, which had no equivalent: macros run in the client
namespace and are not executed by any test, so mistakes in them reach the
beamline unfiltered. The check parses each macro and flags dev.devices
attribute access rather than matching text, so comments and docstrings that
mention the pattern do not trip it. Verified to fail against the unfixed macro.
The rotation axes themselves are not hard-coded: rotx_axis/roty_axis are row
fields holding a device name chosen from the SAXS widget's positioner combo
boxes. Only the four row keys are fixed.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0148tn6uK6oiTH25mzLfJcyc