Skip to content

Commit db33d03

Browse files
authored
Merge pull request #46 from DiamondLightSource/combo-box
Add allowed values for creating combo box widgets
2 parents 151f217 + 68c1930 commit db33d03

File tree

5 files changed

+39
-21
lines changed

5 files changed

+39
-21
lines changed

src/fastcs/attributes.py

+9-1
Original file line numberDiff line numberDiff line change
@@ -117,12 +117,19 @@ def __init__(
117117
access_mode=AttrMode.WRITE,
118118
group: str | None = None,
119119
handler: Sender | None = None,
120+
allowed_values: list[str] | None = None,
120121
) -> None:
121122
super().__init__(datatype, access_mode, group, handler) # type: ignore
122123
self._process_callback: AttrCallback[T] | None = None
123124
self._write_display_callback: AttrCallback[T] | None = None
124125
self._sender = handler
125126

127+
self._allowed_values = allowed_values
128+
129+
@property
130+
def allowed_values(self) -> list[str] | None:
131+
return self._allowed_values
132+
126133
async def process(self, value: T) -> None:
127134
if self._write_display_callback is not None:
128135
await self._write_display_callback(self._datatype.dtype(value))
@@ -156,8 +163,9 @@ def __init__(
156163
access_mode=AttrMode.READ_WRITE,
157164
group: str | None = None,
158165
handler: Handler | None = None,
166+
allowed_values: list[str] | None = None,
159167
) -> None:
160-
super().__init__(datatype, access_mode, group, handler) # type: ignore
168+
super().__init__(datatype, access_mode, group, handler, allowed_values) # type: ignore
161169

162170
async def process(self, value: T) -> None:
163171
await self.set(value)

src/fastcs/backends/epics/gui.py

