Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

injector.Injector.create_object on pydantic-settings BaseSettings does not without factory function in Injector #253

Open
Guibod opened this issue Jun 4, 2024 · 4 comments

Comments

@Guibod
Copy link

Guibod commented Jun 4, 2024

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

https://github.com/Guibod/pydantic-settings-bug-298

@davidparsson
Copy link
Collaborator

Thanks for reporting! Could you please post a stack trace or similar to aid anyone that would be willing to try to solve this?

@Guibod
Copy link
Author

Guibod commented Jul 5, 2024

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/[email protected]/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/[email protected]/Frameworks/Python.framework/Versions/3.8/lib/python3.8/typing.py:270: in _eval_type
    return t._evaluate(globalns, localns)
/opt/homebrew/opt/[email protected]/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/[email protected]/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/[email protected]/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/[email protected]/3.9.19/Frameworks/Python.framework/Versions/3.9/lib/python3.9/typing.py:554: in _evaluate
    eval(self.__forward_code__, globalns, localns),

@jstasiak
Copy link
Collaborator

jstasiak commented Jul 7, 2024

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.

@Guibod
Copy link
Author

Guibod commented Jul 16, 2024

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants