]>
crepu.dev Git - config.git/blob - djavu-asus/elpa/elpy-20230803.1455/elpy/rpc.py
1 """A simple JSON-RPC-like server.
3 The server will read and write lines of JSON-encoded method calls and
6 See the documentation of the JSONRPCServer class for further details.
15 class JSONRPCServer(object):
16 """Simple JSON-RPC-like server.
18 This class will read single-line JSON expressions from stdin,
19 decode them, and pass them to a handler. Return values from the
20 handler will be JSON-encoded and written to stdout.
22 To implement a handler, you need to subclass this class and add
23 methods starting with "rpc_". Methods then will be found.
25 Method calls should be encoded like this:
27 {"id": 23, "method": "method_name", "params": ["foo", "bar"]}
29 This will call self.rpc_method("foo", "bar").
31 Responses will be encoded like this:
33 {"id": 23, "result": "foo"}
35 Errors will be encoded like this:
37 {"id": 23, "error": "Simple error message"}
39 See http://www.jsonrpc.org/ for the inspiration of the protocol.
43 def __init__(self
, stdin
=None, stdout
=None):
44 """Return a new JSON-RPC server object.
46 It will read lines of JSON data from stdin, and write the
51 self
.stdin
= sys
.stdin
55 self
.stdout
= sys
.stdout
60 """Read a single line and decode it as JSON.
62 Can raise an EOFError() when the input source was closed.
65 line
= self
.stdin
.readline()
68 return json
.loads(line
)
70 def write_json(self
, **kwargs
):
71 """Write an JSON object on a single line.
73 The keyword arguments are interpreted as a single JSON object.
74 It's not possible with this method to write non-objects.
77 from elpy
.json_encoder
import JSONEncoder
78 serialized_value
= JSONEncoder().encode(kwargs
)
79 self
.stdout
.write(serialized_value
+ "\n")
82 def handle_request(self
):
83 """Handle a single JSON-RPC request.
85 Read a request, call the appropriate handler method, and
86 return the encoded result. Errors in the handler method are
87 caught and encoded as error objects. Errors in the decoding
88 phase are not caught, as we can not respond with an error
92 request
= self
.read_json()
93 if 'method' not in request
:
94 raise ValueError("Received a bad request: {0}"
96 method_name
= request
['method']
97 request_id
= request
.get('id', None)
98 params
= request
.get('params') or []
100 method
= getattr(self
, "rpc_" + method_name
, None)
101 if method
is not None:
102 result
= method(*params
)
104 result
= self
.handle(method_name
, params
)
105 if request_id
is not None:
106 self
.write_json(result
=result
,
108 except Fault
as fault
:
109 error
= {"message": fault
.message
,
111 if fault
.data
is not None:
112 error
["data"] = fault
.data
113 self
.write_json(error
=error
, id=request_id
)
114 except Exception as e
:
115 error
= {"message": str(e
),
117 "data": {"traceback": traceback
.format_exc()}}
118 self
.write_json(error
=error
, id=request_id
)
120 def handle(self
, method_name
, args
):
121 """Handle the call to method_name.
123 You should overwrite this method in a subclass.
125 raise Fault("Unknown method {0}".format(method_name
))
127 def serve_forever(self
):
128 """Serve requests forever.
130 Errors are not caught, so this is a slight misnomer.
135 self
.handle_request()
136 except (KeyboardInterrupt, EOFError, SystemExit):
140 class Fault(Exception):
141 """RPC Fault instances.
143 code defines the severity of the warning.
145 2xx: Normal behavior lead to end of operation, i.e. a warning
146 4xx: An expected error occurred
147 5xx: An unexpected error occurred (usually includes a traceback)
149 def __init__(self
, message
, code
=500, data
=None):
150 super(Fault
, self
).__init
__(message
)
151 self
.message
= message