Skip to content

Commit

Permalink
Merge branch 'main' into tango_support
Browse files Browse the repository at this point in the history
  • Loading branch information
Devin Burke committed Sep 5, 2024
2 parents c0e2079 + ab4dc46 commit fa2256c
Show file tree
Hide file tree
Showing 30 changed files with 752 additions and 61 deletions.
2 changes: 1 addition & 1 deletion docs/examples/foo_detector.py
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ def __init__(
self.hdf,
path_provider,
lambda: self.name,
adcore.ADBaseShapeProvider(self.drv),
adcore.ADBaseDatasetDescriber(self.drv),
),
config_sigs=(self.drv.acquire_time,),
name=name,
Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,7 @@ commands =


[tool.ruff]
src = ["src", "tests"]
src = ["src", "tests", "system_tests"]
line-length = 88
lint.select = [
"C4", # flake8-comprehensions - https://beta.ruff.rs/docs/rules/#flake8-comprehensions-c4
Expand Down
7 changes: 4 additions & 3 deletions src/ophyd_async/core/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,11 +33,11 @@
from ._providers import (
AutoIncrementFilenameProvider,
AutoIncrementingPathProvider,
DatasetDescriber,
FilenameProvider,
NameProvider,
PathInfo,
PathProvider,
ShapeProvider,
StaticFilenameProvider,
StaticPathProvider,
UUIDFilenameProvider,
Expand All @@ -63,7 +63,7 @@
)
from ._signal_backend import RuntimeSubsetEnum, SignalBackend, SubsetEnum
from ._soft_signal_backend import SignalMetadata, SoftSignalBackend
from ._status import AsyncStatus, WatchableAsyncStatus
from ._status import AsyncStatus, WatchableAsyncStatus, completed_status
from ._utils import (
DEFAULT_TIMEOUT,
CalculatableTimeout,
Expand Down Expand Up @@ -117,7 +117,7 @@
"NameProvider",
"PathInfo",
"PathProvider",
"ShapeProvider",
"DatasetDescriber",
"StaticFilenameProvider",
"StaticPathProvider",
"UUIDFilenameProvider",
Expand Down Expand Up @@ -158,4 +158,5 @@
"get_unique",
"in_micros",
"wait_for_connection",
"completed_status",
]
24 changes: 13 additions & 11 deletions src/ophyd_async/core/_providers.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,13 +26,11 @@ class PathInfo:

class FilenameProvider(Protocol):
@abstractmethod
def __call__(self) -> str:
def __call__(self, device_name: Optional[str] = None) -> str:
"""Get a filename to use for output data, w/o extension"""


class PathProvider(Protocol):
_filename_provider: FilenameProvider

@abstractmethod
def __call__(self, device_name: Optional[str] = None) -> PathInfo:
"""Get the current directory to write files into"""
Expand All @@ -42,7 +40,7 @@ class StaticFilenameProvider(FilenameProvider):
def __init__(self, filename: str):
self._static_filename = filename

def __call__(self) -> str:
def __call__(self, device_name: Optional[str] = None) -> str:
return self._static_filename


Expand All @@ -55,7 +53,7 @@ def __init__(
self._uuid_call_func = uuid_call_func
self._uuid_call_args = uuid_call_args or []

def __call__(self) -> str:
def __call__(self, device_name: Optional[str] = None) -> str:
if (
self._uuid_call_func in [uuid.uuid3, uuid.uuid5]
and len(self._uuid_call_args) < 2
Expand Down Expand Up @@ -84,7 +82,7 @@ def __init__(
self._increment = increment
self._inc_delimeter = inc_delimeter

def __call__(self):
def __call__(self, device_name: Optional[str] = None) -> str:
if len(str(self._current_value)) > self._max_digits:
raise ValueError(
f"Auto incrementing filename counter \
Expand All @@ -111,7 +109,7 @@ def __init__(
self._create_dir_depth = create_dir_depth

def __call__(self, device_name: Optional[str] = None) -> PathInfo:
filename = self._filename_provider()
filename = self._filename_provider(device_name)

return PathInfo(
directory_path=self._directory_path,
Expand Down Expand Up @@ -146,7 +144,7 @@ def __init__(
self._inc_delimeter = inc_delimeter

def __call__(self, device_name: Optional[str] = None) -> PathInfo:
filename = self._filename_provider()
filename = self._filename_provider(device_name)

padded_counter = f"{self._current_value:0{self._max_digits}}"

Expand Down Expand Up @@ -199,7 +197,7 @@ def __call__(self, device_name: Optional[str] = None) -> PathInfo:
current_date,
)

filename = self._filename_provider()
filename = self._filename_provider(device_name)
return PathInfo(
directory_path=self._base_directory_path / ymd_dir_path,
filename=filename,
Expand All @@ -213,7 +211,11 @@ def __call__(self) -> str:
"""Get the name to be used as a data_key in the descriptor document"""


class ShapeProvider(Protocol):
class DatasetDescriber(Protocol):
@abstractmethod
async def np_datatype(self) -> str:
"""Represents the numpy datatype"""

@abstractmethod
async def __call__(self) -> tuple:
async def shape(self) -> tuple[int, ...]:
"""Get the shape of the data collection"""
2 changes: 1 addition & 1 deletion src/ophyd_async/core/_signal.py
Original file line number Diff line number Diff line change
Expand Up @@ -547,7 +547,7 @@ async def wait_for_value(


async def set_and_wait_for_other_value(
set_signal: SignalRW[T],
set_signal: SignalW[T],
set_value: T,
read_signal: SignalR[S],
read_value: S,
Expand Down
18 changes: 17 additions & 1 deletion src/ophyd_async/core/_status.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,16 @@
import functools
import time
from dataclasses import asdict, replace
from typing import AsyncIterator, Awaitable, Callable, Generic, Type, TypeVar, cast
from typing import (
AsyncIterator,
Awaitable,
Callable,
Generic,
Optional,
Type,
TypeVar,
cast,
)

from bluesky.protocols import Status

Expand Down Expand Up @@ -132,3 +141,10 @@ def wrap_f(*args: P.args, **kwargs: P.kwargs) -> WAS:
return cls(f(*args, **kwargs))

return cast(Callable[P, WAS], wrap_f)


@AsyncStatus.wrap
async def completed_status(exception: Optional[Exception] = None):
if exception:
raise exception
return None
2 changes: 1 addition & 1 deletion src/ophyd_async/epics/adaravis/_aravis.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ def __init__(
self.hdf,
path_provider,
lambda: self.name,
adcore.ADBaseShapeProvider(self.drv),
adcore.ADBaseDatasetDescriber(self.drv),
),
config_sigs=(self.drv.acquire_time,),
name=name,
Expand Down
4 changes: 2 additions & 2 deletions src/ophyd_async/epics/adcore/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
)
from ._core_logic import (
DEFAULT_GOOD_STATES,
ADBaseShapeProvider,
ADBaseDatasetDescriber,
set_exposure_time_and_acquire_period_if_supplied,
start_acquiring_driver_and_ensure_status,
)
Expand All @@ -31,7 +31,7 @@
"NDFileHDFIO",
"NDPluginStatsIO",
"DEFAULT_GOOD_STATES",
"ADBaseShapeProvider",
"ADBaseDatasetDescriber",
"set_exposure_time_and_acquire_period_if_supplied",
"start_acquiring_driver_and_ensure_status",
"ADHDFWriter",
Expand Down
11 changes: 7 additions & 4 deletions src/ophyd_async/epics/adcore/_core_logic.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,11 @@
from ophyd_async.core import (
DEFAULT_TIMEOUT,
AsyncStatus,
DatasetDescriber,
DetectorControl,
ShapeProvider,
set_and_wait_for_value,
)
from ophyd_async.epics.adcore._utils import convert_ad_dtype_to_np

from ._core_io import ADBaseIO, DetectorState

Expand All @@ -18,15 +19,17 @@
)


class ADBaseShapeProvider(ShapeProvider):
class ADBaseDatasetDescriber(DatasetDescriber):
def __init__(self, driver: ADBaseIO) -> None:
self._driver = driver

async def __call__(self) -> tuple:
async def np_datatype(self) -> str:
return convert_ad_dtype_to_np(await self._driver.data_type.get_value())

async def shape(self) -> tuple[int, int]:
shape = await asyncio.gather(
self._driver.array_size_y.get_value(),
self._driver.array_size_x.get_value(),
self._driver.data_type.get_value(),
)
return shape

Expand Down
26 changes: 10 additions & 16 deletions src/ophyd_async/epics/adcore/_hdf_writer.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,12 @@
from ophyd_async.core import (
DEFAULT_TIMEOUT,
AsyncStatus,
DatasetDescriber,
DetectorWriter,
HDFDataset,
HDFFile,
NameProvider,
PathProvider,
ShapeProvider,
observe_value,
set_and_wait_for_value,
wait_for_value,
Expand All @@ -22,7 +22,6 @@
from ._core_io import NDArrayBaseIO, NDFileHDFIO
from ._utils import (
FileWriteMode,
convert_ad_dtype_to_np,
convert_param_dtype_to_np,
convert_pv_dtype_to_np,
)
Expand All @@ -34,13 +33,13 @@ def __init__(
hdf: NDFileHDFIO,
path_provider: PathProvider,
name_provider: NameProvider,
shape_provider: ShapeProvider,
dataset_describer: DatasetDescriber,
*plugins: NDArrayBaseIO,
) -> None:
self.hdf = hdf
self._path_provider = path_provider
self._name_provider = name_provider
self._shape_provider = shape_provider
self._dataset_describer = dataset_describer

self._plugins = plugins
self._capture_status: Optional[AsyncStatus] = None
Expand Down Expand Up @@ -79,23 +78,18 @@ async def open(self, multiplier: int = 1) -> Dict[str, DataKey]:
# Wait for it to start, stashing the status that tells us when it finishes
self._capture_status = await set_and_wait_for_value(self.hdf.capture, True)
name = self._name_provider()
detector_shape = tuple(await self._shape_provider())
detector_shape = await self._dataset_describer.shape()
np_dtype = await self._dataset_describer.np_datatype()
self._multiplier = multiplier
outer_shape = (multiplier,) if multiplier > 1 else ()
frame_shape = detector_shape[:-1] if len(detector_shape) > 0 else []
dtype_numpy = (
convert_ad_dtype_to_np(detector_shape[-1])
if len(detector_shape) > 0
else ""
)

# Add the main data
self._datasets = [
HDFDataset(
data_key=name,
dataset="/entry/data/data",
shape=frame_shape,
dtype_numpy=dtype_numpy,
shape=detector_shape,
dtype_numpy=np_dtype,
multiplier=multiplier,
)
]
Expand All @@ -109,19 +103,19 @@ async def open(self, multiplier: int = 1) -> Dict[str, DataKey]:
for child in root:
datakey = child.attrib["name"]
if child.attrib.get("type", "EPICS_PV") == "EPICS_PV":
np_datatye = convert_pv_dtype_to_np(
np_datatype = convert_pv_dtype_to_np(
child.attrib.get("dbrtype", "DBR_NATIVE")
)
else:
np_datatye = convert_param_dtype_to_np(
np_datatype = convert_param_dtype_to_np(
child.attrib.get("datatype", "INT")
)
self._datasets.append(
HDFDataset(
datakey,
f"/entry/instrument/NDAttributes/{datakey}",
(),
np_datatye,
np_datatype,
multiplier,
)
)
Expand Down
2 changes: 1 addition & 1 deletion src/ophyd_async/epics/adkinetix/_kinetix.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ def __init__(
self.hdf,
path_provider,
lambda: self.name,
adcore.ADBaseShapeProvider(self.drv),
adcore.ADBaseDatasetDescriber(self.drv),
),
config_sigs=(self.drv.acquire_time,),
name=name,
Expand Down
2 changes: 1 addition & 1 deletion src/ophyd_async/epics/adpilatus/_pilatus.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ def __init__(
self.hdf,
path_provider,
lambda: self.name,
adcore.ADBaseShapeProvider(self.drv),
adcore.ADBaseDatasetDescriber(self.drv),
),
config_sigs=(self.drv.acquire_time,),
name=name,
Expand Down
2 changes: 1 addition & 1 deletion src/ophyd_async/epics/adsimdetector/_sim.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ def __init__(
self.hdf,
path_provider,
lambda: self.name,
adcore.ADBaseShapeProvider(self.drv),
adcore.ADBaseDatasetDescriber(self.drv),
),
config_sigs=config_sigs,
name=name,
Expand Down
2 changes: 1 addition & 1 deletion src/ophyd_async/epics/advimba/_vimba.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ def __init__(
self.hdf,
path_provider,
lambda: self.name,
adcore.ADBaseShapeProvider(self.drv),
adcore.ADBaseDatasetDescriber(self.drv),
),
config_sigs=(self.drv.acquire_time,),
name=name,
Expand Down
5 changes: 5 additions & 0 deletions src/ophyd_async/epics/eiger/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
from ._eiger import EigerDetector, EigerTriggerInfo
from ._eiger_controller import EigerController
from ._eiger_io import EigerDriverIO

__all__ = ["EigerDetector", "EigerController", "EigerDriverIO", "EigerTriggerInfo"]
Loading

0 comments on commit fa2256c

Please sign in to comment.