python-dependency-injector: Injection not working for class methods
I am not quite sure if this is expected behavior or not. Methods annotated as @classmethod end up getting extra parameters injected. The following code demonstrates. I discovered this while using Closing, but filled out the example a bit as I discovered that it is a general issue for Provide.
import sys
from dependency_injector import containers, providers
from dependency_injector.wiring import Provide, Closing
def my_factory():
return 'test-factory'
def my_resource():
yield 'test-resource'
print('Closing')
class Container(containers.DeclarativeContainer):
factory = providers.Factory(my_factory)
resource = providers.Resource(my_resource)
def do_function_thing(r:str=Closing[Provide[Container.resource]]) -> None:
print('from function', r)
class MyClass():
def do_instance_thing(self, r:str=Closing[Provide[Container.resource]]) -> None:
print('from instance', r)
@classmethod
def do_class_thing(cls, r:str=Closing[Provide[Container.resource]]) -> None:
print('from class', r)
@classmethod
def non_closing_class_thing(cls, r:str=Provide[Container.factory]) -> None:
print('non-closing from class', r)
container = Container()
container.init_resources()
container.wire(modules=[sys.modules[__name__]])
do_function_thing()
c = MyClass()
c.do_instance_thing()
# both of these end up getting multiple values for r:
c.non_closing_class_thing()
c.do_class_thing()
The resulting output is:
from function test-resource
Closing
from instance test-resource
Closing
Traceback (most recent call last):
File "clstest.py", line 49, in <module>
c.non_closing_class_thing()
File "/Users/scott/repos/github.com/scott2b/Starlight/.venv/lib/python3.8/site-packages/dependency_injector/wiring.py", line 296, in _patched
result = fn(*args, **to_inject)
TypeError: non_closing_class_thing() got multiple values for argument 'r'
About this issue
- Original URL
- State: closed
- Created 4 years ago
- Comments: 19 (12 by maintainers)
Thank you @scott2b .
Yep, that’s kind of known thing that classmethod should be on the very top of decorators. What actually happens is that classmethod returns an object that is treated special way by the class. If it’s not on the top, the class recognizes it as usual method. What DI does is “undecorating” of the method to get the original, decorating the original with injecting decorator and then decorating it back as classmethod.
Hi @scott2b. Thanks, I’ll take a look.