From daa0fe1f51d07a3560b56d6f0523bf4023b42e6d Mon Sep 17 00:00:00 2001 From: Brett Sun Date: Fri, 2 Dec 2016 17:29:14 +0100 Subject: [PATCH] Add utility decorator for registering backend dispatches based on modules --- bigchaindb/backend/util.py | 20 +++++++++++ tests/backend/test_util.py | 73 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 93 insertions(+) create mode 100644 bigchaindb/backend/util.py create mode 100644 tests/backend/test_util.py diff --git a/bigchaindb/backend/util.py b/bigchaindb/backend/util.py new file mode 100644 index 00000000..c30f7b53 --- /dev/null +++ b/bigchaindb/backend/util.py @@ -0,0 +1,20 @@ +class BackendModuleDispatchRegisterError(Exception): + """Raised when there is a problem registering dispatched functions for a + backend module""" + + +def make_module_dispatch_registrar(module): + def dispatch_wrapper(obj_type): + def wrapper(func): + func_name = func.__name__ + try: + dispatch_registrar = getattr(module, func_name) + return dispatch_registrar.register(obj_type)(func) + except AttributeError as ex: + raise BackendModuleDispatchRegisterError( + ("'{module}' does not contain a single-dispatchable " + "function named '{func}'. The backend being used has not " + "been implemented correctly!").format( + func=func_name, module=module.__name__)) from ex + return wrapper + return dispatch_wrapper diff --git a/tests/backend/test_util.py b/tests/backend/test_util.py new file mode 100644 index 00000000..ad3f7351 --- /dev/null +++ b/tests/backend/test_util.py @@ -0,0 +1,73 @@ +import pytest + +from types import ModuleType + + +@pytest.fixture +def mock_module(): + return ModuleType('mock_module') + + +def test_module_dispatch_registers(mock_module): + from functools import singledispatch + from bigchaindb.backend.utils import make_module_dispatch_registrar + + @singledispatch + def dispatcher(t): + pass + mock_module.dispatched = dispatcher + mock_dispatch = make_module_dispatch_registrar(mock_module) + + @mock_dispatch(str) + def dispatched(t): + pass + + assert mock_module.dispatched.registry[str] == dispatched + + +def test_module_dispatch_dispatches(mock_module): + from functools import singledispatch + from bigchaindb.backend.utils import make_module_dispatch_registrar + + @singledispatch + def dispatcher(t): + return False + mock_module.dispatched = dispatcher + mock_dispatch = make_module_dispatch_registrar(mock_module) + + @mock_dispatch(str) + def dispatched(t): + return True + + assert mock_module.dispatched(1) is False # Goes to dispatcher() + assert mock_module.dispatched('1') is True # Goes to dispatched() + + +def test_module_dispatch_errors_on_missing_func(mock_module): + from bigchaindb.backend.utils import ( + make_module_dispatch_registrar, + BackendModuleDispatchRegisterError, + ) + mock_dispatch = make_module_dispatch_registrar(mock_module) + + with pytest.raises(BackendModuleDispatchRegisterError): + @mock_dispatch(str) + def dispatched(): + pass + + +def test_module_dispatch_errors_on_non_dispatchable_func(mock_module): + from bigchaindb.backend.utils import ( + make_module_dispatch_registrar, + BackendModuleDispatchRegisterError, + ) + + def dispatcher(): + pass + mock_module.dispatched = dispatcher + mock_dispatch = make_module_dispatch_registrar(mock_module) + + with pytest.raises(BackendModuleDispatchRegisterError): + @mock_dispatch(str) + def dispatched(): + pass