13 FastAPI, Pydantic

image.png լուսանկարի հղումը, Հեղինակ՝ Aram Ramazyan

Open In Colab (ToDo)

Song reference - ToDo

📌 Նկարագիր

📚 Ամբողջական նյութը

📺 Տեսանյութեր

🏡 Տնային

📚 Pydantic Tutorial

What is Pydantic?

Pydantic is a Python library that provides data validation and settings management using Python type annotations. It’s designed to make data validation simple, fast, and reliable.

Key Features:

  • Type Safety: Uses Python type hints for validation
  • Fast: Written in Rust (v2) for performance
  • Easy to Use: Intuitive API design
  • Comprehensive: Supports complex data structures
  • Integration: Works seamlessly with FastAPI

Why Use Pydantic?

  1. Data Validation: Automatically validates input data
  2. Type Conversion: Converts compatible types automatically
  3. Error Handling: Provides detailed error messages
  4. Documentation: Auto-generates JSON schemas
  5. IDE Support: Full type checking and autocomplete

Installation

pip install pydantic

For email validation and other extras:

pip install pydantic[email]

Reminder - dataclasses

!pip install pydantic
from typing import Optional
from pydantic import BaseModel

Basic Pydantic Models

A Pydantic model is a class that inherits from BaseModel. All attributes are defined with type annotations.

user_data = {
    "id": 1,
    "name": "Faylo Bobol",
    "email": "faylo@bolol.am",
    "age": 30, # optional
    # is_active default = True
}
# Basic Pydantic Model
class User(BaseModel):
    id: int
    name: str
    email: str
    age: Optional[int] = None
    is_active: bool = True


user = User(**user_data) # User(id=user_data["id"])

print(user)
print(f"User name: {user.name}")
print(f"User email: {user.email}")
id=1 name='Faylo Bobol' email='faylo@bolol.am' age=30 is_active=True
User name: Faylo Bobol
User email: faylo@bolol.am
# Convert to dictionary
print("\nAs dictionary:")
print(user.model_dump())

# Convert to JSON
print("\nAs JSON:")
print(user.model_dump_json(indent=4))

As dictionary:
{'id': 1, 'name': 'Faylo Bobol', 'email': 'faylo@bolol.am', 'age': 30, 'is_active': True}

As JSON:
{
    "id": 1,
    "name": "Faylo Bobol",
    "email": "faylo@bolol.am",
    "age": 30,
    "is_active": true
}
print(user.model_dump(include={"id", "name"}))
print(user.model_dump(exclude={"id", "name"}))
{'id': 1, 'name': 'Faylo Bobol'}
{'email': 'faylo@bolol.am', 'age': 30, 'is_active': True}

Data Validation

Pydantic automatically validates data types and provides helpful error messages.

# Type conversion - Pydantic tries to convert compatible types
print("=== Type Conversion ===")
user_flexible = User(id="123", 
                     name="Barxudarum", 
                     email="barxudarum@panir.com", 
                     age="25")

print(f"ID (converted from string): {user_flexible.id} (type: {type(user_flexible.id)})")
print(f"Age (converted from string): {user_flexible.age} (type: {type(user_flexible.age)})")
=== Type Conversion ===
ID (converted from string): 123 (type: <class 'int'>)
Age (converted from string): 25 (type: <class 'int'>)
invalid_user = User(id="not_a_number", name="Spiridon", email="tervigen@xunk.am")
---------------------------------------------------------------------------
ValidationError                           Traceback (most recent call last)
Cell In[42], line 1
----> 1 invalid_user = User(id="not_a_number", name="Spiridon", email="tervigen@xunk.am")

File c:\Users\hayk_\.conda\envs\sl\lib\site-packages\pydantic\main.py:253, in BaseModel.__init__(self, **data)
    251 # `__tracebackhide__` tells pytest and some other tools to omit this function from tracebacks
    252 __tracebackhide__ = True
