Загрузка данных


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