Passed
Push — master ( 1de29a...581576 )
by Michael
03:27
created

JsonRpcMethod._add_extra_args_in_args()   A

Complexity

Conditions 4

Size

Total Lines 13
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 9
dl 0
loc 13
rs 9.95
c 0
b 0
f 0
cc 4
nop 3
1
import asyncio
2
import inspect
3
import typing
4
5
from .. import errors, utils
6
7
8
__all__ = (
9
    'JsonRpcMethod',
10
)
11
12
13
class JsonRpcMethod:
14
    separator: str = '__'
15
    prefix: str
16
    name: str
17
    func: typing.Callable
18
    add_extra_args: bool
19
    is_coroutine: bool
20
    supported_args: list
21
    supported_kwargs: list
22
23
    def __init__(self,
24
                 prefix: str,
25
                 func: typing.Callable, *,
26
                 custom_name: typing.Optional[str] = None,
27
                 add_extra_args: bool = True) -> None:
28
        assert callable(func)
29
30
        self.prefix = prefix
31
        self.func = func
32
        self.add_extra_args = add_extra_args
33
        self.name = custom_name if custom_name else func.__name__
34
35
        if prefix:
36
            self.name = f'{prefix}{self.separator}{self.name}'
37
38
        self._inspect_func()
39
40
    async def __call__(self, args: list, kwargs: dict, extra_args: typing.Optional[dict] = None) -> typing.Any:
41
        if self.add_extra_args and extra_args:
42
            args, kwargs = self._add_extra_args_in_args_and_kwargs(args, kwargs, extra_args)
43
44
        try:
45
            inspect.signature(self.func).bind(*args, **kwargs)
46
        except TypeError as e:
47
            raise errors.InvalidParams(utils.get_exc_message(e)) from e
48
49
        if self.is_coroutine:
50
            return await self.func(*args, **kwargs)
51
52
        return self.func(*args, **kwargs)
53
54
    def _inspect_func(self) -> None:
55
        argspec = inspect.getfullargspec(self.func)
56
57
        if inspect.ismethod(self.func):
58
            self.supported_args = argspec.args[1:]
59
        else:
60
            self.supported_args = argspec.args
61
62
        self.supported_kwargs = argspec.kwonlyargs
63
        self.is_coroutine = asyncio.iscoroutinefunction(self.func)
64
65
    def _add_extra_args_in_args_and_kwargs(self,
66
                                           args: list,
67
                                           kwargs: dict,
68
                                           extra_args: dict) -> typing.Tuple[list, dict]:
69
        if not extra_args:
70
            return args, kwargs
71
72
        new_args = self._add_extra_args_in_args(args, extra_args)
73
74
        if (len(new_args) - len(args)) == len(extra_args):
75
            return new_args, kwargs
76
77
        new_kwargs = self._add_extra_kwargs_in_args(kwargs, extra_args)
78
        return new_args, new_kwargs
79
80
    def _add_extra_args_in_args(self, args: list, extra_args: dict) -> list:
81
        new_args = []
82
83
        for supported_arg in self.supported_args:
84
            if supported_arg not in extra_args:
85
                break
86
87
            new_args.append(extra_args[supported_arg])
88
89
        if new_args:
90
            args = [*new_args, *args]
91
92
        return args
93
94
    def _add_extra_kwargs_in_args(self, kwargs: dict, extra_args: dict) -> dict:
95
        new_kwargs = {}
96
97
        for extra_arg, value in extra_args.items():
98
            if extra_arg in self.supported_kwargs:
99
                new_kwargs[extra_arg] = value
100
101
        if new_kwargs:
102
            kwargs = {**kwargs, **new_kwargs}
103
104
        return kwargs
105