--> 253 validated_self = self.__pydantic_validator__.validate_python(data, self_instance=self)
    254 if self is not validated_self:
    255     warnings.warn(
    256         'A custom validator is returning a value other than `self`.\n'
    257         "Returning anything other than `self` from a top level model validator isn't supported when validating via `__init__`.\n"
    258         'See the `model_validator` docs (https://docs.pydantic.dev/latest/concepts/validators/#model-validators) for more details.',
    259         stacklevel=2,
    260     )

ValidationError: 1 validation error for User
id
  Input should be a valid integer, unable to parse string as an integer [type=int_parsing, input_value='not_a_number', input_type=str]
    For further information visit https://errors.pydantic.dev/2.11/v/int_parsing
less_data = User(id=509, email="tervigen@xunk.am")
---------------------------------------------------------------------------
ValidationError                           Traceback (most recent call last)
Cell In[43], line 1
----> 1 less_data = User(id=509, email="tervigen@xunk.am")

File c:\Users\hayk_\.conda\envs\sl\lib\site-packages\pydantic\main.py:253, in BaseModel.__init__(self, **data)
    251 # `__tracebackhide__` tells pytest and some other tools to omit this function from tracebacks
    252 __tracebackhide__ = True
--> 253 validated_self = self.__pydantic_validator__.validate_python(data, self_instance=self)
    254 if self is not validated_self:
    255     warnings.warn(
    256         'A custom validator is returning a value other than `self`.\n'
    257         "Returning anything other than `self` from a top level model validator isn't supported when validating via `__init__`.\n"
    258         'See the `model_validator` docs (https://docs.pydantic.dev/latest/concepts/validators/#model-validators) for more details.',
    259         stacklevel=2,
    260     )

ValidationError: 1 validation error for User
name
  Field required [type=missing, input_value={'id': 509, 'email': 'tervigen@xunk.am'}, input_type=dict]
    For further information visit https://errors.pydantic.dev/2.11/v/missing

Field Constraints and Custom Validators

Pydantic provides Field constraints and custom validators for more sophisticated validation.

# Advanced model with Field constraints and custom validators
from pydantic import Field
from datetime import datetime

class AdvancedUser(BaseModel):
    id: int = Field(gt=0, description="User ID must be positive") # greater than
    username: str = Field(min_length=3, max_length=20, description="Username between 3-20 characters")
    email: str = Field(description="Valid email address")
    age: Optional[int] = Field(default=None, ge=0, le=100, description="Age between 0-100")
    password: str = Field(min_length=8, description="Password minimum 8 characters")
    confirm_password: str = Field(description="Password confirmation")
    full_name: str = Field(description="Full name")
    
    created_at: datetime = Field(default_factory=datetime.now)
advanced_user = AdvancedUser(
    id=1,
    username="Faylo509",
    email="panir@hamov.am",
    age=25,
    password="hndkahav",
    confirm_password="hndkahav",
    full_name="Faylo Bobolyan"
)
print("✅ User created successfully!")
print(advanced_user.model_dump(exclude={'password', 'confirm_password'}))
✅ User created successfully!
{'id': 1, 'username': 'Faylo509', 'email': 'panir@hamov.am', 'age': 25, 'full_name': 'Faylo Bobolyan', 'created_at': datetime.datetime(2025, 8, 13, 18, 25, 25, 638385)}
advanced_user = AdvancedUser(
    id=-3,
    username="Faylo509",
    email="panir@hamov.am",
    age=25,
    password="hndkahav",
    confirm_password="hndkahav",
    full_name="Faylo Bobolyan"
)
print("✅ User created successfully!")
print(advanced_user.model_dump(exclude={'password', 'confirm_password'}))
---------------------------------------------------------------------------
ValidationError                           Traceback (most recent call last)
Cell In[46], line 1
----> 1 advanced_user = AdvancedUser(
      2     id=-3,
      3     username="Faylo509",
      4     email="panir@hamov.am",
      5     age=25,
      6     password="hndkahav",
      7     confirm_password="hndkahav",
      8     full_name="Faylo Bobolyan"
      9 )
     10 print("✅ User created successfully!")
     11 print(advanced_user.model_dump(exclude={'password', 'confirm_password'}))

