Dependency injection does not work as expected
lewoudar opened this issue · 4 comments
Hi everyone,
I was trying the Dependency injection system of Django Ninja Extra and I ran into some difficulties.
I have a project called injection
organized with the following modules:
injection
api.py
asgi.py
modules.py
service.py
settings.py
urls.py
wsgi.py
I define a service in service.py
from abc import ABC, abstractmethod
class IMathService(ABC):
@abstractmethod
def add(self, a: float, b: float) -> float:
pass
@abstractmethod
def subtract(self, a: float, b: float) -> float:
pass
class MathService(IMathService):
def subtract(self, a: float, b: float) -> float:
return a - b
def add(self, a: float, b: float) -> float:
return a + b
the modules.py
module looks like this
from injector import Module, Binder, singleton
from injection.service import MathService, IMathService
class MathModule(Module):
def configure(self, binder: Binder) -> None:
binder.bind(IMathService, to=MathService, scope=singleton)
The api.py
module has the following content
from ninja_extra import NinjaExtraAPI, api_controller, route
from .service import IMathService
api = NinjaExtraAPI(title='injector test')
@api_controller('/math')
class MathController:
def __init__(self, maths: IMathService):
self.maths = maths
@route.get('/add')
def add(self, a: float, b: float):
return {'result': self.maths.add(a, b)}
@route.get('/subtract')
def subtract(self, a: float, b: float):
return {'result': self.maths.subtract(a, b)}
api.register_controllers(MathController)
and in settings.py
module I had this
NinjaExtra = {
'INJECTOR_MODULES': [
'injection.modules.MathModule',
]
}
But when running a simple test using httpie like this: http :8000/api/v1/math/add?a=1&b=2
I have the following error:
Traceback (most recent call last):
File "C:\Users\rolla\PycharmProjects\learning\injection\venv\Lib\site-packages\injector\__init__.py", line 989, in create_object
instance = cls.__new__(cls)
^^^^^^^^^^^^^^^^
TypeError: Can't instantiate abstract class IMathService with abstract methods add, subtract
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "C:\Users\rolla\PycharmProjects\learning\injection\venv\Lib\site-packages\ninja_extra\operation.py", line 192, in run
result = self.view_func(request, **values)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "C:\Users\rolla\PycharmProjects\learning\injection\venv\Lib\site-packages\ninja_extra\controllers\route\route_functions.py", line 87, in as_view
with self._prep_controller_route_execution(context, **kwargs) as ctx:
File "C:\Users\rolla\AppData\Local\Programs\Python\Python311\Lib\contextlib.py", line 137, in __enter__
return next(self.gen)
^^^^^^^^^^^^^^
File "C:\Users\rolla\PycharmProjects\learning\injection\venv\Lib\site-packages\ninja_extra\controllers\route\route_functions.py", line 141, in _prep_controller_route_execution
controller_instance = self._get_controller_instance()
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "C:\Users\rolla\PycharmProjects\learning\injection\venv\Lib\site-packages\ninja_extra\controllers\route\route_functions.py", line 111, in _get_controller_instance
controller_instance: "ControllerBase" = injector.create_object(
^^^^^^^^^^^^^^^^^^^^^^^
File "C:\Users\rolla\PycharmProjects\learning\injection\venv\Lib\site-packages\injector\__init__.py", line 998, in create_object
self.call_with_injection(init, self_=instance, kwargs=additional_kwargs)
File "C:\Users\rolla\PycharmProjects\learning\injection\venv\Lib\site-packages\injector\__init__.py", line 1031, in call_with_injection
dependencies = self.args_to_inject(
^^^^^^^^^^^^^^^^^^^^
File "C:\Users\rolla\PycharmProjects\learning\injection\venv\Lib\site-packages\injector\__init__.py", line 91, in wrapper
return function(*args, **kwargs)
^^^^^^^^^^^^^^^^^^^^^^^^^
File "C:\Users\rolla\PycharmProjects\learning\injection\venv\Lib\site-packages\injector\__init__.py", line 1079, in args_to_inject
instance: Any = self.get(interface)
^^^^^^^^^^^^^^^^^^^
File "C:\Users\rolla\PycharmProjects\learning\injection\venv\Lib\site-packages\injector\__init__.py", line 91, in wrapper
return function(*args, **kwargs)
^^^^^^^^^^^^^^^^^^^^^^^^^
File "C:\Users\rolla\PycharmProjects\learning\injection\venv\Lib\site-packages\injector\__init__.py", line 975, in get
result = provider_instance.get(self)
^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "C:\Users\rolla\PycharmProjects\learning\injection\venv\Lib\site-packages\injector\__init__.py", line 264, in get
return injector.create_object(self._cls)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "C:\Users\rolla\PycharmProjects\learning\injection\venv\Lib\site-packages\injector\__init__.py", line 991, in create_object
reraise(
File "C:\Users\rolla\PycharmProjects\learning\injection\venv\Lib\site-packages\injector\__init__.py", line 190, in reraise
raise exception.with_traceback(tb)
File "C:\Users\rolla\PycharmProjects\learning\injection\venv\Lib\site-packages\injector\__init__.py", line 989, in create_object
instance = cls.__new__(cls)
^^^^^^^^^^^^^^^^
injector.CallError: Call to ABCMeta.__new__() failed: Can't instantiate abstract class IMathService with abstract methods add, subtract (injection stack: [<class 'abc.MathController'>])
However, it is worth noticing that if I install django-injector and configure it correctly in settings.py like this:
INJECTOR_MODULES = [
'injection.modules.MathModule',
]
It works as expected. The issue with django-injector is that it does not support ASGI :/
My environment:
- Django 4.2
- Django-ninja-extra 0.19.3
Hi @lewoudar. Instead of
NinjaExtra = {
'INJECTOR_MODULES': [
'injection.modules.MathModule',
]
}
you should write:
NINJA_EXTRA = {
'INJECTOR_MODULES': [
'injection.modules.MathModule',
]
}
The DependencyInjection tutorial is a little bit misleading in that regard. I will make a PR with the update
Hi @adriangs1996 , indeed, it works with this modification.
Thanks a lot :)
Thanks @adriangs1996 for responding to this
Seems like the PR was merged. So I think I can close this ticket :)