mirror of
https://github.com/ElementsProject/lightning.git
synced 2025-02-22 06:41:44 +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
|
It gets reported as the description when registering the function
|
||||||
as a method with `lightningd`.
|
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')
|
greeting = plugin.get_option('greeting')
|
||||||
s = '{} {}'.format(greeting, name)
|
s = '{} {}'.format(greeting, name)
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
from .lightning import LightningRpc, RpcError, Millisatoshi
|
from .lightning import LightningRpc, RpcError, Millisatoshi
|
||||||
from .plugin import Plugin, monkey_patch
|
from .plugin import Plugin, monkey_patch, RpcException
|
||||||
|
|
||||||
|
|
||||||
__version__ = "0.8.0"
|
__version__ = "0.8.0"
|
||||||
|
@ -9,6 +9,7 @@ __all__ = [
|
||||||
"LightningRpc",
|
"LightningRpc",
|
||||||
"Plugin",
|
"Plugin",
|
||||||
"RpcError",
|
"RpcError",
|
||||||
|
"RpcException",
|
||||||
"Millisatoshi",
|
"Millisatoshi",
|
||||||
"__version__",
|
"__version__",
|
||||||
"monkey_patch"
|
"monkey_patch"
|
||||||
|
|
|
@ -61,6 +61,14 @@ class Method(object):
|
||||||
self.after: List[str] = []
|
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):
|
class Request(dict):
|
||||||
"""A request object that wraps params and allows async return
|
"""A request object that wraps params and allows async return
|
||||||
"""
|
"""
|
||||||
|
@ -102,7 +110,7 @@ class Request(dict):
|
||||||
self.state = RequestState.FINISHED
|
self.state = RequestState.FINISHED
|
||||||
self.termination_tb = "".join(traceback.extract_stack().format()[:-1])
|
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:
|
if self.state != RequestState.PENDING:
|
||||||
assert(self.termination_tb is not None)
|
assert(self.termination_tb is not None)
|
||||||
raise ValueError(
|
raise ValueError(
|
||||||
|
@ -110,13 +118,19 @@ class Request(dict):
|
||||||
"current state is {state}. Request previously terminated at\n"
|
"current state is {state}. Request previously terminated at\n"
|
||||||
"{tb}".format(state=self.state, tb=self.termination_tb))
|
"{tb}".format(state=self.state, tb=self.termination_tb))
|
||||||
self.exc = exc
|
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({
|
self._write_result({
|
||||||
'jsonrpc': '2.0',
|
'jsonrpc': '2.0',
|
||||||
'id': self.id,
|
'id': self.id,
|
||||||
"error": {
|
"error": {
|
||||||
"code": -32600, # "Invalid Request"
|
"code": code,
|
||||||
"message": "Error while processing {method}: {exc}"
|
"message": message,
|
||||||
.format(method=self.method, exc=str(exc)),
|
|
||||||
# 'data' field "may be omitted."
|
# 'data' field "may be omitted."
|
||||||
"traceback": traceback.format_exc(),
|
"traceback": traceback.format_exc(),
|
||||||
},
|
},
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
from pyln.client import Plugin
|
from pyln.client import Plugin
|
||||||
from pyln.client.plugin import Request, Millisatoshi
|
from pyln.client.plugin import Request, Millisatoshi, RpcException
|
||||||
import itertools
|
import itertools
|
||||||
import pytest # type: ignore
|
import pytest # type: ignore
|
||||||
|
|
||||||
|
@ -172,6 +172,39 @@ def test_methods_errors():
|
||||||
assert call_list == []
|
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():
|
def test_positional_inject():
|
||||||
p = Plugin()
|
p = Plugin()
|
||||||
rdict = Request(
|
rdict = Request(
|
||||||
|
|
Loading…
Add table
Reference in a new issue