File c:\Users\hayk_\.conda\envs\sl\lib\site-packages\pydantic\main.py:253, in BaseModel.__init__(self, **data)
    251 # `__tracebackhide__` tells pytest and some other tools to omit this function from tracebacks
    252 __tracebackhide__ = True
--> 253 validated_self = self.__pydantic_validator__.validate_python(data, self_instance=self)
    254 if self is not validated_self:
    255     warnings.warn(
    256         'A custom validator is returning a value other than `self`.\n'
    257         "Returning anything other than `self` from a top level model validator isn't supported when validating via `__init__`.\n"
    258         'See the `model_validator` docs (https://docs.pydantic.dev/latest/concepts/validators/#model-validators) for more details.',
    259         stacklevel=2,
    260     )

ValidationError: 1 validation error for AdvancedUser
id
  Input should be greater than 0 [type=greater_than, input_value=-3, input_type=int]
    For further information visit https://errors.pydantic.dev/2.11/v/greater_than
from pydantic import ValidationError

try:
    advanced_user = AdvancedUser(
    id=-3,
    username="Faylo509",
    email="panir@hamov.am",
    age=123,
    password="hndk",
    confirm_password="hndkahav",
    full_name="Faylo Bobolyan"
)

except ValidationError as e:
    print("❌ Validation failed:")
    for error in e.errors():
        print(f"  {error['loc']}: {error['msg']}")
❌ Validation failed:
  ('id',): Input should be greater than 0
  ('age',): Input should be less than or equal to 100
  ('password',): String should have at least 8 characters

Custom validators

import re # regular expresstion
from pydantic import field_validator, model_validator


class AdvancedUser(BaseModel):
    id: int = Field(gt=0, description="User ID must be positive") # greater than
    username: str = Field(min_length=3, max_length=20, description="Username between 3-20 characters")
    email: str = Field(description="Valid email address")
    age: Optional[int] = Field(default=None, ge=0, le=100, description="Age between 0-100")
    password: str = Field(min_length=8, description="Password minimum 8 characters")
    confirm_password: str = Field(description="Password confirmation")
    full_name: str = Field(description="Full name")

    # https://stackoverflow.com/questions/76972389/fastapi-pydantic-how-to-validate-email
    @field_validator('email') 
    @classmethod
    def validate_email(cls, v):
        # Simple email validation
        pattern = r'^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$'
        if not re.match(pattern, v):
            raise ValueError('Invalid email format')
        return v
    
    @field_validator('username')
    @classmethod
    def validate_username(cls, v):
        if not v.isalnum():
            raise ValueError('Username must be alphanumeric')
        return v
    
    @field_validator('password')
    @classmethod
    def validate_password(cls, v):
        if not any(c.isupper() for c in v):
            raise ValueError('Password must contain at least one uppercase letter')
        if not any(c.islower() for c in v):
            raise ValueError('Password must contain at least one lowercase letter')
        if not any(c.isdigit() for c in v):
            raise ValueError('Password must contain at least one digit')
        return v

    # # Validate that passwords match, after setting the values
    @model_validator(mode='after')
    def validate_passwords_match(self):
        if self.password != self.confirm_password:
            raise ValueError('Passwords do not match')
        return self
try:
    advanced_user = AdvancedUser(
    id=3,
    username="Faylo509",
    email="panir@hamov.am",
    age=25,
    password="Sovorakan_hav509",
    confirm_password="hndkahav",
    full_name="Faylo Bobolyan"
)

except ValidationError as e:
    print("❌ Validation failed:")
    for error in e.errors():
        print(f"  {error['loc']}: {error['msg']}")
❌ Validation failed:
  (): Value error, Passwords do not match
try:
    advanced_user = AdvancedUser(
    id=3,
    username="Faylo509",
    email="panir@hamov.am",
    age=25,
    password="Sovorakan_hav509",
    confirm_password="hndkahav",
    full_name="Faylo Bobolyan"
)

