> ## Documentation Index
> Fetch the complete documentation index at: https://docs.squarecloud.app/llms.txt
> Use this file to discover all available pages before exploring further.

# Validate Python Data with Pydantic

> Pydantic data validation in Python: BaseModel, dataclasses, strict mode, nested models, EmailStr and pydantic-settings to check environment variables at boot.

This guide covers data validation with pydantic, a Python library whose validation core (`pydantic-core`) is written in Rust. The examples use pydantic v2. You need Python and the pydantic library:

```bash theme={"system"}
pip install pydantic
```

## Creating a model

* First, we will need to import and make our class inherit from `pydantic.BaseModel` to start validating. In our example we will create a class named
  `Person` and it will have a name, an age and an e-mail.

```python theme={"system"}
from pydantic import BaseModel

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

* With this class, when we instantiate it, pydantic will validate that `name` and `email` are strings and `age` is an integer.

### Using the model

* Now that we have it created, we will instantiate the class. We will create a dict containing the data and unpack it into our class.

```python theme={"system"}
data = {
    "name": "John",
    "age": 19,
    "email": "john@example.com"
}
person = Person(**data)
```

* The above example will not raise any error since all **fields** have the correct type. By default, pydantic also converts compatible values: if `age` is the string `"19"`, it becomes the integer `19`. Now we will send wrong data to confirm that our validation works.

```python theme={"system"}
data = {
    "name": "John",
    "age": "nineteen",
    "email": "john@example.com"
}
person = Person(**data)
```

* The above example raises a `ValidationError` because `age` needs to be an **integer** and `"nineteen"` cannot be converted to one:

```text theme={"system"}
1 validation error for Person
age
  Input should be a valid integer, unable to parse string as an integer [type=int_parsing, input_value='nineteen', input_type=str]
```

* To handle the error instead of letting it stop your program, catch it with `try`/`except`. Its `errors()` method lists each invalid field:

```python theme={"system"}
from pydantic import ValidationError

try:
    Person(name="John", age="nineteen", email="john@example.com")
except ValidationError as error:
    for item in error.errors():
        print(item["loc"], item["msg"])
# ('age',) Input should be a valid integer, unable to parse string as an integer
```

### Strict mode

* If you want to reject strings like `"19"` too, enable strict mode in the model. Then `age` only accepts a real `int`, and `Person(name="John", age="19", email="john@example.com")` raises `ValidationError`.

```python theme={"system"}
from pydantic import BaseModel, ConfigDict

class Person(BaseModel):
    model_config = ConfigDict(strict=True)

    name: str
    age: int
    email: str
```

## Creating a dataclass

* You can also create **dataclasses** with pydantic. They are similar to standard Python **dataclasses**, but validate their fields like `BaseModel`.

```python theme={"system"}
from pydantic.dataclasses import dataclass

@dataclass
class Person:
    name: str
    age: int
    email: str
```

* If we send the string `"19"` to `age`, it will convert to the `int` `19`.

<Info>
  Pydantic supports recursive validation, meaning that when validating nested models, it also validates the internal
  models.

  If a class has a list of `Person`, `people: list[Person]`, pydantic checks each item of the list and converts it into a `Person`.
</Info>

## Extras

* Pydantic has some extras, like **e-mail** validation and a fallback **timezone** package. To install them, run the following commands:

```bash theme={"system"}
pip install "pydantic[email]"
```

```bash theme={"system"}
pip install "pydantic[timezone]"
```

* You can install both together by running the following command.

```bash theme={"system"}
pip install "pydantic[email,timezone]"
```

* `pydantic[email]` adds the `EmailStr` type, which validates the `user@domain.tld` format and normalizes the address.

```python theme={"system"}
from pydantic import EmailStr
from pydantic.dataclasses import dataclass

@dataclass
class Person:
    name: str
    age: int
    email: EmailStr
```

## Validating environment variables at boot

* Bots and APIs read tokens and settings from environment variables. With `pydantic-settings`, a missing or invalid variable stops the application at startup with a clear error, instead of failing later in the middle of a request.

```bash theme={"system"}
pip install pydantic-settings
```

* Declare the variables your application needs in a class that inherits from `BaseSettings`. Each field reads the environment variable with the same name, ignoring case: `discord_token` reads `DISCORD_TOKEN`.

```python settings.py theme={"system"}
from pydantic import SecretStr
from pydantic_settings import BaseSettings


class Settings(BaseSettings):
    discord_token: SecretStr  # required: the application doesn't start without it
    port: int = 80  # optional: 80 when PORT isn't set
    debug: bool = False


settings = Settings()
```

* If `DISCORD_TOKEN` isn't set, `Settings()` raises a `ValidationError` for `discord_token` with the message `Field required`. A value like `PORT=abc` fails the same way, because `port` must be an integer.
* `SecretStr` hides the token when you print or log the settings. Read the real value with `settings.discord_token.get_secret_value()`.

## Run it on Square Cloud

List pydantic and its extras in your `requirements.txt`, so Square Cloud installs them during the deploy:

```txt requirements.txt theme={"system"}
pydantic[email]
pydantic-settings
```

Create a `squarecloud.app` file at the root of your project. For a bot whose main file is `main.py` and imports `settings` from `settings.py`:

```systemd squarecloud.app theme={"system"}
DISPLAY_NAME=My Python Bot
MAIN=main.py
MEMORY=512
VERSION=recommended
AUTORESTART=true
```

Your ZIP holds your `.py` files, `requirements.txt` and `squarecloud.app`, without the token. Set `DISCORD_TOKEN` and the other variables in the dashboard or with `squarecloud app env set`: see [Environment variables](/en/platform/environment-variables). If a required variable is missing, the `ValidationError` shows up in the application's logs as soon as it starts.

## Next steps

<CardGroup cols={3}>
  <Card title="Environment variables" icon="key" href="/en/platform/environment-variables">
    Set the variables your settings class reads.
  </Card>

  <Card title="FastAPI" icon="python" href="/en/tutorials/api/fastapi">
    Deploy an API that validates its requests with pydantic.
  </Card>

  <Card title="Discord bot" icon="discord" href="/en/tutorials/bots/discord">
    Host a bot that reads its token from the environment.
  </Card>
</CardGroup>

## Did you like this article?

* We created this content with great care to offer the best help possible.
  If this article helped you in any way, support our work! Developers have already rated Square Cloud **4.9/5 across 402 reviews** on Google and Trustpilot: leave yours too! It helps us understand what matters most to you.

<CardGroup cols={2}>
  <Card title="Google Reviews" icon="google" href="https://g.page/r/CYZenpQcDgTzEAI/review">
    Leave your review in Google Reviews.
  </Card>

  <Card title="Trustpilot" icon="star" href="https://www.trustpilot.com/review/squarecloud.app">
    Leave your review in Trustpilot.
  </Card>
</CardGroup>


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.