Загрузка данных
infra\stand_setup_manager.py
from infra.clickhouse_manager import ClickHouseManager
from infra.configuration_manager import ConfigurationManager
self._clickhouse_manager.delete_clickhouse_keys_with_check()
def get_sensor_ids_by_address(self) -> dict[str, int]:
"""
Возвращает словарь address: id из конфигурации, скопированной на runner.
"""
return self._configuration_manager.get_sensor_ids_by_address()
self._clickhouse_manager = ClickHouseManager(
self._stand_client, self._infra_client, self._configuration_file_name
)
self._configuration_manager = ConfigurationManager(self._configuration_file_name)
конфтест
"imitator_start_time": None, # datetime объект времени старта имитатора для расчёта интервалов утечек
}
def _is_rejection_test(item) -> bool:
"""
Проверяет, относится ли текущий pytest item к тестам отбраковки.
"""
return "rejection_case" in getattr(item, "fixturenames", [])
def _update_rejection_sensor_ids(stand_manager: StandSetupManager) -> None:
"""
Для тестов отбраковки обновляет sensor_id по address из конфигурации стенда.
"""
sensor_ids_by_address = stand_manager.get_sensor_ids_by_address()
RejectionSensorTag.update_ids_from_config(sensor_ids_by_address)
pytest.exit(f"[SETUP] [ERROR] ошибка при подготовке стенда: {error}")
if _is_rejection_test(item):
try:
_update_rejection_sensor_ids(stand_manager)
except Exception as error:
pytest.exit(f"[SETUP] [ERROR] ошибка обновления id датчиков отбраковки из конфигурации: {error}")
infra\configuration_manager.py
import json
import logging
from typing import Any
from utils.helpers.configuration_utils import extract_sensor_ids_by_address
from constants.architecture_constants import ImitatorConstants as Imitator_const
logger = logging.getLogger(__name__)
class ConfigurationManager:
"""
Читает локальную конфигурацию стенда и извлекает из нее данные для тестов.
"""
def __init__(self, configuration_file_name: str) -> None:
self._configuration_file_name = configuration_file_name
def get_sensor_ids_by_address(self) -> dict[str, int]:
"""
Возвращает словарь address: id из файла конфигурации.
"""
configuration_json = self._read_configuration_file()
return extract_sensor_ids_by_address(configuration_json)
def _read_configuration_file(self) -> Any:
"""
Чтение файла конфигурации, использует список кодировок.
"""
error_msg = (
f"[CONFIGURATION] [ERROR] Не удалось декодировать файл {self._configuration_file_name} "
f"в кодировках {Imitator_const.DEFAULT_ENCODINGS}"
)
for encoding in Imitator_const.DEFAULT_ENCODINGS:
try:
with open(self._configuration_file_name, "r", encoding=encoding, errors="strict") as conf_file:
data = json.load(conf_file)
if not data:
error_msg = f"Пустой json (кодировка:{encoding}"
logger.error(error_msg)
raise ValueError(error_msg)
return data
except UnicodeDecodeError:
continue
except Exception as error:
logger.exception(error_msg)
raise OSError(error_msg) from error
logger.exception(error_msg)
raise OSError(error_msg)
utils\helpers\configuration_utils.py
from typing import Any
def extract_sensor_ids_by_address(configuration_json: Any) -> dict[str, int]:
"""
Собирает соответствие address -> id для всех объектов конфигурации.
Учитываются только словари, где address и id находятся на одном уровне.
"""
sensor_ids_by_address: dict[str, int] = {}
stack = [configuration_json]
while stack:
current_element = stack.pop()
if isinstance(current_element, dict):
address = current_element.get("address")
sensor_id = current_element.get("id")
if isinstance(address, str) and isinstance(sensor_id, int) and sensor_id != 0:
sensor_ids_by_address[address] = sensor_id
stack.extend(reversed(current_element.values()))
elif isinstance(current_element, list):
stack.extend(reversed(current_element))
return sensor_ids_by_address