Source code for lb.registry
# Copyright 2017 The Lambda-blocks developers. See AUTHORS for details.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""
This module manages the blocks registry. It provides a decorator for
blocks to register themselves, and a Registry class to manage
registered blocks.
"""
import importlib
import inspect
import pkgutil
from lb.log import get_logger
import lb.blocks
from lb.exceptions import BlockError, UnfoundModuleError
logger = get_logger(__name__)
[docs]def block(**kwargs):
"""
Decorator to define a block, so it can get added to the registry.
Use it as follows:
@block(engine='foo', description='bar', my_other_metadata='foobar')
def my_block()...
"""
def block_decorator(func):
func._metadata = kwargs
func._is_block = True
return func
return block_decorator
[docs]class Registry(object):
"""
A registry contains a list of registered blocks, along with their
inferred properties, such as their parameters, metadata, inputs
and output.
"""
[docs] def __init__(self):
"""Inits a registry.
"""
self.blocks = {}
# keeps track of imported modules, to avoid double import
self.imported_modules = []
[docs] def add_module(self, module):
"""Adds all blocks of a module in the registry.
"""
if module not in self.imported_modules:
try:
mod = importlib.import_module(module)
except ImportError:
logger.error('Module {} could not be imported, it was '
'either not found or misses one or more dependency.'.format(module))
else:
for _, func in mod.__dict__.items():
if hasattr(func, '_is_block') and func._is_block:
self._register_block(func)
self.imported_modules.append(module)
[docs] def _register_block(self, func):
"""
Registers a Python function as a block. It must follow block
requirements.
"""
name = func.__name__
# gets the function factory parameters
if callable(func):
sig_outer = inspect.signature(func)
else:
raise BlockError('Malformed block: {}'.format(name))
# gets the inner function parameters
inner = func()
if callable(inner):
sig_inner = inspect.signature(inner)
else:
raise BlockError('Malformed block: {}'.format(name))
# registers the block
if name in self.blocks.keys():
raise BlockError('The registry saw a duplicated block name: {}. '
'It means a block has been defined twice, or the same name '
'has been used to define two blocks.'.format(name))
else:
self.blocks[name] = {
'_func': func,
'_parameters': sig_outer.parameters,
'_inputs': sig_inner.parameters,
'_output': sig_inner.return_annotation,
'_metadata': func._metadata,
}
[docs] def __getitem__(self, block_name):
"""
Returns the registered block block_name.
"""
return self.blocks[block_name]
[docs] def items(self):
"""
Iterates through the registered blocks.
Throw a list of tuples (block_name, block_properties).
"""
return self.blocks.items()
[docs] def keys(self):
"""
Returns the list of registered block names.
"""
return self.blocks.keys()