mirror of
https://github.com/ElementsProject/lightning.git
synced 2025-02-20 13:54:36 +01:00
pyln: add RpcException for finer method failure control.
Allows caller to set code and exact message to be returned. Signed-off-by: Rusty Russell <rusty@rustcorp.com.au> Changelog-Added: pyln-client: plugins can now raise RpcException for finer control over error returns.
This commit is contained in:
parent
423f3944e3
commit
77478408f9
4 changed files with 57 additions and 6 deletions
|
@ -78,6 +78,9 @@ def hello(plugin, name="world"):
|
|||
It gets reported as the description when registering the function
|
||||
as a method with `lightningd`.
|
||||
|
||||
If this returns (a dict), that's the JSON "result" returned. If
|
||||
it raises an exception, that causes a JSON "error" return (raising
|
||||
pyln.client.RpcException allows finer control over the return).
|
||||
"""
|
||||
greeting = plugin.get_option('greeting')
|
||||
s = '{} {}'.format(greeting, name)
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
from .lightning import LightningRpc, RpcError, Millisatoshi
|
||||
from .plugin import Plugin, monkey_patch
|
||||
from .plugin import Plugin, monkey_patch, RpcException
|
||||
|
||||
|
||||
__version__ = "0.8.0"
|
||||
|
@ -9,6 +9,7 @@ __all__ = [
|
|||
"LightningRpc",
|
||||
"Plugin",
|
||||
"RpcError",
|
||||
"RpcException",
|
||||
"Millisatoshi",
|
||||
"__version__",
|
||||
"monkey_patch"
|
||||
|
|
|
@ -61,6 +61,14 @@ class Method(object):
|
|||
self.after: List[str] = []
|
||||
|
||||
|
||||
class RpcException(Exception):
|
||||
# -32600 == "Invalid Request"
|
||||
def __init__(self, message: str, code: int = -32600):
|
||||
self.code = code
|
||||
self.message = message
|
||||
super().__init__("RpcException: {}".format(message))
|
||||
|
||||
|
||||
class Request(dict):
|
||||
"""A request object that wraps params and allows async return
|
||||
"""
|
||||
|
@ -102,7 +110,7 @@ class Request(dict):
|
|||
self.state = RequestState.FINISHED
|
||||
self.termination_tb = "".join(traceback.extract_stack().format()[:-1])
|
||||
|
||||
def set_exception(self, exc: Exception) -> None:
|
||||
def set_exception(self, exc: Union[Exception, RpcException]) -> None:
|
||||
if self.state != RequestState.PENDING:
|
||||
assert(self.termination_tb is not None)
|
||||
raise ValueError(
|
||||
|
@ -110,13 +118,19 @@ class Request(dict):
|
|||
"current state is {state}. Request previously terminated at\n"
|
||||
"{tb}".format(state=self.state, tb=self.termination_tb))
|
||||
self.exc = exc
|
||||
if isinstance(exc, RpcException):
|
||||
code = exc.code
|
||||
message = exc.message
|
||||
else:
|
||||
code = -32600 # "Invalid Request"
|
||||
message = ("Error while processing {method}: {exc}"
|
||||
.format(method=self.method, exc=str(exc)))
|
||||
self._write_result({
|
||||
'jsonrpc': '2.0',
|
||||
'id': self.id,
|
||||
"error": {
|
||||
"code": -32600, # "Invalid Request"
|
||||
"message": "Error while processing {method}: {exc}"
|
||||
.format(method=self.method, exc=str(exc)),
|
||||
"code": code,
|
||||
"message": message,
|
||||
# 'data' field "may be omitted."
|
||||
"traceback": traceback.format_exc(),
|
||||
},
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
from pyln.client import Plugin
|
||||
from pyln.client.plugin import Request, Millisatoshi
|
||||
from pyln.client.plugin import Request, Millisatoshi, RpcException
|
||||
import itertools
|
||||
import pytest # type: ignore
|
||||
|
||||
|
@ -172,6 +172,39 @@ def test_methods_errors():
|
|||
assert call_list == []
|
||||
|
||||
|
||||
def test_method_exceptions():
|
||||
"""A bunch of tests that should fail calling the methods."""
|
||||
p = Plugin(autopatch=False)
|
||||
|
||||
def fake_write_result(resultdict):
|
||||
global result_dict
|
||||
result_dict = resultdict
|
||||
|
||||
@p.method("test_raise")
|
||||
def test_raise():
|
||||
raise RpcException("testing RpcException", code=-1000)
|
||||
|
||||
req = Request(p, 1, "test_raise", {})
|
||||
req._write_result = fake_write_result
|
||||
p._dispatch_request(req)
|
||||
assert result_dict['jsonrpc'] == '2.0'
|
||||
assert result_dict['id'] == 1
|
||||
assert result_dict['error']['code'] == -1000
|
||||
assert result_dict['error']['message'] == "testing RpcException"
|
||||
|
||||
@p.method("test_raise2")
|
||||
def test_raise2():
|
||||
raise Exception("normal exception")
|
||||
|
||||
req = Request(p, 1, "test_raise2", {})
|
||||
req._write_result = fake_write_result
|
||||
p._dispatch_request(req)
|
||||
assert result_dict['jsonrpc'] == '2.0'
|
||||
assert result_dict['id'] == 1
|
||||
assert result_dict['error']['code'] == -32600
|
||||
assert result_dict['error']['message'] == "Error while processing test_raise2: normal exception"
|
||||
|
||||
|
||||
def test_positional_inject():
|
||||
p = Plugin()
|
||||
rdict = Request(
|
||||
|
|
Loading…
Add table
Reference in a new issue