From d0640f70c17186e5783ffebcf11200f664af25bc Mon Sep 17 00:00:00 2001 From: Gary Yendell Date: Thu, 13 Apr 2023 17:10:06 +0100 Subject: [PATCH] WIP - Tables --- src/pvi/_format/utils.py | 5 ++- src/pvi/device.py | 20 +++++---- tests/format/output/dynamic_table_panda.bob | 47 +++++++++++++++++++++ tests/test_dynamic.py | 44 +++++++++++++++---- 4 files changed, 98 insertions(+), 18 deletions(-) create mode 100644 tests/format/output/dynamic_table_panda.bob diff --git a/src/pvi/_format/utils.py b/src/pvi/_format/utils.py index 219eb953..576f9586 100644 --- a/src/pvi/_format/utils.py +++ b/src/pvi/_format/utils.py @@ -521,7 +521,10 @@ def component( sc.value, ) elif isinstance(sc, SignalR) and sc.widget: - if isinstance(sc.widget, (TableRead, TableWrite)): + if ( + isinstance(sc.widget, (TableRead, TableWrite)) + and len(sc.widget.widgets) > 0 + ): widget_bounds = row_bounds.copy() widget_bounds.w *= len(sc.widget.widgets) widget_bounds.h *= 10 # TODO: How do we know the number of rows? diff --git a/src/pvi/device.py b/src/pvi/device.py index 9a2e49ef..cf5e96f5 100644 --- a/src/pvi/device.py +++ b/src/pvi/device.py @@ -94,10 +94,12 @@ class ArrayTrace(ReadWidget): class TableRead(ReadWidget): """Tabular view of an NTTable""" - widgets: Annotated[ - Sequence[ReadWidget], - desc("For each column, what widget should be repeated for every row"), - ] + widgets: Optional[ + Annotated[ + Sequence[ReadWidget], + desc("For each column, what widget should be repeated for every row"), + ] + ] = field(default_factory=list) class ImageRead(ReadWidget): @@ -139,10 +141,12 @@ class ArrayWrite(WriteWidget): @dataclass class TableWrite(WriteWidget): - widgets: Annotated[ - Sequence[Union[ReadWidget, WriteWidget]], - desc("For each column, what widget should be repeated for every row"), - ] + widgets: Optional[ + Annotated[ + Sequence[Union[ReadWidget, WriteWidget]], + desc("For each column, what widget should be repeated for every row"), + ] + ] = field(default_factory=list) @as_discriminated_union diff --git a/tests/format/output/dynamic_table_panda.bob b/tests/format/output/dynamic_table_panda.bob new file mode 100644 index 00000000..fe3147c6 --- /dev/null +++ b/tests/format/output/dynamic_table_panda.bob @@ -0,0 +1,47 @@ + + Display + 0 + 0 + 522 + 234 + 4 + 4 + + Title + TITLE + TableDevice - + 0 + 0 + 522 + 26 + + + + + + + + + true + 1 + + + Table + pva://PANDAQSRV:SEQ1:STRTABLE + 22 + 30 + 496 + 200 + + + Column 1 + false + + + Column 2 + false + + false + + + diff --git a/tests/test_dynamic.py b/tests/test_dynamic.py index 0a3198e4..a96cd761 100644 --- a/tests/test_dynamic.py +++ b/tests/test_dynamic.py @@ -2,13 +2,22 @@ from pvi._format.base import Formatter from pvi._yaml_utils import deserialize_yaml -from pvi.device import LED, ComboBox, Device, SignalR, TableWrite, TextWrite +from pvi.device import ( + LED, + ComboBox, + Device, + SignalR, + TableRead, + TableWrite, + TextRead, + TextWrite, +) HERE = Path(__file__).parent def test_dynamic_table(tmp_path, helper): - formatter_yaml = HERE / "produce_format" / "input" / "dls.bob.pvi.formatter.yaml" + formatter_yaml = HERE / "format" / "input" / "dls.bob.pvi.formatter.yaml" formatter = deserialize_yaml(Formatter, formatter_yaml) table = SignalR( @@ -16,25 +25,42 @@ def test_dynamic_table(tmp_path, helper): "DynamicTable", TableWrite([TextWrite(), LED(), ComboBox(["1", "A", "True"])]), ) - device = Device("TableDevice", children=[table]) + device = Device("TableDevice", "asynPortDriver", children=[table]) - expected_bob = ( - HERE / "produce_format" / "output" / "test_screens" / "dynamic_table.edl" - ) + expected_bob = HERE / "format" / "output" / "dynamic_table.bob" output_bob = tmp_path / "dynamic_table.bob" formatter.format(device, "$(P)$(R)", output_bob) helper.assert_output_matches(expected_bob, output_bob) +def test_dynamic_table_panda(tmp_path, helper): + formatter_yaml = HERE / "format" / "input" / "dls.bob.pvi.formatter.yaml" + formatter = deserialize_yaml(Formatter, formatter_yaml) + + table = SignalR( + "PandA ", + "PANDAQSRV:SEQ1:STRTABLE", + # Can pass no arguments to `TableRead()`, but it will be editable + TableRead([TextRead(), TextRead()]), + ) + device = Device("TableDevice", "asynPortDriver", children=[table]) + + expected_bob = HERE / "format" / "output" / "dynamic_table_panda.bob" + output_bob = tmp_path / "dynamic_table_panda.bob" + formatter.format(device, "", output_bob) + + helper.assert_output_matches(expected_bob, output_bob) + + def test_combo_box(tmp_path, helper): - formatter_yaml = HERE / "produce_format" / "input" / "dls.bob.pvi.formatter.yaml" + formatter_yaml = HERE / "format" / "input" / "dls.bob.pvi.formatter.yaml" formatter = deserialize_yaml(Formatter, formatter_yaml) combo_box = SignalR("Enum", "Enum", ComboBox(["A", "B", "C"])) - device = Device("Device", children=[combo_box]) + device = Device("Device", "asynPortDriver", children=[combo_box]) - expected_bob = HERE / "produce_format" / "output" / "test_screens" / "combo_box.edl" + expected_bob = HERE / "format" / "output" / "combo_box.bob" output_bob = tmp_path / "combo_box.bob" formatter.format(device, "$(P)$(R)", output_bob)