Pydantic type syntax explanation

Viewed 711

In the code below from the official FastAPI tutorials page, I can't wrap my head around the the statements (e.g, name: str).

from typing import Optional

from fastapi import FastAPI
from pydantic import BaseModel


class Item(BaseModel):
    name: str
    description: Optional[str] = None
    price: float
    tax: Optional[float] = None


app = FastAPI()


@app.post("/items/")
async def create_item(item: Item):
    return item

I mean, I understand that they should enforce the type, but how exactly should they do that, as python does not enforce types.

  • I saw also the Pydantic manual, but have seen no explanation regarding this particular syntax (e.g, name: str) in the class declaration.

Could someone please explain this syntax for me, and how can you check for the meant type of a class when you create it in such a way?

Thanks in advance.

3 Answers

Python's typing behaviour

Typing is supported above Python 3.5: https://docs.python.org/3/library/typing.html. If your type hint is incorrect, your code will still run - as the documentation says: it is only a type hint. Python is still a dynamically typed language. You can use MyPy however, to catch these errors before runtime.

Pydantic's typing behaviour

Though it is also important to understand Pydantic's behaviour: if your type is not str, but a conversion is possible, it will convert to string first without any error messages. Otherwise, it will raise an error.

If you want to enforce raising an error without conversion, you should use Pydantic strict types: https://pydantic-docs.helpmanual.io/usage/types/#strict-types

But here is what Pydantic docs are telling you: "[...] annotation-only declaration tells pydantic that this field is required. Strings, bytes or floats will be coerced to ints if possible; otherwise an exception will be raised." (https://pydantic-docs.helpmanual.io/)

In Python 3.5 they introduced the type hints and it follows a specific syntax (see PEP-484 and PEP-3107).

It states that,

PEP 3107 introduced syntax for function annotations, but the semantics were deliberately left undefined. There has now been enough 3rd party usage for static type analysis that the community would benefit from a standard vocabulary and baseline tools within the standard library.

This means Python doesn't enforce the validation or static evaluation, but some 3rd party libraries will able to do that.


Coming to Pydatic's "validation enforcing technique", they wrote the logic in which how to evaluate the classes that inherit from the BaseModel

They've been calling the validators from the __init__(...) method itself and thus you will get the ValidationError exception if the input data doesn't meet the defined validation conditions.


In short, Pydatic's BaseModel is a normal Python class that takes the __init__(...) parameters and validate against the defined class variables.

The syntax “name: str” is a standard feature of Python from 3.6 upwards. It’s a type hint and doesn’t actually change the fundamental behaviour of Python underneath. The variable can have any value but this is a hint to remind you that you intended it to be a string. It also allows linters like mypy to flag that you are calling methods on this variable that do not exist on a str and therefore are likely to break at runtime. Finally it allows context sensitive editors to predict what methods are available because it has a hint of what type of variable this is which it normally wouldn’t in Python

Related