except ValidationError as e:
    print("❌ Validation failed:")
    for error in e.errors():
        print(f"  {error['loc']}: {error['msg']}")
❌ Validation failed:
  (): Value error, Passwords do not match

Config

https://docs.pydantic.dev/latest/api/config/

class AdvancedUser(BaseModel):
    id: int = Field(gt=0, description="User ID must be positive") # greater than
    username: str = Field(min_length=3, max_length=20, description="Username between 3-20 characters")
    email: str = Field(description="Valid email address")
    age: Optional[int] = Field(default=None, ge=0, le=100, description="Age between 0-100")
    password: str = Field(min_length=8, description="Password minimum 8 characters")
    confirm_password: str = Field(description="Password confirmation")
    full_name: str = Field(description="Full name")

    class Config: # https://docs.pydantic.dev/latest/api/config/
        str_to_upper = True  
        # frozen = True      
advanced_user = AdvancedUser(
    id=3,
    username="Faylo509",
    email="panir@hamov.am",
    age=25,
    password="Sovorakan_hav509",
    confirm_password="hndkahav",
    full_name="Faylo Bobolyan"
)

print(advanced_user)

advanced_user.id = 10
print(advanced_user)
id=3 username='FAYLO509' email='PANIR@HAMOV.AM' age=25 password='SOVORAKAN_HAV509' confirm_password='HNDKAHAV' full_name='FAYLO BOBOLYAN'
id=10 username='FAYLO509' email='PANIR@HAMOV.AM' age=25 password='SOVORAKAN_HAV509' confirm_password='HNDKAHAV' full_name='FAYLO BOBOLYAN'

Json Schema

advanced_user.model_json_schema()
{'properties': {'id': {'description': 'User ID must be positive',
   'exclusiveMinimum': 0,
   'title': 'Id',
   'type': 'integer'},
  'username': {'description': 'Username between 3-20 characters',
   'maxLength': 20,
   'minLength': 3,
   'title': 'Username',
   'type': 'string'},
  'email': {'description': 'Valid email address',
   'title': 'Email',
   'type': 'string'},
  'age': {'anyOf': [{'maximum': 100, 'minimum': 0, 'type': 'integer'},
    {'type': 'null'}],
   'default': None,
   'description': 'Age between 0-100',
   'title': 'Age'},
  'password': {'description': 'Password minimum 8 characters',
   'minLength': 8,
   'title': 'Password',
   'type': 'string'},
  'confirm_password': {'description': 'Password confirmation',
   'title': 'Confirm Password',
   'type': 'string'},
  'full_name': {'description': 'Full name',
   'title': 'Full Name',
   'type': 'string'}},
 'required': ['id',
  'username',
  'email',
  'password',
  'confirm_password',
  'full_name'],
 'title': 'AdvancedUser',
 'type': 'object'}

Enum

An Enum (Enumeration) is a way to create a set of symbolic names bound to unique, constant values. It provides a structured way to define a collection of related constants.

geeksforgeeks

from enum import Enum

# Basic Enum example
class UserRole(str, Enum):
    ADMIN = "admin"
    USER = "user"
    MODERATOR = "moderator"

# Usage
role = UserRole.ADMIN
print(role)
print(f"Role: {role}")  # Role: admin
print(f"Role value: {role.value}")  # Role value: admin
print(f"Role name: {role.name}")  # Role name: ADMIN

# # You can iterate over enum values
print("\nAll roles:")
for role in UserRole:
    print(f"  {role.name}: {role.value}")
UserRole.ADMIN
Role: admin
Role value: admin
Role name: ADMIN

All roles:
  ADMIN: admin
  USER: user
  MODERATOR: moderator

Why enum?

  1. Type Safety and Validation
# Without Enum - prone to errors
def check_user_permission(role: str):
    if role == "admin":  # Typo risk: "admni", "Admin", etc.
        return "Full access"
    elif role == "user":
        return "Limited access"
    else:
        return "No access"

