-
Notifications
You must be signed in to change notification settings - Fork 16
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* refactor tests * add attr getter for singleton * add __slots__ to providers * add docs on application settings
- Loading branch information
Showing
20 changed files
with
234 additions
and
79 deletions.
There are no files selected for viewing
This file contains 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 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,24 @@ | ||
# Application settings | ||
For example, you have application settings in `pydantic_settings` | ||
```python | ||
import pydantic_settings | ||
|
||
|
||
class Settings(pydantic_settings.BaseSettings): | ||
service_name: str = "FastAPI template" | ||
debug: bool = False | ||
... | ||
``` | ||
|
||
You can register settings as `Singleton` in DI container | ||
|
||
```python | ||
from that_depends import BaseContainer, providers | ||
|
||
|
||
class DIContainer(BaseContainer): | ||
settings: Settings = providers.Singleton(Settings).cast | ||
some_factory = providers.Factory(SomeFactory, service_name=settings.service_name) | ||
``` | ||
|
||
And when `some_factory` is resolved it will receive `service_name` attribute from `Settings` |
This file contains 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 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 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,48 @@ | ||
import typing | ||
|
||
import pytest | ||
|
||
from tests.container import create_async_resource, create_sync_resource | ||
from that_depends import BaseContainer, providers | ||
|
||
|
||
class DIContainer(BaseContainer): | ||
sync_resource = providers.Resource(create_sync_resource) | ||
async_resource = providers.AsyncResource(create_async_resource) | ||
sequence = providers.List(sync_resource, async_resource) | ||
mapping = providers.Dict(sync_resource=sync_resource, async_resource=async_resource) | ||
|
||
|
||
@pytest.fixture(autouse=True) | ||
async def _clear_di_container() -> typing.AsyncIterator[None]: | ||
try: | ||
yield | ||
finally: | ||
await DIContainer.tear_down() | ||
|
||
|
||
async def test_list_provider() -> None: | ||
sequence = await DIContainer.sequence() | ||
sync_resource = await DIContainer.sync_resource() | ||
async_resource = await DIContainer.async_resource() | ||
|
||
assert sequence == [sync_resource, async_resource] | ||
|
||
|
||
def test_list_failed_sync_resolve() -> None: | ||
with pytest.raises(RuntimeError, match="AsyncResource cannot be resolved synchronously"): | ||
DIContainer.sequence.sync_resolve() | ||
|
||
|
||
async def test_list_sync_resolve_after_init() -> None: | ||
await DIContainer.init_async_resources() | ||
DIContainer.sequence.sync_resolve() | ||
|
||
|
||
async def test_dict_provider() -> None: | ||
mapping = await DIContainer.mapping() | ||
sync_resource = await DIContainer.sync_resource() | ||
async_resource = await DIContainer.async_resource() | ||
|
||
assert mapping == {"sync_resource": sync_resource, "async_resource": async_resource} | ||
assert mapping == DIContainer.mapping.sync_resolve() |
This file was deleted.
Oops, something went wrong.
This file contains 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 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 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,62 @@ | ||
import datetime | ||
import logging | ||
import typing | ||
|
||
import pytest | ||
|
||
from tests.container import create_async_resource, create_sync_resource | ||
from that_depends import BaseContainer, providers | ||
|
||
|
||
logger = logging.getLogger(__name__) | ||
|
||
global_state_for_selector: typing.Literal["sync_resource", "async_resource", "missing"] = "sync_resource" | ||
|
||
|
||
class SelectorState: | ||
def __init__(self) -> None: | ||
self.selector_state: typing.Literal["sync_resource", "async_resource", "missing"] = "sync_resource" | ||
|
||
def get_selector_state(self) -> typing.Literal["sync_resource", "async_resource", "missing"]: | ||
return self.selector_state | ||
|
||
|
||
selector_state = SelectorState() | ||
|
||
|
||
class DIContainer(BaseContainer): | ||
sync_resource = providers.Resource(create_sync_resource) | ||
async_resource = providers.AsyncResource(create_async_resource) | ||
selector: providers.Selector[datetime.datetime] = providers.Selector( | ||
selector_state.get_selector_state, | ||
sync_resource=sync_resource, | ||
async_resource=async_resource, | ||
) | ||
|
||
|
||
async def test_selector_provider_async() -> None: | ||
selector_state.selector_state = "async_resource" | ||
selected = await DIContainer.selector() | ||
async_resource = await DIContainer.async_resource() | ||
|
||
assert selected == async_resource | ||
|
||
|
||
async def test_selector_provider_async_missing() -> None: | ||
selector_state.selector_state = "missing" | ||
with pytest.raises(RuntimeError, match="No provider matches"): | ||
await DIContainer.selector() | ||
|
||
|
||
async def test_selector_provider_sync() -> None: | ||
selector_state.selector_state = "sync_resource" | ||
selected = DIContainer.selector.sync_resolve() | ||
sync_resource = DIContainer.sync_resource.sync_resolve() | ||
|
||
assert selected == sync_resource | ||
|
||
|
||
async def test_selector_provider_sync_missing() -> None: | ||
selector_state.selector_state = "missing" | ||
with pytest.raises(RuntimeError, match="No provider matches"): | ||
DIContainer.selector.sync_resolve() |
This file was deleted.
Oops, something went wrong.
This file contains 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,41 @@ | ||
import dataclasses | ||
|
||
import pydantic | ||
|
||
from that_depends import BaseContainer, providers | ||
|
||
|
||
@dataclasses.dataclass(kw_only=True, slots=True) | ||
class SingletonFactory: | ||
dep1: str | ||
|
||
|
||
class Settings(pydantic.BaseModel): | ||
some_setting: str = "some_value" | ||
other_setting: str = "other_value" | ||
|
||
|
||
class DIContainer(BaseContainer): | ||
settings: Settings = providers.Singleton(Settings).cast | ||
singleton = providers.Singleton(SingletonFactory, dep1=settings.some_setting) | ||
|
||
|
||
async def test_singleton_provider() -> None: | ||
singleton1 = await DIContainer.singleton() | ||
singleton2 = await DIContainer.singleton() | ||
singleton3 = DIContainer.singleton.sync_resolve() | ||
await DIContainer.singleton.tear_down() | ||
singleton4 = DIContainer.singleton.sync_resolve() | ||
|
||
assert singleton1 is singleton2 is singleton3 | ||
assert singleton4 is not singleton1 | ||
|
||
await DIContainer.tear_down() | ||
|
||
|
||
async def test_singleton_attr_getter() -> None: | ||
singleton1 = await DIContainer.singleton() | ||
|
||
assert singleton1.dep1 == Settings().some_setting | ||
|
||
await DIContainer.tear_down() |
This file contains 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 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 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,21 @@ | ||
import typing | ||
|
||
from that_depends.providers.base import AbstractProvider | ||
|
||
|
||
T = typing.TypeVar("T") | ||
P = typing.ParamSpec("P") | ||
|
||
|
||
class AttrGetter(AbstractProvider[T]): | ||
__slots__ = "_provider", "_attr_name" | ||
|
||
def __init__(self, provider: AbstractProvider[T], attr_name: str) -> None: | ||
self._provider = provider | ||
self._attr_name = attr_name | ||
|
||
async def async_resolve(self) -> typing.Any: # noqa: ANN401 | ||
return getattr(await self._provider.async_resolve(), self._attr_name) | ||
|
||
def sync_resolve(self) -> typing.Any: # noqa: ANN401 | ||
return getattr(self._provider.sync_resolve(), self._attr_name) |
This file contains 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 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
Oops, something went wrong.