1
2 """
3 Dependency injection framework.
4
5 The framework provides lously coupled passing of dependencies from
6 providers to the objects that require them.
7
8 Dependencies are identified by keys, that are valid Python
9 identifiers. Dependencies are provided via accessor functions, that
10 in general will be called whenever they are needed.
11 """
12 __all__ = ('inject', 'depends', 'dependency')
13 from functools import wraps
14 from Util import union
18
21
22 - def __init__(self, parent = None, *a, **k):
25
27 self._key_registry.setdefault(key, []).append(injector)
28
30 self._key_registry[key].remove(injector)
31 if not self._key_registry[key]:
32 del self._key_registry[key]
33
34 - def get(self, key, default = None):
35 try:
36 return self._key_registry[key][-1].provides[key]
37 except KeyError:
38 return default
39
40
41 _global_injection_registry = InjectionRegistry()
49
52 """
53 Data descriptor that provides a given dependency looking as an
54 attribute. The depedency is specified as a keyword parameter,
55 whose value can be a default accessor or None. The attribute only
56 tries to fetch the dependency on deman when needed. Example::
57
58 class HttpServer(object):
59 connection_port = dependency(http_port = const(80))
60
61 server = HttpServer()
62 assert server.connection_port == 80
63 with inject(connection_port = const(8000)).everywhere():
64 assert server.connection_port == 8000
65 """
66
68 raise len(k) == 1 or AssertionError
69 self._dependency_name, self._dependency_default = k.items()[0]
70
71 - def __get__(self, obj, cls = None):
72 if obj is None:
73 obj = cls
74 return get_dependency_for(obj, self._dependency_name, self._dependency_default)
75
78 """
79 Decorates a method where dependencies are passed as keyword
80 parameters. Dependencies are specified as keywords with an
81 optional accessor function or None if required. Dependencies can
82 be injected or passed directly as keyword parameters. Example::
83
84 class HttpServer(object):
85 @depends(http_port = const(80))
86 def listen(http_port = None):
87 print "Listening on", http_port
88
89 server = HttpServer()
90 server.listen()
91 server.listen(http_port = 8000)
92 with inject(http_port = const(8000)).everywhere():
93 server.listen()
94
95 Produces the output::
96
97 Listening on port 80
98 Listening on port 8000
99 Listening on port 8000
100 """
101
102 def decorator(func):
103
104 @wraps(func)
105 def wrapper(self, *a, **explicit):
106 deps = dict([ (k, get_dependency_for(self, k, v)) for k, v in dependencies.iteritems() if k not in explicit ])
107 return func(self, *a, **union(deps, explicit))
108
109 return wrapper
110
111 return decorator
112
115
116 @property
119
122
125
129
132
135
136 - def __init__(self, provides = None, registry = None, *a, **k):
140
141 @property
143 return self._provides_dict
144
146 registry = self._registry
147 for k in self._provides_dict:
148 registry.register_key(k, self)
149
151 registry = self._registry
152 for k in self._provides_dict:
153 registry.unregister_key(k, self)
154
167
170 """
171 Inject returns a InjectorFactory that can generate Injectors to
172 inject the provided keys at different levels. The values to
173 inject are specified as keyword parameters mapping keys to given
174 nullary callables that will be used to access the dependency when
175 needed.
176 """
177 return InjectionFactory(k)
178