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


import time
from typing import NamedTuple, Optional

class ReturnFromPostProcessor(NamedTuple):
    is_operation_successful: bool
    next_operation_id: Optional[str]
    local_vars: dict
    global_vars: dict

def post_processor(
    response, operation, user_vars, listener, user_class, *args, **kwargs
) -> ReturnFromPostProcessor:
    
    # Инициализируем дефолтные значения на случай полной деградации user_vars
    current_iter = 0
    total_iter = 1
    num_a = 0.0
    num_b = 0.0
    
    # ОПТИМИЗАЦИЯ 1: Быстрое и безопасное извлечение переменных в один проход
    try:
        if isinstance(user_vars, dict):
            it = user_vars.get('iteration')
            tot = user_vars.get('total_iterations')
            na = user_vars.get('numA')
            nb = user_vars.get('numB')
            
            # Извлекаем значения вне зависимости от того, объект это UserVar или сырой тип
            if it is not None: current_iter = int(it.value if hasattr(it, 'value') else it)
            if tot is not None: total_iter = int(tot.value if hasattr(tot, 'value') else tot)
            if na is not None: num_a = float(na.value if hasattr(na, 'value') else na)
            if nb is not None: num_b = float(nb.value if hasattr(nb, 'value') else nb)
    except (ValueError, TypeError, AttributeError):
        pass  # При любых аномалиях данных безопасно работаем с дефолтами

    # Вычисляем флаг завершения цикла заранее
    remaining = current_iter < (total_iter - 1)
    is_success = False

    # ОПТИМИЗАЦИЯ 2: Безопасная проверка статус-кодов (200 или 204) без риска NoneType
    if hasattr(response, "status_code") and response.status_code in (200, 204):
        is_success = True
        
        # Расчет и подача пэйсинга (только при успешном запросе и наличии следующих итераций)
        if remaining:
            try:
                pacing = (((num_b + num_a) / 2) - 15) / total_iter
                if pacing > 0:
                    time.sleep(pacing)
            except (ZeroDivisionError, ValueError, TypeError):
                pass  # Если total_iter равен 0 или данные побились — просто идем дальше

    # ОПТИМИЗАЦИЯ 3: Плоская матрица возврата (исключает дублирование веток кода)
    if is_success and remaining:
        return ReturnFromPostProcessor(
            True, 
            "UC01_POST_spending_WEB", 
            {"iteration": str(current_iter + 1)}, 
            {}
        )
    
    # Сюда мы попадаем, если:
    # 1. Запрос успешен, но это была последняя итерация цикла.
    # 2. Запрос завершился ошибкой (код не 200/204).
    # В обоих случаях по вашей логике мы сбрасываем итератор в "0" и возвращаем next_operation_id = None
    return ReturnFromPostProcessor(is_success, None, {"iteration": "0"}, {})