mirror of
https://github.com/ElementsProject/lightning.git
synced 2025-01-17 19:03:42 +01:00
pyln.proto.message: add to_py() operation.
This delivers the message contents in a much friendlier form for manipulation: in particular, it makes it easy to compare two messages without having to know all the message type internals. Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
This commit is contained in:
parent
ee76504e53
commit
02338a6b25
@ -1,5 +1,5 @@
|
||||
from .fundamental_types import FieldType, IntegerType, split_field
|
||||
from typing import List, Optional, Dict, Tuple, TYPE_CHECKING, Any
|
||||
from typing import List, Optional, Dict, Tuple, TYPE_CHECKING, Any, Union
|
||||
from io import BufferedIOBase
|
||||
if TYPE_CHECKING:
|
||||
from .message import SubtypeType, TlvStreamType
|
||||
@ -41,6 +41,13 @@ wants an array of some type.
|
||||
s = ','.join(self.elemtype.val_to_str(i, otherfields) for i in v)
|
||||
return '[' + s + ']'
|
||||
|
||||
def val_to_py(self, v: Any, otherfields: Dict[str, Any]) -> Union[str, List[Any]]:
|
||||
"""Convert to a python object: for arrays, this means a list (or hex, if bytes)"""
|
||||
if self.elemtype.name == 'byte':
|
||||
return bytes(v).hex()
|
||||
|
||||
return [self.elemtype.val_to_py(i, otherfields) for i in v]
|
||||
|
||||
def write(self, io_out: BufferedIOBase, v: List[Any], otherfields: Dict[str, Any]) -> None:
|
||||
for i in v:
|
||||
self.elemtype.write(io_out, i, otherfields)
|
||||
@ -143,6 +150,11 @@ class LengthFieldType(FieldType):
|
||||
return self.underlying_type.val_to_str(self.calc_value(otherfields),
|
||||
otherfields)
|
||||
|
||||
def val_to_py(self, v: Any, otherfields: Dict[str, Any]) -> int:
|
||||
"""Convert to a python object: for integer fields, this means an int"""
|
||||
return self.underlying_type.val_to_py(self.calc_value(otherfields),
|
||||
otherfields)
|
||||
|
||||
def name_and_val(self, name: str, v: int) -> str:
|
||||
"""We don't print out length fields when printing out messages:
|
||||
they're implied by the length of other fields"""
|
||||
|
@ -59,6 +59,10 @@ These are further specialized.
|
||||
def val_to_str(self, v: Any, otherfields: Dict[str, Any]) -> str:
|
||||
raise NotImplementedError()
|
||||
|
||||
def val_to_py(self, v: Any, otherfields: Dict[str, Any]) -> Any:
|
||||
"""Convert to a python object: for simple fields, this means a string"""
|
||||
return self.val_to_str(v, otherfields)
|
||||
|
||||
def __str__(self):
|
||||
return self.name
|
||||
|
||||
@ -79,6 +83,10 @@ class IntegerType(FieldType):
|
||||
a, b = split_field(s)
|
||||
return int(a), b
|
||||
|
||||
def val_to_py(self, v: Any, otherfields: Dict[str, Any]) -> int:
|
||||
"""Convert to a python object: for integer fields, this means an int"""
|
||||
return int(v)
|
||||
|
||||
def write(self, io_out: BufferedIOBase, v: int, otherfields: Dict[str, Any]) -> None:
|
||||
io_out.write(struct.pack(self.structfmt, v))
|
||||
|
||||
@ -107,6 +115,10 @@ basically a u64.
|
||||
| (int(parts[1]) << 16)
|
||||
| (int(parts[2]))), b
|
||||
|
||||
def val_to_py(self, v: Any, otherfields: Dict[str, Any]) -> str:
|
||||
# Unlike a normal int, this returns a str.
|
||||
return self.val_to_str(v, otherfields)
|
||||
|
||||
|
||||
class TruncatedIntType(FieldType):
|
||||
"""Truncated integer types"""
|
||||
@ -128,6 +140,10 @@ class TruncatedIntType(FieldType):
|
||||
.format(a, self.name))
|
||||
return int(a), b
|
||||
|
||||
def val_to_py(self, v: Any, otherfields: Dict[str, Any]) -> int:
|
||||
"""Convert to a python object: for integer fields, this means an int"""
|
||||
return int(v)
|
||||
|
||||
def write(self, io_out: BufferedIOBase, v: int, otherfields: Dict[str, Any]) -> None:
|
||||
binval = struct.pack('>Q', v)
|
||||
while len(binval) != 0 and binval[0] == 0:
|
||||
@ -219,6 +235,10 @@ class BigSizeType(FieldType):
|
||||
def val_to_str(self, v: int, otherfields: Dict[str, Any]) -> str:
|
||||
return "{}".format(int(v))
|
||||
|
||||
def val_to_py(self, v: Any, otherfields: Dict[str, Any]) -> int:
|
||||
"""Convert to a python object: for integer fields, this means an int"""
|
||||
return int(v)
|
||||
|
||||
|
||||
def fundamental_types():
|
||||
# From 01-messaging.md#fundamental-types:
|
||||
|
@ -4,7 +4,7 @@ from .fundamental_types import fundamental_types, BigSizeType, split_field, try_
|
||||
from .array_types import (
|
||||
SizedArrayType, DynamicArrayType, LengthFieldType, EllipsisArrayType
|
||||
)
|
||||
from typing import Dict, List, Optional, Tuple, Any, cast
|
||||
from typing import Dict, List, Optional, Tuple, Any, Union, cast
|
||||
|
||||
|
||||
class MessageNamespace(object):
|
||||
@ -278,6 +278,12 @@ inherit from this too.
|
||||
|
||||
return '{' + s + '}'
|
||||
|
||||
def val_to_py(self, val: Dict[str, Any], otherfields: Dict[str, Any]) -> Dict[str, Any]:
|
||||
ret: Dict[str, Any] = {}
|
||||
for k, v in val.items():
|
||||
ret[k] = self.find_field(k).fieldtype.val_to_py(v, val)
|
||||
return ret
|
||||
|
||||
def write(self, io_out: BufferedIOBase, v: Dict[str, Any], otherfields: Dict[str, Any]) -> None:
|
||||
self._raise_if_badvals(v)
|
||||
for fname, val in v.items():
|
||||
@ -471,6 +477,12 @@ tlvdata,reply_channel_range_tlvs,timestamps_tlv,encoding_type,u8,
|
||||
|
||||
return '{' + s + '}'
|
||||
|
||||
def val_to_py(self, val: Dict[str, Any], otherfields: Dict[str, Any]) -> Dict[str, Any]:
|
||||
ret: Dict[str, Any] = {}
|
||||
for k, v in val.items():
|
||||
ret[k] = self.find_field(k).val_to_py(v, val)
|
||||
return ret
|
||||
|
||||
def write(self, io_out: BufferedIOBase, v: Optional[Dict[str, Any]], otherfields: Dict[str, Any]) -> None:
|
||||
# If they didn't specify this tlvstream, it's empty.
|
||||
if v is None:
|
||||
@ -662,3 +674,12 @@ Must not have missing fields.
|
||||
if f.name in self.fields:
|
||||
ret += f.fieldtype.name_and_val(f.name, self.fields[f.name])
|
||||
return ret
|
||||
|
||||
def to_py(self) -> Dict[str, Any]:
|
||||
"""Convert to a Python native object: dicts, lists, strings, ints"""
|
||||
ret: Dict[str, Union[Dict[str, Any], List[Any], str, int]] = {}
|
||||
for f, v in self.fields.items():
|
||||
fieldtype = self.messagetype.find_field(f).fieldtype
|
||||
ret[f] = fieldtype.val_to_py(v, self.fields)
|
||||
|
||||
return ret
|
||||
|
Loading…
Reference in New Issue
Block a user