Pydantic — это мощная библиотека проверки данных и управления настройками для Python, созданная для повышения прочности и надежности вашей кодовой базы. Pydantic может справиться практически с любым сценарием проверки данных с минимальным количеством кода: от проверки, является ли переменная целым числом, до обеспечения правильных типов данных для ключей и значений вложенных словарей.
Библиотека Pydantic
Одной из главных особенностей Python является то, что это динамически типизированный язык. Динамическая типизация означает, что типы переменных определяются во время выполнения программы.
Для сравнения — в статически типизированных языках типы явно объявляются во время компиляции.
Динамическая типизация отлично подходит для быстрой разработки и простоты использования, но для реальных приложений часто требуется более надежная проверка типов и валидация данных.
В этом вам поможет библиотека Python Pydantic. Она быстро завоевала популярность, и сейчас это самая распространенная библиотека проверки данных для Python.
Знакомство с Pydantic
Pydantic — это мощная библиотека Python, которая использует подсказки типов, чтобы помочь вам легко проверять и сериализовать схемы данных. Это делает ваш код более надежным, читабельным, лаконичным и легким для отладки.
Pydantic также хорошо интегрируется со многими популярными инструментами статической типизации и IDE, что позволяет выявлять проблемы со схемами до запуска кода.
Отличительные особенности Pydantic:
- Кастомизация. С помощью Pydantic можно проверять данные практически любого типа. Эта библиотека позволяет валидировать и сериализовать практически любой объект Python, от примитивных типов до высоко вложенных структур данных.
- Гибкость. Pydantic дает вам контроль над строгостью проверки данных. В некоторых случаях вы можете захотеть принудительно привести входящие данные к правильному типу. Например, вы можете принять данные, которые должны иметь тип float, но получены как целое число. В других случаях вы можете захотеть строго придерживаться типов получаемых данных. Pydantic позволяет вам поступать и так, и эдак.
- Сериализация. Вы можете сериализовать и десериализовать объекты Pydantic в виде словарей и строк JSON. Это означает, что можно легко преобразовывать объекты Pydantic в JSON и обратно. Эта возможность привела к созданию самодокументированных API и интеграции практически с любым инструментом, поддерживающим JSON-схемы.
- Производительность. Благодаря основной логике валидации, написанной на языке Rust, Pydantic работает исключительно быстро. Это преимущество в производительности обеспечивает быструю и надежную обработку данных, особенно в высокопроизводительных приложениях, таких как REST API, которые должны масштабироваться до большого количества запросов.
- Экосистема и промышленное внедрение. Pydantic является зависимостью многих популярных библиотек Python, таких как FastAPI, LangChain и Polars. Эту библиотеку также используют большинство крупнейших технологических компаний. Это свидетельствует о поддержке сообщества, надежности и устойчивости Pydantic.
Эти особенности делают Pydantic привлекательной библиотекой проверки данных. В нашем руководстве мы покажем их в действии.
Установка Pydantic
Pydantic доступна на PyPI, и вы можете установить ее с помощью pip. Откройте терминал или командную строку, создайте новое виртуальное окружение, а затем выполните следующую команду для установки Pydantic:
(venv) $ python -m pip install pydantic
Эта команда установит последнюю версию Pydantic из PyPI на вашу машину. Чтобы убедиться, что установка прошла успешно, запустите Python REPL и импортируйте Pydantic:
>>> import pydantic
Если импорт пройдет без ошибок, значит, библиотека установлена успешно, и теперь в вашей системе есть ядро Pydantic.
Добавление дополнительных зависимостей
Вместе с Pydantic можно установить и дополнительные зависимости. Например, в этой статье мы будем работать с проверкой электронной почты, поэтому вы можете включить в свою установку эти зависимости:
(venv) $ python -m pip install "pydantic[email]"
В Pydantic есть отдельный пакет для управления настройками, который мы тоже рассмотрим. Чтобы установить его, выполните следующую команду:
(venv) $ python -m pip install pydantic-settings
Итак, вы установили все зависимости, необходимые для этого урока, и готовы приступить к изучению Pydantic. Начнем с моделей — основного способа определения схем данных в Pydantic.
Использование моделей
Основной способ определения схем данных в Pydantic — это модели. Модель Pydantic — это объект, похожий на dataclass Python, который определяет и хранит данные о сущности с аннотированными полями. В отличие от классов данных, Pydantic сосредоточен на автоматических парсинге, валидации и сериализации данных.
Лучший способ разобраться во всем этом — создать свои собственные модели.
Работа с Pydantic BaseModels
Предположим, вы создаете приложение, используемое отделом кадров для управления информацией о сотрудниках. Вам нужен способ проверить, что информация о новом сотруднике представлена в правильной форме. Например, каждый сотрудник должен иметь ID, имя, email, дату рождения, зарплату, отдел и выбор льгот. Это идеальный вариант использования модели Pydantic!
Чтобы определить модель сотрудника, вы создаете класс, который наследуется от BaseModel Pydantic:
Сначала вы импортируете зависимости, необходимые для определения модели сотрудника. Затем вы создаете enum для представления различных отделов вашей компании и используете его для аннотирования поля department в модели сотрудника.
После этого вы определяете свою модель Employee, которая наследует от BaseModel и определяет имена и ожидаемые типы полей с помощью аннотаций. Вот описание каждого поля, которое вы определили в Employee, и того, как Pydantic проверяет его при создании объекта Employee:
- employee_id. Это UUID сотрудника, информацию о котором вы хотите сохранить. Используя аннотацию UUID, Pydantic гарантирует, что это поле всегда будет валидным UUID. Каждому экземпляру Employee по умолчанию будет присвоен UUID, который вы указали, вызвав uuid4().
- name. Имя сотрудника, которое Pydantic ожидает как строку.
- email. Pydantic убедится, что email каждого сотрудника является валидным, используя под капотом библиотеку Python email-validator.
- date_of_birth. Дата рождения каждого сотрудника должна быть валидной датой, поскольку аннотирована как date из модуля Python datetime. Если вы передадите в date_of_birth строку, Pydantic попытается разобрать ее и преобразовать в объект date.
- salary. Это зарплата сотрудника, и ожидается, что это будет число с плавающей запятой.
- department. Отдел каждого сотрудника должен быть или HR, или SALES, или IT, или ENGINEERING, как определено в Department enum.
- elected_benefits: Это поле хранит информацию о том, есть ли у сотрудника льготы, и Pydantic ожидает, что это будет булево значение.
Самый простой способ создать объект Employee — это инстанцировать его, как и любой другой объект Python. Для этого откройте Python REPL и запустите следующий код:
В этом блоке вы импортируете Employee и создаете объект со всеми необходимыми полями сотрудника. Pydantic успешно проверяет и принудительно обрабатывает переданные вами поля и создает корректный объект Employee. Обратите внимание, как Pydantic автоматически преобразует строку даты в объект date, а строку IT — в соответствующее перечисление Department.
Теперь давайте посмотрим, как Pydantic отреагирует, если попытаться передать экземпляру Employee недопустимые данные:
В этом примере вы создали объект Employee с недопустимыми полями данных. Pydantic выдает подробное сообщение об ошибке для каждого поля, сообщая, что ожидалось, что было получено и куда можно обратиться, чтобы узнать больше об ошибке.
Такая подробная валидация очень важна, поскольку она предотвращает сохранение недействительных данных в Employee. Это также дает вам уверенность в том, что объекты Employee, которые вы создаете без ошибок, содержат ожидаемые данные, и вы можете доверять этим данным в дальнейшем в своем коде или в других приложениях.
BaseModel оснащена набором методов, которые позволяют легко создавать модели из других объектов, таких как словари и JSON. Например, если вы хотите создать объект Employee из словаря, вы можете использовать метод класса .model_validate():
Здесь мы создаем new_employee_dict, словарь с полями сотрудников, и передаем его в .model_validate() для создания экземпляра Employee. Под капотом Pydantic проверяет каждую запись словаря, чтобы убедиться, что она соответствует ожидаемым данным. Если какие-либо данные окажутся невалидными, Pydantic выдаст ошибку тем же способом, который вы видели ранее. Вы также получите уведомление, если в словаре отсутствуют какие-либо поля.
То же самое можно сделать с объектами JSON, используя .model_validate_json():
Работа с валидаторами
До этого момента мы использовали BaseModel Pydantic для валидации полей модели с предопределенными типами, а для дальнейшей настройки валидации включили Field.
И хотя даже на BaseModel и Field можно далеко продвинуться, для более сложных сценариев валидации, требующих пользовательской логики, вам понадобится использовать валидаторы Pydantic.
С помощью валидаторов можно выполнить практически любую логику проверки, которую можно выразить в функции. Далее вы увидите, как это сделать.
Валидация моделей и полей
Продолжим использовать пример с сотрудниками. Предположим, что ваша компания придерживается политики, согласно которой на работу принимаются сотрудники не моложе восемнадцати лет.
Каждый раз, когда вы создаете новый объект Employee, вам нужно убедиться, что сотрудник старше восемнадцати лет. Для этого можно добавить поле «age» и использовать класс Field, чтобы убедиться, что сотруднику не менее восемнадцати лет. Однако это кажется излишним, поскольку вы уже храните дату рождения сотрудника.
Лучшее решение — использовать валидатор полей Pydantic. Валидаторы полей позволяют применять пользовательскую логику проверки к полям BaseModel путем добавления методов класса в модель. Чтобы убедиться, что всем сотрудникам не меньше восемнадцати лет, вы можете добавить в модель Employee следующий валидатор поля:
В этом блоке мы импортируем field_validator и используем его для оформления метода класса в Employee под названием .check_valid_age(). Валидаторы полей должны быть определены как методы класса. В .check_valid_age() мы вычисляем сегодняшнюю дату, но восемнадцать лет назад. Если date_of_birth сотрудника окажется после этой даты, будет выдана ошибка.
Чтобы увидеть, как работает этот валидатор, посмотрите этот пример:
Здесь мы указываем birth_date на семнадцать лет раньше текущей даты. Когда вы вызываете .model_validate() для проверки данных young_employee_data, вы получаете ошибку, говорящую о том, что сотрудникам должно быть не менее восемнадцати лет.
Функция field_validator() в Pydantic позволяет произвольно настраивать валидацию полей. Однако field_validator() не подойдет, если вы хотите сравнить несколько полей друг с другом или проверить модель в целом. Для этого вам придется использовать валидаторы модели.
Заключение
Pydantic — это простая в использовании, быстрая и широко распространенная библиотека проверки данных на Python. В этой статье вы получили широкий обзор Pydantic, и теперь у вас есть знания и ресурсы, необходимые для того, чтобы начать использовать эту библиотеку в ваших собственных проектах.
Перевод статьи «Pydantic: Simplifying Data Validation in Python».