k now... emacs>vim
This commit is contained in:
151
.emacs.d/elpa/elpy-20171206.847/elpy/rpc.py
Normal file
151
.emacs.d/elpa/elpy-20171206.847/elpy/rpc.py
Normal file
@@ -0,0 +1,151 @@
|
||||
"""A simple JSON-RPC-like server.
|
||||
|
||||
The server will read and write lines of JSON-encoded method calls and
|
||||
responses.
|
||||
|
||||
See the documentation of the JSONRPCServer class for further details.
|
||||
|
||||
"""
|
||||
|
||||
import json
|
||||
import sys
|
||||
import traceback
|
||||
|
||||
|
||||
class JSONRPCServer(object):
|
||||
"""Simple JSON-RPC-like server.
|
||||
|
||||
This class will read single-line JSON expressions from stdin,
|
||||
decode them, and pass them to a handler. Return values from the
|
||||
handler will be JSON-encoded and written to stdout.
|
||||
|
||||
To implement a handler, you need to subclass this class and add
|
||||
methods starting with "rpc_". Methods then will be found.
|
||||
|
||||
Method calls should be encoded like this:
|
||||
|
||||
{"id": 23, "method": "method_name", "params": ["foo", "bar"]}
|
||||
|
||||
This will call self.rpc_method("foo", "bar").
|
||||
|
||||
Responses will be encoded like this:
|
||||
|
||||
{"id": 23, "result": "foo"}
|
||||
|
||||
Errors will be encoded like this:
|
||||
|
||||
{"id": 23, "error": "Simple error message"}
|
||||
|
||||
See http://www.jsonrpc.org/ for the inspiration of the protocol.
|
||||
|
||||
"""
|
||||
|
||||
def __init__(self, stdin=None, stdout=None):
|
||||
"""Return a new JSON-RPC server object.
|
||||
|
||||
It will read lines of JSON data from stdin, and write the
|
||||
responses to stdout.
|
||||
|
||||
"""
|
||||
if stdin is None:
|
||||
self.stdin = sys.stdin
|
||||
else:
|
||||
self.stdin = stdin
|
||||
if stdout is None:
|
||||
self.stdout = sys.stdout
|
||||
else:
|
||||
self.stdout = stdout
|
||||
|
||||
def read_json(self):
|
||||
"""Read a single line and decode it as JSON.
|
||||
|
||||
Can raise an EOFError() when the input source was closed.
|
||||
|
||||
"""
|
||||
line = self.stdin.readline()
|
||||
if line == '':
|
||||
raise EOFError()
|
||||
return json.loads(line)
|
||||
|
||||
def write_json(self, **kwargs):
|
||||
"""Write an JSON object on a single line.
|
||||
|
||||
The keyword arguments are interpreted as a single JSON object.
|
||||
It's not possible with this method to write non-objects.
|
||||
|
||||
"""
|
||||
self.stdout.write(json.dumps(kwargs) + "\n")
|
||||
self.stdout.flush()
|
||||
|
||||
def handle_request(self):
|
||||
"""Handle a single JSON-RPC request.
|
||||
|
||||
Read a request, call the appropriate handler method, and
|
||||
return the encoded result. Errors in the handler method are
|
||||
caught and encoded as error objects. Errors in the decoding
|
||||
phase are not caught, as we can not respond with an error
|
||||
response to them.
|
||||
|
||||
"""
|
||||
request = self.read_json()
|
||||
if 'method' not in request:
|
||||
raise ValueError("Received a bad request: {0}"
|
||||
.format(request))
|
||||
method_name = request['method']
|
||||
request_id = request.get('id', None)
|
||||
params = request.get('params') or []
|
||||
try:
|
||||
method = getattr(self, "rpc_" + method_name, None)
|
||||
if method is not None:
|
||||
result = method(*params)
|
||||
else:
|
||||
result = self.handle(method_name, params)
|
||||
if request_id is not None:
|
||||
self.write_json(result=result,
|
||||
id=request_id)
|
||||
except Fault as fault:
|
||||
error = {"message": fault.message,
|
||||
"code": fault.code}
|
||||
if fault.data is not None:
|
||||
error["data"] = fault.data
|
||||
self.write_json(error=error, id=request_id)
|
||||
except Exception as e:
|
||||
error = {"message": str(e),
|
||||
"code": 500,
|
||||
"data": {"traceback": traceback.format_exc()}}
|
||||
self.write_json(error=error, id=request_id)
|
||||
|
||||
def handle(self, method_name, args):
|
||||
"""Handle the call to method_name.
|
||||
|
||||
You should overwrite this method in a subclass.
|
||||
"""
|
||||
raise Fault("Unknown method {0}".format(method_name))
|
||||
|
||||
def serve_forever(self):
|
||||
"""Serve requests forever.
|
||||
|
||||
Errors are not caught, so this is a slight misnomer.
|
||||
|
||||
"""
|
||||
while True:
|
||||
try:
|
||||
self.handle_request()
|
||||
except (KeyboardInterrupt, EOFError, SystemExit):
|
||||
break
|
||||
|
||||
|
||||
class Fault(Exception):
|
||||
"""RPC Fault instances.
|
||||
|
||||
code defines the severity of the warning.
|
||||
|
||||
2xx: Normal behavior lead to end of operation, i.e. a warning
|
||||
4xx: An expected error occurred
|
||||
5xx: An unexpected error occurred (usually includes a traceback)
|
||||
"""
|
||||
def __init__(self, message, code=500, data=None):
|
||||
super(Fault, self).__init__(message)
|
||||
self.message = message
|
||||
self.code = code
|
||||
self.data = data
|
||||
Reference in New Issue
Block a user