`injector.Injector.create_object` on pydantic-settings `BaseSettings` does not without factory function in Injector
Guibod opened this issue · 4 comments
As stated in this closed bug at pydantic-settings
, i cannot achieve an initialization through injector
on python 3.8 and 3.9 (works ok on 3.10+) without a factory method.
The issue was turned down by the pydantic-settings
team.
The error message
TypeError: unsupported operand type(s) for |: 'type' and 'NoneType'
Why ?
Pydantic BaseSettings base class uses PEP-604 (str | None
) annotation instead of PEP-484 (Union
, Optional
).
It seems that Pydantic BaseSettings class don’t like to be initialized through cls.__new__(cls)
.
This works
class Configuration(Module):
def configure(self, binder: Binder):
binder.bind(BaseSettings, scope=SingletonScope, to=lambda: BaseSettings())
This does not
class Configuration(Module):
def configure(self, binder: Binder):
binder.bind(BaseSettings, scope=SingletonScope)
Reproduced issue
Thanks for reporting! Could you please post a stack trace or similar to aid anyone that would be willing to try to solve this?
As displayed through pytest, while running the attached project with the reproducable error:
Python 3.8
E TypeError: unsupported operand type(s) for |: 'type' and 'NoneType'
raised by:
.tox/py38/lib/python3.8/site-packages/injector/__init__.py:91: in wrapper
return function(*args, **kwargs)
.tox/py38/lib/python3.8/site-packages/injector/__init__.py:974: in get
provider_instance = scope_instance.get(interface, binding.provider)
.tox/py38/lib/python3.8/site-packages/injector/__init__.py:91: in wrapper
return function(*args, **kwargs)
.tox/py38/lib/python3.8/site-packages/injector/__init__.py:800: in get
instance = self._get_instance(key, provider, self.injector)
.tox/py38/lib/python3.8/site-packages/injector/__init__.py:811: in _get_instance
return provider.get(injector)
.tox/py38/lib/python3.8/site-packages/injector/__init__.py:264: in get
return injector.create_object(self._cls)
.tox/py38/lib/python3.8/site-packages/injector/__init__.py:1002: in create_object
reraise(e, CallError(instance, init_function, (), additional_kwargs, e, self._stack))
.tox/py38/lib/python3.8/site-packages/injector/__init__.py:190: in reraise
raise exception.with_traceback(tb)
.tox/py38/lib/python3.8/site-packages/injector/__init__.py:998: in create_object
self.call_with_injection(init, self_=instance, kwargs=additional_kwargs)
.tox/py38/lib/python3.8/site-packages/injector/__init__.py:1020: in call_with_injection
bindings = get_bindings(callable)
.tox/py38/lib/python3.8/site-packages/injector/__init__.py:1161: in get_bindings
type_hints = get_type_hints(callable, include_extras=True)
.tox/py38/lib/python3.8/site-packages/typing_extensions.py:1234: in get_type_hints
hint = typing.get_type_hints(obj, globalns=globalns, localns=localns)
/opt/homebrew/opt/python@3.8/Frameworks/Python.framework/Versions/3.8/lib/python3.8/typing.py:1264: in get_type_hints
value = _eval_type(value, globalns, localns)
/opt/homebrew/opt/python@3.8/Frameworks/Python.framework/Versions/3.8/lib/python3.8/typing.py:270: in _eval_type
return t._evaluate(globalns, localns)
/opt/homebrew/opt/python@3.8/Frameworks/Python.framework/Versions/3.8/lib/python3.8/typing.py:518: in _evaluate
eval(self.__forward_code__, globalns, localns),
Python 3.9
E TypeError: unsupported operand type(s) for |: 'type' and 'NoneType'
raised by
.tox/py39/lib/python3.9/site-packages/injector/__init__.py:91: in wrapper
return function(*args, **kwargs)
.tox/py39/lib/python3.9/site-packages/injector/__init__.py:974: in get
provider_instance = scope_instance.get(interface, binding.provider)
.tox/py39/lib/python3.9/site-packages/injector/__init__.py:91: in wrapper
return function(*args, **kwargs)
.tox/py39/lib/python3.9/site-packages/injector/__init__.py:800: in get
instance = self._get_instance(key, provider, self.injector)
.tox/py39/lib/python3.9/site-packages/injector/__init__.py:811: in _get_instance
return provider.get(injector)
.tox/py39/lib/python3.9/site-packages/injector/__init__.py:264: in get
return injector.create_object(self._cls)
.tox/py39/lib/python3.9/site-packages/injector/__init__.py:1002: in create_object
reraise(e, CallError(instance, init_function, (), additional_kwargs, e, self._stack))
.tox/py39/lib/python3.9/site-packages/injector/__init__.py:190: in reraise
raise exception.with_traceback(tb)
.tox/py39/lib/python3.9/site-packages/injector/__init__.py:998: in create_object
self.call_with_injection(init, self_=instance, kwargs=additional_kwargs)
.tox/py39/lib/python3.9/site-packages/injector/__init__.py:1020: in call_with_injection
bindings = get_bindings(callable)
.tox/py39/lib/python3.9/site-packages/injector/__init__.py:1161: in get_bindings
type_hints = get_type_hints(callable, include_extras=True)
/opt/homebrew/Cellar/python@3.9/3.9.19/Frameworks/Python.framework/Versions/3.9/lib/python3.9/typing.py:1497: in get_type_hints
value = _eval_type(value, globalns, localns)
/opt/homebrew/Cellar/python@3.9/3.9.19/Frameworks/Python.framework/Versions/3.9/lib/python3.9/typing.py:292: in _eval_type
return t._evaluate(globalns, localns, recursive_guard)
/opt/homebrew/Cellar/python@3.9/3.9.19/Frameworks/Python.framework/Versions/3.9/lib/python3.9/typing.py:554: in _evaluate
eval(self.__forward_code__, globalns, localns),
Hey @Guibod, sorry for your bad experience here.
From a quick look it looks like a pydantic-settings problem – using Python 3.10+ constructs on older Python versions – and I'm not sure trying to find a way to hack around that is the right thing to do.
At least the issue is documented, as well as a work-around. So you don’t have to be sorry about it.
It was discarded by pydantic-settings
team, so if you cannot achieve a solution on your own, i’m cool with it.
You can close or leave the ticket open. It’s your choice.