mirror of
https://github.com/aljazceru/lightning.git
synced 2025-12-20 15:44:21 +01:00
pylightning: Better inject arguments in plugin method calls
If the `request` or `plugin` parameter that are injected by the framework where before or inbetween positional arguments we'd be injecting them incorrectly, i.e., we'd be providing them both as `args` (and mismapping another argument) as well as `kwargs`. This is a better way to map arguments, which takes advantage of the fact that JSON-RPC calls are either all positional or named arguments. I also included a test for various scenarios, that hopefull cover the most common cases. Reported-by: Rene Pickhardt <@renepickhardt> Signed-off-by: Christian Decker <decker.christian@gmail.com>
This commit is contained in:
@@ -1,3 +1,5 @@
|
||||
from collections import OrderedDict
|
||||
|
||||
import sys
|
||||
import os
|
||||
import json
|
||||
@@ -131,18 +133,36 @@ class Plugin(object):
|
||||
|
||||
def _exec_func(self, func, request):
|
||||
params = request['params']
|
||||
args = params.copy() if isinstance(params, list) else []
|
||||
kwargs = params.copy() if isinstance(params, dict) else {}
|
||||
|
||||
sig = inspect.signature(func)
|
||||
|
||||
if 'plugin' in sig.parameters:
|
||||
kwargs['plugin'] = self
|
||||
arguments = OrderedDict()
|
||||
for name, value in sig.parameters.items():
|
||||
arguments[name] = inspect.Signature.empty
|
||||
|
||||
if 'request' in sig.parameters:
|
||||
kwargs['request'] = request
|
||||
# Fill in any injected parameters
|
||||
if 'plugin' in arguments:
|
||||
arguments['plugin'] = self
|
||||
|
||||
ba = sig.bind(*args, **kwargs)
|
||||
if 'request' in arguments:
|
||||
arguments['request'] = request
|
||||
|
||||
# Now zip the provided arguments and the prefilled a together
|
||||
if isinstance(params, dict):
|
||||
arguments.update(params)
|
||||
else:
|
||||
pos = 0
|
||||
for k, v in arguments.items():
|
||||
if v is not inspect.Signature.empty:
|
||||
continue
|
||||
if pos < len(params):
|
||||
# Apply positional args if we have them
|
||||
arguments[k] = params[pos]
|
||||
else:
|
||||
# For the remainder apply default args
|
||||
arguments[k] = sig.parameters[k].default
|
||||
pos += 1
|
||||
|
||||
ba = sig.bind(**arguments)
|
||||
ba.apply_defaults()
|
||||
return func(*ba.args, **ba.kwargs)
|
||||
|
||||
|
||||
51
contrib/pylightning/lightning/test_plugin.py
Normal file
51
contrib/pylightning/lightning/test_plugin.py
Normal file
@@ -0,0 +1,51 @@
|
||||
from .plugin import Plugin
|
||||
import itertools
|
||||
|
||||
|
||||
def test_positional_inject():
|
||||
p = Plugin()
|
||||
rdict = {
|
||||
'id': 1,
|
||||
'jsonrpc':
|
||||
'2.0',
|
||||
'method': 'func',
|
||||
'params': {'a': 1, 'b': 2, 'kwa': 3, 'kwb': 4}
|
||||
}
|
||||
rarr = {
|
||||
'id': 1,
|
||||
'jsonrpc': '2.0',
|
||||
'method': 'func',
|
||||
'params': [1, 2, 3, 4]
|
||||
}
|
||||
|
||||
def pre_args(plugin, a, b, kwa=3, kwb=4):
|
||||
assert (plugin, a, b, kwa, kwb) == (p, 1, 2, 3, 4)
|
||||
|
||||
def in_args(a, plugin, b, kwa=3, kwb=4):
|
||||
assert (plugin, a, b, kwa, kwb) == (p, 1, 2, 3, 4)
|
||||
|
||||
def post_args(a, b, plugin, kwa=3, kwb=4):
|
||||
assert (plugin, a, b, kwa, kwb) == (p, 1, 2, 3, 4)
|
||||
|
||||
def post_kwargs(a, b, kwa=3, kwb=4, plugin=None):
|
||||
assert (plugin, a, b, kwa, kwb) == (p, 1, 2, 3, 4)
|
||||
|
||||
def in_multi_args(a, request, plugin, b, kwa=3, kwb=4):
|
||||
assert request in [rarr, rdict]
|
||||
assert (plugin, a, b, kwa, kwb) == (p, 1, 2, 3, 4)
|
||||
|
||||
def in_multi_mix_args(a, plugin, b, request=None, kwa=3, kwb=4):
|
||||
assert request in [rarr, rdict]
|
||||
assert (plugin, a, b, kwa, kwb) == (p, 1, 2, 3, 4)
|
||||
|
||||
def extra_def_arg(a, b, c, d, e=42):
|
||||
""" Also uses a different name for kwa and kwb
|
||||
"""
|
||||
assert (a, b, c, d, e) == (1, 2, 3, 4, 42)
|
||||
|
||||
funcs = [pre_args, in_args, post_args, post_kwargs, in_multi_args]
|
||||
|
||||
for func, request in itertools.product(funcs, [rdict, rarr]):
|
||||
p._exec_func(func, request)
|
||||
|
||||
p._exec_func(extra_def_arg, rarr)
|
||||
Reference in New Issue
Block a user