Метакласс Python: проверка парных методов prepare и render

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

Другие упражнения по этой теме: Метаклассы и init_subclass Python: задачи на проверку классов.

Метакласс согласования стадий конвейера

Генератор витрин данных строит аналитические сводки с помощью специализированных классов-обработчиков. В каждом таком классе шаги построения отчёта разделены на две стадии: подготовка данных методом с префиксом prepare_ и последующее форматирование методом с префиксом render_. Чтобы конвейер работал предсказуемо, обе фазы должны быть строго согласованы: каждому этапу расчёта обязана соответствовать собственная стадия отрисовки с точно таким же именем.

Эту симметрию контролирует метакласс в момент конструирования нового типа. Он просматривает сырой словарь атрибутов объявляемого класса и находит все имена с указанными префиксами. Если для какого-то шага prepare_<name> не оказывается парного render_<name> либо обнаруживается одинокий метод отрисовки, метакласс немедленно прерывает создание класса исключением TypeError. Такая проверка срабатывает ещё до появления первых экземпляров отчёта, отсекая ошибки рассинхронизации на этапе импорта модулей.

Если же все методы образовали корректные пары, метакласс формирует готовый кортеж PIPELINE_STEPS и записывает его прямо в пространство имён создаваемого класса. В него входят названия всех подтверждённых стадий — общие суффиксы парных функций, упорядоченные по алфавиту.

Реализуйте метакласс, который следит за парной структурой методов обработки и автоматически собирает алфавитный список этапов конвейера.

Что уже дано

В редакторе объявлен класс PipelineMeta(type) с методом __new__(mcls, name, bases, namespace, **kwargs), который вам предстоит реализовать.

Вспомогательные функции observe_paired_pipeline и observe_pipeline_classcell доступны во время исполнения для проверки корректности создания классов; реализовывать их самостоятельно не требуется.

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

Реализуйте метод __new__(mcls, name, bases, namespace, **kwargs) метакласса PipelineMeta.

Метод принимает следующие аргументы:

  • mcls — сам метакласс PipelineMeta;
  • name — имя создаваемого класса (строка);
  • bases — кортеж базовых классов;
  • namespace — словарь атрибутов создаваемого класса (пространство имён);
  • **kwargs — именованные аргументы, переданные в заголовке объявления класса.

Правила валидации и создания класса:

  • Проверьте только собственные имена из словаря namespace текущего класса (от 0 до 100 имён с префиксами). Унаследованные методы из базовых классов bases не входят в сырой namespace текущего класса и не должны проверяться или объединяться с ним.
  • Выделите суффиксы для всех имён, начинающихся с prepare_, и отдельно суффиксы для всех имён, начинающихся с render_. Суффиксы состоят из букв ASCII, цифр или знаков подчёркивания и могут быть пустыми.
  • Множества суффиксов обеих групп должны строго совпадать. Если множества различаются (найден одиночный prepare_ без пары или одиночный render_ без пары), возбудите исключение семейства TypeError до вызова конструктора типа и до фактического создания некорректного класса.
  • При валидации проверяйте только строковые имена ключей. Не вызывайте и не связывайте сами функции или методы из namespace (среди них могут быть обычные методы, staticmethod, classmethod, а также сторонние дескрипторы).
  • Если множества суффиксов совпали, сформируйте кортеж PIPELINE_STEPS, содержащий все подтверждённые суффиксы стадий, отсортированные в стандартном лексикографическом порядке строк Python. Если таких методов в классе нет, кортеж должен быть пустым (). Если в namespace уже присутствовало старое значение PIPELINE_STEPS, его необходимо перезаписать вычисленным кортежем.
  • Запишите полученный кортеж PIPELINE_STEPS в namespace до конструирования типа через super().__new__, чтобы дескрипторы (включая хуки __set_name__) и хуки __init_subclass__ родительских классов видели актуальное значение.
  • Сохраните все остальные исходные элементы словаря namespace и штатное поведение создания классов в Python, включая поддержку компиляторного замыкания __classcell__ и бесконтекстного вызова super() в методах.
  • Все дополнительные именованные аргументы **kwargs передайте дальше в вызов super().__new__(mcls, name, bases, namespace, **kwargs) без изменений, чтобы их могли обработать хуки базовых классов.

Ввод и вывод

Стандартные потоки ввода stdin и вывода stdout в решении не используются: считывать ввод и вызывать print() не нужно. После выполнения кода учащегося проверяющая система считывает из пространства имён модуля метакласс верхнего уровня PipelineMeta и вызывает его с проверочными аргументами.

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

class Report(metaclass=PipelineMeta):
    def render_summary(self):
        pass
    def prepare_detail(self):
        pass
    def prepare_summary(self):
        pass
    def render_detail(self):
        pass
print(Report.PIPELINE_STEPS)

Вывод:

('detail', 'summary')
РешениеPython

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

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

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