Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
3a4fe22
[TASK] version to beta: tests at BESSY II succeded
hzb-ps Jan 20, 2026
da096e8
[TASK] measurement execution engine: make task async
hzb-ps Jan 20, 2026
86d1ca9
[TASK] design: initial version
hzb-ps Jan 21, 2026
deea30e
[TASK] sphinx build files, install option added to pyproject
hzb-ps Jan 22, 2026
29145b3
[TASK] improved documentation strings
hzb-ps Jan 22, 2026
e9976b9
[TASK] added dunder all
hzb-ps Jan 22, 2026
15718c3
[TASK] CI for accml_lib docs
hzb-ps Jan 22, 2026
688aed4
[FIX] install only accml lib here, install packages required for docs
hzb-ps Jan 22, 2026
2681644
[FIX] installation path for accml_lib
hzb-ps Jan 22, 2026
85e4a40
[FIX] call to sphinx apidoc
hzb-ps Jan 22, 2026
edaf7a9
[FIX] need to enter docs directory for building doc
hzb-ps Jan 22, 2026
2c51d4a
[FIX] use python directly and sphinx commands to build the documentation
hzb-ps Jan 22, 2026
65e60d7
[FIX] all details will be in accml
hzb-ps Jan 22, 2026
0cabf1a
[TASK] improved installation instructions
hzb-ps Jan 22, 2026
5d65fb8
[TRY] build doc in docs directory
hzb-ps Jan 22, 2026
bb77647
[FIX] already in docs directory
hzb-ps Jan 22, 2026
9106f20
[FIX] doc page badge
hzb-ps Jan 22, 2026
469ea19
[TASK] move test from accml to here as it only tests accml_lib functi…
hzb-ps Jan 22, 2026
503cd0b
[TASK] addded dunder all, blackified it
hzb-ps Jan 22, 2026
21195c2
[TASK] measurement execution engine: make task async
hzb-ps Jan 20, 2026
416a79d
Merge branch 'dev/feature/mexec-async-interface' of https://github.co…
hzb-ps Jan 22, 2026
1854fda
Merge pull request #9 from python-accelerator-middle-layer/dev/featur…
Sulimankhail Jan 23, 2026
2604b0c
[TASK] measurement execution engine: make task async
hzb-ps Jan 20, 2026
4a24824
Merge branch 'dev/feature/mexec-async-interface' of https://github.co…
hzb-ps Jan 23, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 40 additions & 0 deletions .github/workflows/docs.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
name: Build and deploy accml_lib docs

on:
push:
branches: [ main ] # build on pushes to main (adjust as needed)
pull_request:
branches: [ main ]

jobs:
build-deploy:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v6
with:
fetch-depth: 0
submodules: true

- name: Set up Python
uses: actions/setup-python@v6
with:
python-version: '3.11' # choose your supported version

- name: Install dependencies
run: |
python -m pip install --upgrade pip
python3 -m pip install -e ./[bluesky-epics,docs,pyat-simulator]

- name: Build docs
working-directory: docs
run: |
python3 -m sphinx.ext.apidoc -o src/ ../src/accml_lib/ || echo "failed to create auto/API docs!"
python3 -m sphinx.cmd.build --conf-dir ./ ./ _build/html/

- name: Deploy to gh-pages
uses: peaceiris/actions-gh-pages@v4
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
publish_dir: ./docs/_build/html
# optional: cname: docs.example.com
5 changes: 5 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
# emacs autosave files
*~

# doc build files
doc/_build/
# put api auto generated doc here
doc/src/

# files for running fixtures
fixtures/

Expand Down
29 changes: 27 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# accml: Accelerator middle layer
# accml_lib: Particle accelerator middle layer: library part

`accml` is a software stack designed to facilitate implementing tools
characterising (high) energy charged accelerator.
Expand All @@ -10,6 +10,9 @@ These tools typically address:

