Asyncio TaskGroup: сбор результатов с отменёнными задачами

Напишите решение на Python и проверьте его на странице.

Другие упражнения по этой теме: Asyncio TaskGroup и gather: задачи на ошибки и отмену корутин.

Сбор результатов валидации документов

Сервис распределённой проверки документов запускает группу независимых валидаторов внутри контекста asyncio.TaskGroup. Во время работы отдельный валидатор может решить, что документ проверять не нужно, и самостоятельно завершиться возбуждением asyncio.CancelledError. По контракту группы такая точечная отмена не считается сбоем и не приводит к каскадной отмене остальных проверок.

Сложность возникает уже после выхода из контекста, когда диспетчер начинает подводить итоги. Прямой вызов task.result() у отменённой задачи повторно выбрасывает CancelledError, из-за чего весь процесс сбора результатов может аварийно завершиться.

Диспетчеру необходимо аккуратно обойти все задачи группы и проверить индивидуальный статус каждой из них. Успешные результаты требуется сохранить в итоговый словарь, а отменённые проверки отметить специальным маркером пропуска, не допуская необработанного исключения.

Что уже дано

В среде выполнения доступен модуль asyncio и специальный уникальный объект-маркер SKIPPED. В редакторе представлена заготовка асинхронной функции collect_validators(validators).

Что нужно сделать

Реализуйте асинхронную функцию collect_validators(validators) -> dict[str, object].

Параметр validators — словарь, содержащий от 0 до 50 элементов. Ключами являются уникальные строковые имена длиной от 1 до 64 символов, а значениями — фабрики без аргументов, возвращающие корутины проверки.

Требования к выполнению:

  • Запустите корутину каждого валидатора ровно один раз строго внутри контекстного менеджера asyncio.TaskGroup.
  • Все созданные задачи должны быть полностью завершены до выхода из функции. Оставлять незавершённые фоновые задачи в цикле событий запрещено.
  • Каждый валидатор либо завершается успешно, возвращая значение (скаляр, список, словарь, включая None, False, 0 и пустые структуры данных), либо выполняет самоотмену возбуждением asyncio.CancelledError. Обычные исключения валидаторы не выбрасывают.
  • Самоотмена отдельного валидатора не должна приводить к отмене остальных проверок.
  • После завершения работы группы сформируйте и верните словарь, ключи которого в точности совпадают с ключами входного словаря validators (порядок ключей значения не имеет):
  • для завершившегося штатно валидатора значением должно быть возвращённое им значение (включая None, False, 0 и пустые коллекции);
  • для отменённого валидатора значением должен стать точный предоставленный маркер SKIPPED (не строка 'SKIPPED' и не None).
  • Чтение результата отменённой задачи не должно приводить к падению функции из-за необработанного asyncio.CancelledError.
  • Если на вход передан пустой словарь validators, функция должна вернуть пустой словарь {}.

Ввод и вывод

Стандартные потоки stdin и stdout не используются: считывать данные и выводить результат через print не требуется. Тестирующая система после выполнения скрипта получает функцию верхнего уровня collect_validators, передаёт в неё словарь с именами и фабриками корутин и ожидает её завершения.

Пример использования

async def valid():
    await asyncio.sleep(0)
    return None

async def skipped():
    raise asyncio.CancelledError()

async def example():
    answers = await collect_validators({"A": valid, "B": skipped})
    print(answers["A"] is None)
    print(answers["B"] is SKIPPED)

asyncio.run(example())

Вывод:

True
True
РешениеPython

Без регистрации. Гостевая проверка не сохраняет прогресс. Для сохранения перейдите к уроку.

Отправьте решение, чтобы увидеть результаты тестов.

Связанные задачи