Pydantic: Fast and Pythonic Data Validation for Your Python Applications

Pydantic: Fast and Pythonic Data Validation for Your Python Applications

In any application, ensuring that the data you’re working with is valid and well-formed is a critical part of ensuring that the application runs smoothly and reliably. In Python, there are many libraries available for data validation, but one that stands out for its ease of use, performance, and Pythonic API is Pydantic.

In this blog post, we’ll explore Pydantic and its features, and some examples of how you can use Pydantic in your Python applications.

Overview

  • What is Pydantic?
  • Pydantic Features: Type Annotations, Data Validation, Parsing and Serialization, Model Configuration
  • Pydantic usage with flask.
  • Pydantic usage with FastAPI.

What is Pydantic?

Pydantic is a data validation library for Python that uses Python type annotations to validate and parse data.

Pydantic is designed to be fast, lightweight, and easy to use, and it’s specifically designed to work well with modern Python features like type hints, async and await syntax, and more. It provides the following major features:

  1. Type validation: Pydantic provides strong type validation for your Python data structures, ensuring that data is of the correct type before it is used. This helps to prevent bugs and errors in your code caused by unexpected data types.
  2. Easy integration with other Python libraries: Pydantic integrates easily with other popular Python libraries such as Flask, Django, FastAPI, and SQLAlchemy, making it easy to use in existing projects.
  3. Automatic data conversion: Pydantic automatically converts data to the correct type if possible, making it easy to work with data from different sources without worrying about data types.
  4. Schema generation: Pydantic can automatically generate JSON schemas for your Python data structures, making it easy to generate documentation for your APIs or other data-driven applications.
  5. Fast serialization and deserialization: Pydantic provides fast serialization and deserialization of Python objects, which is important for high-performance applications. It achieves this by using fast C code for serialization and deserialization.

Pydantic Features

Let’s explore some of the key features of Pydantic:

1. Type Annotations

Pydantic uses Python type annotations to specify the types of the data you want to validate. This makes it easy to use, as you don’t need to learn a new syntax or write complex configuration files.

from pydantic import BaseModel

class Person(BaseModel):
    name: str
    age: int

In this example, we define a Person class that inherits from BaseModel, and we specify the types of the name and age fields using Python type annotations.

2. Data Validation

Pydantic uses the type annotations to validate the data you’re working with, ensuring that it matches the expected types and values. This can help catch bugs early in development and prevent runtime errors caused by invalid data.

person = Person(name='Alice', age='30')  # raises a TypeError

In this example, we try to create a Person object with a string value for age, which is not a valid integer. Pydantic raises a TypeError to indicate that the data is invalid.

Custom Validation Example

from pydantic import BaseModel, validator

class Person(BaseModel):
    first_name: str
    last_name: str
    age: int

    @validator('age')
    def validate_age(cls, value):
        if value < 0 or value > 120:
            raise ValueError("Age must be between 0 and 120")
        return value

3. Parsing and Serialization

Pydantic can also be used to parse data from external sources, such as JSON or YAML files, and serialize data to those formats as well. This can help simplify the process of reading and writing data in your applications.

person_json = '{"name": "Alice", "age": 30}'
person = Person.parse_raw(person_json)

In this example, we use parse_raw() to parse a JSON string into a Person object.

4. Model Configurations

Pydantic also allows you to configure various aspects of your models, such as default values, aliases, and more. This can help customize the behavior of your models to better fit your specific use case.

class Person(BaseModel):
    name: str
    age: int = 18

    class Config:
            fields = {'name': 'full_name'}


# Notice how we are able to pass full_name attribute while creating
# person object 
person = Person(full_name='John Smith', age=25)

In this example, we define a Person class with a default value for age and an alias for the name field.

Usage with Flask

Pydantic can be used with your flask code to validate incoming requests and to serialize responses.

from flask import Flask, jsonify, request
from pydantic import BaseModel, ValidationError

app = Flask(__name__)

# Define a Pydantic model for incoming requests
class User(BaseModel):
    name: str
    email: str

# Define a Flask route that accepts a POST request with JSON data
@app.route('/users', methods=['POST'])
def create_user():
    try:
        # Parse the JSON data into a Pydantic model
        user = User.parse_raw(request.data)

        # Save the user to the database, etc.

        # Return a JSON response with the user data
        return jsonify(user.dict())

    except ValidationError as e:
        # If the JSON data doesn't match the Pydantic model, return a 400 Bad Request response
        return jsonify({'error': str(e)}), 400

if __name__ == '__main__':
    app.run(debug=True)

Usage with FastAPI

from fastapi import FastAPI
from pydantic import BaseModel

app = FastAPI()

# Define a Pydantic model for incoming requests
class User(BaseModel):
    name: str
    email: str

# Define a FastAPI route that accepts a POST request with JSON data
@app.post('/users')
def create_user(user: User):
    # Save the user to the database, etc.

    # Return a JSON response with the user data
    return user.dict()

if __name__ == '__main__':
    import uvicorn
    uvicorn.run(app, host='0.0.0.0', port=8000)

What Next?

There are multiple alternatives to pydantic. A major one is Python dataclasses. In future blogs, we’ll cover the difference between Pydantic and dataclasses!

Do checkout our interesting article getting your Python Configurations right everytime with Pydantic Settings: https://www.kubeblogs.com/python-configurations/