# With Enum - type safe
def check_user_permission_safe(role: UserRole):
    if role == UserRole.ADMIN:  # IDE autocomplete, no typos
        return "Full access"
    elif role == UserRole.USER:
        return "Limited access"
    else:
        return "No access"

# Demonstration
print("=== Type Safety Demo ===")
# print(f"{check_user_permission('admni') = }", "(Typo, but no error!)")
print(f"{check_user_permission_safe(UserRole.ADMIN) = }", "(Safe!)")
=== Type Safety Demo ===
check_user_permission_safe(UserRole.ADMIN) = 'Full access' (Safe!)
  1. Centralized Constants
class User(BaseModel):
    role: str 
    status: str 
    
user = User(role="admin", status="active")

# Bad: Magic strings scattered throughout code
if user.role == "admin":  # Magic string
    pass
if user.status == "active":  # Another magic string
    pass

# Good: Centralized in Enum
class UserStatus(str, Enum):
    ACTIVE = "active"
    INACTIVE = "inactive"
    SUSPENDED = "suspended"

if user.role == UserRole.ADMIN:  # Clear, centralized
    pass
if user.status == UserStatus.ACTIVE:  # Clear, centralized
    pass
  1. IDE Support and Autocomplete
# With Enum, your IDE provides:
# - Autocomplete for UserRole.
# - Error detection for invalid values
# - Refactoring support

role = UserRole.  # IDE shows: ADMIN, USER, MODERATOR

Enum vs typing.Literal

from typing import Literal

# Using Literal
def process_with_literal(status: Literal["pending", "approved", "rejected"]):
    return f"Processing {status}"

# Using Enum
class Status(str, Enum):
    PENDING = "pending"
    APPROVED = "approved"
    REJECTED = "rejected"

def process_with_enum(status: Status):
    return f"Processing {status.value}"
    
# 1. Runtime Validation
def test_literal(value: Literal["a", "b", "c"]):
    # No runtime validation - any string can be passed
    return value

def test_enum(value: Status):
    # Runtime validation when creating enum instance
    return value

print("=== Runtime Validation ===")
print(test_literal("invalid"))  # No error!

print(test_enum(Status("invalid")))  # Will raise ValueError
=== Runtime Validation ===
invalid
---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
Cell In[78], line 13
     10 print("=== Runtime Validation ===")
     11 print(test_literal("invalid"))  # No error!
---> 13 print(test_enum(Status("invalid")))  # Will raise ValueError

File c:\Users\hayk_\.conda\envs\sl\lib\enum.py:385, in EnumMeta.__call__(cls, value, names, module, qualname, type, start)
    360 """
    361 Either returns an existing member, or creates a new enum class.
    362 
   (...)
    382 `type`, if set, will be mixed in as the first base class.
    383 """
    384 if names is None:  # simple value lookup
--> 385     return cls.__new__(cls, value)
    386 # otherwise, functional API: we're creating a new Enum type
    387 return cls._create_(
    388         value,
    389         names,
   (...)
    393         start=start,
    394         )

File c:\Users\hayk_\.conda\envs\sl\lib\enum.py:710, in Enum.__new__(cls, value)
    708 ve_exc = ValueError("%r is not a valid %s" % (value, cls.__qualname__))
    709 if result is None and exc is None:
--> 710     raise ve_exc
    711 elif exc is None:
    712     exc = TypeError(
    713             'error in %s._missing_: returned %r instead of None or a valid member'
    714             % (cls.__name__, result)
    715             )

ValueError: 'invalid' is not a valid Status

# 2. Iteration and Introspection
print("\n=== Iteration ===")
# Literal - cannot iterate
# for item in Literal["a", "b", "c"]:  # Not possible

# Enum - can iterate
for status in Status:
    print(f"Status: {status.name} = {status.value}")

=== Iteration ===
Status: PENDING = pending
Status: APPROVED = approved
Status: REJECTED = rejected
# 3. Extensibility
class ExtendedStatus(str, Enum):
    PENDING = "pending"
    APPROVED = "approved"
    REJECTED = "rejected"
    
    def is_final(self) -> bool:
        """Check if status is final (approved or rejected)"""
        return self in (self.APPROVED, self.REJECTED)
    
    @classmethod
    def get_initial_status(cls):
        """Get the initial status for new items"""
        return cls.PENDING

