diff --git a/.vscode/settings.json b/.vscode/settings.json index c3c03f7..276d25f 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -3,5 +3,8 @@ "python.analysis.typeCheckingMode": "standard", "python.testing.pytestArgs": ["tests"], "python.testing.unittestEnabled": false, - "python.testing.pytestEnabled": true + "python.testing.pytestEnabled": true, + "[python]": { + "editor.defaultFormatter": "charliermarsh.ruff" + } } diff --git a/src/uncoupled/container.py b/src/uncoupled/container.py index 7ee05a3..acb1d75 100644 --- a/src/uncoupled/container.py +++ b/src/uncoupled/container.py @@ -121,14 +121,9 @@ def get_concrete_instance[I]( def make_proxy_method(name: str): def proxy_method(self, *args: Any, **kwargs: Any) -> Any: - if concrete := object.__getattribute__(self, "_concrete"): - return getattr(concrete, name)(*args, **kwargs) - interface = object.__getattribute__(self, "_interface") resolver = object.__getattribute__(self, "_resolver") concrete = Container._get_instance().get_concrete_instance(interface, resolver) - - object.__setattr__(self, "_concrete", concrete) return getattr(concrete, name)(*args, **kwargs) return proxy_method @@ -139,8 +134,6 @@ def __init__(self, interface: type[I], resolver: Resolver | None = None) -> None self._interface = interface self._resolver = resolver - self._concrete: I | None = None - __call__ = make_proxy_method("__call__") __getattribute__ = make_proxy_method("__getattribute__") __repr__ = make_proxy_method("__repr__") diff --git a/src/uncoupled/providers/scoped.py b/src/uncoupled/providers/scoped.py index 8e28bb1..b6be2e1 100644 --- a/src/uncoupled/providers/scoped.py +++ b/src/uncoupled/providers/scoped.py @@ -52,8 +52,13 @@ def get[T](self, interface: type[T], resolver: Resolver[T] | None = None) -> T: def _get_scoped_instance[T](self, registered: Registered[T]) -> T: scoped = self._registered_to_scoped[registered] - if scoped.current_instance is None or scoped.current_scope != self._get_scope(): - scoped.current_scope = self._get_scope() + new_scope = self._get_scope() + if scoped.current_instance is None or scoped.current_scope != new_scope: + self._logger.debug( + f"Creating new instance of {registered.concrete.__name__} " + f"old scope was {scoped.current_scope}, new scope is {new_scope}" + ) + scoped.current_scope = new_scope scoped.current_instance = registered.concrete() return scoped.current_instance diff --git a/tests/test_depends_scoped.py b/tests/test_depends_scoped.py new file mode 100644 index 0000000..8ae7e5a --- /dev/null +++ b/tests/test_depends_scoped.py @@ -0,0 +1,36 @@ +from collections.abc import Generator +from typing import Protocol +from uuid import uuid4 +import pytest + +from uncoupled.container import Container, Depends + + +class Interface(Protocol): + def unique_id(self) -> str: ... + + +class Impl(Interface): + def __init__(self) -> None: + self._unique_id = str(uuid4()) + + def unique_id(self) -> str: + return self._unique_id + + +@pytest.fixture(autouse=True) +def init_container_scoped() -> Generator: + c = Container.create(get_scope=lambda: uuid4()) + c.add_scoped(Interface, Impl) + yield + Container._delete_instance() + + +def test_instance_recreated() -> None: + def get_instance(inst: Interface = Depends(Interface)) -> Interface: + return inst + + i1 = get_instance() + i2 = get_instance() + + assert i1.unique_id() != i2.unique_id()