Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Pydantic: Save nested settings

I'm currently trying to automatically save a pydantic.BaseSettings-object to a json-file on change. The model is loaded out of the json-File beforehand. A minimal working example of the saving procedure is as follows:

import json
from pydantic import BaseModel, BaseSettings, root_validator
from typing import Any, Dict


class NestedSettings(BaseModel):
    test: str = 'foobar'


class Settings(BaseSettings):
    nested: NestedSettings = NestedSettings()
    foo: str = 'bar'

    @root_validator
    def save_settings(cls, values: Dict[str, Any]) -> Dict[str, Any]:
        print('SAVING!')

        def serialize_basemodel(model: BaseModel):
            if isinstance(model, BaseModel):
                return model.dict()
            else:
                raise TypeError(f'{type(model)} is not serializable!')

        with open('config.json', 'w', encoding='utf-8') as f:
            json.dump(values, f, ensure_ascii=False, indent=2,
                      default=serialize_basemodel)
        return values

    class Config:
        validate_assignment: bool = True


s = Settings()
print('Saving top level:')
s.foo = 'baz'
print('Saving bottom level:')
s.nested.test = 'bar'

The output generated is:

SAVING!
Saving top level:
SAVING!
Saving bottom level:

I'd like to let the object save even after assigning the bottom level s.nested.bar. Is there any way to achieve this?

Thanks in advance for any hints!

like image 389
H. Müller Avatar asked Oct 15 '25 04:10

H. Müller


1 Answers

My answer isn't elegant, but since the validate_assignment seems to only check the the root fields you can still take advantage of the of the action by changing

s.nested.test

to

s.nested = {'test': 'bar'}

and it will work. Here is the example code and output for better demonstration.

class Settings(BaseSettings):
    nested: NestedSettings = NestedSettings()
    foo: str = 'bar'

    @root_validator(pre=False)
    def save_settings(cls, values: Dict[str, Any]) -> Dict[str, Any]:
        print('SAVING!')
        print(values)
        def serialize_basemodel(model: BaseModel):
            if isinstance(model, BaseModel):
                return model.dict()
            else:
                raise TypeError(f'{type(model)} is not serializable!')

        with open('config.json', 'w', encoding='utf-8') as f:
            json.dump(values, f, ensure_ascii=False, indent=2,
                      default=serialize_basemodel)
        return values

    class Config:
        validate_assignment: bool = True


s = Settings()
print('Saving top level:')
s.foo = 'baz'
print('Saving bottom level:')
s.nested = {'test': 'bar'}
SAVING!
{'nested': NestedSettings(test='foobar'), 'foo': 'bar'}
Saving top level:
SAVING!
{'nested': NestedSettings(test='foobar'), 'foo': 'baz'}
Saving bottom level:
SAVING!
{'nested': NestedSettings(test='bar'), 'foo': 'baz'}
like image 163
Troy Sincomb Avatar answered Oct 17 '25 18:10

Troy Sincomb



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!