ClsFunction.__init__()   C
last analyzed

Complexity

Conditions 9

Size

Total Lines 33
Code Lines 27

Duplication

Lines 33
Ratio 100 %

Importance

Changes 0
Metric Value
cc 9
eloc 27
nop 2
dl 33
loc 33
rs 6.6666
c 0
b 0
f 0
1
import inspect
2
from collections import OrderedDict
3
from typing import Callable, Any, Union, Iterable, Dict, Tuple
4
5
from typish._types import Empty
6
from typish.classes._cls_dict import ClsDict
7
8
9 View Code Duplication
class ClsFunction:
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
10
    """
11
    ClsDict is a callable that takes a ClsDict or a dict. When called, it uses
12
    the first argument to check for the right function in its body, executes it
13
    and returns the result.
14
    """
15
    def __init__(self, body: Union[ClsDict,
16
                                   Dict[type, Callable],
17
                                   Iterable[Tuple[type, Callable]],
18
                                   Iterable[Callable]]):
19
        from typish.functions._instance_of import instance_of
20
21
        if isinstance(body, ClsDict):
22
            self.body = body
23
        elif isinstance(body, dict):
24
            self.body = ClsDict(body)
25
        elif instance_of(body, Iterable[Callable]):
26
            list_of_tuples = []
27
            for func in body:
28
                signature = inspect.signature(func)
29
                params = list(signature.parameters.keys())
30
                if not params:
31
                    raise TypeError('ClsFunction expects callables that take '
32
                                    'at least one parameter, {} does not.'
33
                                    .format(func.__name__))
34
                first_param = signature.parameters[params[0]]
35
                hint = first_param.annotation
36
                key = Any if hint == Empty else hint
37
                list_of_tuples.append((key, func))
38
            self.body = ClsDict(OrderedDict(list_of_tuples))
39
        elif instance_of(body, Iterable[Tuple[type, Callable]]):
40
            self.body = ClsDict(OrderedDict(body))
41
        else:
42
            raise TypeError('ClsFunction expects a ClsDict or a dict that can '
43
                            'be turned to a ClsDict or an iterable of '
44
                            'callables.')
45
46
        if not all(isinstance(value, Callable) for value in self.body.values()):
47
            raise TypeError('ClsFunction expects a dict or ClsDict with only '
48
                            'callables as values.')
49
50
    def understands(self, item: Any) -> bool:
51
        """
52
        Check to see if this ClsFunction can take item.
53
        :param item: the item that is checked.
54
        :return: True if this ClsFunction can take item.
55
        """
56
        try:
57
            self.body[item]
58
            return True
59
        except KeyError:
60
            return False
61
62
    def __call__(self, *args, **kwargs):
63
        if not args:
64
            raise TypeError('ClsFunction must be called with at least 1 '
65
                            'positional argument.')
66
        callable_ = self.body[args[0]]
67
        try:
68
            return callable_(*args, **kwargs)
69
        except TypeError as err:
70
            raise TypeError('Unable to call function for \'{}\': {}'
71
                            .format(args[0], err.args[0]))
72