Getting Started¶
This page shows that how Autowire provides resource management and dependency injection.
Resource¶
Resource is a implementable resorce definition. It can have default implementation and also can have different implementation for each contexts.
Resource have two type of names. First is name, and second one is namespace name.
from autowire import Resource
basic = Resource('basic', __name__)
The first parameter is name, and second parameter is namespace.
Generally you can pass __name__ to second parameter.
Note
Since python uses dot (.) as module separator, name cannot have any dot characters.
The resource will make canonical name with two names
>>> basic.canonical_name
'some.module.name.basic'
You can set default implementation to resource by autowire.impl.implement()
import contextlib
from autowire import impl
@impl.implementation
@contextlib.contextmanager
def implementaion(resource, context):
print('Enter')
try:
yield 'Value'
finally:
print('Leave')
basic.implement(implementation)
The implementation should be an instance of Implementation
implementation() decorator converts contextmanager function
to instance of Implementation.
You can also create resource with implementation at once.
import contextlib
from autowire import resource
@resource.create
@impl.implementation
@contextlib.contextmanager
def basic(context):
print('Enter')
try:
yield('Value')
finally:
print('Leave')
The function basic will be a resource and also be a function.
Context¶
Context is a resource implementation container.
You can provide different context for each context, so that you can configure running environment, testing options, injecting mock-ups.
You can define context like this
from autowire import Context
context = Context()
Each contexts can have parent context.
child_context = Context(context)
The root parent of all contexts is root_context.
Providing Implementation to context¶
You can provide an implementation for the resource by using
provide() method.
@impl.implementation
@contextlib.contextmanager
def context_implementation(resource, context):
yield 'Custom Value'
child_context.provide(basic, context_implementation)
provide() also can be used as a decorator
@child_context.provide(basic)
@impl.implementation
@contextlib.contextmanager
def context_implementation(resource, context):
yield 'Custom Value'
Resolving Resource¶
Resources can have different implementations for each contexts. This is how to resolve implementation of them.
with context.resolve(basic) as value:
print(value)
with child_context.resolve(basic) as value:
print(value)
The output will be like this
Enter
Value
Leave
Custom Value
When there’s no implementaion to be provided, it will raise ResourceNotProvidedError
null = Resource('null', __name__)
with context.resolve(null) as value: # raise ResourceNotProvidedError
pass
Functional Interface¶
You don’t always need neither resource or context for your implementation. And also you don’t need any resource management for providing implementation.
There are some useful utilities for these use cases.
First one is contextual(). It converts simple context manager
function to implementation.
import contextlib
from autowire import impl
@res.implement
@impl.contexual
@contextlib.contextmanager
def res_impl():
value = build_resource()
try:
yield value
finally:
destroy_resource(value)
Second one is contextmanager(), which is a shortcut for above.
from autowire import impl
@res.implement
@impl.contextmanager
def res_impl():
value = build_resource()
try:
yield value
finally:
destroy_resource(value)
Last one is plain(). It converts plain function to implementation.
from autowire import impl
@res.implement
@impl.plain
def get_impl():
return "Implementation!"
All functional interface decorators preserve decorated function’s interface.
>>> get_impl()
"Implementation!"
Dependency Inejection¶
Basically, you can resolve some other resources from the context in impementations.
@impl.implementation
@contextlib.contextmanager
def some_implementation(resource, context):
with context.resolve(basic) as value:
yield 'Hello, {}'.format(value)
By the above code, we injected basic resource to implementation of other_resource.
This is clear, but little boilerplateful.
So we provide autowired() decorator to do this simply.
@other_resource.implement
@impl.autowired('basic', basic)
@impl.plain
def with_other_resource(basic)
reutnr 'Hello, {}'.format(basic)
First argument is a name that be used for keyword argument. Second one is resource to be resolved.
When the name is not provided, The name property of resource will be used by default.
autowired() decorator can be only used for functional interface implementations.