Skip to content

Instantly share code, notes, and snippets.

@timcowlishaw
Created July 31, 2012 08:43
Show Gist options
  • Select an option

  • Save timcowlishaw/3215075 to your computer and use it in GitHub Desktop.

Select an option

Save timcowlishaw/3215075 to your computer and use it in GitHub Desktop.
Simple Dependency Injection in Python
class Container:
def __init__(self):
self.factories = {}
self.instances = {}
def add(self, feature, implementation):
if callable(implementation):
self.factories[feature] = implementation
else:
self.instances[feature] = implementation
def __getitem__(self,feature):
try:
instance = self.instances[feature]
except KeyError:
try:
instance = self.instances[feature] = self.factories[feature]()
except KeyError:
raise KeyError, "No implementation registered for feature '%s'" % feature
return instance
def depends(features, container):
def wrap(cls):
orig_init = cls.__init__
def new_init(self):
deps = [container[feature] for feature in features]
orig_init(self, *deps)
cls.__init__ = new_init
return cls;
return wrap
def provides(features, container):
def wrap(cls):
for feature in features:
container.add(feature, cls);
return cls;
return wrap
from unittest import TestCase
from mock import MagicMock, sentinel
from container import Container, depends, provides
class TestContainer(TestCase):
def test_it_exposes_callables_passed_in_as_a_factory(self):
container = Container()
instance = sentinel
callable = lambda : instance
container.add('callable', callable)
self.assertEqual(instance, container['callable'])
def test_it_exposes_non_callables_passed_in_as_singletons(self):
container = Container()
instance = sentinel
container.add("non-callable", instance)
self.assertEqual(instance, container['non-callable'])
def test_it_memoizes_created_instances_from_factories(self):
container = Container()
instance = sentinel
factory = MagicMock(return_value=instance)
container.add('factory', factory)
first = container['factory']
second = container['factory']
factory.assert_called_once
def test_it_raises_an_error_if_no_implementation_is_available(self):
container = Container()
with self.assertRaises(KeyError) as context:
container['non-existent']
self.assertEqual("No implementation registered for feature 'non-existent'", context.exception.message)
class TestProvides(TestCase):
def test_it_adds_decorated_class_to_container_as_a_factory(self):
container = Container()
@provides(features=['factory'], container=container)
class Factory:
def __init__(self):
pass
self.assertIsInstance(container['factory'], Factory)
class TestDepends(TestCase):
def test_it_constructs_decorated_class_with_implementations_of_dependencies_from_container(self):
container = Container()
instance = sentinel
container.add('dependency', sentinel)
receiver = MagicMock()
@depends(features=['dependency'], container=container)
class Dependency():
def __init__(self, dep):
receiver(dep)
created = Dependency()
receiver.assert_called_with(instance)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment