def test_inheritance(): foo = Resource("foo", __name__) bar = Resource("bar", __name__) parent = Container() class NoopImplementation(Implementation): @contextlib.contextmanager def reify(self, resource, provider): yield foo_impl1 = NoopImplementation() foo_impl2 = NoopImplementation() bar_impl = NoopImplementation() parent.provide(foo, foo_impl1) parent.provide(bar, bar_impl) child = Container(parent) child.provide(foo, foo_impl2) assert foo_impl1 == parent.find_implementation(foo) assert bar_impl == parent.find_implementation(bar) assert foo_impl2 == child.find_implementation(foo) assert bar_impl == child.find_implementation(bar)
def test_pool(): container = Container() count = 0 counter = Resource("counter", __name__) squared_counter = Resource("squared_counter", __name__) @counter.plain() def next_count(): nonlocal count count += 1 return count @squared_counter.plain(counter) def next_squred_counter(counter: int): return counter**2 with container.context() as context: assert 1 == context.resolve(counter) assert 1 == context.resolve(counter) assert 1 == context.resolve(counter) assert 1 == context.resolve(squared_counter) assert 1 == context.resolve(squared_counter) assert 1 == context.resolve(squared_counter) with container.context() as context: assert 2 == context.resolve(counter) assert 2 == context.resolve(counter) assert 2 == context.resolve(counter) assert 4 == context.resolve(squared_counter) assert 4 == context.resolve(squared_counter) assert 4 == context.resolve(squared_counter)
def test_drain_exception(): container = Container() foo = Resource("foo", __name__) bar = Resource("bar", __name__) # aliving flag for foo foo_alive = False @foo.contextual() @contextlib.contextmanager def get_foo(): nonlocal foo_alive foo_alive = True try: with pytest.raises(ZeroDivisionError): yield "foo" finally: foo_alive = False @bar.contextual(foo) @contextlib.contextmanager def get_bar(foo: str): try: yield "bar" finally: 1 / 0 with pytest.raises(ZeroDivisionError): with container.context() as context: assert "foo" == context.resolve(foo) assert "bar" == context.resolve(bar) assert foo_alive is True assert foo_alive is False
def test_contextual(): container = Container() foo = Resource("foo", __name__) bar = Resource("bar", __name__) @container.contextual(bar) @contextlib.contextmanager def with_bar(): yield "BAR" @container.contextual(foo, bar) @contextlib.contextmanager def with_foo(bar: str): yield f"FOO.{bar}" with container.context() as context: "BAR" == context.resolve(bar) "FOO" == context.resolve(foo) # and context managers should be left as context managers with with_foo("bar") as foo_value: assert "FOO.bar" == foo_value with with_bar() as bar_value: assert "BAR" == bar_value
def test_provide(): foo = Resource("foo", __name__) container = Container() class SimpleImplementation(Implementation): @contextlib.contextmanager def reify(self, resource, provider): pass impl = SimpleImplementation() with pytest.raises(ResourceNotProvidedError): container.find_implementation(foo) container.provide(foo, impl) assert impl == container.find_implementation(foo)
def test_default_implemenation(): container = Container() foo = Resource("foo", __name__) @foo.plain() def get_foo(): return "FOO" class SimpleImplementation(Implementation): @contextlib.contextmanager def reify(self, resource, provider): yield "FOO-2" assert foo.default_implementation == container.find_implementation(foo) impl = SimpleImplementation() container.provide(foo, impl) assert impl == container.find_implementation(foo)
def test_drain(): container = Container() refcount = 0 reference = Resource("reference", __name__) @reference.contextual() @contextlib.contextmanager def next_count(): nonlocal refcount refcount += 1 try: yield refcount finally: refcount -= 1 with container.context() as context: assert 1 == context.resolve(reference) assert 1 == refcount assert 0 == refcount
def test_child(): foo = Resource("foo", __name__) bar = Resource("bar", __name__) container = Container() foo_refs = 0 bar_refs = 0 @container.plain(foo) def get_foo(): nonlocal foo_refs foo_refs += 1 return f"foo-{foo_refs}" @container.plain(bar) def get_bar(): nonlocal bar_refs bar_refs += 1 return f"bar-{bar_refs}" with container.context(preload=[foo]) as parent: assert 1 == foo_refs assert "foo-1" == parent.resolve(foo) with parent.child() as child1: assert "foo-1" == child1.resolve(foo) assert "bar-1" == child1.resolve(bar) with parent.child(preload=[bar]) as child2: assert 2 == bar_refs assert "foo-1" == child2.resolve(foo) assert "bar-2" == child2.resolve(bar) assert 1 == foo_refs assert 2 == bar_refs
def test_plain(): container = Container() foo = Resource("foo", __name__) bar = Resource("bar", __name__) baz: Resource[Baz] = Resource("baz", __name__) @container.plain(bar) def get_bar(): return "BAR" @container.plain(foo, bar) def get_foo(bar: str): return f"FOO.{bar}" @container.plain(baz, foo, bar) class Baz(object): def __init__(self, foo, bar): super().__init__() self.foo = foo self.bar = bar with container.context() as context: # type: Context "BAR" == context.resolve(bar) "FOO" == context.resolve(foo) "FOO" == context.resolve(baz).foo "BAR" == context.resolve(baz).bar # and functions should be left as plain functions assert "FOO.bar" == get_foo("bar") assert "BAR" == get_bar() baz_instance = Baz("foo", "bar") assert isinstance(baz_instance, Baz) assert "foo" == baz_instance.foo assert "bar" == baz_instance.bar