summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDolph Mathews <dolph.mathews@gmail.com>2014-09-10 14:31:05 +0000
committerDolph Mathews <dolph.mathews@gmail.com>2014-09-10 14:31:05 +0000
commit5e432fc52860ce7789f646dcde52c4e9b1792cf2 (patch)
tree4dd30e1dca31ed6d72140a98cf08e0e7d53f7ffc
parent8a5913be1f602dc65193233551ff13ada3424e5d (diff)
downloadkeystone-5e432fc52860ce7789f646dcde52c4e9b1792cf2.tar.gz
improve dependency injection doc strings
This also renames the provider_name argument to better convey it's status as a kwarg for internal use only. Change-Id: Ie1afee4e37cfa149ddb73a001985c98aa90b97a5
-rw-r--r--keystone/common/dependency.py80
1 files changed, 45 insertions, 35 deletions
diff --git a/keystone/common/dependency.py b/keystone/common/dependency.py
index c29f727dd..d8808c20b 100644
--- a/keystone/common/dependency.py
+++ b/keystone/common/dependency.py
@@ -14,14 +14,15 @@
"""This module provides support for dependency injection.
-Providers are registered via the 'provider' decorator, and dependencies on them
-are registered with 'requires' or 'optional'. Providers are available to their
-consumers via an attribute. See the documentation for the individual functions
-for more detail.
+Providers are registered via the ``@provider()`` decorator, and dependencies on
+them are registered with ``@requires()`` or ``@optional()``. Providers are
+available to their consumers via an attribute. See the documentation for the
+individual functions for more detail.
See also:
https://en.wikipedia.org/wiki/Dependency_injection
+
"""
import six
@@ -38,8 +39,10 @@ _factories = {}
class UnresolvableDependencyException(Exception):
- """An UnresolvableDependencyException is raised when a required dependency
- is not resolvable; see 'resolve_future_dependencies'.
+ """Raised when a required dependency is not resolvable.
+
+ See ``resolve_future_dependencies()`` for more details.
+
"""
def __init__(self, name):
msg = 'Unregistered dependency: %s' % name
@@ -47,11 +50,11 @@ class UnresolvableDependencyException(Exception):
def provider(name):
- """'provider' is a class decorator used to register providers.
+ """A class decorator used to register providers.
- When 'provider' is used to decorate a class, members of that class will
- register themselves as providers for the named dependency. As an example,
- In the code fragment::
+ When ``@provider()`` is used to decorate a class, members of that class
+ will register themselves as providers for the named dependency. As an
+ example, In the code fragment::
@dependency.provider('foo_api')
class Foo:
@@ -62,10 +65,11 @@ def provider(name):
foo = Foo()
- The object 'foo' will be registered as a provider for 'foo_api'. No more
- than one such instance should be created; additional instances will replace
- the previous ones, possibly resulting in different instances being used by
- different consumers.
+ The object ``foo`` will be registered as a provider for ``foo_api``. No
+ more than one such instance should be created; additional instances will
+ replace the previous ones, possibly resulting in different instances being
+ used by different consumers.
+
"""
def wrapper(cls):
def wrapped(init):
@@ -107,7 +111,7 @@ def provider(name):
REGISTRY[name] = self
register_event_callbacks(self)
- resolve_future_dependencies(name)
+ resolve_future_dependencies(__provider_name=name)
return __wrapped_init__
@@ -136,11 +140,11 @@ def _process_dependencies(obj):
def requires(*dependencies):
- """'requires' is a class decorator used to inject providers into consumers.
+ """A class decorator used to inject providers into consumers.
The required providers will be made available to instances of the decorated
- class via an attribute with the same name as the provider. For example,
- in the code fragment::
+ class via an attribute with the same name as the provider. For example, in
+ the code fragment::
@dependency.requires('foo_api', 'bar_api')
class FooBarClient:
@@ -151,15 +155,17 @@ def requires(*dependencies):
client = FooBarClient()
- The object 'client' will have attributes named 'foo_api' and 'bar_api',
- which are instances of the named providers.
+ The object ``client`` will have attributes named ``foo_api`` and
+ ``bar_api``, which are instances of the named providers.
Objects must not rely on the existence of these attributes until after
- 'resolve_future_dependencies' has been called; they may not exist
+ ``resolve_future_dependencies()`` has been called; they may not exist
beforehand.
- Dependencies registered via 'required' must have providers - if not, an
- exception will be raised when 'resolve_future_dependencies' is called.
+ Dependencies registered via ``@required()`` must have providers; if not,
+ an ``UnresolvableDependencyException`` will be raised when
+ ``resolve_future_dependencies()`` is called.
+
"""
def wrapper(self, *args, **kwargs):
"""Inject each dependency from the registry."""
@@ -171,6 +177,7 @@ def requires(*dependencies):
The dependencies of the parent class are combined with that of the
child class to create a new set of dependencies.
+
"""
existing_dependencies = getattr(cls, '_dependencies', set())
cls._dependencies = existing_dependencies.union(dependencies)
@@ -183,8 +190,10 @@ def requires(*dependencies):
def optional(*dependencies):
- """'optional' is the same as 'requires', except that the dependencies are
- optional - if no provider is available, the attributes will be set to None.
+ """Similar to ``@requires()``, except that the dependencies are optional.
+
+ If no provider is available, the attributes will be set to ``None``.
+
"""
def wrapper(self, *args, **kwargs):
"""Inject each dependency from the registry."""
@@ -196,8 +205,8 @@ def optional(*dependencies):
The dependencies of the parent class are combined with that of the
child class to create a new set of dependencies.
- """
+ """
existing_optionals = getattr(cls, '_optionals', set())
cls._optionals = existing_optionals.union(dependencies)
if not hasattr(cls, '__wrapped_init__'):
@@ -208,8 +217,8 @@ def optional(*dependencies):
return wrapped
-def resolve_future_dependencies(provider_name=None):
- """'resolve_future_dependencies' forces injection of all dependencies.
+def resolve_future_dependencies(__provider_name=None):
+ """Forces injection of all dependencies.
Before this function is called, circular dependencies may not have been
injected. This function should be called only once, after all global
@@ -217,21 +226,22 @@ def resolve_future_dependencies(provider_name=None):
call, it must not have circular dependencies.
If any required dependencies are unresolvable, this function will raise an
- UnresolvableDependencyException.
+ ``UnresolvableDependencyException``.
Outside of this module, this function should be called with no arguments;
- the optional argument is used internally, and should be treated as an
- implementation detail.
+ the optional argument, ``__provider_name`` is used internally, and should
+ be treated as an implementation detail.
+
"""
new_providers = dict()
- if provider_name:
+ if __provider_name:
# A provider was registered, so take care of any objects depending on
# it.
- targets = _future_dependencies.pop(provider_name, [])
- targets.extend(_future_optionals.pop(provider_name, []))
+ targets = _future_dependencies.pop(__provider_name, [])
+ targets.extend(_future_optionals.pop(__provider_name, []))
for target in targets:
- setattr(target, provider_name, REGISTRY[provider_name])
+ setattr(target, __provider_name, REGISTRY[__provider_name])
return