JsonRpcBatchRequest.dump()   A
last analyzed

Complexity

Conditions 1

Size

Total Lines 2
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 2
dl 0
loc 2
rs 10
c 0
b 0
f 0
cc 1
nop 1
1
import typing
2
from dataclasses import dataclass, field
3
4
from .. import constants, errors, typedefs, utils
5
6
7
__all__ = (
8
    'JsonRpcRequest',
9
    'JsonRpcBatchRequest',
10
)
11
12
13
@dataclass
14
class JsonRpcRequest:
15
    method_name: str
16
    # If `id` is `None` then `JsonRpcRequest` is a notification.
17
    id: typing.Optional[typedefs.JsonRpcIdType] = None
18
    jsonrpc: str = constants.VERSION_2_0
19
    extra_args: typing.MutableMapping = field(default_factory=dict)
20
    context: typing.MutableMapping = field(default_factory=dict)
21
    params: typing.Any = constants.NOTHING  # Use `NOTHING`, because `None` is a valid value.
22
    # We don't convert `args`. So `args` can be `list`, `tuple` or other type.
23
    args: typing.Optional[typing.Sequence] = None
24
    # We don't convert `kwargs`. So `kwargs` can be `dict` or other type.
25
    kwargs: typing.Optional[typing.Mapping] = None
26
27
    def __post_init__(self) -> None:
28
        utils.validate_jsonrpc(self.jsonrpc)
29
30
        if self.params is constants.NOTHING:
31
            self.set_args_and_kwargs(self.args, self.kwargs)
32
        elif self.args is None and self.kwargs is None:
33
            self.set_params(self.params)
34
        else:
35
            raise errors.InvalidParams('Need use params or args with kwargs.')
36
37
    def set_params(self, params: typing.Any) -> None:
38
        self.params = params
39
        self.args, self.kwargs = utils.convert_params_to_args_and_kwargs(params)
40
41
    def set_args_and_kwargs(self,
42
                            args: typing.Optional[typing.Sequence] = None,
43
                            kwargs: typing.Optional[typing.Mapping] = None) -> None:
44
        self.params, self.args, self.kwargs = utils.parse_args_and_kwargs(args, kwargs)
45
46
    @property
47
    def is_notification(self) -> bool:
48
        return self.id is None
49
50
    @classmethod
51
    def load(cls, data: typing.Any, **kwargs) -> 'JsonRpcRequest':
52
        cls._validate_json_request(data)
53
54
        return cls(
55
            id=data.get('id'),
56
            method_name=data['method'],
57
            params=data.get('params', constants.NOTHING),
58
            jsonrpc=data['jsonrpc'],
59
            **kwargs,
60
        )
61
62
    def dump(self) -> typing.Mapping[str, typing.Any]:
63
        data: typing.Dict[str, typing.Any] = {
64
            'method': self.method_name,
65
            'jsonrpc': self.jsonrpc,
66
        }
67
68
        if not self.is_notification:
69
            data['id'] = self.id
70
71
        if self.params is not constants.NOTHING:
72
            data['params'] = self.params
73
74
        return data
75
76
    @staticmethod
77
    def _validate_json_request(data: typing.Any) -> None:
78
        if not isinstance(data, typing.Mapping):
79
            raise errors.InvalidRequest('The request must be of the dict type.')
80
81
        if not ({'method', 'jsonrpc'}) <= data.keys():
82
            raise errors.InvalidRequest('The request must contain "method" and "jsonrpc".')
83
84
        utils.validate_jsonrpc(data['jsonrpc'])
85
86
87
@dataclass
88
class JsonRpcBatchRequest:
89
    requests: typing.Tuple[JsonRpcRequest, ...] = field(default_factory=tuple)
90
91
    @property
92
    def is_notification(self) -> bool:
93
        return all(request.is_notification for request in self.requests)
94
95
    @classmethod
96
    def load(cls, data: typing.Any, **kwargs) -> 'JsonRpcBatchRequest':
97
        if not isinstance(data, typing.Sequence):
98
            raise errors.InvalidRequest('A batch request must be of the list type.')
99
100
        return cls(requests=tuple(
101
            JsonRpcRequest.load(item, **kwargs)
102
            for item in data
103
        ))
104
105
    def dump(self) -> typing.Tuple[typing.Mapping[str, typing.Any], ...]:
106
        return tuple(request.dump() for request in self.requests)
107