gac berninaandClaude Sonnet 5 59b8d30b53 Add a Log Viewer button to eco's JupyterLab and Voila dashboards
Native menu bars are frontend-only in JupyterLab (same conclusion reached
earlier this session for auto-opening a Console tab -- no server-side hook
exists), so eco desktop's Tools -> Log Viewer menu action has no direct
equivalent there. A button on the dashboard is the closest achievable
analogue, wired through eco.logs's existing prefer= mechanism so all three
front-ends share one code path instead of three parallel ones:

- eco.logs._open_timeline gained a "sidecar" prefer option: renders the
  timeline's HTML into a new eco.widgets.jupyter_sidecar.open_html_in_
  sidecar() panel -- a real, separate dockable Sidecar, matching desktop's
  menu action opening its own window.
- eco.widgets.jupyter_sidecar.NamespaceDashboard (the JupyterLab
  counterpart to EcoDesktopApp) gained a "Log Viewer" button above the
  Namespace launcher, calling eco.logs.widget(prefer="sidecar"); reopening
  replaces (closes) the previous panel rather than piling up, and it's
  torn down in .close() alongside everything else.
- eco.widgets.widget_tray.make_namespace_dashboard (Voila) gained the same
  button, calling eco.logs.widget(prefer="jupyter") into a dedicated
  ipywidgets.Output() -- Voila has no Sidecar shell to dock into, so this
  renders inline instead, same reasoning as its existing WidgetTray.

Verified via scripted construction against fake namespaces (button
present, opens, reopening replaces, torn down on close) and the full test
suite (347/349 -- the 2 failures are pre-existing in
test_config_lazy_init.py, unrelated). Along the way, found and worked
around a real pre-existing test-isolation hazard: IPython's
InteractiveShell.instance() is a process-wide singleton, and an earlier,
unrelated test building a real ipykernel-backed shell leaves a stale one
behind that later display()/Output.clear_output() calls in the same
pytest session crash against -- not something this change caused, but the
first tests to actually exercise that code path, so the new tests
short-circuit the specific stale calls rather than depending on that
global state.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-22 08:43:34 +02:00
2026-08-18 21:56:17 +02:00
2026-08-18 21:56:17 +02:00
2026-08-21 15:10:25 +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
2021-01-13 13:11:22 +01: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
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
Languages
Python 86.7%
HTML 10.4%
Jupyter Notebook 2%
Shell 0.8%