-
-
Notifications
You must be signed in to change notification settings - Fork 325
Fix annotated attribute injection #889
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
Merged
Merged
Changes from 14 commits
Commits
Show all changes
15 commits
Select commit
Hold shift + click to select a range
19600d9
Add example for Annotated attribute injection for module/class attrib…
rmk135 783b91b
Fix attribute injection with Annotated types
rmk135 770694b
Add unit tests for Annotated attribute and argument injection in wiring
rmk135 7048c35
Add .cursor to .gitignore
rmk135 4e77408
Style: add blank lines between class definitions and attributes in an…
rmk135 457b6de
Docs: clarify and format module/class attribute injection for classic…
rmk135 686fc92
Changelog: add note and discussion link for Annotated attribute injec…
rmk135 3e5dffe
Fix nls
rmk135 9622442
Fix CI checks and Python 3.8 tests
rmk135 c6d82b0
Fix PR issues
rmk135 08e2330
Fix Python 3.8 tests
rmk135 c2619cc
Fix flake8 issues
rmk135 164a45c
Fix: robust Annotated detection for wiring across Python versions
rmk135 2ab78f3
Refactor: extract annotation retrieval and improve typing for Python …
rmk135 5030387
Update src/dependency_injector/wiring.py
rmk135 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -73,3 +73,6 @@ src/**/*.html | |
.workspace/ | ||
|
||
.vscode/ | ||
|
||
# Cursor project files | ||
.cursor |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
"""Wiring attribute example with Annotated.""" | ||
|
||
from typing import Annotated | ||
|
||
from dependency_injector import containers, providers | ||
from dependency_injector.wiring import Provide | ||
|
||
|
||
class Service: | ||
... | ||
|
||
|
||
class Container(containers.DeclarativeContainer): | ||
|
||
service = providers.Factory(Service) | ||
|
||
|
||
service: Annotated[Service, Provide[Container.service]] | ||
|
||
|
||
class Main: | ||
|
||
service: Annotated[Service, Provide[Container.service]] | ||
|
||
|
||
if __name__ == "__main__": | ||
container = Container() | ||
container.wire(modules=[__name__]) | ||
|
||
assert isinstance(service, Service) | ||
assert isinstance(Main.service, Service) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,126 @@ | ||
"""Test module for wiring with Annotated.""" | ||
|
||
import sys | ||
import pytest | ||
|
||
if sys.version_info < (3, 9): | ||
pytest.skip("Annotated is only available in Python 3.9+", allow_module_level=True) | ||
|
||
from decimal import Decimal | ||
from typing import Callable, Annotated | ||
|
||
from dependency_injector import providers | ||
from dependency_injector.wiring import inject, Provide, Provider | ||
|
||
from .container import Container, SubContainer | ||
from .service import Service | ||
|
||
service: Annotated[Service, Provide[Container.service]] | ||
service_provider: Annotated[Callable[..., Service], Provider[Container.service]] | ||
undefined: Annotated[Callable, Provide[providers.Provider()]] | ||
|
||
class TestClass: | ||
service: Annotated[Service, Provide[Container.service]] | ||
service_provider: Annotated[Callable[..., Service], Provider[Container.service]] | ||
undefined: Annotated[Callable, Provide[providers.Provider()]] | ||
|
||
@inject | ||
def __init__(self, service: Annotated[Service, Provide[Container.service]]): | ||
self.service = service | ||
|
||
@inject | ||
def method(self, service: Annotated[Service, Provide[Container.service]]): | ||
return service | ||
|
||
@classmethod | ||
@inject | ||
def class_method(cls, service: Annotated[Service, Provide[Container.service]]): | ||
return service | ||
|
||
@staticmethod | ||
@inject | ||
def static_method(service: Annotated[Service, Provide[Container.service]]): | ||
return service | ||
|
||
@inject | ||
def test_function(service: Annotated[Service, Provide[Container.service]]): | ||
return service | ||
|
||
@inject | ||
def test_function_provider(service_provider: Annotated[Callable[..., Service], Provider[Container.service]]): | ||
service = service_provider() | ||
return service | ||
|
||
@inject | ||
def test_config_value( | ||
value_int: Annotated[int, Provide[Container.config.a.b.c.as_int()]], | ||
value_float: Annotated[float, Provide[Container.config.a.b.c.as_float()]], | ||
value_str: Annotated[str, Provide[Container.config.a.b.c.as_(str)]], | ||
value_decimal: Annotated[Decimal, Provide[Container.config.a.b.c.as_(Decimal)]], | ||
value_required: Annotated[str, Provide[Container.config.a.b.c.required()]], | ||
value_required_int: Annotated[int, Provide[Container.config.a.b.c.required().as_int()]], | ||
value_required_float: Annotated[float, Provide[Container.config.a.b.c.required().as_float()]], | ||
value_required_str: Annotated[str, Provide[Container.config.a.b.c.required().as_(str)]], | ||
value_required_decimal: Annotated[str, Provide[Container.config.a.b.c.required().as_(Decimal)]], | ||
): | ||
return ( | ||
value_int, | ||
value_float, | ||
value_str, | ||
value_decimal, | ||
value_required, | ||
value_required_int, | ||
value_required_float, | ||
value_required_str, | ||
value_required_decimal, | ||
) | ||
|
||
@inject | ||
def test_config_value_required_undefined( | ||
value_required: Annotated[int, Provide[Container.config.a.b.c.required()]], | ||
): | ||
return value_required | ||
|
||
@inject | ||
def test_provide_provider(service_provider: Annotated[Callable[..., Service], Provide[Container.service.provider]]): | ||
service = service_provider() | ||
return service | ||
|
||
@inject | ||
def test_provider_provider(service_provider: Annotated[Callable[..., Service], Provider[Container.service.provider]]): | ||
service = service_provider() | ||
return service | ||
|
||
@inject | ||
def test_provided_instance(some_value: Annotated[int, Provide[Container.service.provided.foo["bar"].call()]]): | ||
return some_value | ||
|
||
@inject | ||
def test_subcontainer_provider(some_value: Annotated[int, Provide[Container.sub.int_object]]): | ||
return some_value | ||
|
||
@inject | ||
def test_config_invariant(some_value: Annotated[int, Provide[Container.config.option[Container.config.switch]]]): | ||
return some_value | ||
|
||
@inject | ||
def test_provide_from_different_containers( | ||
service: Annotated[Service, Provide[Container.service]], | ||
some_value: Annotated[int, Provide[SubContainer.int_object]], | ||
): | ||
return service, some_value | ||
|
||
class ClassDecorator: | ||
def __init__(self, fn): | ||
self._fn = fn | ||
|
||
def __call__(self, *args, **kwargs): | ||
return self._fn(*args, **kwargs) | ||
|
||
@ClassDecorator | ||
@inject | ||
def test_class_decorator(service: Annotated[Service, Provide[Container.service]]): | ||
return service | ||
|
||
def test_container(container: Annotated[Container, Provide[Container]]): | ||
return container.service() |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.