status = ExtendedStatus.PENDING
print(f"=== Extended Methods ===")
print(f"Is {status.value} final? {status.is_final()}")
print(f"Initial status: {ExtendedStatus.get_initial_status().value}")

=== Extended Methods ===
Is pending final? False
Initial status: pending

Enums with Pydantic

from enum import Enum
from pydantic import BaseModel, ValidationError

class UserRole(str, Enum):
    ADMIN = "admin"
    USER = "user"
    MODERATOR = "moderator"

try:
    role = UserRole("panir")
except ValueError as e:
    print(f"❌ Error: {e}")

# Correct usage:
role = UserRole.MODERATOR
print(f"✅ Correct: {role}")
❌ Error: 'panir' is not a valid UserRole
✅ Correct: moderator
# Pydantic Model with Enum
class UserWithRole(BaseModel):
    id: int
    role: UserRole
    name: str

# Valid creation
user_with_role = UserWithRole(id=1, role="admin", name="Mavses") # hardcoded
print(f"\n=== Pydantic with Enum ===")
print(f"User: {user_with_role}")
print(f"Role type: {type(user_with_role.role)}")
print(f"Role value: {user_with_role.role.value}")

# # Pydantic automatically validates enum values
wrong_role = "panir"

try:
    invalid_user = UserWithRole(id=2, role=wrong_role, name="Goro")
except ValidationError as e:
    print(f"\n❌ Validation Error:")
    for error in e.errors():
        print(f"  {error['loc']}: {error['msg']}")

=== Pydantic with Enum ===
User: id=1 role=<UserRole.ADMIN: 'admin'> name='Mavses'
Role type: <enum 'UserRole'>
Role value: admin

❌ Validation Error:
  ('role',): Input should be 'admin', 'user' or 'moderator'

We can also make it so it exports the value instead of the enum object itself

class UserWithRole(BaseModel):
    id: int
    role: UserRole
    name: str

    # class Config:
    #     use_enum_values = True
        
user = UserWithRole(id=509, role=UserRole.USER, name="DVD Gugo")

user.role
<UserRole.USER: 'user'>

We can add methods to enums

# Complex example with multiple enums
class Priority(str, Enum):
    LOW = "low"
    MEDIUM = "medium"
    HIGH = "high"
    CRITICAL = "critical"
    
    def __lt__(self, other):
        """Enable priority comparison"""
        order = {"low": 1, "medium": 2, "high": 3, "critical": 4}
        return order[self.value] < order[other.value]

class TaskStatus(str, Enum):
    TODO = "todo"
    IN_PROGRESS = "in_progress"
    REVIEW = "review"
    DONE = "done"
    CANCELLED = "cancelled"
    
    def can_transition_to(self, new_status: 'TaskStatus') -> bool:
        """Define valid status transitions"""
        transitions = {
            self.TODO: [self.IN_PROGRESS, self.CANCELLED],
            self.IN_PROGRESS: [self.REVIEW, self.CANCELLED],
            self.REVIEW: [self.DONE, self.IN_PROGRESS],
            self.DONE: [],
            self.CANCELLED: [self.TODO]
        }
        return new_status in transitions.get(self, [])

class Task(BaseModel):
    id: int
    title: str
    priority: Priority
    status: TaskStatus = TaskStatus.TODO
    
    def update_status(self, new_status: TaskStatus) -> bool:
        """Update status with validation"""
        if self.status.can_transition_to(new_status):
            self.status = new_status
            return True
        return False

# Usage example
print("\n=== Advanced Enum Example ===")
task = Task(id=1, title="Fix bug", priority=Priority.HIGH)
print(f"Initial task: {task}")

=== Advanced Enum Example ===
Initial task: id=1 title='Fix bug' priority=<Priority.HIGH: 'high'> status=<TaskStatus.TODO: 'todo'>

