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"""
# 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.
Catalog.object_a.in_scope()
Catalog.object_a.in_scope('request')
object_a5 = Catalog.object_a()
object_a6 = Catalog.object_a()
object_a1 = 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_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)
assert object_a1 is object_a2
assert object_a1.db is object_a2.db

View File

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