For details of its concept see [design.md](https://github.com/python-accelerator-middle-layer/accml/design.md).

Additional [![Documentation](https://github.com/python-accelerator-middle-layer/accml_lib/actions/workflows/docs.yml/badge.svg)](https://python-accelerator-middle-layer.github.io/accml_lib/)


## 🚀 Installation and Running Instructions

### 1. Clone the Repository
Expand All @@ -25,9 +28,31 @@ git checkout dev/main
git submodule update --init --recursive
```
### 3. Install the Package

Please note: typically, especially as a user, you would install
accml, which in turn will install accml_lib. So typically
you want to look to https://github.com/python-accelerator-middle-layer/accml
and install everything there

#### 3.1 Installing only accml_lib for an EPICS facility

For an EPICS facility install

```bash
python3 -m pip install -e .
python3 -m pip install -e \
./[bluesky-epics,pyat-simulator]
```

#### 3.1 Installing only accml_lib for a TANGO facility

**NB** this installation is not yet tested. In case of
experiencing trouble please drop us a line or share your
experience in case of success.
```bash
python3 -m pip install -e \
./[bluesky-tango,pyat-simulator]
```

### 4. Run the Virtual Accelerator (Test bench) --EPICS VERSION
```bash
apptainer run oras://registry.hzdr.de/digital-twins-for-accelerators/containers/pyat-softioc-digital-twin:v0-1-2-bessy.2475331
Expand Down
20 changes: 20 additions & 0 deletions docs/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# Minimal makefile for Sphinx documentation
#

# You can set these variables from the command line, and also
# from the environment for the first two.
SPHINXOPTS ?=
SPHINXBUILD ?= sphinx-build
SOURCEDIR = .
BUILDDIR = _build

# Put it first so that "make" without argument is like "make help".
help:
@$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)

.PHONY: help Makefile

# Catch-all target: route all unknown targets to Sphinx using the new
# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS).
%: Makefile
@$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
55 changes: 55 additions & 0 deletions docs/conf.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
import os
import sys
# so accml_lib is found
sys.path.insert(0, os.path.abspath('../../'))

project = 'accml_lib'
copyright = '2026, Helmholtz Zentrum Berlin'
author = 'Pierre Schnizer, Waheedullah Sulaiman Khail'

# -- General configuration ---------------------------------------------------
# https://www.sphinx-doc.org/en/master/usage/configuration.html#general-configuration
extensions = [
'sphinx.ext.autodoc',
'sphinx.ext.napoleon',
'sphinx.ext.viewcode',
'sphinx.ext.intersphinx',
'sphinx_autodoc_typehints',
'sphinx.ext.autosummary',
"sphinx.ext.todo",
"sphinxcontrib.bibtex",
]
bibtex_bibfiles = ["refs.bib"]

# Optional formatting settings:
bibtex_default_style = "unsrt" # or "alpha", "plain", etc.
bibtex_reference_style = "author_year" # controls :cite: rendering style

autosummary_generate = True
autodoc_typehints = 'description'
html_theme = 'sphinx_rtd_theme'

templates_path = ['_templates']
exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store']


# optional: mock imports if your package has heavy optional deps
# autodoc_mock_imports = ['numpy', 'scipy', "lat2db", "acclerator-toolbox"]


# Intersphinx configuration: cross-reference external docs
intersphinx_mapping = {
"python": ("https://docs.python.org/3", None),
"numpy": ("https://numpy.org/doc/stable", None),
"scipy": ("https://docs.scipy.org/doc/scipy", None),
}

# -- Options for HTML output -------------------------------------------------
# https://www.sphinx-doc.org/en/master/usage/configuration.html#options-for-html-output

html_static_path = ['_static']

# -- Options for todo extension ----------------------------------------------
# https://www.sphinx-doc.org/en/master/usage/extensions/todo.html#configuration

todo_include_todos = True
16 changes: 16 additions & 0 deletions docs/index.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
accml\_lib: documentation
=========================

accml contains all the modules which are used by
client code or twin.

Its general concepts are explained in
the design document of `accml`.

API
---

.. toctree::
:maxdepth: 4

src/accml_lib
35 changes: 35 additions & 0 deletions docs/make.bat
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
@ECHO OFF

pushd %~dp0

REM Command file for Sphinx documentation

if "%SPHINXBUILD%" == "" (
set SPHINXBUILD=sphinx-build
)
set SOURCEDIR=.
set BUILDDIR=_build

%SPHINXBUILD% >NUL 2>NUL
if errorlevel 9009 (
echo.
echo.The 'sphinx-build' command was not found. Make sure you have Sphinx
echo.installed, then set the SPHINXBUILD environment variable to point
echo.to the full path of the 'sphinx-build' executable. Alternatively you
echo.may add the Sphinx directory to PATH.
echo.
echo.If you don't have Sphinx installed, grab it from
echo.https://www.sphinx-doc.org/
exit /b 1
)

if "%1" == "" goto help

%SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O%
goto end

:help
%SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O%

:end
popd
12 changes: 11 additions & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -60,8 +60,18 @@ transitions = {version ="*", optional = true}
# for testing
pytest-asyncio = {version = "*", optional = true}

# for documentation
sphinx = {version = ">=5", optional = true}
sphinx-rtd-theme = {version = "*", optional = true}
sphinx-autodoc-typehints = {version = "*", optional = true}
sphinxcontrib-napoleon = {version = "*", optional = true}
sphinxcontrib-bibtex = {version = "*", optional = true}


[tool.poetry.extras]
bluesky-epics = ["ophyd-async", "aioca", "p4p", "epics", "bluesky", "databroker"]
bluesky-tango = ["ophyd-async", "pytango", "bluesky", "databroker"]
pyat-simulator = ["accelerator-toolbox", "transitions"]
testing = ["pytest-asyncio", "accelerator-toolbox", "transitions"]
testing = ["pytest-asyncio", "accelerator-toolbox", "transitions"]

docs = ["sphinx", "sphinx-rtd-theme", "sphinx-autodoc-typehints", "sphinxcontrib-napoleon", "sphinxcontrib-bibtex"]
1 change: 1 addition & 0 deletions src/accml_lib/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
__all__ = ["core", "custom"]
18 changes: 18 additions & 0 deletions src/accml_lib/core/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
"""accm\_lib core packages

The `core` contains the modules which
are to be independent of any facility
and form the basis of `àccml\_lib`.

It contains the following main parts:

* models: data models used within the package
* bl: business logic or modules that provide
basic functionality
* config: configuration data

Interfaces are used to export the interfaces
used within this package.
"""

__all__ = ["model", "config", "bl", "interfaces"]
8 changes: 8 additions & 0 deletions src/accml_lib/core/bl/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
__all__ = [
"yellow_pages",
"liaison_manager",
"translator_service",
"command_rewritter",
"unit_conversion",
"delta_backend"
]
61 changes: 42 additions & 19 deletions src/accml_lib/core/bl/command_rewritter.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,6 @@

Please note:
here we have to map (lattice_name, property) -> (device_name, property)

Todo:
Split up content in different modules
"""

from typing import Sequence
Expand All @@ -14,7 +11,11 @@
from ...core.interfaces.utils.liaison_manager import LiaisonManagerBase
from ...core.interfaces.utils.translator_service import TranslatorServiceBase
from ...core.model.utils.command import Command
from ...core.model.utils.identifiers import DevicePropertyID, LatticeElementPropertyID, ConversionID
from ...core.model.utils.identifiers import (
DevicePropertyID,
LatticeElementPropertyID,
ConversionID,
)


class CommandRewriter(CommandRewriterBase):
Expand All @@ -28,7 +29,11 @@ class CommandRewriter(CommandRewriterBase):
to convert the command values between representations.
"""

def __init__(self, liaison_manager: LiaisonManagerBase, translation_service: TranslatorServiceBase):
def __init__(
self,
liaison_manager: LiaisonManagerBase,
translation_service: TranslatorServiceBase,
):
"""
Initialize the CommandRewriter with the required services.

Expand All @@ -49,17 +54,24 @@ def inverse(self, cmd: Command) -> Sequence[Command]:
Returns:
A sequence of commands corresponding to the inverse translations.
"""
dev_prop_id = DevicePropertyID(
device_name=cmd.id, property=cmd.property
)
dev_prop_id = DevicePropertyID(device_name=cmd.id, property=cmd.property)
rcmd = self.inverse_read_command(cmd)
lat_prop_ids = [LatticeElementPropertyID(element_name=r.id, property=r.property) for r in rcmd]

return [self.inverse_translate_one(cmd, dev_prop_id, lat_prop_id) for lat_prop_id in lat_prop_ids]

def inverse_translate_one(self, cmd: Command, dev_prop_id: DevicePropertyID,
lat_prop_id: LatticeElementPropertyID
) -> Command:
lat_prop_ids = [
LatticeElementPropertyID(element_name=r.id, property=r.property)
for r in rcmd
]

return [
self.inverse_translate_one(cmd, dev_prop_id, lat_prop_id)
for lat_prop_id in lat_prop_ids
]

def inverse_translate_one(
self,
cmd: Command,
dev_prop_id: DevicePropertyID,
lat_prop_id: LatticeElementPropertyID,
) -> Command:
"""
Perform a single inverse translation.

Expand All @@ -72,11 +84,15 @@ def inverse_translate_one(self, cmd: Command, dev_prop_id: DevicePropertyID,
A new Command with the value converted to the lattice state.
"""
translation_object = self.translator_service.get(
ConversionID(lattice_property_id=lat_prop_id, device_property_id=dev_prop_id)
ConversionID(
lattice_property_id=lat_prop_id, device_property_id=dev_prop_id
)
)

if dev_prop_id.device_name is None:
raise ValueError("Device name cannot be None in device property identifier.")
raise ValueError(
"Device name cannot be None in device property identifier."
)

ncmd = Command(
id=lat_prop_id.element_name,
Expand All @@ -94,7 +110,9 @@ def forward(self, cmd: Command) -> Command:
dev_prop_id = DevicePropertyID(device_name=rcmd.id, property=rcmd.property)

translation_object = self.translator_service.get(
ConversionID(lattice_property_id=lat_prop_id, device_property_id=dev_prop_id)
ConversionID(
lattice_property_id=lat_prop_id, device_property_id=dev_prop_id
)
)
ncmd = Command(
id=dev_prop_id.device_name,
Expand All @@ -116,4 +134,9 @@ def inverse_read_command(self, command: ReadCommand) -> Sequence[ReadCommand]:
device_name=command.id, property=command.property
)
lat_prop_ids = self.liaison_manager.inverse(dev_prop_id)
return [ReadCommand(id=lp.element_name, property=lp.property) for lp in lat_prop_ids]
return [
ReadCommand(id=lp.element_name, property=lp.property) for lp in lat_prop_ids
]


__all__ = ["CommandRewriter"]
Loading
Loading