diff --git a/src/videoipath_automation_tool/apps/inventory/inventory_api.py b/src/videoipath_automation_tool/apps/inventory/inventory_api.py index e6c32f4..5881536 100644 --- a/src/videoipath_automation_tool/apps/inventory/inventory_api.py +++ b/src/videoipath_automation_tool/apps/inventory/inventory_api.py @@ -18,7 +18,7 @@ from videoipath_automation_tool.apps.inventory.model.inventory_request_rpc import InventoryRequestRpc from videoipath_automation_tool.connector.models.response_rpc import ResponseRPC from videoipath_automation_tool.connector.vip_connector import VideoIPathConnector -from videoipath_automation_tool.utils.cross_app_utils import create_fallback_logger +from videoipath_automation_tool.utils.cross_app_utils import create_fallback_logger, extract_natural_sort_key from videoipath_automation_tool.validators.device_id import validate_device_id @@ -372,16 +372,27 @@ def fetch_device_ids_list(self) -> List[str]: return [device["_id"] for device in response.data["config"]["devman"]["devices"]["_items"]] def fetch_device_ids_by_driver(self, driver: DriverLiteral) -> List[str]: - """Method to fetch all device ids by driver id from VideoIPath-Inventory""" + """Fetch all device IDs by driver ID from VideoIPath-Inventory with natural sorting.""" driver_organization, driver_name, driver_version = extract_driver_info_from_id(driver_id=driver) + escaped_driver_organization = urllib.parse.quote(driver_organization, safe="") escaped_driver_name = urllib.parse.quote(driver_name, safe="") escaped_driver_version = urllib.parse.quote(driver_version, safe="") - url_path = f"/rest/v2/data/config/devman/devices/* where (config.driver.name='{escaped_driver_name}' and config.driver.version='{escaped_driver_version}' and config.driver.organization='{escaped_driver_organization}') /**" + + url_path = ( + f"/rest/v2/data/config/devman/devices/* " + f"where (config.driver.name='{escaped_driver_name}' " + f"and config.driver.version='{escaped_driver_version}' " + f"and config.driver.organization='{escaped_driver_organization}') /**" + ) + response = self.vip_connector.rest.get(url_path) + if not response.data: raise ValueError("Response data is empty.") - return [device["_id"] for device in response.data["config"]["devman"]["devices"]["_items"]] + + device_ids = [device["_id"] for device in response.data["config"]["devman"]["devices"]["_items"]] + return sorted(device_ids, key=extract_natural_sort_key) # --- Bulk Device Label Fetching Methods --- def fetch_devices_factory_labels_as_dict(self) -> dict[str, str]: diff --git a/src/videoipath_automation_tool/utils/cross_app_utils.py b/src/videoipath_automation_tool/utils/cross_app_utils.py index 07e93cc..7d2cbc4 100644 --- a/src/videoipath_automation_tool/utils/cross_app_utils.py +++ b/src/videoipath_automation_tool/utils/cross_app_utils.py @@ -1,4 +1,5 @@ import logging +import re import uuid from typing_extensions import deprecated @@ -19,6 +20,11 @@ def generate_uuid_4(): return str(uuid.uuid4()) +# --- Natural Sort Device ID list --- +def extract_natural_sort_key(s: str): + return [int(text) if text.isdigit() else text.lower() for text in re.split(r"(\d+)", s)] + + # --- Deprecated Functions for Device ID Validation --- # --- Device ID string validation --- @deprecated("Use 'validate_device_id' from 'videoipath_automation_tool.validators.device_id' instead.")