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
Injection not working for class methods #318
Comments
Hi @scott2b. Thanks, I'll take a look. |
@scott2b , reproduced the issue. Working on a fix. PS: The funny thing. I had a test for |
@scott2b , fixed in |
Seems to be working. Thanks!!! |
So, FYI. I am not sure if Python dictates that @classmethod should be the final decorator on the method? The injection wiring breaks if it is not the final decorator and is stacked on top of other decorators .... but that may be a moot issue if @classmethod is supposed to be last anyway. This is not an issue for me, just thought you would want to be aware. Thanks again. |
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. |
Thank you @scott2b . |
@rmk135 Is there any workaround to make it work with decorated functions/methods? I'm trying to integrate it with yet another framework and wiring doesn't work if the method is decorated as:
The result is, service is not injected. |
Hey @LKay. What framework do you use? |
Im trying to use FastAPI. Tried to declare route using both decorator and |
Ok, got it. I didn't try FastAPI. I'll try to build a sample application with it. |
@rmk135 This is minmal, not working example: import sys
from dependency_injector import containers, providers
from dependency_injector.wiring import Provide
from fastapi import FastAPI
class Service:
def ok(self):
return 'OK'
class Container(containers.DeclarativeContainer):
service = providers.Factory(
Service
)
container = Container()
container.wire(modules=[sys.modules[__name__]])
app = FastAPI()
@app.get('/')
async def get_root(service = Provide[Container.service]):
return service.ok() |
Hey @LKay , I have just released version import sys
from dependency_injector import containers, providers
from dependency_injector.wiring import Provide
from fastapi import FastAPI
class Service:
def ok(self):
return 'OK'
class Container(containers.DeclarativeContainer):
service = providers.Factory(
Service
)
async def get_root(service = Provide[Container.service]):
return service.ok()
container = Container()
container.wire(modules=[sys.modules[__name__]])
app = FastAPI()
app.add_api_route('/', get_root) |
@rmk135 Thanks a lot for addressing this promptly! Is there any way to make it work with decorated functions as well on top of explicit |
@rmk135 There is also one bug with the above solution. If you explicitly specify the type of what was injected, the app will fail to boot app: async def get_root(service: Service = Provide[Container.service]):
return service.ok() will result in:
Also when async def get_root(service: Service = Depends(Provider[Container.service])):
return service.ok() results in error:
But according to docs https://python-dependency-injector.ets-labs.org/wiring.html#markers The |
Yes, but make sure you put from dependency_injector.wiring import inject, Provide
@app.api_route('/')
@inject
async def get_root(service = Provide[Container.service]):
return service.ok() |
I don't know how to fix it. That's something that FastAPI type checking system does. I'll think about kind of trick to make it work. |
I believe it's because you use The idea of using |
Hey @LKay , I've released a new version import sys
from dependency_injector import containers, providers
from dependency_injector.wiring import inject, Provide
from fastapi import FastAPI, Depends
class Service:
def ok(self):
return 'OK'
class Container(containers.DeclarativeContainer):
service = providers.Factory(
Service
)
app = FastAPI()
@app.get('/')
@inject
async def get_root(service: Service = Depends(Provide[Container.service]):
return service.ok()
container = Container()
container.wire(modules=[sys.modules[__name__]]) Using |
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.
The resulting output is:
The text was updated successfully, but these errors were encountered: