Skip to content

Commit

Permalink
STY: Apply pre-commit changes
Browse files Browse the repository at this point in the history
  • Loading branch information
Nolan Stelter committed Oct 2, 2023
1 parent 5a12da9 commit c1a712a
Show file tree
Hide file tree
Showing 9 changed files with 153 additions and 95 deletions.
18 changes: 12 additions & 6 deletions slam/alarm_configuration_widget.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,14 @@ class AlarmConfigurationWidget(QDialog):
The parent of this widget
"""

def __init__(self, alarm_item: AlarmItem, kafka_producer: KafkaProducer,
topic: str, annunciate: bool = False, parent: Optional[QObject] = None,):
def __init__(
self,
alarm_item: AlarmItem,
kafka_producer: KafkaProducer,
topic: str,
annunciate: bool = False,
parent: Optional[QObject] = None,
):
super().__init__(parent=parent)
self.alarm_item = alarm_item
self.kafka_producer = kafka_producer
Expand All @@ -57,10 +63,10 @@ def __init__(self, alarm_item: AlarmItem, kafka_producer: KafkaProducer,
self.cant_edit_label = QLabel("Warning: Cannot edit - requires alarm admin privileges")
self.cant_edit_label.setStyleSheet("background-color: orange")

self.behavior_label = QLabel('Behavior:')
self.enabled_checkbox = QCheckBox('Enabled')
self.latch_checkbox = QCheckBox('Latched')
self.annunciate_checkbox = QCheckBox('Annunciate')
self.behavior_label = QLabel("Behavior:")
self.enabled_checkbox = QCheckBox("Enabled")
self.latch_checkbox = QCheckBox("Latched")
self.annunciate_checkbox = QCheckBox("Annunciate")
self.annunciate_checkbox.setEnabled(annunciate)

self.disable_date_label = QLabel("Disable Until:")
Expand Down
16 changes: 13 additions & 3 deletions slam/alarm_table_model.py
Original file line number Diff line number Diff line change
Expand Up @@ -147,9 +147,19 @@ def update_row(

if name not in self.alarm_items:
# This item does not yet exist in the table, so create it and return
self.append(AlarmItem(name=name, path=path, alarm_severity=severity, alarm_status=status,
alarm_time=time, alarm_value=value, pv_severity=pv_severity,
pv_status=pv_status, description=description))
self.append(
AlarmItem(
name=name,
path=path,
alarm_severity=severity,
alarm_status=status,
alarm_time=time,
alarm_value=value,
pv_severity=pv_severity,
pv_status=pv_status,
description=description,
)
)
return

# Otherwise update the row with the newly received data
Expand Down
11 changes: 9 additions & 2 deletions slam/alarm_table_view.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,8 +54,15 @@ class AlarmTableViewWidget(QWidget):

plot_signal = Signal(str)

def __init__(self, tree_model: AlarmItemsTreeModel, kafka_producer: KafkaProducer,
topic: str, table_type: AlarmTableType, plot_slot: Callable, annunciate: bool = False):
def __init__(
self,
tree_model: AlarmItemsTreeModel,
kafka_producer: KafkaProducer,
topic: str,
table_type: AlarmTableType,
plot_slot: Callable,
annunciate: bool = False,
):
super().__init__()
self.resize(1035, 600)

Expand Down
4 changes: 2 additions & 2 deletions slam/alarm_tree_model.py
Original file line number Diff line number Diff line change
Expand Up @@ -161,10 +161,10 @@ def update_item(
item_to_update.filtered = True
elif item_to_update.filtered:
item_to_update.filtered = False
if (status != "OK" and status != "Disabled" ) and item_to_update.annunciating:
if (status != "OK" and status != "Disabled") and item_to_update.annunciating:
# prints bell character, cross platform way to generate "beep" noise,
# could be replaced with call to audio library for more sound options
print ('\a')
print("\a")

self.layoutChanged.emit()

Expand Down
9 changes: 7 additions & 2 deletions slam/alarm_tree_view.py
Original file line number Diff line number Diff line change
Expand Up @@ -173,8 +173,13 @@ def tree_menu(self, pos: QPoint) -> None:
def create_alarm_configuration_widget(self, index: QModelIndex) -> None:
"""Create and display the alarm configuration widget for the alarm item with the input index"""
alarm_item = self.treeModel.getItem(index)
alarm_config_window = AlarmConfigurationWidget(alarm_item=alarm_item, kafka_producer=self.kafka_producer,
topic=self.topic, parent=self, annunciate=self.annunciate)
alarm_config_window = AlarmConfigurationWidget(
alarm_item=alarm_item,
kafka_producer=self.kafka_producer,
topic=self.topic,
parent=self,
annunciate=self.annunciate,
)
alarm_config_window.show()

def copy_to_clipboard(self) -> None:
Expand Down
28 changes: 16 additions & 12 deletions slam/main_window.py
Original file line number Diff line number Diff line change
Expand Up @@ -73,18 +73,22 @@ def __init__(self, topics: List[str], bootstrap_servers: List[str], annunciate:
self.last_received_update_time[topic] = datetime.now()
self.alarm_select_combo_box.addItem(topic)
self.alarm_trees[topic] = AlarmTreeViewWidget(self.kafka_producer, topic, self.plot_pv, annunciate)
self.active_alarm_tables[topic] = AlarmTableViewWidget(self.alarm_trees[topic].treeModel,
self.kafka_producer,
topic,
AlarmTableType.ACTIVE,
self.plot_pv,
annunciate)
self.acknowledged_alarm_tables[topic] = AlarmTableViewWidget(self.alarm_trees[topic].treeModel,
self.kafka_producer,
topic,
AlarmTableType.ACKNOWLEDGED,
self.plot_pv,
annunciate)
self.active_alarm_tables[topic] = AlarmTableViewWidget(
self.alarm_trees[topic].treeModel,
self.kafka_producer,
topic,
AlarmTableType.ACTIVE,
self.plot_pv,
annunciate,
)
self.acknowledged_alarm_tables[topic] = AlarmTableViewWidget(
self.alarm_trees[topic].treeModel,
self.kafka_producer,
topic,
AlarmTableType.ACKNOWLEDGED,
self.plot_pv,
annunciate,
)

# Sync the column widths in the active and acknowledged tables, resizing a column will effect both tables.
# Managing the width of tables is done with their headers (QHeaderViews).
Expand Down
87 changes: 43 additions & 44 deletions slam/tests/test_alarm_configuration_widget.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,47 +25,46 @@ def test_create_and_show(qtbot, alarm_item, mock_kafka_producer):

@pytest.mark.parametrize("enabled, latching, annunciating", [(False, False, False), (True, True, True)])
def test_save_configuration(qtbot, alarm_item, mock_kafka_producer, enabled, latching, annunciating):
""" Verify that the information saved in the configuration widget is sent to the kafka cluster correctly """
alarm_config_widget = AlarmConfigurationWidget(alarm_item=alarm_item,
kafka_producer=mock_kafka_producer,
topic='TEST',
annunciate=annunciating)
qtbot.addWidget(alarm_config_widget)

# Simulate the user typing in several suggestions for how to handle this particular alarm
alarm_config_widget.enabled_checkbox.setChecked(enabled)
alarm_config_widget.latch_checkbox.setChecked(latching)
if annunciating:
alarm_config_widget.annunciate_checkbox.setChecked(True)
else:
assert alarm_config_widget.annunciate_checkbox.isEnabled() == False

alarm_config_widget.guidance_table.cellWidget(0, 0).setText("Call")
alarm_config_widget.guidance_table.cellWidget(0, 1).setText("Somebody")
alarm_config_widget.guidance_table.cellWidget(1, 0).setText("Read")
alarm_config_widget.guidance_table.cellWidget(1, 1).setText("the manual")

alarm_config_widget.displays_table.cellWidget(0, 0).setText("RF Display")

alarm_config_widget.commands_table.cellWidget(0, 0).setText("How to run display")
alarm_config_widget.commands_table.cellWidget(0, 1).setText("bash run_display.sh")

# Save all the values entered into the form
alarm_config_widget.save_configuration()

assert mock_kafka_producer.topic == "TEST"
assert mock_kafka_producer.key == "config:/ROOT/SECTOR_ONE/TEST:PV:ONE"
values_sent = mock_kafka_producer.values

# Verify the user input was read from the check boxes and tables and sent to kafka in the form it expects
assert values_sent["enabled"] == enabled
assert values_sent["latching"] == latching
assert values_sent["annunciating"] == annunciating
assert values_sent["guidance"][0]["title"] == "Call"
assert values_sent["guidance"][0]["details"] == "Somebody"
assert values_sent["guidance"][1]["title"] == "Read"
assert values_sent["guidance"][1]["details"] == "the manual"
assert values_sent["displays"][0]["title"] == "RF Display"
assert values_sent["displays"][0]["details"] == ""
assert values_sent["commands"][0]["title"] == "How to run display"
assert values_sent["commands"][0]["details"] == "bash run_display.sh"
"""Verify that the information saved in the configuration widget is sent to the kafka cluster correctly"""
alarm_config_widget = AlarmConfigurationWidget(
alarm_item=alarm_item, kafka_producer=mock_kafka_producer, topic="TEST", annunciate=annunciating
)
qtbot.addWidget(alarm_config_widget)

# Simulate the user typing in several suggestions for how to handle this particular alarm
alarm_config_widget.enabled_checkbox.setChecked(enabled)
alarm_config_widget.latch_checkbox.setChecked(latching)
if annunciating:
alarm_config_widget.annunciate_checkbox.setChecked(True)
else:
assert alarm_config_widget.annunciate_checkbox.isEnabled() is False

alarm_config_widget.guidance_table.cellWidget(0, 0).setText("Call")
alarm_config_widget.guidance_table.cellWidget(0, 1).setText("Somebody")
alarm_config_widget.guidance_table.cellWidget(1, 0).setText("Read")
alarm_config_widget.guidance_table.cellWidget(1, 1).setText("the manual")

alarm_config_widget.displays_table.cellWidget(0, 0).setText("RF Display")

alarm_config_widget.commands_table.cellWidget(0, 0).setText("How to run display")
alarm_config_widget.commands_table.cellWidget(0, 1).setText("bash run_display.sh")

# Save all the values entered into the form
alarm_config_widget.save_configuration()

assert mock_kafka_producer.topic == "TEST"
assert mock_kafka_producer.key == "config:/ROOT/SECTOR_ONE/TEST:PV:ONE"
values_sent = mock_kafka_producer.values

# Verify the user input was read from the check boxes and tables and sent to kafka in the form it expects
assert values_sent["enabled"] == enabled
assert values_sent["latching"] == latching
assert values_sent["annunciating"] == annunciating
assert values_sent["guidance"][0]["title"] == "Call"
assert values_sent["guidance"][0]["details"] == "Somebody"
assert values_sent["guidance"][1]["title"] == "Read"
assert values_sent["guidance"][1]["details"] == "the manual"
assert values_sent["displays"][0]["title"] == "RF Display"
assert values_sent["displays"][0]["details"] == ""
assert values_sent["commands"][0]["title"] == "How to run display"
assert values_sent["commands"][0]["details"] == "bash run_display.sh"
56 changes: 40 additions & 16 deletions slam/tests/test_alarm_tree_model.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import sys
from io import StringIO


def test_clear(tree_model, alarm_item):
"""A quick check that clear is removing data as expected."""
tree_model.nodes.append(alarm_item)
Expand Down Expand Up @@ -149,40 +150,63 @@ def test_remove_item(tree_model):


def test_annunciation(tree_model):
""" Test making an update to an item that has already been placed in the alarm tree """
alarm_item = AlarmItem('TEST:PV', path='/path/to/TEST:PV', alarm_severity=AlarmSeverity.OK,
alarm_status='OK', pv_severity=AlarmSeverity.OK, annunciating=True)
"""Test making an update to an item that has already been placed in the alarm tree"""
alarm_item = AlarmItem(
"TEST:PV",
path="/path/to/TEST:PV",
alarm_severity=AlarmSeverity.OK,
alarm_status="OK",
pv_severity=AlarmSeverity.OK,
annunciating=True,
)

tree_model.nodes.append(alarm_item)
tree_model.added_paths['TEST:PV'] = ['/path/to/TEST:PV']
tree_model.added_paths["TEST:PV"] = ["/path/to/TEST:PV"]

stdout_buffer = StringIO()
# redirect stdout to buffer
sys.stdout = stdout_buffer

tree_model.update_item('TEST:PV', '/path/to/TEST:PV', AlarmSeverity.MINOR, 'STATE_ALARM', None, 'FAULT',
AlarmSeverity.MINOR, 'alarm_status')

tree_model.update_item(
"TEST:PV",
"/path/to/TEST:PV",
AlarmSeverity.MINOR,
"STATE_ALARM",
None,
"FAULT",
AlarmSeverity.MINOR,
"alarm_status",
)

# restore original stdout stream
sys.stdout = sys.__stdout__

captured_output = stdout_buffer.getvalue()
assert captured_output == "\x07\n"

# Verify the update applied successfully
assert tree_model.nodes[0].name == 'TEST:PV'
assert tree_model.nodes[0].name == "TEST:PV"
assert tree_model.nodes[0].alarm_severity == AlarmSeverity.MINOR
assert tree_model.nodes[0].alarm_status == 'alarm' or tree_model.nodes[0].alarm_status == 'STATE_ALARM'
assert tree_model.nodes[0].alarm_value == 'FAULT'
assert tree_model.nodes[0].alarm_status == "alarm" or tree_model.nodes[0].alarm_status == "STATE_ALARM"
assert tree_model.nodes[0].alarm_value == "FAULT"
assert tree_model.nodes[0].pv_severity == AlarmSeverity.MINOR
assert tree_model.nodes[0].pv_status == 'alarm_status'
assert tree_model.nodes[0].pv_status == "alarm_status"

# Send a disable update message, verify the alarm gets marked filtered
tree_model.update_item('TEST:PV', '/path/to/TEST:PV', AlarmSeverity.MINOR, 'Disabled', None, 'FAULT',
AlarmSeverity.MINOR, 'alarm_status')
tree_model.update_item(
"TEST:PV",
"/path/to/TEST:PV",
AlarmSeverity.MINOR,
"Disabled",
None,
"FAULT",
AlarmSeverity.MINOR,
"alarm_status",
)
assert tree_model.nodes[0].filtered

# And then send a message re-enabling the alarm and verify it is marked enabled again
tree_model.update_item('TEST:PV', '/path/to/TEST:PV', AlarmSeverity.MINOR, 'OK', None, 'FAULT',
AlarmSeverity.MINOR, 'alarm_status')
assert not tree_model.nodes[0].filtered
tree_model.update_item(
"TEST:PV", "/path/to/TEST:PV", AlarmSeverity.MINOR, "OK", None, "FAULT", AlarmSeverity.MINOR, "alarm_status"
)
assert not tree_model.nodes[0].filtered
19 changes: 11 additions & 8 deletions slam_launcher/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,18 @@


def main():

parser = argparse.ArgumentParser(description="SLAC Alarm Manager")
parser.add_argument('--topics', help='Comma separated list of kafka alarm topics to listen to')
parser.add_argument('--bootstrap-servers',
default='localhost:9092',
help='Comma separated list of urls for one or more kafka boostrap servers')
parser.add_argument('--user-permissions', default='admin', help='One of read-only, operator, admin')
parser.add_argument('--log', default='warning', help='Logging level. debug, info, warning, error, critical')
parser.add_argument('--annunciate', action='store_true', help='Enable beep from alarms that have annunciate setting enabled') # default=False
parser.add_argument("--topics", help="Comma separated list of kafka alarm topics to listen to")
parser.add_argument(
"--bootstrap-servers",
default="localhost:9092",
help="Comma separated list of urls for one or more kafka boostrap servers",
)
parser.add_argument("--user-permissions", default="admin", help="One of read-only, operator, admin")
parser.add_argument("--log", default="warning", help="Logging level. debug, info, warning, error, critical")
parser.add_argument(
"--annunciate", action="store_true", help="Enable beep from alarms that have annunciate setting enabled"
) # default=False

app_args = parser.parse_args()

Expand Down

0 comments on commit c1a712a

Please sign in to comment.