Skip to content

Commit

Permalink
Merge pull request #157 from PandABlocks/154-allow-changing-values-of…
Browse files Browse the repository at this point in the history
…-metadata-labels

Allow changing values of metadata labels
  • Loading branch information
evalott100 authored Jan 7, 2025
2 parents 4d6eea0 + c5d7e58 commit c1e8056
Show file tree
Hide file tree
Showing 4 changed files with 92 additions and 24 deletions.
59 changes: 39 additions & 20 deletions src/pandablocks_ioc/ioc.py
Original file line number Diff line number Diff line change
Expand Up @@ -258,17 +258,34 @@ async def introspect_panda(

values, all_values_dict = _create_dicts_from_changes(changes, block_dict)

panda_dict = {}
for (block_name, block_info), field_info in zip(
block_dict.items(), field_infos, strict=False
):
panda_dict[block_name] = _BlockAndFieldInfo(
block_info=block_info, fields=field_info, values=values[block_name]
panda_dict = {
block_name: _BlockAndFieldInfo(block_info, field_info, values[block_name])
for (block_name, block_info), field_info in zip(
block_dict.items(), field_infos, strict=False
)
}

return (panda_dict, all_values_dict)


def extract_label_from_metadata(block_name_number, field_name: str):
# Parse *METADATA.LABEL_<block><num> into "<block>" key and
# "<block><num>:LABEL" value
if block_name_number.startswith("*METADATA") and field_name.startswith("LABEL_"):
_, block_name_number = field_name.split("_", maxsplit=1)

# The block is fixed with metadata, it should end with a number
# "*METADATA.LABEL_SEQ2": "NewSeqMetadataLabel",
if not block_name_number[-1].isdigit():
raise ValueError(
f"Recieved metadata for a block name {block_name_number} that "
"didn't contain a number"
)

return block_name_number
return None


def _create_dicts_from_changes(
changes: Changes, block_info_dict: dict[str, BlockInfo]
) -> tuple[dict[str, dict[EpicsName, RecordValue]], dict[EpicsName, RecordValue]]:
Expand Down Expand Up @@ -298,22 +315,12 @@ def _store_values(

block_name_number, field_name = block_and_field_name.split(".", maxsplit=1)

# Parse *METADATA.LABEL_<block><num> into "<block>" key and
# "<block><num>:LABEL" value
if block_name_number.startswith("*METADATA") and field_name.startswith(
"LABEL_"
if label_block_name_number := extract_label_from_metadata(
block_name_number, field_name
):
_, block_name_number = field_name.split("_", maxsplit=1)

# The block is fixed with metadata, it should end with a number
# "*METADATA.LABEL_SEQ2": "NewSeqMetadataLabel",
if not block_name_number[-1].isdigit():
raise ValueError(
f"Recieved metadata for a block name {block_name_number} that "
"didn't contain a number"
)
block_name_number = label_block_name_number
block_name_no_number = re.sub(r"\d*$", "", label_block_name_number)

block_name_no_number = re.sub(r"\d*$", "", block_name_number)
number_of_blocks = block_info_dict[block_name_no_number].number

if number_of_blocks == 1:
Expand Down Expand Up @@ -2095,6 +2102,18 @@ async def update(
field = PandAName(field)
field = panda_to_epics_name(field)

if block_label := extract_label_from_metadata(
*field.split(":", maxsplit=1)
):
block_label_no_number = re.sub(r"\d*$", "", block_label)
block_label = f"{block_label}:LABEL"
block_label_no_number = f"{block_label_no_number}:LABEL"

if block_label_no_number in all_records:
field = block_label_no_number
elif block_label in all_records:
field = block_label

if field not in all_records:
logging.error(
f"Unknown field {field} returned from GetChanges values"
Expand Down
4 changes: 2 additions & 2 deletions tests/fixtures/mocked_panda.py
Original file line number Diff line number Diff line change
Expand Up @@ -859,18 +859,18 @@ def standard_responses(table_field_info, table_data_1, table_data_2):
"PCAP.GATE.DELAY": "1",
"PCAP.ARM": "0",
"*METADATA.LABEL_PCAP1": "PcapMetadataLabel",
"*METADATA.LABEL_PULSE1": "OriginalLabel",
"PULSE.DELAY": "100",
"PULSE.DELAY.UNITS": "ms",
},
multiline_values={"SEQ.TABLE": table_data_1},
),
# 0.5 seconds of no changes in case the ioc setup completes
# before the test starts
respond_with_no_changes(number_of_iterations=15),
changes_iterator_wrapper(
values={
"PCAP.TRIG_EDGE": "Either",
"PULSE.DELAY.UNITS": "s",
"*METADATA.LABEL_PULSE1": "ANewLabel",
},
multiline_values={"SEQ.TABLE": table_data_2},
),
Expand Down
31 changes: 29 additions & 2 deletions tests/test-bobfiles/PULSE.bob
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
<x>0</x>
<y use_class="true">0</y>
<width>506</width>
<height>116</height>
<height>177</height>
<grid_step_x>4</grid_step_x>
<grid_step_y>4</grid_step_y>
<widget type="label" version="2.0.0">
Expand All @@ -26,10 +26,37 @@
<horizontal_alignment>1</horizontal_alignment>
</widget>
<widget type="group" version="2.0.0">
<name>PARAMETERS</name>
<name>INPUTS</name>
<x>5</x>
<y>30</y>
<width>496</width>
<height>56</height>
<transparent>true</transparent>
<widget type="label" version="2.0.0">
<name>Label</name>
<text>Label</text>
<x>0</x>
<y>0</y>
<width>250</width>
<height>20</height>
<tooltip>$(text)</tooltip>
</widget>
<widget type="textentry" version="3.0.0">
<name>TextEntry</name>
<pv_name>TEST_PREFIX:PULSE:LABEL</pv_name>
<x>255</x>
<y>0</y>
<width>205</width>
<height>20</height>
<horizontal_alignment>1</horizontal_alignment>
<format>6</format>
</widget>
</widget>
<widget type="group" version="2.0.0">
<name>PARAMETERS</name>
<x>5</x>
<y>91</y>
<width>496</width>
<height>81</height>
<transparent>true</transparent>
<widget type="label" version="2.0.0">
Expand Down
22 changes: 22 additions & 0 deletions tests/test_ioc_system.py
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ async def test_introspect_panda(
"PULSE:DELAY": "100",
"PCAP:ARM": "0",
"PULSE:DELAY:UNITS": "ms",
"PULSE:LABEL": "OriginalLabel",
"SEQ:TABLE": table_data_1,
}

Expand Down Expand Up @@ -541,6 +542,27 @@ async def test_metadata_parses_into_single_pv(mocked_panda_standard_responses):
) in multiprocessing_queue_to_list(command_queue)


async def test_metadata_label_update_from_panda_updates_pv(
mocked_panda_standard_responses,
):
(
tmp_path,
child_conn,
response_handler,
command_queue,
test_prefix,
) = mocked_panda_standard_responses
camonitor_queue = asyncio.Queue()
m1 = camonitor(
test_prefix + ":PULSE:LABEL", camonitor_queue.put, datatype=DBR_CHAR_STR
)
try:
assert await asyncio.wait_for(camonitor_queue.get(), TIMEOUT) == "OriginalLabel"
assert await asyncio.wait_for(camonitor_queue.get(), TIMEOUT) == "ANewLabel"
finally:
m1.close()


async def test_metadata_parses_into_multiple_pvs_caput_single_pv(
mocked_panda_multiple_seq_responses,
):
Expand Down

0 comments on commit c1e8056

Please sign in to comment.