Support pydantic 2 settings

In pydantic 2, the BaseSettings class was exported to a standalone package.

This change preserves support pydantic 1 while adding support pydantic 2. All error related to loading pydantic settings reflect the structure of pydantic 2.
This commit is contained in:
Arian Amiri 2024-02-17 16:49:20 -05:00
parent b058afc615
commit 3bb4eea9c8
2 changed files with 38 additions and 18 deletions

View File

@ -75,8 +75,8 @@ setup(name="dependency-injector",
"yaml": [ "yaml": [
"pyyaml", "pyyaml",
], ],
"pydantic": [ "pydantic-settings": [
"pydantic", "pydantic-settings",
], ],
"flask": [ "flask": [
"flask", "flask",

View File

@ -48,6 +48,13 @@ try:
except ImportError: except ImportError:
yaml = None yaml = None
try:
import pydantic_settings
except ImportError:
pydantic_settings = None
try: try:
import pydantic import pydantic
except ImportError: except ImportError:
@ -61,6 +68,17 @@ from .errors import (
cimport cython cimport cython
if pydantic_settings:
pydantic_settings_pkg = pydantic_settings
using_pydantic_2 = True
elif pydantic and pydantic.version.VERSION.startswith("1"):
pydantic_settings_pkg = pydantic.settings
using_pydantic_2 = False
else:
pydantic_settings_pkg = None
using_pydantic_2 = None
if sys.version_info[0] == 3: # pragma: no cover if sys.version_info[0] == 3: # pragma: no cover
CLASS_TYPES = (type,) CLASS_TYPES = (type,)
else: # pragma: no cover else: # pragma: no cover
@ -1796,26 +1814,27 @@ cdef class ConfigurationOption(Provider):
:rtype: None :rtype: None
""" """
if pydantic is None: if pydantic_settings_pkg is None:
raise Error( raise Error(
"Unable to load pydantic configuration - pydantic is not installed. " "Unable to load pydantic-settings configuration - pydantic-settings is not installed. "
"Install pydantic or install Dependency Injector with pydantic extras: " "Install pydantic-settings or install Dependency Injector with pydantic-settings extras: "
"\"pip install dependency-injector[pydantic]\"" "\"pip install dependency-injector[pydantic-settings]\""
) )
if isinstance(settings, CLASS_TYPES) and issubclass(settings, pydantic.BaseSettings): if isinstance(settings, CLASS_TYPES) and issubclass(settings, pydantic_settings_pkg.BaseSettings):
raise Error( raise Error(
"Got settings class, but expect instance: " "Got settings class, but expect instance: "
"instead \"{0}\" use \"{0}()\"".format(settings.__name__) "instead \"{0}\" use \"{0}()\"".format(settings.__name__)
) )
if not isinstance(settings, pydantic.BaseSettings): if not isinstance(settings, pydantic_settings_pkg.BaseSettings):
raise Error( raise Error(
"Unable to recognize settings instance, expect \"pydantic.BaseSettings\", " "Unable to recognize settings instance, expect \"pydantic_settings.BaseSettings\", "
"got {0} instead".format(settings) "got {0} instead".format(settings)
) )
self.from_dict(settings.dict(**kwargs), required=required) settings_dict = settings.model_dump(**kwargs) if using_pydantic_2 else settings.dict(**kwargs)
self.from_dict(settings_dict, required=required)
def from_dict(self, options, required=UNDEFINED): def from_dict(self, options, required=UNDEFINED):
"""Load configuration from the dictionary. """Load configuration from the dictionary.
@ -2365,26 +2384,27 @@ cdef class Configuration(Object):
:rtype: None :rtype: None
""" """
if pydantic is None: if pydantic_settings_pkg is None:
raise Error( raise Error(
"Unable to load pydantic configuration - pydantic is not installed. " "Unable to load pydantic-settings configuration - pydantic-settings is not installed. "
"Install pydantic or install Dependency Injector with pydantic extras: " "Install pydantic-settings or install Dependency Injector with pydantic-settings extras: "
"\"pip install dependency-injector[pydantic]\"" "\"pip install dependency-injector[pydantic-settings]\""
) )
if isinstance(settings, CLASS_TYPES) and issubclass(settings, pydantic.BaseSettings): if isinstance(settings, CLASS_TYPES) and issubclass(settings, pydantic_settings_pkg.BaseSettings):
raise Error( raise Error(
"Got settings class, but expect instance: " "Got settings class, but expect instance: "
"instead \"{0}\" use \"{0}()\"".format(settings.__name__) "instead \"{0}\" use \"{0}()\"".format(settings.__name__)
) )
if not isinstance(settings, pydantic.BaseSettings): if not isinstance(settings, pydantic_settings_pkg.BaseSettings):
raise Error( raise Error(
"Unable to recognize settings instance, expect \"pydantic.BaseSettings\", " "Unable to recognize settings instance, expect \"pydantic_settings.BaseSettings\", "
"got {0} instead".format(settings) "got {0} instead".format(settings)
) )
self.from_dict(settings.dict(**kwargs), required=required) settings_dict = settings.model_dump(**kwargs) if using_pydantic_2 else settings.dict(**kwargs)
self.from_dict(settings_dict, required=required)
def from_dict(self, options, required=UNDEFINED): def from_dict(self, options, required=UNDEFINED):
"""Load configuration from the dictionary. """Load configuration from the dictionary.