From 3bb4eea9c8b1dc6847b83359d1af8a3ca99f09b9 Mon Sep 17 00:00:00 2001 From: Arian Amiri Date: Sat, 17 Feb 2024 16:49:20 -0500 Subject: [PATCH] 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. --- setup.py | 4 +-- src/dependency_injector/providers.pyx | 52 ++++++++++++++++++--------- 2 files changed, 38 insertions(+), 18 deletions(-) diff --git a/setup.py b/setup.py index 3edd5c08..25c56b3a 100644 --- a/setup.py +++ b/setup.py @@ -75,8 +75,8 @@ setup(name="dependency-injector", "yaml": [ "pyyaml", ], - "pydantic": [ - "pydantic", + "pydantic-settings": [ + "pydantic-settings", ], "flask": [ "flask", diff --git a/src/dependency_injector/providers.pyx b/src/dependency_injector/providers.pyx index 8208ad63..508a82b8 100644 --- a/src/dependency_injector/providers.pyx +++ b/src/dependency_injector/providers.pyx @@ -48,6 +48,13 @@ try: except ImportError: yaml = None + +try: + import pydantic_settings +except ImportError: + pydantic_settings = None + + try: import pydantic except ImportError: @@ -61,6 +68,17 @@ from .errors import ( 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 CLASS_TYPES = (type,) else: # pragma: no cover @@ -1796,26 +1814,27 @@ cdef class ConfigurationOption(Provider): :rtype: None """ - if pydantic is None: + if pydantic_settings_pkg is None: raise Error( - "Unable to load pydantic configuration - pydantic is not installed. " - "Install pydantic or install Dependency Injector with pydantic extras: " - "\"pip install dependency-injector[pydantic]\"" + "Unable to load pydantic-settings configuration - pydantic-settings is not installed. " + "Install pydantic-settings or install Dependency Injector with pydantic-settings extras: " + "\"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( "Got settings class, but expect instance: " "instead \"{0}\" use \"{0}()\"".format(settings.__name__) ) - if not isinstance(settings, pydantic.BaseSettings): + if not isinstance(settings, pydantic_settings_pkg.BaseSettings): raise Error( - "Unable to recognize settings instance, expect \"pydantic.BaseSettings\", " + "Unable to recognize settings instance, expect \"pydantic_settings.BaseSettings\", " "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): """Load configuration from the dictionary. @@ -2365,26 +2384,27 @@ cdef class Configuration(Object): :rtype: None """ - if pydantic is None: + if pydantic_settings_pkg is None: raise Error( - "Unable to load pydantic configuration - pydantic is not installed. " - "Install pydantic or install Dependency Injector with pydantic extras: " - "\"pip install dependency-injector[pydantic]\"" + "Unable to load pydantic-settings configuration - pydantic-settings is not installed. " + "Install pydantic-settings or install Dependency Injector with pydantic-settings extras: " + "\"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( "Got settings class, but expect instance: " "instead \"{0}\" use \"{0}()\"".format(settings.__name__) ) - if not isinstance(settings, pydantic.BaseSettings): + if not isinstance(settings, pydantic_settings_pkg.BaseSettings): raise Error( - "Unable to recognize settings instance, expect \"pydantic.BaseSettings\", " + "Unable to recognize settings instance, expect \"pydantic_settings.BaseSettings\", " "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): """Load configuration from the dictionary.