Metadata-Version: 2.5
Name: redsun
Version: 0.15.0rc0
Summary: Event-driven data acquisition software for scientific applications.
Project-URL: bugs, https://github.com/redsun-acquisition/redsun/issues
Project-URL: changelog, https://github.com/redsun-acquisition/redsun/blob/master/changelog.md
Project-URL: homepage, https://github.com/redsun-acquisition/redsun
Author-email: Jacopo Abramo <jacopo.abramo@gmail.com>
Maintainer-email: Jacopo Abramo <jacopo.abramo@gmail.com>
License: Apache-2.0
License-File: LICENSE
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Developers
Classifier: Intended Audience :: Science/Research
Classifier: License :: OSI Approved :: Apache Software License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Programming Language :: Python :: 3.14
Classifier: Programming Language :: Python :: Implementation :: CPython
Classifier: Topic :: Scientific/Engineering
Classifier: Typing :: Typed
Requires-Python: >=3.11
Requires-Dist: annotated-types>=0.7
Requires-Dist: bluesky>=1.15.1
Requires-Dist: culsans>=0.11.0
Requires-Dist: in-n-out>=0.2.1
Requires-Dist: ophyd-async>=0.21.3
Requires-Dist: platformdirs>=4.12.1
Requires-Dist: psygnal>=0.16.1
Requires-Dist: pydantic>=2.13.5
Requires-Dist: pyyaml>=6.0.3
Requires-Dist: typing-extensions>=4.16.0
Provides-Extra: ome-zarr
Requires-Dist: ome-writers[acquire-zarr]>=0.3.2; extra == 'ome-zarr'
Provides-Extra: profile
Requires-Dist: py-spy>=0.4.2; extra == 'profile'
Requires-Dist: pyinstrument>=5.1.3; extra == 'profile'
Provides-Extra: pyqt
Requires-Dist: app-model>=0.5.1; extra == 'pyqt'
Requires-Dist: fonticon-materialdesignicons7>=7.2.96; extra == 'pyqt'
Requires-Dist: magicgui>=0.10.2; extra == 'pyqt'
Requires-Dist: pyqt6-qt6!=6.11.0,!=6.11.1; extra == 'pyqt'
Requires-Dist: pyqt6>=6.11.0; extra == 'pyqt'
Requires-Dist: qtpy>=2.4.3; extra == 'pyqt'
Requires-Dist: superqt>=0.8.2; extra == 'pyqt'
Provides-Extra: pyside
Requires-Dist: app-model>=0.5.1; extra == 'pyside'
Requires-Dist: fonticon-materialdesignicons7>=7.2.96; extra == 'pyside'
Requires-Dist: magicgui>=0.10.2; extra == 'pyside'
Requires-Dist: pyside6-essentials!=6.11.0,!=6.11.1,>=6.10.2; extra == 'pyside'
Requires-Dist: qtpy>=2.4.3; extra == 'pyside'
Requires-Dist: superqt>=0.8.2; extra == 'pyside'
Provides-Extra: qlementine-pyqt
Requires-Dist: app-model>=0.5.1; extra == 'qlementine-pyqt'
Requires-Dist: fonticon-materialdesignicons7>=7.2.96; extra == 'qlementine-pyqt'
Requires-Dist: magicgui>=0.10.2; extra == 'qlementine-pyqt'
Requires-Dist: pyqt6-qlementine>=1.5.1; extra == 'qlementine-pyqt'
Requires-Dist: pyqt6-qt6!=6.11.0,!=6.11.1; extra == 'qlementine-pyqt'
Requires-Dist: pyqt6>=6.11.0; extra == 'qlementine-pyqt'
Requires-Dist: qtpy>=2.4.3; extra == 'qlementine-pyqt'
Requires-Dist: superqt>=0.8.2; extra == 'qlementine-pyqt'
Provides-Extra: qlementine-pyside
Requires-Dist: app-model>=0.5.1; extra == 'qlementine-pyside'
Requires-Dist: fonticon-materialdesignicons7>=7.2.96; extra == 'qlementine-pyside'
Requires-Dist: magicgui>=0.10.2; extra == 'qlementine-pyside'
Requires-Dist: pyside6-essentials!=6.11.0,!=6.11.1,>=6.10.2; extra == 'qlementine-pyside'
Requires-Dist: pyside6-qlementine>=1.5.1; extra == 'qlementine-pyside'
Requires-Dist: qtpy>=2.4.3; extra == 'qlementine-pyside'
Requires-Dist: superqt>=0.8.2; extra == 'qlementine-pyside'
Provides-Extra: qt-common
Requires-Dist: app-model>=0.5.1; extra == 'qt-common'
Requires-Dist: fonticon-materialdesignicons7>=7.2.96; extra == 'qt-common'
Requires-Dist: magicgui>=0.10.2; extra == 'qt-common'
Requires-Dist: qtpy>=2.4.3; extra == 'qt-common'
Requires-Dist: superqt>=0.8.2; extra == 'qt-common'
Provides-Extra: testing
Requires-Dist: pytest>=8; extra == 'testing'
Provides-Extra: tiled
Requires-Dist: ome-tiled[bluesky]>=0.2.0; (python_full_version < '3.14') and extra == 'tiled'
Requires-Dist: tiled[client,server]>=0.2.18; (python_full_version < '3.14') and extra == 'tiled'
Provides-Extra: zarr
Requires-Dist: acquire-zarr>=0.10.0; extra == 'zarr'
Description-Content-Type: text/markdown

