|
|
|
@ -41,7 +41,7 @@ required:
|
|
|
|
|
|
|
|
|
|
import binascii
|
|
|
|
|
from io import BytesIO
|
|
|
|
|
from typing import Any
|
|
|
|
|
from typing import Any, Optional
|
|
|
|
|
|
|
|
|
|
_UVARINT_BUFFER = bytearray(1)
|
|
|
|
|
|
|
|
|
@ -348,37 +348,63 @@ def dump_message(writer, msg):
|
|
|
|
|
raise TypeError
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def format_message(pb: MessageType, indent: int=0, sep: str= ' ' * 4) -> str:
|
|
|
|
|
def format_message(pb: MessageType,
|
|
|
|
|
indent: int = 0,
|
|
|
|
|
sep: str = ' ' * 4,
|
|
|
|
|
truncate_after: Optional[int] = 256,
|
|
|
|
|
truncate_to: Optional[int] = 64,
|
|
|
|
|
collapse_cointypes: bool = False) -> str:
|
|
|
|
|
|
|
|
|
|
def mostly_printable(bytes):
|
|
|
|
|
if not bytes:
|
|
|
|
|
return True
|
|
|
|
|
printable = sum(1 for byte in bytes if 0x20 <= byte <= 0x7e)
|
|
|
|
|
return printable / len(bytes) > 0.8
|
|
|
|
|
|
|
|
|
|
def pformat_value(value: Any, indent: int) -> str:
|
|
|
|
|
level = sep * indent
|
|
|
|
|
leadin = sep * (indent + 1)
|
|
|
|
|
if isinstance(value, MessageType):
|
|
|
|
|
return format_message(value, indent, sep)
|
|
|
|
|
if isinstance(value, list):
|
|
|
|
|
lines = []
|
|
|
|
|
lines.append('[')
|
|
|
|
|
lines += [leadin + pformat_value(x, indent + 1) + ',' for x in value]
|
|
|
|
|
lines.append(level + ']')
|
|
|
|
|
# short list of simple values
|
|
|
|
|
if not value or not isinstance(value[0], MessageType):
|
|
|
|
|
return repr(value)
|
|
|
|
|
|
|
|
|
|
# long list, one line per entry
|
|
|
|
|
lines = ['[', level + ']']
|
|
|
|
|
lines[1:1] = [leadin + pformat_value(x, indent + 1) + ',' for x in value]
|
|
|
|
|
return '\n'.join(lines)
|
|
|
|
|
if isinstance(value, dict):
|
|
|
|
|
lines = []
|
|
|
|
|
lines.append('{')
|
|
|
|
|
lines = ['{']
|
|
|
|
|
for key, val in sorted(value.items()):
|
|
|
|
|
if val is None or val == []:
|
|
|
|
|
continue
|
|
|
|
|
if key == 'address_n' and isinstance(val, list):
|
|
|
|
|
lines.append(leadin + key + ': ' + repr(val) + ',')
|
|
|
|
|
else:
|
|
|
|
|
lines.append(leadin + key + ': ' + pformat_value(val, indent + 1) + ',')
|
|
|
|
|
lines.append(leadin + key + ': ' + pformat_value(val, indent + 1) + ',')
|
|
|
|
|
lines.append(level + '}')
|
|
|
|
|
return '\n'.join(lines)
|
|
|
|
|
if isinstance(value, bytearray):
|
|
|
|
|
return 'bytearray(0x{})'.format(binascii.hexlify(value).decode('ascii'))
|
|
|
|
|
if isinstance(value, (bytes, bytearray)):
|
|
|
|
|
length = len(value)
|
|
|
|
|
suffix = ''
|
|
|
|
|
if truncate_after and length > truncate_after:
|
|
|
|
|
suffix = '...'
|
|
|
|
|
value = value[:truncate_to or 0]
|
|
|
|
|
if mostly_printable(value):
|
|
|
|
|
output = repr(value)
|
|
|
|
|
else:
|
|
|
|
|
output = '0x' + binascii.hexlify(value).decode('ascii')
|
|
|
|
|
return '{} bytes {}{}'.format(length, output, suffix)
|
|
|
|
|
|
|
|
|
|
return repr(value)
|
|
|
|
|
|
|
|
|
|
from .messages import Features
|
|
|
|
|
pb_dict = pb.__dict__.copy()
|
|
|
|
|
if collapse_cointypes and isinstance(pb, Features):
|
|
|
|
|
del pb_dict['coins']
|
|
|
|
|
pb_dict['coins (shortened)'] = ' '.join(coin.coin_shortcut for coin in pb.coins)
|
|
|
|
|
|
|
|
|
|
return '{name} ({size} bytes) {content}'.format(
|
|
|
|
|
name=pb.__class__.__name__,
|
|
|
|
|
size=pb.ByteSize(),
|
|
|
|
|
content=pformat_value(pb.__dict__, indent)
|
|
|
|
|
content=pformat_value(pb_dict, indent)
|
|
|
|
|
)
|
|
|
|
|