Initial BEC ophyd integration for the SmarGon goniometer via the smargopolo
RESTful API. Controls the virtual SCS axes (the server runs the kinematics; the
underlying q1..q6 stages are never commanded directly). Structure mirrors the
Canon CR-N300 device: an ophyd-free transport (real RestTransport over urllib +
in-memory FakeTransport) with threaded poll-to-tolerance positioners and a
PSIDeviceBase parent.
Scope / decisions:
- v1 movable axes: SHX SHY SHZ CHI PHI; OMEGA optional via has_omega (YAML).
- Referencing is a deliberate operator action (reference()); moves refuse unless
Mode.READY.
- Soft limits are user-set; smargopolo owns the coupled hardware limits. Both
fault paths handled: up-front PUT rejection fails the move immediately, and a
mid-move fault (mode -> 99 ERROR) aborts the in-flight move with the rosout
detail (SmarGon._raise_if_error).
- Move completion = readback within (user-set) tolerance, done on first
in-tolerance sample (robust to active position-hold dither).
Status: DRAFT. 27 unit tests pass against FakeTransport, but NOTHING has been
tested against a real smargopolo server or hardware. Do not commission as-is.
Open questions (to confirm with the smargopolo maintainer, W. Glettig):
- Stop semantics: no explicit stop endpoint; we abort by retargeting an axis to
its current readback ("Follow Target" halt). Confirm this is the intended way.
- Mid-move fault signalling: we rely on /mode -> 99 (ERROR) with the reason in
/readbackMCS rosout.msg. Confirm an out-of-range / coupled-limit violation
reliably drives this, so the abort path is dependable.
- Per-poll cost: the mid-move check adds a /readbackMCS GET alongside the
/readbackSCS position read (~20 req/s per moving axis at 0.1s). Revisit once we
know whether /readbackSCS also carries mode, or once the per-motor `state`
strings can give a truer moving/settled flag.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Getting Started with Testing using pytest
BEC is using the pytest framework. It can be installed via
pip install pytest
in your python environment.
We note that pytest is part of the optional-dependencies [dev] of the plugin package.
Introduction
Tests in this package should be stored in the tests directory.
We suggest to sort tests of different submodules, i.e. scans or devices in the respective folder structure, and to folow a naming convention of <test_module_name.py>.
It is mandatory for test files to begin with test_ for pytest to discover them.
To run all tests, navigate to the directory of the plugin from the command line, and run the command
pytest -v --random-order ./tests
Note, the python environment needs to be active.
The additional arg -v allows pytest to run in verbose mode which provides more detailed information about the tests being run.
The argument --random-order instructs pytest to run the tests in random order, which is the default in the CI pipelines.
Test examples
Writing tests can be quite specific for the given function. We recommend writing tests as isolated as possible, i.e. try to test single functions instead of full classes. A very useful class to enable isolated testing is MagicMock. In addition, we also recommend to take a look at the How-to guides from pytest.