Source code for ska_mid_dish_manager.utils.input_validation

"""Input validation and formatting."""

import json
from typing import List

from ska_mid_dish_manager.utils.ska_epoch_to_tai import get_current_tai_timestamp_from_unix_time


[docs]class ConfigureBandValidationError(Exception): """Exception raised for errors in the configure band input validation."""
[docs]class TrackTableTimestampError(ValueError): """Class that is used to represent timestamp errors in the track load table."""
[docs]def validate_configure_band_input(data: str) -> dict: """Validate the input JSON for configure_band command. :param data: JSON string containing the configure band parameters. :type data: str :raises ConfigureBandValidationError: If the input JSON is invalid. :return: Parsed JSON as a dictionary if valid. """ try: data_json = json.loads(data) dish_data = data_json.get("dish") receiver_band = dish_data.get("receiver_band") if receiver_band not in ["1", "2", "3", "4", "5a", "5b"]: raise ConfigureBandValidationError("Invalid receiver band in JSON.") # TODO: remove validation of two fields for sub band # after decision about JSON schema is finalised b5dc_sub_band = None sub_band = dish_data.get("sub_band") band5_downconversion_subband = dish_data.get("band5_downconversion_subband") b5dc_sub_band = sub_band or band5_downconversion_subband if receiver_band == "5b": # raise error if expected sub band fields are not provided or invalid if b5dc_sub_band is None: raise ConfigureBandValidationError( "Invalid configuration JSON. sub_band or" " band5_downconversion_subband field is required for" " requested receiver_band [5b]." ) if b5dc_sub_band not in ["1", "2", "3"]: raise ConfigureBandValidationError( "Invalid configuration JSON. Valid sub band required for" ' requested receiver_band [5b]. Expected "1", "2"' ' or "3".' ) if b5dc_sub_band: # TODO: remove segment below after decision about JSON schema is finalised # Remove band5_downconversion_subband # field to maintain compatibility with SPFRx firmware data_json["dish"]["sub_band"] = b5dc_sub_band if "band5_downconversion_subband" in data_json["dish"]: data_json["dish"].pop("band5_downconversion_subband") except (json.JSONDecodeError, AttributeError) as err: raise ConfigureBandValidationError("Error parsing JSON.") from err return data_json
[docs]class TrackLoadTableFormatting: """Class that encapsulates related validation and mapping for TrackLoadTable command."""
[docs] def check_track_table_input_valid(self, table: List[float], lead_time: int) -> None: """Entry point for track table validation. :param table: Track table input that is to be validated :param lead_time: The amount of time in seconds from the current time timestamps are allowed :raises ValueError: table list is not a multiple of 3 :raises TrackTableTimestampError: when timestamps are less than lead_time seconds into the future :return: None """ length_of_table = len(table) # length validaton if length_of_table > 0: # Checks that the table length is a multiple of 3 if length_of_table % 3 != 0: raise ValueError( f"Length of table ({len(table)}) is not a multiple of 3 " "(timestamp, azimuth coordinate, elevation coordinate) as expected." ) try: self._check_timestamp(table, length_of_table, lead_time) except TrackTableTimestampError as timestamp_error: raise timestamp_error
def _check_timestamp( self, table: List[float], length_of_table: int, lead_time: float, ) -> None: """Check that the timestamps are in the future by at least lead_time in seconds and that they are monotonically increasing. :param table: Track table input that is to be validated :param length_of_table: Length of the track table :param lead_time: Duration in seconds ahead of the current time that table timestamps should be ahead of :raises TrackTableTimestampError: when timestamps are less than lead_time seconds into the future, or if the timestamps are not monotonically increasing. :return: None """ current_tai_timestamp = get_current_tai_timestamp_from_unix_time() prev_timestamp = -1 for i in range(0, length_of_table, 3): timestamp_tai_s = table[i] # check for lead_time violation delta = timestamp_tai_s - current_tai_timestamp if delta < lead_time: raise TrackTableTimestampError( "Check track table parameters." f" Timestamps less than {lead_time}s into the future." f" Violation detected for timestamp ({timestamp_tai_s}) which is less than " f" {lead_time}s ahead of current time ({current_tai_timestamp})." ) # check for monotonically increasing if i != 0: row_time_delta = timestamp_tai_s - prev_timestamp if row_time_delta < 0: raise TrackTableTimestampError( "Check track table parameters." "Timestamps are not monotonically increasing." f"Last two timestamps (tai) {timestamp_tai_s},{prev_timestamp},..." ) prev_timestamp = timestamp_tai_s