From 4764ee160d8bac8ef53c32b7571531eb1de34743 Mon Sep 17 00:00:00 2001 From: Christian Decker Date: Mon, 15 Jun 2020 12:52:42 +0200 Subject: [PATCH] pyln-client: Add support to monkey patch the JSONEncoder Several times we had issues with plugins not being able to re-encode an RPC result because they forgot to use the custom encoder class. This allows us to patch the JSONEncoder when we start the RPC or the plugin and automagically support classes that provide a `to_json` method. --- contrib/pyln-client/pyln/client/lightning.py | 34 ++++++++++++++++++-- 1 file changed, 31 insertions(+), 3 deletions(-) diff --git a/contrib/pyln-client/pyln/client/lightning.py b/contrib/pyln-client/pyln/client/lightning.py index 1ac25530a..096809e38 100644 --- a/contrib/pyln-client/pyln/client/lightning.py +++ b/contrib/pyln-client/pyln/client/lightning.py @@ -5,6 +5,21 @@ import logging import os import socket import warnings +from json import JSONEncoder + + +def _patched_default(self, obj): + return getattr(obj.__class__, "to_json", _patched_default.default)(obj) + + +def monkey_patch_json(patch=True): + is_patched = JSONEncoder.default == _patched_default + + if patch and not is_patched: + _patched_default.default = JSONEncoder.default # Save unmodified + JSONEncoder.default = _patched_default # Replace it. + elif not patch and is_patched: + JSONEncoder.default = _patched_default.default class RpcError(ValueError): @@ -327,7 +342,10 @@ class LightningRpc(UnixDomainSocketRpc): return json.JSONEncoder.default(self, o) class LightningJSONDecoder(json.JSONDecoder): - def __init__(self, *, object_hook=None, parse_float=None, parse_int=None, parse_constant=None, strict=True, object_pairs_hook=None): + def __init__(self, *, object_hook=None, parse_float=None, + parse_int=None, parse_constant=None, + strict=True, object_pairs_hook=None, + patch_json=True): self.object_hook_next = object_hook super().__init__(object_hook=self.millisatoshi_hook, parse_float=parse_float, parse_int=parse_int, parse_constant=parse_constant, strict=strict, object_pairs_hook=object_pairs_hook) @@ -357,8 +375,18 @@ class LightningRpc(UnixDomainSocketRpc): obj = self.object_hook_next(obj) return obj - def __init__(self, socket_path, executor=None, logger=logging): - super().__init__(socket_path, executor, logger, self.LightningJSONEncoder, self.LightningJSONDecoder()) + def __init__(self, socket_path, executor=None, logger=logging, + patch_json=True): + super().__init__( + socket_path, + executor, + logger, + self.LightningJSONEncoder, + self.LightningJSONDecoder() + ) + + if patch_json: + monkey_patch_json(patch=True) def autocleaninvoice(self, cycle_seconds=None, expired_by=None): """