Make injection and singleton scope thread safe

This commit is contained in:
Jakub Stasiak 2013-01-16 22:02:47 +00:00
parent 40fe997913
commit 9cd643964a
3 changed files with 63 additions and 0 deletions

View File

@ -410,6 +410,14 @@ class instance on the time of method call::
After such call all ``inject``-decorated methods will work just as you'd expect
them to work.
Thread safety
=============
The following functions are thread safe:
* ``Injector.get``
* injection provided by ``inject`` decorator (please note, however, that it doesn't say anything about decorated function thread safety)
Footnote
========
This framework is similar to snake-guice, but aims for simplification.

View File

@ -29,6 +29,17 @@ __author__ = 'Alec Thomas <alec@swapoff.org>'
__version__ = '0.5.2'
__version_tag__ = ''
def synchronized(lock):
def outside_wrapper(function):
@functools.wraps(function)
def wrapper(*args, **kwargs):
with lock:
return function(*args, **kwargs)
return wrapper
return outside_wrapper
lock = threading.RLock()
class Error(Exception):
"""Base exception."""
@ -353,6 +364,7 @@ class SingletonScope(Scope):
def configure(self):
self._context = {}
@synchronized(lock)
def get(self, key, provider):
try:
return self._context[key]
@ -493,6 +505,7 @@ class Injector(object):
"""
instance.__injector__ = self
@synchronized(lock)
def args_to_inject(self, function, bindings, owner_key):
"""Inject arguments into a function.

View File

@ -11,6 +11,7 @@
"""Functional tests for the Pollute dependency injection framework."""
from contextlib import contextmanager
from time import sleep
import abc
import threading
@ -664,3 +665,44 @@ def test_assisted_builder_works_when_injected():
injector = Injector()
x = injector.get(X)
assert ((x.obj.a, x.obj.b) == (str(), 234))
class TestThreadSafety(object):
def setup(self):
def configure(binder):
binder.bind(str, to=lambda: sleep(1) and 'this is str')
class XXX(object):
@inject(s=str)
def __init__(self, s):
pass
self.injector = Injector(configure)
self.cls = XXX
def gather_results(self, count):
objects = []
lock = threading.Lock()
def target():
o = self.injector.get(self.cls)
with lock:
objects.append(o)
threads = [threading.Thread(target=target) for i in range(2)]
for t in threads:
t.start()
for t in threads:
t.join()
return objects
def test_injection_is_thread_safe(self):
objects = self.gather_results(2)
assert (len(objects) == 2)
def test_singleton_scope_is_thread_safe(self):
self.injector.binder.bind(self.cls, scope=singleton)
a, b = self.gather_results(2)
assert (a is b)