From 1cdf393f56d3f535ece162728d31394bbe98fee5 Mon Sep 17 00:00:00 2001 From: Roman Mogilatov Date: Wed, 28 Jan 2015 00:21:31 +0200 Subject: [PATCH] adding scoped provider with examples --- examples/scoped_provider.py | 67 +++++++++++++++++++++++++++++++++++++ objects/providers.py | 54 ++++++++++++++++++++++++++++++ 2 files changed, 121 insertions(+) create mode 100644 examples/scoped_provider.py diff --git a/examples/scoped_provider.py b/examples/scoped_provider.py new file mode 100644 index 00000000..1a007bd0 --- /dev/null +++ b/examples/scoped_provider.py @@ -0,0 +1,67 @@ +""" +Scoped provider examples. +""" + +from objects import AbstractCatalog +from objects.providers import Singleton, Scoped +from objects.injections import InitArg, Attribute +import sqlite3 + + +class ObjectA(object): + def __init__(self, db): + self.db = db + + +# Catalog of objects providers. +class Catalog(AbstractCatalog): + """ + Objects catalog. + """ + + database = Singleton(sqlite3.Connection, + InitArg('database', ':memory:'), + Attribute('row_factory', sqlite3.Row)) + """ :type: (objects.Provider) -> sqlite3.Connection """ + + object_a = Scoped(ObjectA, + InitArg('db', database)) + """ :type: (objects.Provider) -> ObjectA """ + + +with Catalog.object_a as object_a_provider: + object_a1 = object_a_provider() + object_a2 = object_a_provider() + + assert object_a1 is object_a2 + assert object_a1.db is object_a2.db + +with Catalog.object_a as object_a_provider: + object_a3 = object_a_provider() + object_a4 = object_a_provider() + + assert object_a3 is object_a4 + assert object_a3.db is object_a4.db + + assert (object_a1 is not object_a3) and \ + (object_a1 is not object_a4) + assert (object_a2 is not object_a3) and \ + (object_a2 is not object_a4) + + +Catalog.object_a.in_scope() + +object_a5 = Catalog.object_a() +object_a6 = Catalog.object_a() + +assert object_a5 is object_a6 +assert object_a5.db is object_a6.db + +assert (object_a1 is not object_a3) and \ + (object_a1 is not object_a4) and \ + (object_a1 is not object_a5) and \ + (object_a1 is not object_a6) +assert (object_a2 is not object_a3) and \ + (object_a2 is not object_a4) and \ + (object_a2 is not object_a5) and \ + (object_a2 is not object_a6) diff --git a/objects/providers.py b/objects/providers.py index 2c5ef271..2d0fbdd1 100644 --- a/objects/providers.py +++ b/objects/providers.py @@ -108,6 +108,60 @@ class Singleton(NewInstance): self.instance = super(Singleton, self).__call__(*args, **kwargs) return self.instance + def _reset_instance(self): + """ + Resets instance. + """ + self.instance = None + + +class Scoped(Singleton): + """ + Scoped provider will create instance once for every scope and return it on every call. + """ + + def __init__(self, *args, **kwargs): + """ + Initializer. + """ + self.is_in_scope = None + super(Scoped, self).__init__(*args, **kwargs) + + def in_scope(self): + """ + Sets provider in "in scope" state. + """ + self.is_in_scope = True + self._reset_instance() + + def out_of_scope(self): + """ + Sets provider in "out of scope" state. + """ + self.is_in_scope = False + self._reset_instance() + + def __call__(self, *args, **kwargs): + """ + Returns provided instance. + """ + if not self.is_in_scope: + raise RuntimeError('Trying to provide {} while provider is not in scope'.format(self.provides)) + return super(Scoped, self).__call__(*args, **kwargs) + + def __enter__(self): + """ + With __enter__() implementation. Makes provider to be in scope. + """ + self.in_scope() + return self + + def __exit__(self, *_): + """ + With __exit__() implementation. Makes provider to be out of scope. + """ + self.out_of_scope() + class ExternalDependency(Provider): """