2025, Oct 20 21:31
pydantic-settings में YAML पढ़ना: BaseSettings से YamlConfigSettingsSource तक
जानें क्यों सिर्फ yaml_file व yaml_config_section देने से pydantic-settings YAML नहीं पढ़ता, और settings_customise_sources व YamlConfigSettingsSource जोड़कर सही लोड करें.
pydantic-settings के साथ YAML से कॉन्फ़िगरेशन पढ़ना model_config में मौजूद yaml_file और yaml_config_section की वजह से देखने में बहुत आसान लगता है। लेकिन सिर्फ़ इन विकल्पों को सेट कर देने से BaseSettings YAML नहीं पढ़ता—अकसर यह गुम फ़ील्ड्स से जुड़ी ValidationError के रूप में सामने आता है। नीचे संक्षेप में बताया गया है कि ऐसा क्यों होता है और दस्तावेज़ित customization hook का इस्तेमाल करके YAML को ठीक तरह कैसे जोड़ा जाए।
समस्या को पुनः उत्पन्न करना
उद्देश्य है कि YAML के किसी सेक्शन से एक integer सेटिंग्स मॉडल में लोड हो। कोड में yaml_file और yaml_config_section दिए गए हैं, और एक फ़ील्ड है जिसे YAML से भरना अनिवार्य है।
from pathlib import Path
from pydantic_settings import BaseSettings, SettingsConfigDict
class AppConfig(BaseSettings):
    model_config = SettingsConfigDict(
        yaml_file=Path('cfg.yaml'),
        yaml_config_section='section',
    )
    svc_port: int
cfg = AppConfig()
और कोड के साथ रखा गया YAML फ़ाइल:
section:
  svc_port: 123
रन करते समय missing field की त्रुटि आती है। मूल मामले में संदेश कुछ यूं था:
pydantic_core._pydantic_core.ValidationError: 1 validation error for Settings
port
  Field required [type=missing, input_value={}, input_type=dict]
    For further information visit https://errors.pydantic.dev/2.11/v/missing
यह साफ़ दिखाता है कि YAML पढ़ा ही नहीं गया।
असल में हो क्या रहा है
yaml_file और yaml_config_section मौजूद तो हैं, पर अपने आप कुछ नहीं करते। YAML फ़ाइलों को सीधे पढ़ने पर Pydantic की कुछ पाबंदियों के कारण आपको settings sources को कस्टमाइज़ कर के YamlConfigSettingsSource को स्पष्ट रूप से जोड़ना पड़ता है — जैसा कि दस्तावेज़ में बताया गया है। तभी YAML से जुड़ी सेटिंग्स मायने रखती हैं। इस ओवरराइड के बिना BaseSettings YAML पढ़ने की कोशिश ही नहीं करेगा और आपके फ़ील्ड्स missing माने जाएंगे।
सेक्शन मॉडल के साथ काम करने वाला समाधान
एक व्यावहारिक तरीक़ा यह है कि YAML के सेक्शन को nested BaseModel के रूप में परिभाषित करें और customization hook के ज़रिए YamlConfigSettingsSource जोड़ दें।
from pydantic import BaseModel
from pydantic_settings import BaseSettings, YamlConfigSettingsSource
class SectionConfig(BaseModel):
    svc_port: int
class AppConfig(BaseSettings):
    section: SectionConfig
    @classmethod
    def settings_customise_sources(cls, settings_cls, **kwargs):
        return (YamlConfigSettingsSource(settings_cls, "cfg.yaml"),)
conf = AppConfig()
print(conf.section.svc_port)
यदि YAML ऐसा हो:
section:
  svc_port: 123
आउटपुट अपेक्षित रूप से 123 होगा।
विकल्प: YAML विकल्प model_config के ज़रिए देना
आप चाहें तो yaml_file और yaml_config_section को model_config में रख सकते हैं और YamlConfigSettingsSource बनाते समय फ़ाइलनाम न दें। ऐसे में स्रोत ये पैरामीटर model_config से अपने आप ले लेता है।
from pydantic_settings import BaseSettings, YamlConfigSettingsSource, SettingsConfigDict
class RootOptions(BaseSettings):
    svc_port: int
    model_config = SettingsConfigDict(
        yaml_file='cfg.yaml',
        yaml_config_section='section',
    )
    @classmethod
    def settings_customise_sources(cls, settings_cls, **kwargs):
        return (YamlConfigSettingsSource(settings_cls),)
opts = RootOptions()
print(opts.svc_port)
उसी YAML संरचना के साथ:
section:
  svc_port: 123
यह भी 123 ही प्रिंट करता है।
“extra” फ़ील्ड्स पर एक टिप्पणी
सिर्फ़ YAML सेक्शन से मान पढ़ने के लिए extra="allow" चालू करना ज़रूरी नहीं है। अगर कोई कुंजी “extra” के रूप में दिखे, तो आमतौर पर इसका मतलब है कि आपके मॉडल में उसका मिलान करता हुआ फ़ील्ड घोषित नहीं है। जब फ़ील्ड घोषित कर देते हैं, तो मान सही तरह मैप हो जाता है। इसका सेक्शन वाले पैरामीटर्स से कोई लेना-देना नहीं है।
यह क्यों मायने रखता है
सिर्फ़ yaml_file और yaml_config_section पर भरोसा करने से उलझन पैदा होती है, क्योंकि YAML पढ़ा ही नहीं जाता। समाधान है कि दस्तावेज़ में सुझाए मुताबिक settings_customise_sources के ज़रिए YamlConfigSettingsSource को स्पष्ट रूप से जोड़ें। यह छोटा लेकिन अहम कदम समझ लेने से समय बचता है और कॉन्फ़िगरेशन लोडिंग अनुमानित रहती है।
मुख्य बातें
यदि आप pydantic-settings के साथ YAML लोड करना चाहते हैं, तो पहले अपने फ़ील्ड्स घोषित करें, और फिर YAML को एक settings source के रूप में सक्षम करें। आप या तो फ़ाइलनाम सीधे YamlConfigSettingsSource को दे सकते हैं, या YAML से जुड़ी सभी सेटिंग्स model_config में रखकर स्रोत को वहीं से पढ़ने दें। अगर आपने YAML को सेक्शनों में बाँटा है, तो चाहें तो उस सेक्शन को nested BaseModel के रूप में मॉडल करें, या अपनी पसंद के अनुसार उन्हीं फ़ील्ड्स में सीधे पढ़ लें। सबसे अहम बात यह है कि YAML तभी पढ़ा जाएगा जब आप स्रोतों को इसी तरह कस्टमाइज़ करेंगे।