Created
November 3, 2023 00:39
-
-
Save alexanderankin/310c078250521d1b067ece78a0f132df 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
# 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