- pyproject.toml: rename package eco -> eco-suite (eco was already taken on
PyPI); move escape-fel + dask-jobqueue into core dependencies since
eco.elements.assembly unconditionally needs them (a bare `import eco` was
broken without the psi extra, verified in a clean venv); drop git-URL
installs for scilog/escape-fel now that both are on public PyPI; update
project URLs to the GitHub mirror and ReadTheDocs.
- Add LICENSE (GPLv3, matching what pyproject.toml already declared).
- Add MANIFEST.in to keep the vendored eco/elements/textual test/ subproject
out of the sdist (it was already excluded from the wheel, but not the
sdist, via the existing packages.find/exclude-package-data config).
- Add .github/workflows/publish.yml (PyPI Trusted Publishing on v*.*.* tags)
and .githooks/pre-push (auto-bump a patch tag on push to master), mirroring
the escape-fel release setup.
Real bug reported after live testing: `eco jupyterlab` rendered the
Namespace launcher as a large inline block (full notebook width, not a
narrow sidebar like eco desktop's dock), and opening a device apparently
popped a Qt window instead of an ipywidgets view. Root cause: eco jupyterlab
was pointed at the same voila_app.ipynb used by `eco webapp`, which renders
everything via eco.widgets.widget_tray.make_namespace_dashboard -- built
for Voila, which (per eco.widgets.jupyter_sidecar's own existing docstring)
has no Lumino shell to dock into at all, so there was never a "narrow
sidebar" option available there in the first place. JupyterLab DOES have a
Lumino shell, and eco already had eco.widgets.jupyter_sidecar.open_in_sidecar
for exactly this -- it just wasn't wired up to the CLI.
- NamespaceLauncherWidget now takes a generic on_open(obj, label) callback
instead of a hardcoded WidgetTray, so it can drive either a WidgetTray
panel (Voila/webapp, unchanged) or a Sidecar panel (JupyterLab, new).
- New eco.widgets.jupyter_sidecar.open_namespace_dashboard(): docks the
Namespace launcher in its own Sidecar panel, and routes each opened
device into its own Sidecar panel too -- the closest browser-side
analogue to eco desktop's dockable Namespace panel + tiled device docks.
- New eco/jupyterlab_app.ipynb (packaged; added to package-data, learned
that lesson the hard way earlier this session) uses it, with its code
cell collapsed by default (standard nbformat source_hidden metadata) --
JupyterLab has no server-side route to auto-open a real Console tab (it's
a frontend-only command, confirmed by grepping jupyterlab's own source
for any matching handler), so a notebook is still the minimal anchor tab
needed for Sidecar/ipywidgets to have something to render into; this
keeps its visible footprint to just the dashboard.
- New _write_jupyterlab_notebook(): opening an *existing* .ipynb always
uses the kernel named in its own file, not JupyterLab's server-wide
default -- so eco_cli.py now regenerates a copy with its kernelspec
pointed at the just-registered eco-<scope> kernel, same as
_register_eco_kernel's other generated files.
Voila (`eco webapp`) is unchanged -- make_namespace_dashboard/WidgetTray
remains correct there, confirmed working earlier this session.
Verified: the notebook's cell code executes without error against a real
eco-bernina kernel (same mechanism used to verify the kernel registration
earlier), a scripted Sidecar dashboard construction + simulated click
against a fake namespace, and the full test suite (338/340 -- the 2
failures are pre-existing in test_config_lazy_init.py, unrelated).
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Real bug found via manual testing ("even not closing, desktop is super
unresponsive and laggy... the qt console, when entering something takes
ages to update, 30s ish"): eco.utilities.config.Proxy (the lazy device
proxy) only special-cases __class__ to avoid resolving while unresolved --
__dir__ isn't one of lazy_object_proxy's protected operations, so it
forwards straight to __wrapped__, fully constructing the device (real
EPICS calls) the moment anything calls dir() on it. Confirmed for real:
dir() on a still-lazy complex device took 62.7s. Since eco desktop's
console now has ~180 bare device names in its namespace (many still lazy),
and any completion mechanism scanning that namespace calls dir() on
candidates, typing in the console could trigger this on nearly every
keystroke. Added Proxy.__dir__, mirroring __class__'s existing "stay shy
to introspection" pattern exactly. Also measured Jedi-based completion as
independently slower (5.8s vs 0.001s) and less correct (0 matches vs 63)
than the classic completer for this dynamic a namespace -- now disabled
for every eco console (build_console_widget, so it applies uniformly to
both in-process and subprocess kernels).
Second, separate perf issue in the Namespace launcher panel: its
live-refresh timer (every 2s) fully rebuilds the table, and the Required
column (added last session) used a real QCheckBox+QWidget+QHBoxLayout per
row -- constructing/destroying ~120 native Qt widgets twice a second at
bernina's scale is real, visible GUI-thread cost. Switched to checkable
QTableWidgetItems (blockSignals()'d during the rebuild so programmatic
setCheckState() calls don't themselves trigger spurious required_names()
writes) -- same functionality, far cheaper to rebuild.
New: "Save Startup Script..." in the desktop window's Workspace menu --
writes a standalone, executable .sh (paired with a .json workspace file,
same format as Save Workspace) that relaunches `eco desktop` with just
this session's open widgets reopened. Lazy loading means nothing else in
the namespace gets touched, so this is a fast, minimal per-task dashboard
instead of the full namespace. New --workspace PATH flag on both eco_cli's
desktop subcommand and eco.widgets.desktop_app's own CLI loads a workspace
on startup; desktop_app._main() now builds the window and loads it before
entering run()'s blocking loop, instead of auto-starting straight into
that block.
Also: the Namespace launcher's lazy (not actively loading) entries no
longer show a spinner-adjacent hourglass -- gray text alone marks
"not built yet"; the animated spinner is now reserved for "actually
initializing right now". And the desktop window's Material dark theme
(qt-material's dark_teal.xml) is now the default -- it already existed as
an opt-in --theme dark, but wasn's what a first `eco desktop` showed; added
'none' as an explicit choice for anyone who wants native OS style back,
and qt-material to eco[gui]'s extras so pip installs get the real theme
too, not just the built-in approximation.
All confirmed via scripted offscreen reproductions of each bug before
writing its fix (not just after), plus the full test suite (336/338 --
the 2 failures are pre-existing in test_config_lazy_init.py, confirmed
via git stash, unrelated to any of this).
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
eco.aliases.aliases.NamespaceCollection globs eco/aliases/namespaces/*.json
to build its namespace attributes, and eco.bernina.bernina points
Namespace._show_svg at eco/bernina/beamline_interact.svg -- both are
git-tracked but were never declared in [tool.setuptools.package-data], and
include-package-data=false means setuptools doesn't auto-sweep them in. Every
built wheel/install was silently missing them, breaking
`NamespaceCollection().bernina` with AttributeError. Verified by building a
wheel and checking its contents before/after.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>