From 5935c19387a616acdd1c756265d9e3ab6c63a66e Mon Sep 17 00:00:00 2001 From: udf Date: Sun, 4 Nov 2018 14:58:37 +0200 Subject: [PATCH 1/4] Add message info plugin --- stdplugins/info.py | 98 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 98 insertions(+) create mode 100644 stdplugins/info.py diff --git a/stdplugins/info.py b/stdplugins/info.py new file mode 100644 index 0000000..4cd2621 --- /dev/null +++ b/stdplugins/info.py @@ -0,0 +1,98 @@ +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +import string + +from telethon import events +from telethon.utils import add_surrogate +from telethon.tl.types import MessageEntityPre +from telethon.tl.tlobject import TLObject +import datetime + +PRINTABLE_SET = set(bytes(string.printable, 'ascii')) +STR_LEN_MAX = 256 +BYTE_LEN_MAX = 64 + + +def parse_pre(text): + text = text.strip() + return ( + text, + [MessageEntityPre(offset=0, length=len(add_surrogate(text)), language='potato')] + ) + + +def yaml_format(obj, indent=0): + """ + Pretty formats the given object as a YAML string which is returned. + (based on TLObject.pretty_format) + """ + result = [] + if isinstance(obj, TLObject): + obj = obj.to_dict() + + if isinstance(obj, dict): + result.append(obj.get('_', 'dict') + ':') + if obj: + items = obj.items() + has_multiple_items = len(items) > 2 + if has_multiple_items: + result.append('\n') + indent += 2 + for k, v in items: + if k == '_' or v is None: + continue + formatted = yaml_format(v, indent) + if not formatted.strip(): + continue + result.append(' ' * (indent if has_multiple_items else 1)) + result.append(f'{k}: {formatted}') + result.append('\n') + result.pop() + indent -= 2 + result.append(' ' * indent) + elif isinstance(obj, str): + # truncate long strings and display elipsis + result.append(repr(obj[:STR_LEN_MAX])) + if len(obj) > STR_LEN_MAX: + result.append('…') + elif isinstance(obj, bytes): + # repr() bytes if it's printable, hex like "FF EE BB" otherwise + if all(c in PRINTABLE_SET for c in obj): + result.append(repr(obj)) + else: + if len(obj) > BYTE_LEN_MAX: + result.append('<…>') + else: + result.append(' '.join(f'{b:02X}' for b in obj)) + elif isinstance(obj, datetime.datetime): + # ISO-8601 without timezone offset (telethon dates are always UTC) + result.append(obj.strftime('%Y-%m-%d %H:%M:%S')) + elif hasattr(obj, '__iter__'): + # display iterables one after another at the base indentation level + result.append('\n') + indent += 2 + for x in obj: + result.append(' ' * indent) + result.append(yaml_format(x, indent)) + result.append('\n') + result.pop() + indent -= 2 + result.append(' ' * indent) + else: + result.append(repr(obj)) + + return ''.join(result) + + +@borg.on(events.NewMessage(pattern=r"\.info", outgoing=True)) +async def _(event): + if not event.message.is_reply: + return + msg = await event.message.get_reply_message() + yaml_text = yaml_format(msg) + await event.edit( + yaml_text, + parse_mode=parse_pre + ) From e7600622180e44f1e2a4e8ed472fa58a72b66849 Mon Sep 17 00:00:00 2001 From: udf Date: Wed, 21 Nov 2018 22:13:42 +0200 Subject: [PATCH 2/4] Minor code cleanup --- stdplugins/info.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/stdplugins/info.py b/stdplugins/info.py index 4cd2621..260c007 100644 --- a/stdplugins/info.py +++ b/stdplugins/info.py @@ -10,7 +10,7 @@ from telethon.tl.types import MessageEntityPre from telethon.tl.tlobject import TLObject import datetime -PRINTABLE_SET = set(bytes(string.printable, 'ascii')) +PRINTABLE_SET = set(string.printable.encode()) STR_LEN_MAX = 256 BYTE_LEN_MAX = 64 @@ -19,7 +19,7 @@ def parse_pre(text): text = text.strip() return ( text, - [MessageEntityPre(offset=0, length=len(add_surrogate(text)), language='potato')] + [MessageEntityPre(offset=0, length=len(add_surrogate(text)), language='')] ) From 778a604d6941a09f635021559800a136e042c85b Mon Sep 17 00:00:00 2001 From: udf Date: Wed, 21 Nov 2018 22:38:02 +0200 Subject: [PATCH 3/4] Prepend list items with "- " --- stdplugins/info.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/stdplugins/info.py b/stdplugins/info.py index 260c007..8c18420 100644 --- a/stdplugins/info.py +++ b/stdplugins/info.py @@ -74,8 +74,7 @@ def yaml_format(obj, indent=0): result.append('\n') indent += 2 for x in obj: - result.append(' ' * indent) - result.append(yaml_format(x, indent)) + result.append(f"{' ' * indent}- {yaml_format(x, indent + 2)}") result.append('\n') result.pop() indent -= 2 From 35b6e7d1e405d6ab1cefe51263fffd9c85839e14 Mon Sep 17 00:00:00 2001 From: udf Date: Wed, 21 Nov 2018 22:49:17 +0200 Subject: [PATCH 4/4] Return immediately in some cases instead of using the result list I like it better now, but I still dislike it; We need to rewrite the entire function --- stdplugins/info.py | 54 +++++++++++++++++++++++----------------------- 1 file changed, 27 insertions(+), 27 deletions(-) diff --git a/stdplugins/info.py b/stdplugins/info.py index 8c18420..4e8ace0 100644 --- a/stdplugins/info.py +++ b/stdplugins/info.py @@ -33,42 +33,42 @@ def yaml_format(obj, indent=0): obj = obj.to_dict() if isinstance(obj, dict): + if not obj: + return 'dict:' result.append(obj.get('_', 'dict') + ':') - if obj: - items = obj.items() - has_multiple_items = len(items) > 2 - if has_multiple_items: - result.append('\n') - indent += 2 - for k, v in items: - if k == '_' or v is None: - continue - formatted = yaml_format(v, indent) - if not formatted.strip(): - continue - result.append(' ' * (indent if has_multiple_items else 1)) - result.append(f'{k}: {formatted}') - result.append('\n') - result.pop() - indent -= 2 - result.append(' ' * indent) + items = obj.items() + has_multiple_items = len(items) > 2 + if has_multiple_items: + result.append('\n') + indent += 2 + for k, v in items: + if k == '_' or v is None: + continue + formatted = yaml_format(v, indent) + if not formatted.strip(): + continue + result.append(' ' * (indent if has_multiple_items else 1)) + result.append(f'{k}: {formatted}') + result.append('\n') + result.pop() + indent -= 2 + result.append(' ' * indent) elif isinstance(obj, str): # truncate long strings and display elipsis - result.append(repr(obj[:STR_LEN_MAX])) + result = repr(obj[:STR_LEN_MAX]) if len(obj) > STR_LEN_MAX: - result.append('…') + result += '…' + return result elif isinstance(obj, bytes): # repr() bytes if it's printable, hex like "FF EE BB" otherwise if all(c in PRINTABLE_SET for c in obj): - result.append(repr(obj)) + return repr(obj) else: - if len(obj) > BYTE_LEN_MAX: - result.append('<…>') - else: - result.append(' '.join(f'{b:02X}' for b in obj)) + return ('<…>' if len(obj) > BYTE_LEN_MAX else + ' '.join(f'{b:02X}' for b in obj)) elif isinstance(obj, datetime.datetime): # ISO-8601 without timezone offset (telethon dates are always UTC) - result.append(obj.strftime('%Y-%m-%d %H:%M:%S')) + return obj.strftime('%Y-%m-%d %H:%M:%S') elif hasattr(obj, '__iter__'): # display iterables one after another at the base indentation level result.append('\n') @@ -80,7 +80,7 @@ def yaml_format(obj, indent=0): indent -= 2 result.append(' ' * indent) else: - result.append(repr(obj)) + return repr(obj) return ''.join(result)