from:Introduction to Pydantic - BUGBYTES

Pydantic is the most widely used data validation library for Python.

main.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
from pydantic import ValidationError
import requests

from models import Student

# print(
# json.dumps(Student.model_json_schema(), indent=2)
# ) # Print the JSON schema of the Student model

url = "https://raw.githubusercontent.com/bugbytes-io/datasets/master/students_v3.json"

response = requests.get(url)
data = response.json()

for student in data:
try:
model = Student(**student)
print(model.tags)
except ValidationError as e:
print(e)

# print(model)

# print(model.model_dump(exclude={"id", "modules"}))

# exclude = {
# "id": True,
# "modules": {"__all__": {"registration_code"}},
# } # Exclude id and registration_code of all modules
# print(model.model_dump_json(exclude=exclude))
models.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
from datetime import date, datetime, timedelta
from typing import Literal
from uuid import UUID
from pydantic import (
BaseModel,
Field,
field_validator,
model_validator,
)

from enums import DepartmentEnum


class Module(BaseModel):
id: UUID | int
name: str
professor: str
credits: Literal[10, 20]
registration_code: str


class Student(BaseModel):
id: UUID = Field(exclude=True)
name: str
date_of_birth: date = Field(default_factory=lambda: datetime.today().date())
# GPA: float
# GPA: confloat(ge=0.0, le=4.0)
GPA: float = Field(gt=0.0, lt=4.0)
course: str | None
department: DepartmentEnum
fees_paid: bool
# modules: list[Module] = []
modules: list[Module] = Field(default=[], max_items=10)

tags: list[str]

class Config:
use_enum_values = (
True # Store the enum's value in the model, instead of the enum instance
)
extra = "forbid" # Forbid extra fields that are not defined in the model
str_strip_whitespace = True # Strip whitespace from strings

@field_validator(
"tags", mode="before"
) # before standard validation tags: list[str]
def split_tags(cls, value):
# return [tag.strip() for tag in value.split(",")]
return value.split(",")

@field_validator("GPA")
def validate_gpa(cls, value, values):
# print(values) # The values dict contains all previously validated fields id, name, date_of_birth.
return value

@model_validator(mode="after") # after all fields are validated
def validate_gpa_and_fees(self):
if not (self.GPA >= 2 and self.fees_paid):
raise ValueError("Invalid GPA/fees combination!")
return self

@field_validator("modules")
def validate_module_length(cls, value):
if len(value) and len(value) != 3:
raise ValueError("List of modules should have length 3")
return value

@field_validator("date_of_birth")
def ensure_16_or_over(cls, value):
sixteen_years_ago = (datetime.now() - timedelta(days=16 * 365)).date()
if value > sixteen_years_ago:
raise ValueError("The age must be at least 16 years old.")
return value
enums.py
1
2
3
4
5
6
7
from enum import Enum


class DepartmentEnum(Enum):
ARTS_AND_HUMANITIES = "Arts and Humanities"
LIFE_SCIENCES = "Life Sciences"
SCIENCE_AND_ENGINEERING = "Science and Engineering"
student_v3.json
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
[
{
"id": "d15782d9-3d8f-4624-a88b-c8e836569df8",
"name": "Eric Travis",
"date_of_birth": "1995-05-25",
"GPA": "3.0",
"course": "Computer Science",
"department": "Science and Engineering",
"fees_paid": false,
"modules": [
{
"id": 1,
"name": "Data Science and Machine Learning",
"professor": "Prof. Susan Love",
"credits": 20,
"registration_code": "abc"
},
{
"id": "e96e86a6-c4e0-4441-af43-0c22cc472e18",
"name": "Web Development",
"professor": "Prof. James Herman",
"credits": 20,
"registration_code": "abc"
},
{
"id": 3,
"name": "Relational Databases and SQL",
"professor": "Prof. Samantha Curtis",
"credits": 10,
"registration_code": "abc"
}
],
"tags": "motivated, skilled, hard-working"
},
{
"id": "4c7b4c43-c863-4855-abc0-3657c078ce23",
"name": "Mark Smith",
"date_of_birth": "1996-02-10",
"GPA": "2.5",
"course": null,
"department": "Science and Engineering",
"fees_paid": true,
"tags": "slacker, lazy"
},
{
"id": "5cd9ad59-fcf1-462c-8863-282a9fb693e4",
"name": "Marissa Barker",
"date_of_birth": "1996-10-01",
"GPA": "3.5",
"course": "Biology",
"department": "Life Sciences",
"fees_paid": false,
"modules": [
{
"id": 55,
"name": "Genes, Molecules and Cells",
"professor": "Prof. Joseph Clark",
"credits": 20,
"registration_code": "abc"
},
{
"id": 66,
"name": "Animal Biology",
"professor": "Prof. Marilyn Gordon",
"credits": 20,
"registration_code": "abc"
},
{
"id": "8df954b5-bd3e-4316-8153-7d3d68fc0cef",
"name": "Sports Science",
"professor": "Prof. Nicole Johnson",
"credits": 10,
"registration_code": "abc"
}
],
"tags": "motivated, skilled, hard-working"
},
{
"id": "48dda775-785d-41e3-b0dd-26a4a2f7722f",
"name": "Justin Holden",
"date_of_birth": "1994-08-22",
"GPA": "3.23",
"course": "Philosophy",
"department": "Arts and Humanities",
"fees_paid": true,
"modules": [
{
"id": "f82d9771-1774-4c65-b290-592bb402d66a",
"name": "Externalism and Reference",
"professor": "Prof. Brian Sellers",
"credits": 20,
"registration_code": "abc"
},
{
"id": "86e9b8cd-b24c-4465-b3cd-7cf3ebd99e4e",
"name": "Formal Logic",
"professor": "Prof. Gregory Fisher",
"credits": 20,
"registration_code": "abc"
},
{
"id": "b762ddd2-2d99-47b0-b022-4c629e0d1f41",
"name": "Moral Philosophy",
"professor": "Prof. Michelle Wilson",
"credits": 10,
"registration_code": "abc"
}
],
"tags": "hipster, lazy, slacker"
},
{
"id": "7ffe2ceb-562b-4edd-b74c-3741e1b08453",
"name": "Michelle Thompson",
"date_of_birth": "1995-08-05",
"GPA": "3.9",
"course": "Film Studies",
"department": "Arts and Humanities",
"fees_paid": true,
"modules": [
{
"id": 101,
"name": "Japanese Cinema",
"professor": "Prof. Travis Hudson",
"credits": 20,
"registration_code": "abc"
},
{
"id": 102,
"name": "South Korean Cinema",
"professor": "Prof. Todd Black",
"credits": 20,
"registration_code": "abc"
},
{
"id": 103,
"name": "French New Wave Cinema",
"professor": "Prof. Bailey Stanley",
"credits": 10,
"registration_code": "abc"
}
],
"tags": "erudite, clever, motivated"
}
]
Edited on