[![PyPI](https://img.shields.io/pypi/v/redsun.svg?color=green)](https://pypi.org/project/redsun)
[![PyPI - Python Version](https://img.shields.io/pypi/pyversions/redsun)](https://pypi.org/project/redsun)
[![PyPI - Status](https://img.shields.io/pypi/status/redsun)](https://pypi.org/project/redsun)
[![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://opensource.org/licenses/Apache-2.0)
[![CI](https://github.com/redsun-acquisition/redsun/actions/workflows/ci.yaml/badge.svg?branch=main)](https://github.com/redsun-acquisition/redsun/actions/workflows/ci.yaml)
[![PyQt6](https://github.com/redsun-acquisition/redsun/actions/workflows/pyqt6.yaml/badge.svg?branch=main)](https://github.com/redsun-acquisition/redsun/actions/workflows/pyqt6.yaml)
[![PySide6](https://github.com/redsun-acquisition/redsun/actions/workflows/pyside6.yaml/badge.svg?branch=main)](https://github.com/redsun-acquisition/redsun/actions/workflows/pyside6.yaml)
[![codecov](https://codecov.io/gh/redsun-acquisition/redsun/graph/badge.svg?token=XAL7NBIU9N)](https://codecov.io/gh/redsun-acquisition/redsun)
[![Documentation](https://img.shields.io/website?url=https%3A%2F%2Fredsun-acquisition.github.io%2Fredsun&label=docs)](https://redsun-acquisition.github.io/redsun)
[![uv](https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/uv/main/assets/badge/v0.json)](https://github.com/astral-sh/uv)
[![Ruff](https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/ruff/main/assets/badge/v2.json)](https://github.com/astral-sh/ruff)
[![Checked with mypy](https://www.mypy-lang.org/static/mypy_badge.svg)](https://mypy-lang.org/)
[![Conventional Commits](https://img.shields.io/badge/Conventional%20Commits-1.0.0-%23FE5196?logo=conventionalcommits&logoColor=white)](https://www.conventionalcommits.org)

# `redsun`

`redsun` is a [Python] toolkit for building your own modular software for scientific data acquisition. It builds on the [Bluesky] ecosystem and makes no assumptions about your hardware, so each lab can build the control software its experiments need.

To learn `redsun`, start with the [tutorials], where you build one application step by step without any hardware.

> [!NOTE]
> `redsun` is usable today, but it's still maturing, so expect breaking changes.

## Problem statement

When research depends on controlling hardware, one of the hardest problems is making different instruments work together in workflows that are reusable, reliable and documented. On top of that, the software needs an interface that people with less technical background can understand and use correctly.

That's hard because experiments keep changing. It's next to impossible to predict everything the software will finally need to do, especially when the people using it are scientists with no engineering background.

So rather than shipping one complete program, `redsun` follows the idea of [component-based development](https://en.wikipedia.org/wiki/Component-based_software_engineering): it ships ready-made components, and you assemble and wire them for what you need.

## Component-based development (CBD)

In component-based development, what matters most is the interface of each component. A component says what it needs to be built, and offers features that other components can use.

You put components together in a session, which builds the application for you, so you can focus on what each component does.

```python
from collections.abc import Iterator
from typing import Annotated

from mylab.devices import MyMotor
from mylab.presenters import MyController
from mylab.views import MyView

from redsun import AsDevice, AsPresenter, AsView, Declare, Link
from redsun.qt import QtSession


class MyApp(QtSession):
    stage: Annotated[AsDevice[MyMotor], Declare(axis=["X", "Y"], egu="mm")]
    ctrl: Annotated[AsPresenter[MyController], Declare(timeout=2.0)]
    panel: AsView[MyView]

    def wire(self) -> Iterator[Link]:
        yield self.ctrl.sig_position_changed, self.panel.update_position


MyApp({"session": "my-session"}).run()
```

You declare each component once, with the arguments it needs, and `wire` says which signal reaches which slot. The session then builds everything in order and connects it.

`redsun` provides the shared code that connects components, so you can use it to ship a whole application or a single reusable component. Through [Python entry points](https://packaging.python.org/en/latest/specifications/entry-points/), you can also ship an application as a single YAML configuration file, as long as each package that contributes components includes a `redsun.yaml` manifest.

The same application then looks like this:

```yaml
# session.yaml
schema_version: 1.0
frontend: qt
session: my-session

devices:
  stage:
    plugin_name: mylab
    plugin_id: my_motor
    axis: ["X", "Y"]
    egu: mm

presenters:
  ctrl:
    plugin_name: mylab
    plugin_id: my_controller
    timeout: 2.0

views:
  panel:
    plugin_name: mylab
    plugin_id: my_view

wiring:
  ctrl.sig_position_changed: panel.update_position
```

The session looks up each `plugin_id` in the manifest that the contributing package ships:

```yaml
# mylab/redsun.yaml
devices:
  my_motor: mylab.devices:MyMotor
presenters:
  my_controller: mylab.presenters:MyController
views:
  my_view: mylab.views:MyView
```

Launch it with:

```python
from redsun import Session

Session.from_config("session.yaml").run()
```

> [!TIP]
> When you launch a session from a configuration file, the component packages it names (`mylab` in this example) must be installed in the environment you run it from.

## Session architecture

Each `redsun` session is a [Device-View-Presenter](https://redsun-acquisition.github.io/redsun/explanation/session/) (DVP) application. DVP resembles the Model-View-Presenter (MVP) architecture, except that the bottom layer of the application is the *Device layer*, which uses [`ophyd-async`](https://github.com/bluesky/ophyd-async) to talk to the hardware.

This design makes a clear point: `redsun` is first of all about device control, and tries to do it well.

## Documentation

The [documentation] covers everything else.

[bluesky]: https://blueskyproject.io/bluesky/main/index.html
[python]: https://www.python.org/
[documentation]: https://redsun-acquisition.github.io/redsun/
[tutorials]: https://redsun-acquisition.github.io/redsun/tutorials/

## License

`redsun` is released under the Apache 2.0 license. See the [license](./LICENSE) for the full text.
