Skip to content

Instantly share code, notes, and snippets.

@robbienohra
Last active December 12, 2025 14:51
Show Gist options
  • Select an option

  • Save robbienohra/f9378f595e545d201abef04e4a0b0409 to your computer and use it in GitHub Desktop.

Select an option

Save robbienohra/f9378f595e545d201abef04e4a0b0409 to your computer and use it in GitHub Desktop.
"""
Demonstration of field validator order dependency in Pydantic.
This script shows that field validators with mode='after' process fields
in definition order, meaning info.data only contains previously validated fields.
"""
from typing import Any
import pydantic
print('=' * 80)
print('DEMONSTRATION: Field Validator Order Dependency')
print('=' * 80)
class ProblematicSettings(pydantic.BaseModel):
# These fields are defined BEFORE secret_prefix
field_before_1: str = 'value1'
field_before_2: str = 'value2'
# The prefix field
secret_prefix: str = 'PREFIX'
# These fields are defined AFTER secret_prefix
field_after_1: str = 'value3'
field_after_2: str = 'value4'
@pydantic.field_validator('*', mode='after')
@classmethod
def track_validation_order(cls, value: Any, info: pydantic.ValidationInfo):
"""Track which fields are available in info.data during validation."""
if info.field_name == 'secret_prefix':
print(f"\n✓ Validating '{info.field_name}': {value}")
print(f' Available in info.data: {list(info.data.keys())}')
return value
# Try to get secret_prefix from info.data
prefix = info.data.get('secret_prefix', '<NOT AVAILABLE>')
print(f"\n✓ Validating '{info.field_name}': {value}")
print(f" secret_prefix from info.data: '{prefix}'")
print(f' Available fields in info.data: {list(info.data.keys())}')
# Simulate what would happen if we tried to use it
if prefix == '<NOT AVAILABLE>':
print(f" ⚠️ WARNING: secret_prefix not yet validated! Would use None or ''")
return value
print("\n\n1. Using field_validator with mode='after'")
print('-' * 80)
print('Creating instance with explicit values to trigger validators...')
problematic = ProblematicSettings(
field_before_1='value1',
field_before_2='value2',
secret_prefix='PREFIX',
field_after_1='value3',
field_after_2='value4',
)
# Now demonstrate the SOLUTION with model validators
print('\n\n' + '=' * 80)
class CorrectSettings(pydantic.BaseModel):
# Same field order as before
field_before_1: str = 'value1'
field_before_2: str = 'value2'
secret_prefix: str = 'PREFIX'
field_after_1: str = 'value3'
field_after_2: str = 'value4'
@pydantic.model_validator(mode='after')
def process_all_fields(self) -> 'CorrectSettings':
"""Model validator runs after ALL fields are validated."""
print(f'\n✓ Model validator running')
print(f" secret_prefix is ALWAYS available: '{self.secret_prefix}'")
print(f' All fields accessible: {list(self.__class__.model_fields.keys())}')
print(f' ✓ Can safely use secret_prefix for all fields regardless of order')
return self
print("2. Using model_validator with mode='after'")
print('-' * 80)
print('Creating instance with explicit values...')
correct = CorrectSettings(
field_before_1='value1',
field_before_2='value2',
secret_prefix='PREFIX',
field_after_1='value3',
field_after_2='value4',
)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment