Skip to content

Instantly share code, notes, and snippets.

@alexanderankin
Created November 3, 2023 00:39
Show Gist options
  • Save alexanderankin/310c078250521d1b067ece78a0f132df to your computer and use it in GitHub Desktop.
Save alexanderankin/310c078250521d1b067ece78a0f132df to your computer and use it in GitHub Desktop.
# https://docs.pydantic.dev/latest/concepts/pydantic_settings/#adding-sources
from typing import Any
from pydantic.fields import FieldInfo, Field
from pydantic_settings import (
BaseSettings,
PydanticBaseSettingsSource, SettingsConfigDict,
)
class CustomSettingsSource(PydanticBaseSettingsSource):
"""demo of how to write a settings source"""
def get_field_value(self, field: FieldInfo, field_name: str) -> tuple[Any, str, bool]:
"""some fun variations"""
if field_name == 'empty':
return None, field_name, False
if field_name == 'complex':
return {'complex': True}, field_name, True
if field.json_schema_extra:
custom_field_param = field.json_schema_extra.get('custom_param', None)
if custom_field_param:
return f'{field_name};cfp={custom_field_param}', field_name, False
custom_param = self.settings_cls.model_config.get('custom_param', None)
if custom_param:
return f'{field_name}-{custom_param}', field_name, False
return f'{field_name}-value', field_name, False
def prepare_field_value(self, field_name: str, field: FieldInfo, value: Any, value_is_complex: bool) -> Any:
return value
def __call__(self, *args, **kwargs):
d = {}
for name, field in self.settings_cls.model_fields.items():
value, key, is_complex = self.get_field_value(field, name)
value = self.prepare_field_value(name, field, value, is_complex)
if value is not None:
d[key] = value
return d
class CustomSettings(BaseSettings):
"""demo of how wire that source up to a settings via base class"""
@classmethod
def settings_customise_sources(
cls,
settings_cls: type[BaseSettings],
*args: PydanticBaseSettingsSource,
**kwargs: PydanticBaseSettingsSource) -> \
tuple[PydanticBaseSettingsSource, ...]:
# create source
css: PydanticBaseSettingsSource = CustomSettingsSource(settings_cls)
# add it
return tuple([css] + list(args) + list(kwargs.values()))
if __name__ == '__main__':
import os
class ExampleBaseSettings(BaseSettings):
model_config = SettingsConfigDict()
foobar: str = Field(default='abc')
print(ExampleBaseSettings()) # foobar=abc
os.environ['FOOBAR'] = 'baz'
print(ExampleBaseSettings()) # foobar=baz
class ExampleSettings(CustomSettings):
model_config = SettingsConfigDict()
foobar: str = Field()
print(ExampleSettings()) # foobar=foobar-value
class ExampleSettingsWithParam(CustomSettings):
model_config = SettingsConfigDict(custom_param='apples')
foobar: str = Field()
print(ExampleSettingsWithParam()) # foobar=foobar-apples
class ExampleSettingsWithFieldParam(CustomSettings):
model_config = SettingsConfigDict()
foobar: str = Field(custom_param='field-param')
print(ExampleSettingsWithFieldParam()) # foobar='foobar;cfp=field-param'
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment