Last active
December 12, 2025 14:51
-
-
Save robbienohra/f9378f595e545d201abef04e4a0b0409 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| """ | |
| 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