From 56faccf151716e9a7bbae1109a5f9a01ec4a588a Mon Sep 17 00:00:00 2001 From: Lonami Exo Date: Fri, 4 Feb 2022 12:19:53 +0100 Subject: [PATCH] Fix and update usage of parse_mode --- telethon/_client/auth.py | 6 +--- telethon/_client/messageparse.py | 3 +- telethon/_client/telegrambaseclient.py | 1 - telethon/_client/telegramclient.py | 7 ++-- telethon/_misc/utils.py | 47 ++++++++++---------------- telethon/types/_custom/message.py | 38 +++------------------ telethon_examples/quart_login.py | 7 ++-- 7 files changed, 35 insertions(+), 74 deletions(-) diff --git a/telethon/_client/auth.py b/telethon/_client/auth.py index 7d122d8f..59f64933 100644 --- a/telethon/_client/auth.py +++ b/telethon/_client/auth.py @@ -284,11 +284,7 @@ async def sign_up( pass # code is correct and was used, now need to sign in if self._tos and self._tos.text: - if self.parse_mode: - t = self.parse_mode.unparse(self._tos.text, self._tos.entities) - else: - t = self._tos.text - sys.stderr.write("{}\n".format(t)) + sys.stderr.write("{}\n".format(self._tos.text)) sys.stderr.flush() phone, phone_code_hash = \ diff --git a/telethon/_client/messageparse.py b/telethon/_client/messageparse.py index f545a2f3..1366bca3 100644 --- a/telethon/_client/messageparse.py +++ b/telethon/_client/messageparse.py @@ -4,6 +4,7 @@ import typing from .._misc import helpers, utils from ..types import _custom +from ..types._custom.inputmessage import InputMessage from .. import _tl if typing.TYPE_CHECKING: @@ -29,7 +30,7 @@ async def _parse_message_text(self: 'TelegramClient', message, parse_mode): Returns a (parsed message, entities) tuple depending on ``parse_mode``. """ if parse_mode == (): - parse_mode = self._parse_mode + parse_mode = InputMessage._default_parse_mode else: parse_mode = utils.sanitize_parse_mode(parse_mode) diff --git a/telethon/_client/telegrambaseclient.py b/telethon/_client/telegrambaseclient.py index 8af7ec52..948c6776 100644 --- a/telethon/_client/telegrambaseclient.py +++ b/telethon/_client/telegrambaseclient.py @@ -141,7 +141,6 @@ def init( self._connect_timeout = connect_timeout self.flood_sleep_threshold = flood_sleep_threshold self._flood_waited_requests = {} # prevent calls that would floodwait entirely - self._parse_mode = markdown # Update handling. self._catch_up = catch_up diff --git a/telethon/_client/telegramclient.py b/telethon/_client/telegramclient.py index 851f39d1..0cd55d4a 100644 --- a/telethon/_client/telegramclient.py +++ b/telethon/_client/telegramclient.py @@ -2196,7 +2196,8 @@ class TelegramClient: await client.send_message('me', 'Hello **world**!') # Default to another parse mode - client.parse_mode = 'html' + from telethon.types import Message + Message.set_default_parse_mode('html') await client.send_message('me', 'Some bold and italic text') await client.send_message('me', 'An URL') @@ -2204,8 +2205,8 @@ class TelegramClient: await client.send_message('me', 'Mentions') # Explicit parse mode - # No parse mode by default - client.parse_mode = None + # No parse mode by default (import Message first) + Message.set_default_parse_mode(None) # ...but here I want markdown await client.send_message('me', 'Hello, **world**!', parse_mode='md') diff --git a/telethon/_misc/utils.py b/telethon/_misc/utils.py index b8c62b6a..b2834b93 100644 --- a/telethon/_misc/utils.py +++ b/telethon/_misc/utils.py @@ -748,37 +748,26 @@ def get_attributes(file, *, attributes=None, mime_type=None, return list(attr_dict.values()), mime_type -def sanitize_parse_mode(mode): - """ - Converts the given parse mode into an object with - ``parse`` and ``unparse`` callable properties. - """ - if not mode: - return None - - if callable(mode): - class CustomMode: - @staticmethod - def unparse(text, entities): - raise NotImplementedError - - CustomMode.parse = mode - return CustomMode - elif (all(hasattr(mode, x) for x in ('parse', 'unparse')) - and all(callable(x) for x in (mode.parse, mode.unparse))): - return mode +def sanitize_parse_mode(mode, *, _nop_parse=lambda t: (t, []), _nop_unparse=lambda t, e: t): + if mode is None: + mode = (_nop_parse, _nop_unparse) elif isinstance(mode, str): - try: - return { - 'md': markdown, - 'markdown': markdown, - 'htm': html, - 'html': html - }[mode.lower()] - except KeyError: - raise ValueError('Unknown parse mode {}'.format(mode)) + mode = mode.lower() + if mode in ('md', 'markdown'): + mode = (markdown.parse, markdown.unparse) + elif mode in ('htm', 'html'): + mode = (html.parse, html.unparse) + else: + raise ValueError(f'mode must be one of md, markdown, htm or html, but was {mode!r}') + elif callable(mode): + mode = (mode, _nop_unparse) + elif isinstance(mode, tuple): + if not (len(mode) == 2 and callable(mode[0]) and callable(mode[1])): + raise ValueError(f'mode must be a tuple of exactly two callables') else: - raise TypeError('Invalid parse mode type {}'.format(mode)) + raise TypeError(f'mode must be either a str, callable or tuple, but was {mode!r}') + + return mode def get_input_location(location): diff --git a/telethon/types/_custom/message.py b/telethon/types/_custom/message.py index e1bfff41..17f70a90 100644 --- a/telethon/types/_custom/message.py +++ b/telethon/types/_custom/message.py @@ -489,7 +489,8 @@ class Message(ChatGetter, SenderGetter): * A string equal to ``'md'`` or ``'markdown`` for parsing with commonmark, ``'htm'`` or ``'html'`` for parsing HTML. * A ``callable``, which accepts a ``str`` as input and returns a tuple of - ``(parsed str, formatting entities)``. + ``(parsed str, formatting entities)``. Obtaining formatted text from a message in + this setting is not supported and will instead return the plain text. * A ``tuple`` of two ``callable``. The first must accept a ``str`` as input and return a tuple of ``(parsed str, list of formatting entities)``. The second must accept two parameters, a parsed ``str`` and a ``list`` of formatting entities, and must return @@ -497,25 +498,7 @@ class Message(ChatGetter, SenderGetter): If it's not one of these values or types, the method fails accordingly. """ - if isinstance(mode, str): - mode = mode.lower() - if mode in ('md', 'markdown'): - mode = (_misc.markdown.parse, _misc.markdown.unparse) - elif mode in ('htm', 'html'): - mode = (_misc.html.parse, _misc.html.unparse) - else: - raise ValueError(f'mode must be one of md, markdown, htm or html, but was {mode!r}') - elif callable(mode): - mode = (mode, lambda t, e: t) - elif isinstance(mode, tuple): - if len(mode) == 2 and callable(mode[0]) and callable(mode[1]): - mode = mode - else: - raise ValueError(f'mode must be a tuple of exactly two callables') - else: - raise TypeError(f'mode must be either a str, callable or tuple, but was {mode!r}') - - InputMessage._default_parse_mode = mode + InputMessage._default_parse_mode = utils.sanitize_parse_mode(mode) @classmethod def set_default_link_preview(cls, enabled): @@ -545,22 +528,11 @@ class Message(ChatGetter, SenderGetter): The message text, formatted using the client's default parse mode. Will be `None` for :tl:`MessageService`. """ - if self._text is None and self._client: - if not self._client.parse_mode: - self._text = self.message - else: - self._text = self._client.parse_mode.unparse( - self.message, self.entities) - - return self._text + return InputMessage._default_parse_mode[1](self.message, self.entities) @text.setter def text(self, value): - self._text = value - if self._client and self._client.parse_mode: - self.message, self.entities = self._client.parse_mode.parse(value) - else: - self.message, self.entities = value, [] + self.message, self.entities = InputMessage._default_parse_mode[0](value) @property def raw_text(self): diff --git a/telethon_examples/quart_login.py b/telethon_examples/quart_login.py index 20eae383..507c55a5 100644 --- a/telethon_examples/quart_login.py +++ b/telethon_examples/quart_login.py @@ -5,6 +5,7 @@ import hypercorn.asyncio from quart import Quart, render_template_string, request from telethon import TelegramClient, utils +from telethon.types import Message from telethon.errors import SessionPasswordNeededError @@ -51,9 +52,11 @@ SESSION = os.environ.get('TG_SESSION', 'quart') API_ID = int(get_env('TG_API_ID', 'Enter your API ID: ')) API_HASH = get_env('TG_API_HASH', 'Enter your API hash: ') +# Render things nicely (global setting) +Message.set_default_parse_mode('html') + # Telethon client client = TelegramClient(SESSION, API_ID, API_HASH) -client.parse_mode = 'html' # <- Render things nicely phone = None # Quart app @@ -69,7 +72,7 @@ async def format_message(message): message.raw_text ) else: - # client.parse_mode = 'html', so bold etc. will work! + # The Message parse_mode is 'html', so bold etc. will work! content = (message.text or '(action message)').replace('\n', '
') return '

{}: {}{}

'.format(