Skip to content

Broken wiring of sync inject-decorated methods #672

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

Closed
martlaf opened this issue Feb 28, 2023 · 6 comments · Fixed by #673
Closed

Broken wiring of sync inject-decorated methods #672

martlaf opened this issue Feb 28, 2023 · 6 comments · Fixed by #673

Comments

@martlaf
Copy link
Contributor

martlaf commented Feb 28, 2023

Hi,

following use case seems broken in versions >= 4.39.0:

from dependency_injector import containers, providers
from dependency_injector.wiring import inject, Provide


class Service:
    @staticmethod
    def run():
        print("hello world!")


class Container(containers.DeclarativeContainer):
    service = providers.Factory(Service)


class MyClass:
    @inject
    def __init__(self, service=Provide[Container.service]):
        service.run()


container = Container()
container.wire(modules=[MyClass])
MyClass()

Output in version 4.38.0:

hello world!

Output in versions >4.38.0

Traceback (most recent call last):
  File "C:\Users\myself\file.py", line 23, in <module>
    MyClass()
  File "src/dependency_injector/_cwiring.pyx", line 28, in dependency_injector._cwiring._get_sync_patched._patched
  File "C:\Users\myself\file.py", line 18, in __init__
    service.run()
AttributeError: 'Provide' object has no attribute 'run'

What seem to happen is that since the _get_sync_patched decorator has been moved to the cython part of the package, the signature of the @inject-decorated func/methods are now cython (type(MyClass.__init__) resolves to cython_function_or_method), therefore inspect.isfunction()/inspect.ismethod() resolve to False, and so those functions are never patched during container wiring.

Might be related to #589.

Finally, I have successfully tested here using the same patch that was applied in 4.39.1 for _get_async_patched coroutine that wasn't properly signed from cython coroutine, so creating the _get_sync_patched in wiring.py that calls _cwiring's _sync_inject, which effectively conserves behavior when running wiring.

@sgenya
Copy link

sgenya commented Apr 9, 2023

@rmk135 Would it be possible to release a fix for this bug in an upcoming release?

@yakimka
Copy link

yakimka commented Aug 28, 2023

Any updates?

@Astral1020
Copy link

Any updates? I have same issue, For now I just using dependency-injector==4.38.0

@tsdaemon
Copy link

I have a similar issue. Is there a workaround?

@ZipFile
Copy link
Contributor

ZipFile commented Feb 2, 2025

You're not supposed to pass into modules something other than list of module objects or import strings. In the example from OP post, if you do container.wire(modules=[__name__]) it will work as expected.

But either way, there are "clever" frameworks/libraries that use isfunction in a wild, so making functions decorated by @inject recognizable by isfunction will improve our interoperability.

@ZipFile
Copy link
Contributor

ZipFile commented Feb 25, 2025

Fixed in v4.46.0 (#673).

@ZipFile ZipFile closed this as completed Feb 25, 2025
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

Successfully merging a pull request may close this issue.

6 participants