lemke_handClaude Sonnet 5 634a10a086 Serve aliases from the status server; use it by default in Daq
The server already holds a fully-initialized namespace, so its
namespace.alias.get_all() is complete and free (pure in-memory tree
walk, no CA traffic). The client side's own copy_aliases_to_scan
called self.namespace.alias.get_all() unconditionally, including in
status-server mode - against a namespace that mode deliberately never
initializes, so aux/aliases.json was silently missing everything the
local session had not happened to touch.

- namespace_server.py: GET /aliases (synchronous, for direct
  inspection) and POST /aliases/capture (async: compute, write
  aliases.json, upload to the run - mirrors /status/capture, shares
  its job-id space via GET /status/job/<id>).
- storage.py: write_aliases_file(), same group-writable-tree handling
  as write_status_snapshot().
- client.py: StatusServerClient.aliases() / .capture_aliases().
- daq_client.py: copy_aliases_to_scan now asks the same per-scan
  status-server decision append_start_status_to_scan already makes
  and caches, delegating to the server when it's in use and falling
  back to the local path (unchanged) otherwise.

Also fixes a latent bug found along the way: Daq.__init__ accepted an
`instrument` kwarg but never stored it as self.instrument, so every
f"/sf/{self.instrument or 'bernina'}/..." path in
_write_status_locally()/write_status() raised AttributeError on any
real Daq - masked because the only test reaching that path tolerates
"any exception" as "fell back correctly".

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-07 14:30:18 +02:00
2026-09-05 14:42:02 +02:00
2026-08-18 21:56:17 +02:00
2026-08-28 18:20:00 +02:00
2026-09-06 16:34:29 +02:00
2026-08-18 21:56:17 +02:00
2026-08-18 21:56:17 +02:00
2018-07-06 12:38:44 +02:00
2026-08-18 21:56:17 +02:00
2026-08-18 21:56:17 +02:00
2026-08-18 21:56:17 +02:00
2026-08-28 14:25:39 +02:00
2021-01-13 13:11:22 +01:00
2026-08-28 21:58:29 +02:00
2026-08-18 21:56:17 +02:00
2026-08-21 15:10:25 +02:00
2026-08-21 15:10:25 +02:00
2025-06-24 15:33:02 +02:00

eco — Experiment Control

                       ___ _______
                      / -_) __/ _ \
 Experiment Control   \__/\__/\___/

eco is a Python-based control environment for experiments, developed and used at SwissFEL, PSI. It is used both as:

  • a library of experimental devices for higher-level Python applications or GUIs, and
  • an interactive command-line interface, e.g. from an IPython/Jupyter shell or notebook.

eco follows an object-oriented approach: every device is represented as a Python object with a small, predictable interface, so devices can be freely combined in generic control/acquisition routines and analysed with the scientific Python ecosystem. For a general introduction to object-oriented Python, see e.g. this short introduction.

Documentation

The full documentation — installation, core concepts, and worked examples (listening monitors, archiver data and strip charts, pipeline offload, motor configuration) — lives in docs/ and is built with Sphinx, configured to build on Read the Docs via .readthedocs.yaml.

Build it locally:

pip install -r docs/requirements.txt
sphinx-build -b html docs docs/_build/html

Installation

conda install -c paulscherrerinstitute eco

or, for development, in editable mode from a checkout:

git clone https://github.com/paulscherrerinstitute/eco.git
cd eco
pip install -e .

See Installation for beamline-specific setup (the eco launcher, .ecorc defaults) and the full dependency picture.

Creating a new device

New devices are implemented as a subclass of Assembly, which provides naming, aliasing, and shell representation:

from eco.elements.assembly import Assembly

class MyDevice(Assembly):
    def __init__(self, name=None):
        super().__init__(name=name)
        self._append(MySubObject, name="my_sub_object", is_setting=True, is_status=True)

is_setting=True marks the child as a setting of the assembly (shown by .settings() and captured when settings are saved); is_status=True marks it as contributing to the assembly's .status(). See Representing real devices — the Assembly in the full docs for the rest of the model (Adjustable, Detector, Namespace) and a from-scratch, runnable example of each.

S
Description
Experimental control package
Readme GPL-3.0
8.8 MiB
0 Stars 0 Watchers 0 Forks
Languages
Python 86.7%
HTML 10.4%
Jupyter Notebook 2%
Shell 0.8%