python-jsonrpc-lib 0.3.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- jsonrpc/__init__.py +83 -0
- jsonrpc/errors.py +131 -0
- jsonrpc/jsonrpc.py +881 -0
- jsonrpc/method.py +561 -0
- jsonrpc/openapi.py +505 -0
- jsonrpc/py.typed +0 -0
- jsonrpc/request.py +164 -0
- jsonrpc/response.py +169 -0
- jsonrpc/types.py +53 -0
- jsonrpc/validation.py +297 -0
- python_jsonrpc_lib-0.3.1.dist-info/METADATA +141 -0
- python_jsonrpc_lib-0.3.1.dist-info/RECORD +14 -0
- python_jsonrpc_lib-0.3.1.dist-info/WHEEL +4 -0
- python_jsonrpc_lib-0.3.1.dist-info/licenses/LICENSE +21 -0
jsonrpc/__init__.py
ADDED
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
"""Pure-Python JSON-RPC 1.0/2.0 protocol implementation.
|
|
2
|
+
|
|
3
|
+
This library provides a transport-agnostic implementation of the JSON-RPC protocol,
|
|
4
|
+
supporting both version 1.0 and 2.0 specifications.
|
|
5
|
+
|
|
6
|
+
Example:
|
|
7
|
+
>>> from jsonrpc import JSONRPC, MethodGroup, Method
|
|
8
|
+
>>> from dataclasses import dataclass
|
|
9
|
+
>>>
|
|
10
|
+
>>> @dataclass
|
|
11
|
+
... class AddParams:
|
|
12
|
+
... a: int
|
|
13
|
+
... b: int
|
|
14
|
+
...
|
|
15
|
+
>>> class Add(Method):
|
|
16
|
+
... def execute(self, params: AddParams) -> int:
|
|
17
|
+
... return params.a + params.b
|
|
18
|
+
...
|
|
19
|
+
>>> math = MethodGroup()
|
|
20
|
+
>>> math.register("add", Add())
|
|
21
|
+
>>>
|
|
22
|
+
>>> rpc = JSONRPC()
|
|
23
|
+
>>> rpc.register("math", math)
|
|
24
|
+
>>>
|
|
25
|
+
>>> response = rpc.handle('{"jsonrpc":"2.0","method":"math.add","params":{"a":1,"b":2},"id":1}')
|
|
26
|
+
>>> print(response)
|
|
27
|
+
{"jsonrpc": "2.0", "result": 3, "id": 1}
|
|
28
|
+
"""
|
|
29
|
+
|
|
30
|
+
from .errors import (
|
|
31
|
+
InternalError,
|
|
32
|
+
InvalidParamsError,
|
|
33
|
+
InvalidRequestError,
|
|
34
|
+
InvalidResultError,
|
|
35
|
+
JSONRPCError,
|
|
36
|
+
MethodNotFoundError,
|
|
37
|
+
ParseError,
|
|
38
|
+
RPCError,
|
|
39
|
+
ServerError,
|
|
40
|
+
)
|
|
41
|
+
from .jsonrpc import JSONRPC
|
|
42
|
+
from .method import Method, MethodGroup
|
|
43
|
+
from .openapi import OpenAPIGenerator
|
|
44
|
+
from .request import build_notification, build_request, parse_request
|
|
45
|
+
from .response import build_error_response, build_response, parse_response
|
|
46
|
+
from .types import ErrorResponse, Request, Response, Version
|
|
47
|
+
from .validation import validate_params, validate_result_type
|
|
48
|
+
|
|
49
|
+
__version__ = '0.3.1'
|
|
50
|
+
|
|
51
|
+
__all__ = [
|
|
52
|
+
# Main classes
|
|
53
|
+
'JSONRPC',
|
|
54
|
+
'Method',
|
|
55
|
+
'MethodGroup',
|
|
56
|
+
# Types
|
|
57
|
+
'Request',
|
|
58
|
+
'Response',
|
|
59
|
+
'ErrorResponse',
|
|
60
|
+
'RPCError',
|
|
61
|
+
'Version',
|
|
62
|
+
# Errors
|
|
63
|
+
'JSONRPCError',
|
|
64
|
+
'ParseError',
|
|
65
|
+
'InvalidRequestError',
|
|
66
|
+
'MethodNotFoundError',
|
|
67
|
+
'InvalidParamsError',
|
|
68
|
+
'InvalidResultError',
|
|
69
|
+
'InternalError',
|
|
70
|
+
'ServerError',
|
|
71
|
+
# Request/Response builders
|
|
72
|
+
'build_request',
|
|
73
|
+
'build_notification',
|
|
74
|
+
'build_response',
|
|
75
|
+
'build_error_response',
|
|
76
|
+
'parse_request',
|
|
77
|
+
'parse_response',
|
|
78
|
+
# Utilities
|
|
79
|
+
'validate_params',
|
|
80
|
+
'validate_result_type',
|
|
81
|
+
# OpenAPI
|
|
82
|
+
'OpenAPIGenerator',
|
|
83
|
+
]
|
jsonrpc/errors.py
ADDED
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
"""JSON-RPC error classes per specification.
|
|
2
|
+
|
|
3
|
+
Error codes:
|
|
4
|
+
-32700: Parse error - Invalid JSON
|
|
5
|
+
-32600: Invalid Request - Not a valid Request object
|
|
6
|
+
-32601: Method not found - Method does not exist
|
|
7
|
+
-32602: Invalid params - Invalid method parameters
|
|
8
|
+
-32603: Internal error - Internal JSON-RPC error
|
|
9
|
+
-32001: Invalid result - Return type mismatch (implementation-defined)
|
|
10
|
+
-32000 to -32099: Server error - Reserved for implementation
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
from dataclasses import dataclass
|
|
14
|
+
from typing import Any
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
@dataclass
|
|
18
|
+
class RPCError:
|
|
19
|
+
"""JSON-RPC error object."""
|
|
20
|
+
|
|
21
|
+
code: int
|
|
22
|
+
message: str
|
|
23
|
+
data: Any = None
|
|
24
|
+
|
|
25
|
+
def to_dict(self) -> dict[str, Any]:
|
|
26
|
+
"""Convert to JSON-RPC error object dict."""
|
|
27
|
+
result: dict[str, Any] = {
|
|
28
|
+
'code': self.code,
|
|
29
|
+
'message': self.message,
|
|
30
|
+
}
|
|
31
|
+
if self.data is not None:
|
|
32
|
+
result['data'] = self.data
|
|
33
|
+
return result
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
class JSONRPCError(Exception):
|
|
37
|
+
"""Base exception for JSON-RPC errors."""
|
|
38
|
+
|
|
39
|
+
code: int = -32603
|
|
40
|
+
message: str = 'Internal error'
|
|
41
|
+
|
|
42
|
+
def __init__(
|
|
43
|
+
self,
|
|
44
|
+
message: str | None = None,
|
|
45
|
+
code: int | None = None,
|
|
46
|
+
data: Any = None,
|
|
47
|
+
) -> None:
|
|
48
|
+
self._message = message if message is not None else self.message
|
|
49
|
+
self._code = code if code is not None else self.code
|
|
50
|
+
self.data = data
|
|
51
|
+
super().__init__(self._message)
|
|
52
|
+
|
|
53
|
+
@property
|
|
54
|
+
def error(self) -> RPCError:
|
|
55
|
+
"""Get RPCError object for this exception."""
|
|
56
|
+
return RPCError(
|
|
57
|
+
code=self._code,
|
|
58
|
+
message=self._message,
|
|
59
|
+
data=self.data,
|
|
60
|
+
)
|
|
61
|
+
|
|
62
|
+
def to_dict(self) -> dict[str, Any]:
|
|
63
|
+
"""Convert to JSON-RPC error object dict."""
|
|
64
|
+
return self.error.to_dict()
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
class ParseError(JSONRPCError):
|
|
68
|
+
"""Invalid JSON was received by the server."""
|
|
69
|
+
|
|
70
|
+
code = -32700
|
|
71
|
+
message = 'Parse error'
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
class InvalidRequestError(JSONRPCError):
|
|
75
|
+
"""The JSON sent is not a valid Request object."""
|
|
76
|
+
|
|
77
|
+
code = -32600
|
|
78
|
+
message = 'Invalid Request'
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
class MethodNotFoundError(JSONRPCError):
|
|
82
|
+
"""The method does not exist / is not available."""
|
|
83
|
+
|
|
84
|
+
code = -32601
|
|
85
|
+
message = 'Method not found'
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
class InvalidParamsError(JSONRPCError):
|
|
89
|
+
"""Invalid method parameter(s)."""
|
|
90
|
+
|
|
91
|
+
code = -32602
|
|
92
|
+
message = 'Invalid params'
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
class InvalidResultError(JSONRPCError):
|
|
96
|
+
"""Method result doesn't match declared result_type.
|
|
97
|
+
|
|
98
|
+
This is an implementation-defined server error that indicates a contract
|
|
99
|
+
violation between the method implementation and its declared return type.
|
|
100
|
+
Uses code -32001 (in the -32000 to -32099 range reserved for implementation).
|
|
101
|
+
"""
|
|
102
|
+
|
|
103
|
+
code = -32001
|
|
104
|
+
message = 'Invalid result'
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
class InternalError(JSONRPCError):
|
|
108
|
+
"""Internal JSON-RPC error."""
|
|
109
|
+
|
|
110
|
+
code = -32603
|
|
111
|
+
message = 'Internal error'
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
class ServerError(JSONRPCError):
|
|
115
|
+
"""Reserved for implementation-defined server-errors.
|
|
116
|
+
|
|
117
|
+
Code must be in range -32000 to -32099.
|
|
118
|
+
"""
|
|
119
|
+
|
|
120
|
+
code = -32000
|
|
121
|
+
message = 'Server error'
|
|
122
|
+
|
|
123
|
+
def __init__(
|
|
124
|
+
self,
|
|
125
|
+
message: str | None = None,
|
|
126
|
+
code: int | None = None,
|
|
127
|
+
data: Any = None,
|
|
128
|
+
) -> None:
|
|
129
|
+
if code is not None and not (-32099 <= code <= -32000):
|
|
130
|
+
raise ValueError(f'Server error code must be in range -32099 to -32000, got {code}')
|
|
131
|
+
super().__init__(message, code, data)
|