Hidden powers of pydantic

Photo by Jeremy Bishop on Unsplash
A snippet presenting a pydantic model and how to use it
An example of use of pydantic

Validation decorator

Pydantic provides a decorator validate_arguments which allows us to validate arguments passed to a function leveraging type annotations. The feature is still in beta but having using it in a recent project, I think the use is worth it. Let’s see with an example where we will compute the distance between two points after checking the points passed as input.

Example of validation without pydantic decorator — 1
  • This example will work fine starting with python3.7 where dataclasses appeared first.
  • Inside the function compute_distance, from line 12 to line 15 we check that the arguments given are really Point instances.
Example of validation with pydantic decorator — 1
  • The body of compute_distance is now simplified. We no longer have boilerplate code to check the arguments. Instead, we can focus on the main purpose of this function making it simpler and more readable :)
  • The only place to check for errors is where we use the function. We need to try/except pydantic ValidationError which is raised if an argument is invalid. Try to pass an invalid value and see how the error is displayed. Pydantic makes it easier to understand what is wrong with an intuitive error message.
  • A side effect of using the pydantic decorator is that it works just like the pydantic BaseModel, i.e it will try to convert given data if they don’t have the expected type. In concrete terms a tuple value like (1,2) or a dictionary like {‘x’: 3, ‘y’: 5} will not raise an error because they can be converted to a Point dataclass instance. You should be aware of that. 😉
Example of validation without pydantic decorator — 2
  • From line 6 to line 9, we check that arguments are int or float, the only valid types for our operation.
  • From line 14 to line 17, we check that values are correct.
  • The line 19 is where the operation is done and the value returned.
Example of validation with pydantic decorator — 2
  • Notice that in the definition of the function, we no longer use a Union annotation because pydantic will convert integers to float values.
  • We add metadata to arguments by assigning them the return of a special pydantic function named Field (yeah it is a function and not a class even if it starts with a capital letter). The first value the function takes, is a default value for the argument. In our case, we don’t want to assign a default value so we give the ellipsis value to tell pydantic that this argument is mandatory. For more information you can look this section of the official documentation.
  • We also specified in the field function that the value must be greater than 0 using the gt argument. A detail list of Field arguments is described on this page.
  • Look at the body of the function, only one line of code! This is really amazing, we save a lot of energy for the things that matter.💃🕺
  • Again we need to check for errors when using our function, in our case it happens from line 14 to line 17 where we try/except a pydantic ValidationError.
Example of validation with pydantic decorator — 3
  • Line 4, we import Annotated from pydantic. But if you are using python3.9+, you can directly import it from the typing standard library.
  • Lines 9 and 10, we no longer assigned a value for the arguments. Instead we use the Annotated type, passing the real type as its first argument, in our case float, and pydantic metadata to help for validation.
  • Note that in Field definition, we don’t the ellipsis value because we are no longer assigned the return value of the Field function, we just define a constraint for the minimum value allowed.

Pydantic dataclasses

Looking at our first example, more specifically the Point dataclass, what would you think will happen if you define an object like this: Point(‘foo’, 2)? The answer is that python will not complained at all because the dataclass decorator does not perform argument validation. What if we could bring the power of pydantic BaseModel into dataclasses?

Example of pydantic dataclass

Secret variables

This is a bonus section. Often when we log actions from our system (web application, cli, etc…) we don’t want to leak sensible information like passwords, credit cards, etc… Do you know that pydantic have some types made for it?

pydantic example of SecretStr class
pydantic example of PaymedCardNumber class

--

--

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store
Kevin Tewouda

Kevin Tewouda

69 Followers

Déserteur camerounais résidant désormais en France. Passionné de programmation, sport, de cinéma et mangas. J’écris en français et en anglais dû à mes origines.