# Valid transition
if task.update_status(TaskStatus.IN_PROGRESS):
    print(f"✅ Status updated: {task.status}")
else:
    print("❌ Invalid status transition")

# Invalid transition
if task.update_status(TaskStatus.DONE):
    print(f"✅ Status updated: {task.status}")
else:
    print("❌ Invalid transition from IN_PROGRESS to DONE (must go through REVIEW)")
✅ Status updated: in_progress
❌ Invalid transition from IN_PROGRESS to DONE (must go through REVIEW)
# Priority comparison
high_priority = Priority.HIGH
critical_priority = Priority.CRITICAL
print(f"\nPriority comparison:")
print(f"High < Critical: {high_priority < critical_priority}")

Priority comparison:
High < Critical: True

# JSON serialization
print(f"\nJSON output: {task.model_dump_json(indent=2)}")

JSON output: {
  "id": 1,
  "title": "Fix bug",
  "priority": "high",
  "status": "in_progress"
}

Complex Data Structures and Nested Models

Pydantic can handle complex nested structures, lists, and enums.

from enum import Enum
from typing import Optional
from datetime import datetime
from pydantic import BaseModel, Field

class UserRole(str, Enum):
    ADMIN = "admin"
    USER = "user"

class Status(str, Enum):
    ACTIVE = "active"
    INACTIVE = "inactive"

# Simplified nested models
class Address(BaseModel):
    street: str
    city: str
    postal_code: str = Field(pattern=r'^\d{5}$')  # 5-digit ZIP code


# Simplified complex user model
class ComplexUser(BaseModel):
    id: int
    role: UserRole
    status: Status = Status.ACTIVE
    address: Optional[Address] = None
    created_at: datetime = Field(default_factory=datetime.now)

# Example data
user_data = {
    "id": 1,
    "role": "admin",
    # no status -> default
    "address": {
        "street": "Padnijni Pskov",
        "city": "Hervashen",
        "postal_code": "0031"
    },
    
}

# Create complex user
user = ComplexUser(**user_data)
print("=== Complex User Created ===")
print(f"Role: {user.role}")
print(f"Address: {user.address.street}, {user.address.city}")


# JSON output
print("\n=== JSON Representation ===")
print(user.model_dump_json(indent=2, exclude={'created_at'}))
---------------------------------------------------------------------------
ValidationError                           Traceback (most recent call last)
Cell In[96], line 43
     30 user_data = {
     31     "id": 1,
     32     "role": "admin",
   (...)
     39     
     40 }
     42 # Create complex user
---> 43 user = ComplexUser(**user_data)
     44 print("=== Complex User Created ===")
     45 print(f"Role: {user.role}")

File c:\Users\hayk_\.conda\envs\sl\lib\site-packages\pydantic\main.py:253, in BaseModel.__init__(self, **data)
    251 # `__tracebackhide__` tells pytest and some other tools to omit this function from tracebacks
    252 __tracebackhide__ = True
--> 253 validated_self = self.__pydantic_validator__.validate_python(data, self_instance=self)
    254 if self is not validated_self:
    255     warnings.warn(
    256         'A custom validator is returning a value other than `self`.\n'
    257         "Returning anything other than `self` from a top level model validator isn't supported when validating via `__init__`.\n"
    258         'See the `model_validator` docs (https://docs.pydantic.dev/latest/concepts/validators/#model-validators) for more details.',
    259         stacklevel=2,
    260     )

ValidationError: 1 validation error for ComplexUser
address.postal_code
  String should match pattern '^\d{5}$' [type=string_pattern_mismatch, input_value='0031', input_type=str]
    For further information visit https://errors.pydantic.dev/2.11/v/string_pattern_mismatch
The Kernel crashed while executing code in the current cell or a previous cell. 

Please review the code in the cell(s) to identify a possible cause of the failure. 

Click <a href='https://aka.ms/vscodeJupyterKernelCrash'>here</a> for more info. 

View Jupyter <a href='command:jupyter.viewOutput'>log</a> for further details.

🎲 31 (13)

Flag Counter