Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ classifiers = [

dependencies = [
"PyTango>=10.1.1",
"accelerator-middle-layer<=0.2.2",
"accelerator-middle-layer>=0.2.2",
"pydantic>=2.0"
]

Expand Down
2 changes: 1 addition & 1 deletion tango/pyaml/__init__.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
__version__ = "0.3.2"
__version__ = "0.3.3"

import logging.config
import os
Expand Down
22 changes: 21 additions & 1 deletion tango/pyaml/multi_attribute.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import logging
from typing import Tuple, Optional

import numpy as np
import pyaml
Expand Down Expand Up @@ -28,11 +29,14 @@ class ConfigModel(BaseModel):
Group name.
unit : str, optional
Unit of the attributes.
range : tuple(min, max), optional
Range of valid values. Use null for -∞ or +∞.
"""

attributes: list[str] = []
name: str = ""
unit: str = ""
range: Optional[Tuple[Optional[float], Optional[float]]] = None


class MultiAttribute(DeviceAccessList):
Expand All @@ -41,7 +45,9 @@ def __init__(self, cfg: ConfigModel = None):
self._cfg = cfg
if self._cfg:
for attribute in self._cfg.attributes:
attr_config = AttrConfig(attribute=attribute, unit=self._cfg.unit)
attr_config = AttrConfig(
attribute=attribute, unit=self._cfg.unit, range=self._cfg.range
)
attr = Attribute(attr_config)
self.append(attr)

Expand Down Expand Up @@ -128,6 +134,20 @@ def readback(self) -> np.array:

return np.array(values)

def get_range(self) -> list[float]:
attr_range: list[float] = []
for device in self:
attr_range.extend(device.get_range())
return attr_range

def check_device_availability(self) -> bool:
available = False
for device in self:
available = device.check_device_availability()
if not available:
break
return available

def unit(self) -> str:
if self._cfg:
return self._cfg.unit
Expand Down
15 changes: 15 additions & 0 deletions tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,21 @@ def config_multi():
return MultiAttrCM(**cfg_dict)


@pytest.fixture
def config_multi_range():
conf = """
attributes:
- "sys/tg_test/1/float_scalar"
- "sys/tg_test/2/float_scalar"
- "sys/tg_test/3/float_scalar"
- "sys/tg_test/4/float_scalar"
unit: "A"
range: [-15, 15]
"""
cfg_dict = yaml.safe_load(conf)
return MultiAttrCM(**cfg_dict)


@pytest.fixture
def config_tango_cs():
conf = """
Expand Down
15 changes: 14 additions & 1 deletion tests/test_multi_attribute.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import random


from .mocked_control_system_initialized import MockedControlSystemInitialized
from .mocked_device_proxy import MockedDeviceProxy
from unittest.mock import patch
Expand All @@ -24,3 +23,17 @@ def test_multi_read_write(self, config_multi):
assert len(vals) == len(values)
for index, val in enumerate(vals):
assert val == values[index]

def test_multiattribute_range(self, config_multi_range):
with (
patch("tango.DeviceProxy", new=MockedDeviceProxy),
patch(
"tango.pyaml.controlsystem.TangoControlSystem",
new=MockedControlSystemInitialized,
),
):
ma = MultiAttribute(config_multi_range)
attr_range = ma.get_range()
assert attr_range is not None
assert len(attr_range) == 8 # (4*2)
assert attr_range == [-15, 15, -15, 15, -15, 15, -15, 15]