diff --git a/MethodicConfigurator/annotate_params.py b/MethodicConfigurator/annotate_params.py index 31a8144..862e6fc 100755 --- a/MethodicConfigurator/annotate_params.py +++ b/MethodicConfigurator/annotate_params.py @@ -209,6 +209,7 @@ def format_params(param_dict: Dict[str, 'Par'], file_format: str = "missionplann Parameters: param_dict (Dict[str, 'Par']): A dictionary of 'Par' objects. Each key is a parameter name and each value is a 'Par' object. + Par can be a simple float or a Par object with a comment. file_format (str): Can be "missionplanner" or "mavproxy" Returns: @@ -303,7 +304,7 @@ def print_out(formatted_params: List[str], name: str) -> None: print(line) -def get_xml_data(base_url: str, directory: str, filename: str) -> ET.Element: +def get_xml_data(base_url: str, directory: str, filename: str, vehicle_type: str) -> ET.Element: """ Fetches XML data from a local file or a URL. @@ -311,6 +312,7 @@ def get_xml_data(base_url: str, directory: str, filename: str) -> ET.Element: base_url (str): The base URL for fetching the XML file. directory (str): The directory where the XML file is expected. filename (str): The name of the XML file. + vehicle_type (str): The type of the vehicle. Returns: ET.Element: The root element of the parsed XML data. @@ -336,13 +338,24 @@ def get_xml_data(base_url: str, directory: str, filename: str) -> ET.Element: raise SystemExit("requests package is not installed") from exc try: # Send a GET request to the URL - response = requests_get(base_url + filename, timeout=5) + url = base_url + filename + response = requests_get(url, timeout=5) if response.status_code != 200: - logging.critical("Remote URL: %s", base_url + filename) + logging.warning("Remote URL: %s", url) raise requests_exceptions.RequestException(f"HTTP status code {response.status_code}") except requests_exceptions.RequestException as e: - logging.critical("Unable to fetch XML data: %s", e) - raise SystemExit("unable to fetch online XML documentation") from e + logging.warning("Unable to fetch XML data: %s", e) + # Send a GET request to the URL to the fallback (DEV) URL + try: + url = BASE_URL + vehicle_type + '/' + PARAM_DEFINITION_XML_FILE + logging.warning("Falling back to the DEV XML file: %s", url) + response = requests_get(url, timeout=5) + if response.status_code != 200: + logging.critical("Remote URL: %s", url) + raise requests_exceptions.RequestException(f"HTTP status code {response.status_code}") + except requests_exceptions.RequestException as exp: + logging.critical("Unable to fetch XML data: %s", exp) + raise SystemExit("unable to fetch online XML documentation") from exp # Get the text content of the response xml_data = response.text try: @@ -695,7 +708,7 @@ def get_xml_url(vehicle_type: str, firmware_version: str) -> str: def parse_parameter_metadata(xml_url: str, xml_dir: str, xml_file: str, vehicle_type: str, max_line_length: int) -> Dict[str, Any]: - xml_root = get_xml_data(xml_url, xml_dir, xml_file) + xml_root = get_xml_data(xml_url, xml_dir, xml_file, vehicle_type) return create_doc_dict(xml_root, vehicle_type, max_line_length) diff --git a/MethodicConfigurator/backend_flightcontroller.py b/MethodicConfigurator/backend_flightcontroller.py index 7aae7d8..2b0b6d9 100644 --- a/MethodicConfigurator/backend_flightcontroller.py +++ b/MethodicConfigurator/backend_flightcontroller.py @@ -316,9 +316,9 @@ def __process_autopilot_version(self, m, banner_msgs) -> str: # the banner message after the ChibiOS one contains the FC type fc_product = '' if os_custom_version_index is not None: - fc_type_msgs = banner_msgs[os_custom_version_index+1].split(' ') - if len(fc_type_msgs) >= 3: - fc_product = fc_type_msgs[0] + fc_product_banner_substrings = banner_msgs[os_custom_version_index+1].split(' ') + if len(fc_product_banner_substrings) >= 3: + fc_product = fc_product_banner_substrings[0] if fc_product != self.info.product: logging_warning("FC product mismatch: %s (BANNER)!= %s(AUTOPILOT_VERSION)", fc_product, self.info.product) self.info.product = fc_product # force the one from the banner because it is more reliable diff --git a/unittests/annotate_params_test.py b/unittests/annotate_params_test.py index 263d8a0..0b9e9b1 100755 --- a/unittests/annotate_params_test.py +++ b/unittests/annotate_params_test.py @@ -76,7 +76,7 @@ def test_get_xml_data_local_file(self, mock_load_param, mock_isfile, mock_open): mock_load_param.side_effect = FileNotFoundError # Call the function with a local file - result = get_xml_data("/path/to/local/file/", ".", "test.xml") + result = get_xml_data("/path/to/local/file/", ".", "test.xml", "ArduCopter") # Check the result self.assertIsInstance(result, ET.Element) @@ -97,7 +97,7 @@ def test_get_xml_data_remote_file(self, mock_get): pass # Call the function with a remote file - result = get_xml_data("http://example.com/", ".", "test.xml") + result = get_xml_data("http://example.com/", ".", "test.xml", "ArduCopter") # Check the result self.assertIsInstance(result, ET.Element) @@ -120,7 +120,7 @@ def side_effect(filename): mock_open = mock.mock_open(read_data='') with patch('builtins.open', mock_open): # Call the function with a filename that exists in the script directory - result = get_xml_data(BASE_URL, ".", PARAM_DEFINITION_XML_FILE) + result = get_xml_data(BASE_URL, ".", PARAM_DEFINITION_XML_FILE, "ArduCopter") # Check the result self.assertIsInstance(result, ET.Element) @@ -140,7 +140,7 @@ def test_get_xml_data_no_requests_package(self): # Call the function with a remote file with self.assertRaises(SystemExit): - get_xml_data("http://example.com/", ".", "test.xml") + get_xml_data("http://example.com/", ".", "test.xml", "ArduCopter") @patch('requests.get') def test_get_xml_data_request_failure(self, mock_get): @@ -155,7 +155,7 @@ def test_get_xml_data_request_failure(self, mock_get): # Call the function with a remote file with self.assertRaises(SystemExit): - get_xml_data("http://example.com/", ".", "test.xml") + get_xml_data("http://example.com/", ".", "test.xml", "ArduCopter") @patch('requests.get') def test_get_xml_data_valid_xml(self, mock_get): @@ -164,7 +164,7 @@ def test_get_xml_data_valid_xml(self, mock_get): mock_get.return_value.text = "" # Call the function with a remote file - result = get_xml_data("http://example.com/", ".", "test.xml") + result = get_xml_data("http://example.com/", ".", "test.xml", "ArduCopter") # Check the result self.assertIsInstance(result, ET.Element) @@ -183,7 +183,7 @@ def test_get_xml_data_invalid_xml(self, mock_get): # Call the function with a remote file with self.assertRaises(ET.ParseError): - get_xml_data("http://example.com/", ".", "test.xml") + get_xml_data("http://example.com/", ".", "test.xml", "ArduCopter") @patch('requests.get') @patch('os.path.isfile') @@ -201,7 +201,7 @@ def test_get_xml_data_missing_file(self, mock_isfile, mock_get): # Call the function with a local file with self.assertRaises(FileNotFoundError): - get_xml_data("/path/to/local/file/", ".", "test.xml") + get_xml_data("/path/to/local/file/", ".", "test.xml", "ArduCopter") @patch('requests.get') def test_get_xml_data_network_issue(self, mock_get): @@ -210,7 +210,7 @@ def test_get_xml_data_network_issue(self, mock_get): # Call the function with a remote file with self.assertRaises(SystemExit): - get_xml_data("http://example.com/", ".", "test.xml") + get_xml_data("http://example.com/", ".", "test.xml", "ArduCopter") def test_remove_prefix(self): # Test case 1: Normal operation