Python initsubclass: проверка порядка миграций схемы
Напишите решение на Python и проверьте его на странице.
Другие упражнения по этой теме: Метаклассы и init_subclass Python: задачи на проверку классов.
Реестр миграций схемы
В хранилище документов цепочка обновлений схемы данных строится из отдельных классов, каждый из которых отвечает за свой шаг изменений. Чтобы последовательность оставалась надёжной, базовый класс миграций контролирует правильный порядок стадий прямо в момент объявления их классов с помощью __init_subclass__.
Каждый класс-наследник передаёт в заголовке объявления целое число version и имя класса-предшественника previous. Корневая миграция начинает цепочку: её предшественник равен None, а версия — строго 1. Любой последующий класс обязан ссылаться на уже зарегистрированного предшественника, а его версия должна быть строго больше версии этого предка. Если указанный предшественник ещё не известен или новая версия оказывается меньше либо равна версии предшественника, объявление такого класса немедленно возбуждает ValueError.
Реализуйте базовый класс, который проверяет связность и строгую монотонность версий при создании каждого класса миграции.
Что уже дано
В редакторе представлена заготовка базового класса MigrationBase с пустым общим словарём registry и заглушкой метода __init_subclass__.
Что нужно сделать
Реализуйте класс MigrationBase со следующим поведением:
- Атрибут класса
registry— изначально пустой словарьdict[str, type], общий для всех наследников. В него заносятся только успешно созданные классы: ключ — имя класса (cls.__name__), значение — сам объект созданного класса. - Метод
__init_subclass__(cls, version, previous, **kwargs)принимает обязательные именованные параметры заголовка класса: version(int) — номер версии от-1 000 000до1 000 000;previous(str | None) —Noneили строка с именем класса-предшественника (до 40 символов).- При успешной проверке созданный класс должен содержать публичные атрибуты
versionиpreviousс переданными значениями и быть зарегистрирован вMigrationBase.registry. - Правила валидации при объявлении класса:
- Если
previous is None, объявляется корневая миграция. Её версия обязана быть строго равна1. При любом другом значенииversionсоздание класса отклоняется ошибкойValueError. - Если
previous— строка, она должна быть именем уже успешно созданного и зарегистрированного вregistryкласса, а значениеversionобязано быть строго больше версии этого предшественника. Если предшественник отсутствует в реестре либо новая версия меньше или равна версии предка, создание класса отклоняется ошибкойValueError(допускаются также её подклассы; текст ошибки не регламентируется). - Отклонённые классы ни при каких обстоятельствах не должны попадать в
registryили повреждать уже существующие записи. - Разрешены несколько корневых миграций, независимые ветвления цепочек, одинаковые версии на разных ветках и пропуски номеров при возрастании. Имена всех объявляемых классов уникальны (допустимые идентификаторы Python длиной до 40 символов). Всего в рамках одного прогона выполняется от 0 до 512 попыток создания классов.
Ввод и вывод
Стандартные потоки stdin и stdout не используются: считывать ввод и вызывать print в решении не требуется. Тестирующая система считывает класс верхнего уровня MigrationBase после выполнения кода ученика, объявляет подклассы миграций и проверяет содержимое словаря MigrationBase.registry.
Пример использования
class Initial(MigrationBase, version=1, previous=None):
pass
class Expanded(MigrationBase, version=4, previous='Initial'):
pass
print(list(MigrationBase.registry))
print(Expanded.version, Expanded.previous)
try:
class InvalidStep(MigrationBase, version=4, previous='Expanded'):
pass
except ValueError:
print('ValueError')
Вывод:
['Initial', 'Expanded']
4 Initial
ValueError
Без регистрации. Гостевая проверка не сохраняет прогресс. Для сохранения перейдите к уроку.
Отправьте решение, чтобы увидеть результаты тестов.
Связанные задачи
- Когда вызывается initsubclass в Python: тест
- Метаклассы Python: передача аргументов класса в initsubclass
- Python initsubclass: запрет переопределения констант
- Метакласс Python: регистрация методов в пространстве имён
- MRO в Python: проверка порядка примесей в наследовании
- Метакласс Python: проверка парных методов prepare и render
