Passed
Push — mpeta ( ff9ea9...522f25 )
by Konstantinos
01:42
created

so_magic.data.command_factories   A

Complexity

Total Complexity 4

Size/Duplication

Total Lines 62
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
eloc 33
dl 0
loc 62
rs 10
c 0
b 0
f 0
wmc 4

3 Methods

Rating   Name   Duplication   Size   Complexity  
A DataManagerCommandFactory.__call__() 0 4 1
A DataManagerCommandFactoryBuilder.create_factory() 0 9 1
A DataManagerCommandFactory.build_command_prototype() 0 15 2
1
from abc import ABC
2
import attr
3
from typing import Callable
4
from so_magic.utils import Command, Subject
5
from .command_factory_interface import CommandFactoryInterface, CommandFactoryType
6
7
8
class DataManagerCommandFactoryBuilder(metaclass=CommandFactoryType):
9
    """[summary]
10
11
    Args:
12
        metaclass ([type], optional): [description]. Defaults to CommandFactoryType.
13
14
    Returns:
15
        [type]: [description]
16
    """
17
   
18
    @classmethod
19
    def create_factory(cls, name, callback):
20
        @DataManagerCommandFactoryBuilder.register_as_subclass(name)
21
        class DataManagerRuntimeCommandFactory(CommandFactoryInterface):
22
            def construct(self, *args, **kwargs) -> Command:
23
                receiver = args[0]
24
                def command(*runtime_args):
25
                    callback(receiver, *runtime_args)
26
                return Command(command, '__call__', *args[1:])
27
28
29
@attr.s
30
class DataManagerCommandFactory(Subject):
31
    """[summary]
32
33
    Args:
34
        Subject ([type]): [description]
35
36
    Returns:
37
        [type]: [description]
38
    """
39
    _data_manager = attr.ib(init=True)
40
    command_factory = attr.ib(init=True, default=DataManagerCommandFactoryBuilder)
41
42
    def __call__(self, command_type, *args, **kwargs):
43
        self._state, self.name = self.command_factory.create(command_type).construct(self._data_manager, *args, **kwargs), command_type
44
        self.notify()
45
        return self._state
46
47
    def build_command_prototype(self):
48
        def wrapper(a_callable: Callable) -> Callable:
49
            """Build and register a new Command given a callable object that holds the important business logic.
50
51
            Args:
52
                a_callable (Callable): the Command's important underlying business logic
53
            """
54
            if hasattr(a_callable, '__code__'):  # a_callable object has been defined with the def python keyword
55
                decorated_function_name = a_callable.__code__.co_name
56
                self.command_factory.create_factory(decorated_function_name, a_callable)
57
                self(decorated_function_name)
58
            else:
59
                raise RuntimeError(f"Expected a function to be decorated; got {type(a_callable)}")
60
            return a_callable
61
        return wrapper
62