+18-11
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
from pvi.device import (
77
LED,
88
ButtonPanel,
9+
ComboBox,
910
Component,
1011
Device,
1112
Grid,
@@ -27,7 +28,7 @@
2728

2829
from fastcs.attributes import Attribute, AttrR, AttrRW, AttrW
2930
from fastcs.cs_methods import Command
30-
from fastcs.datatypes import Bool, DataType, Float, Int, String
31+
from fastcs.datatypes import Bool, Float, Int, String
3132
from fastcs.exceptions import FastCSException
3233
from fastcs.mapping import Mapping, SingleMapping, _get_single_mapping
3334
from fastcs.util import snake_to_pascal
@@ -55,27 +56,33 @@ def _get_pv(self, attr_path: list[str], name: str):
5556
return f"{attr_prefix}:{name.title().replace('_', '')}"
5657

5758
@staticmethod
58-
def _get_read_widget(datatype: DataType) -> ReadWidget:
59-
match datatype:
59+
def _get_read_widget(attribute: AttrR) -> ReadWidget:
60+
match attribute.datatype:
6061
case Bool():
6162
return LED()
6263
case Int() | Float():
6364
return TextRead()
6465
case String():
6566
return TextRead(format=TextFormat.string)
66-
case _:
67+
case datatype:
6768
raise FastCSException(f"Unsupported type {type(datatype)}: {datatype}")
6869

6970
@staticmethod
70-
def _get_write_widget(datatype: DataType) -> WriteWidget:
71-
match datatype:
71+
def _get_write_widget(attribute: AttrW) -> WriteWidget:
72+
match attribute.allowed_values:
73+
case allowed_values if allowed_values is not None:
74+
return ComboBox(choices=allowed_values)
75+
case _:
76+
pass
77+
78+
match attribute.datatype:
7279
case Bool():
7380
return ToggleButton()
7481
case Int() | Float():
7582
return TextWrite()
7683
case String():
7784
return TextWrite(format=TextFormat.string)
78-
case _:
85+
case datatype:
7986
raise FastCSException(f"Unsupported type {type(datatype)}: {datatype}")
8087

8188
def _get_attribute_component(
@@ -86,8 +93,8 @@ def _get_attribute_component(
8693

8794
match attribute:
8895
case AttrRW():
89-
read_widget = self._get_read_widget(attribute.datatype)
90-
write_widget = self._get_write_widget(attribute.datatype)
96+
read_widget = self._get_read_widget(attribute)
97+
write_widget = self._get_write_widget(attribute)
9198
return SignalRW(
9299
name=name,
93100
write_pv=pv,
@@ -96,10 +103,10 @@ def _get_attribute_component(
96103
read_widget=read_widget,
97104
)
98105
case AttrR():
99-
read_widget = self._get_read_widget(attribute.datatype)
106+
read_widget = self._get_read_widget(attribute)
100107
return SignalR(name=name, read_pv=pv, read_widget=read_widget)
101108
case AttrW():
102-
write_widget = self._get_write_widget(attribute.datatype)
109+
write_widget = self._get_write_widget(attribute)
103110
return SignalW(name=name, write_pv=pv, write_widget=write_widget)
104111

105112
def _get_command_component(self, attr_path: list[str], name: str):

tests/backends/epics/test_gui.py

+8-5
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
from pvi.device import (
22
ButtonPanel,
3+
ComboBox,
34
SignalR,
45
SignalRW,
56
SignalW,
@@ -32,18 +33,20 @@ def test_get_components(mapping):
3233
read_pv="DEVICE:ReadInt",
3334
read_widget=TextRead(),
3435
),
35-
SignalR(
36-
name="ReadString",
37-
read_pv="DEVICE:ReadString",
38-
read_widget=TextRead(format="string"),
39-
),
4036
SignalRW(
4137
name="ReadWriteFloat",
4238
write_pv="DEVICE:ReadWriteFloat",
4339
write_widget=TextWrite(),
4440
read_pv="DEVICE:ReadWriteFloat_RBV",
4541
read_widget=TextRead(),
4642
),
43+
SignalRW(
44+
name="StringEnum",
45+
read_pv="DEVICE:StringEnum_RBV",
46+
read_widget=TextRead(format="string"),
47+
write_pv="DEVICE:StringEnum",
48+
write_widget=ComboBox(choices=["red", "green", "blue"]),
49+
),
4750
SignalW(
4851
name="WriteBool",
4952
write_pv="DEVICE:WriteBool",

tests/backends/tango/test_dsr.py

+3-3
Original file line numberDiff line numberDiff line change
@@ -11,14 +11,14 @@ def test_collect_attributes(mapping):
1111
# Check that attributes are created and of expected type
1212
assert list(attributes.keys()) == [
1313
"ReadInt",
14-
"ReadString",
1514
"ReadWriteFloat",
15+
"StringEnum",
1616
"WriteBool",
1717
]
1818
assert attributes["ReadInt"].attr_write == AttrWriteType.READ
1919
assert attributes["ReadInt"].attr_type == CmdArgType.DevLong64
20-
assert attributes["ReadString"].attr_write == AttrWriteType.READ
21-
assert attributes["ReadString"].attr_type == CmdArgType.DevString
20+
assert attributes["StringEnum"].attr_write == AttrWriteType.READ_WRITE
21+
assert attributes["StringEnum"].attr_type == CmdArgType.DevString
2222
assert attributes["ReadWriteFloat"].attr_write == AttrWriteType.READ_WRITE
2323
assert attributes["ReadWriteFloat"].attr_type == CmdArgType.DevDouble
2424
assert attributes["WriteBool"].attr_write == AttrWriteType.WRITE

tests/conftest.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ class TestController(Controller):
2525
read_int: AttrR = AttrR(Int())
2626
read_write_float: AttrRW = AttrRW(Float())
2727
write_bool: AttrW = AttrW(Bool())
28-
read_string: AttrR = AttrR(String())
28+
string_enum: AttrRW = AttrRW(String(), allowed_values=["red", "green", "blue"])
2929

3030
@command()
3131
async def go(self):

0 commit comments

Comments
 (0)