Add support of multiple scopes for providers.Scoped

This commit is contained in:
Roman Mogilatov 2015-03-15 01:18:59 +02:00
parent fa113af977
commit 7ab731eacc
2 changed files with 26 additions and 57 deletions

View File

@ -34,44 +34,13 @@ class Catalog(AbstractCatalog):
""":type: (objects.Provider) -> ObjectA""" """:type: (objects.Provider) -> ObjectA"""
# Making scope using `with` statement.
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
# Making another one scope using `with` statement.
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)
# Making one more scope using provider methods. # Making one more scope using provider methods.
Catalog.object_a.in_scope() Catalog.object_a.in_scope('request')
object_a5 = Catalog.object_a() object_a1 = Catalog.object_a()
object_a6 = Catalog.object_a() object_a2 = Catalog.object_a()
Catalog.object_a.out_of_scope() Catalog.object_a.out_of_scope('request')
assert object_a5 is object_a6 assert object_a1 is object_a2
assert object_a5.db is object_a6.db assert object_a1.db is object_a2.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)

View File

@ -134,7 +134,7 @@ class Singleton(NewInstance):
self.instance = None self.instance = None
class Scoped(Singleton): class Scoped(NewInstance):
"""Scoped provider. """Scoped provider.
@ -142,38 +142,38 @@ class Scoped(Singleton):
on every call. on every call.
""" """
__slots__ = ('is_in_scope',) __slots__ = ('current_scope', 'scopes_to_instances')
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
"""Initializer.""" """Initializer."""
self.is_in_scope = None self.current_scope = None
self.scopes_to_instances = dict()
super(Scoped, self).__init__(*args, **kwargs) super(Scoped, self).__init__(*args, **kwargs)
def in_scope(self): def in_scope(self, scope):
"""Set provider in "in scope" state.""" """Set provider in "in scope" state."""
self.is_in_scope = True self.current_scope = scope
self.reset()
def out_of_scope(self): def out_of_scope(self, scope):
"""Set provider in "out of scope" state.""" """Set provider in "out of scope" state."""
self.is_in_scope = False self.current_scope = None
self.reset() try:
del self.scopes_to_instances[scope]
except KeyError:
raise Error('Trying to move out of undefined scope '
'"{}"'.format(scope))
def __call__(self, *args, **kwargs): def __call__(self, *args, **kwargs):
"""Return provided instance.""" """Return provided instance."""
if not self.is_in_scope: if not self.current_scope:
raise Error('Trying to provide {} '.format(self.provides) + raise Error('Trying to provide {} '.format(self.provides) +
'while provider is not in scope') 'while provider is not in scope')
return super(Scoped, self).__call__(*args, **kwargs) try:
instance = self.scopes_to_instances[self.current_scope]
def __enter__(self): except KeyError:
"""Make provider to be in scope.""" instance = super(Scoped, self).__call__(*args, **kwargs)
self.in_scope() self.scopes_to_instances[self.current_scope] = instance
return self return instance
def __exit__(self, *_):
"""Make provider to be out of scope."""
self.out_of_scope()
class ExternalDependency(Provider): class ExternalDependency(Provider):