Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package python-Telethon for openSUSE:Factory checked in at 2022-10-29 20:17:28 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/python-Telethon (Old) and /work/SRC/openSUSE:Factory/.python-Telethon.new.2275 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python-Telethon" Sat Oct 29 20:17:28 2022 rev:8 rq:1032173 version:1.25.4 Changes: -------- --- /work/SRC/openSUSE:Factory/python-Telethon/python-Telethon.changes 2022-09-26 18:48:30.856089448 +0200 +++ /work/SRC/openSUSE:Factory/.python-Telethon.new.2275/python-Telethon.changes 2022-10-29 20:18:37.534696197 +0200 @@ -1,0 +2,6 @@ +Thu Oct 27 21:22:55 UTC 2022 - Yogalakshmi Arunachalam <yarunacha...@suse.com> + +- Update to 1.25.4 + * Revert accidental NO_UPDATES_TIMEOUT + +------------------------------------------------------------------- Old: ---- Telethon-1.25.0.tar.gz New: ---- Telethon-1.25.4.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ python-Telethon.spec ++++++ --- /var/tmp/diff_new_pack.3dbOnG/_old 2022-10-29 20:18:38.082699117 +0200 +++ /var/tmp/diff_new_pack.3dbOnG/_new 2022-10-29 20:18:38.090699159 +0200 @@ -21,7 +21,7 @@ %define skip_python2 1 %define modname Telethon Name: python-Telethon -Version: 1.25.0 +Version: 1.25.4 Release: 0 Summary: Full-featured Telegram client library for Python 3 License: MIT ++++++ Telethon-1.25.0.tar.gz -> Telethon-1.25.4.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Telethon-1.25.0/.github/ISSUE_TEMPLATE/bug-report.md new/Telethon-1.25.4/.github/ISSUE_TEMPLATE/bug-report.md --- old/Telethon-1.25.0/.github/ISSUE_TEMPLATE/bug-report.md 2022-08-30 12:57:34.000000000 +0200 +++ new/Telethon-1.25.4/.github/ISSUE_TEMPLATE/bug-report.md 2022-10-14 18:43:44.000000000 +0200 @@ -8,9 +8,11 @@ --- **Checklist** + +<!-- Put x inside the boxes (like [x]) to mark them as complete (but only if you've actually completed them!) --> * [ ] The error is in the library's code, and not in my own. * [ ] I have searched for this issue before posting it and there isn't a duplicate. -* [ ] I ran `pip install -U https://github.com/LonamiWebs/Telethon/archive/master.zip` and triggered the bug in the latest version. +* [ ] I ran `pip install -U https://github.com/LonamiWebs/Telethon/archive/v1.zip` and triggered the bug in the latest version. **Code that causes the issue** ```python diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Telethon-1.25.0/readthedocs/basic/installation.rst new/Telethon-1.25.4/readthedocs/basic/installation.rst --- old/Telethon-1.25.0/readthedocs/basic/installation.rst 2022-08-30 12:57:34.000000000 +0200 +++ new/Telethon-1.25.4/readthedocs/basic/installation.rst 2022-10-14 18:43:44.000000000 +0200 @@ -25,7 +25,7 @@ .. code-block:: sh - python3 -m pip install --upgrade https://github.com/LonamiWebs/Telethon/archive/master.zip + python3 -m pip install --upgrade https://github.com/LonamiWebs/Telethon/archive/v1.zip .. note:: diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Telethon-1.25.0/readthedocs/concepts/errors.rst new/Telethon-1.25.4/readthedocs/concepts/errors.rst --- old/Telethon-1.25.0/readthedocs/concepts/errors.rst 2022-08-30 12:57:34.000000000 +0200 +++ new/Telethon-1.25.4/readthedocs/concepts/errors.rst 2022-10-14 18:43:44.000000000 +0200 @@ -150,6 +150,6 @@ VoIP numbers are very limited, and some countries are more limited too. -.. _list of known errors: https://github.com/LonamiWebs/Telethon/blob/master/telethon_generator/data/errors.csv +.. _list of known errors: https://github.com/LonamiWebs/Telethon/blob/v1/telethon_generator/data/errors.csv .. _raw API page: https://tl.telethon.dev/ .. _messages.sendMessage: https://tl.telethon.dev/methods/messages/send_message.html diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Telethon-1.25.0/readthedocs/examples/users.rst new/Telethon-1.25.4/readthedocs/examples/users.rst --- old/Telethon-1.25.0/readthedocs/examples/users.rst 2022-08-30 12:57:34.000000000 +0200 +++ new/Telethon-1.25.4/readthedocs/examples/users.rst 2022-10-14 18:43:44.000000000 +0200 @@ -25,7 +25,7 @@ # or even full = await client(GetFullUserRequest('username')) - bio = full.about + bio = full.full_user.about See :tl:`UserFull` to know what other fields you can access. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Telethon-1.25.0/readthedocs/examples/working-with-messages.rst new/Telethon-1.25.4/readthedocs/examples/working-with-messages.rst --- old/Telethon-1.25.0/readthedocs/examples/working-with-messages.rst 2022-08-30 12:57:34.000000000 +0200 +++ new/Telethon-1.25.4/readthedocs/examples/working-with-messages.rst 2022-10-14 18:43:44.000000000 +0200 @@ -42,4 +42,49 @@ await client.send_file('me', stickers.documents[0]) -.. _issues: https://github.com/LonamiWebs/Telethon/issues/215 +Sending reactions +================= + +It works very similar to replying to a message. You need to specify the chat, +message ID you wish to react to, and reaction, using :tl:`SendReaction`: + +.. code-block:: python + + from telethon.tl.functions.messages import SendReactionRequest + + await client(SendReactionRequest( + peer=chat, + msg_id=42, + reaction='??????' + )) + +Note that you cannot use strings like ``:heart:`` for the reaction. You must +use the desired emoji directly. You can most easily achieve this by +copy-pasting the emoji from an official application such as Telegram Desktop. + +If for some reason you cannot embed emoji directly into the code, you can also +use its unicode escape (which you can find using websites like +`unicode-table.com`_), or install a different package, like `emoji`_: + +.. code-block:: python + + # All of these work exactly the same (you only need one): + import emoji + reaction = emoji.emojize(':red_heart:') + reaction = '??????' + reaction = '\u2764' + + from telethon.tl.functions.messages import SendReactionRequest + await client(SendReactionRequest( + peer=chat, + msg_id=42, + reaction=reaction + )) + +Please make sure to check the help pages of the respective websites you use +if you need a more in-depth explanation on how they work. Telethon only needs +you to provide the emoji in some form. Some packages or websites can make this +easier. + +.. _unicode-table.com: https://unicode-table.com/en/emoji/ +.. _emoji: https://pypi.org/project/emoji/ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Telethon-1.25.0/readthedocs/misc/changelog.rst new/Telethon-1.25.4/readthedocs/misc/changelog.rst --- old/Telethon-1.25.0/readthedocs/misc/changelog.rst 2022-08-30 12:57:34.000000000 +0200 +++ new/Telethon-1.25.4/readthedocs/misc/changelog.rst 2022-10-14 18:43:44.000000000 +0200 @@ -13,6 +13,37 @@ .. contents:: List of All Versions +Bug fixes (v1.25.1) +=================== + +This version should fix some of the problems that came with the revamped +update handling. + +* Some inline URLs were not parsing correctly with markdown. +* ``events.Raw`` was handling :tl:`UpdateShort` which it shouldn't do. +* ``events.Album`` should now work again. +* ``CancelledError`` was being incorrectly logged as a fatal error. +* Some fixes to update handling primarly aimed for bot accounts. +* Update handling now can deal with more errors without crashing. +* Unhandled errors from update handling will now be propagated through + ``client.run_until_disconnected``. +* Invite links with ``+`` are now recognized. +* Added new known RPC errors. +* ``telethon.types`` could not be used as a module. +* 0-length message entities are now stripped to avoid errors. +* ``client.send_message`` was not returning a message with ``reply_to`` + in some cases. +* ``aggressive`` in ``client.iter_participants`` now does nothing (it did + not really work anymore anyway, and this should prevent other errors). +* ``client.iter_participants`` was failing in some groups. +* Text with HTML URLs could sometimes fail to parse. +* Added a hard timeout during disconnect in order to prevent the program + from freezing. + +Please be sure to report issues with update handling if you still encounter +some errors! + + Update handling overhaul (v1.25) ================================ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Telethon-1.25.0/readthedocs/quick-references/faq.rst new/Telethon-1.25.4/readthedocs/quick-references/faq.rst --- old/Telethon-1.25.0/readthedocs/quick-references/faq.rst 2022-08-30 12:57:34.000000000 +0200 +++ new/Telethon-1.25.4/readthedocs/quick-references/faq.rst 2022-10-14 18:43:44.000000000 +0200 @@ -239,4 +239,4 @@ .. _logging: https://docs.python.org/3/library/logging.html .. _@SpamBot: https://t.me/SpamBot .. _issue 297: https://github.com/LonamiWebs/Telethon/issues/297 -.. _quart_login.py: https://github.com/LonamiWebs/Telethon/tree/master/telethon_examples#quart_loginpy +.. _quart_login.py: https://github.com/LonamiWebs/Telethon/tree/v1/telethon_examples#quart_loginpy diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Telethon-1.25.0/telethon/__init__.py new/Telethon-1.25.4/telethon/__init__.py --- old/Telethon-1.25.0/telethon/__init__.py 2022-08-30 12:57:34.000000000 +0200 +++ new/Telethon-1.25.4/telethon/__init__.py 2022-10-14 18:43:44.000000000 +0200 @@ -1,9 +1,8 @@ from .client.telegramclient import TelegramClient from .network import connection -from .tl import types, functions, custom from .tl.custom import Button from .tl import patched as _ # import for its side-effects -from . import version, events, utils, errors +from . import version, events, utils, errors, types, functions, custom __version__ = version.__version__ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Telethon-1.25.0/telethon/_updates/messagebox.py new/Telethon-1.25.4/telethon/_updates/messagebox.py --- old/Telethon-1.25.0/telethon/_updates/messagebox.py 2022-08-30 12:57:34.000000000 +0200 +++ new/Telethon-1.25.4/telethon/_updates/messagebox.py 2022-10-14 18:43:44.000000000 +0200 @@ -22,6 +22,7 @@ from enum import Enum from .session import SessionState, ChannelState from ..tl import types as tl, functions as fn +from ..helpers import get_running_loop # Telegram sends `seq` equal to `0` when "it doesn't matter", so we use that value too. @@ -53,7 +54,7 @@ _sentinel = object() def next_updates_deadline(): - return asyncio.get_running_loop().time() + NO_UPDATES_TIMEOUT + return get_running_loop().time() + NO_UPDATES_TIMEOUT class GapError(ValueError): @@ -237,7 +238,7 @@ If a deadline expired, the corresponding entries will be marked as needing to get its difference. While there are entries pending of getting their difference, this method returns the current instant. """ - now = asyncio.get_running_loop().time() + now = get_running_loop().time() if self.getting_diff_for: return now @@ -283,7 +284,7 @@ # Convenience to reset a channel's deadline, with optional timeout. def reset_channel_deadline(self, channel_id, timeout): - self.reset_deadline(channel_id, asyncio.get_running_loop().time() + (timeout or NO_UPDATES_TIMEOUT)) + self.reset_deadline(channel_id, get_running_loop().time() + (timeout or NO_UPDATES_TIMEOUT)) # Reset all the deadlines in `reset_deadlines_for` and then empty the set. def apply_deadlines_reset(self): @@ -302,15 +303,22 @@ # # Should be called right after login if [`MessageBox::new`] was used, otherwise undesirable # updates will be fetched. - def set_state(self, state): + def set_state(self, state, reset=True): deadline = next_updates_deadline() - if state.pts != NO_SEQ: + if state.pts != NO_SEQ or not reset: self.map[ENTRY_ACCOUNT] = State(pts=state.pts, deadline=deadline) else: self.map.pop(ENTRY_ACCOUNT, None) - if state.qts != NO_SEQ: + # Telegram seems to use the `qts` for bot accounts, but while applying difference, + # it might be reset back to 0. See issue #3873 for more details. + # + # During login, a value of zero would mean the `pts` is unknown, + # so the map shouldn't contain that entry. + # But while applying difference, if the value is zero, it (probably) + # truly means that's what should be used (hence the `reset` flag). + if state.qts != NO_SEQ or not reset: self.map[ENTRY_SECRET] = State(pts=state.qts, deadline=deadline) else: self.map.pop(ENTRY_SECRET, None) @@ -392,7 +400,9 @@ seq_start = getattr(updates, 'seq_start', None) or seq users = getattr(updates, 'users', None) or [] chats = getattr(updates, 'chats', None) or [] - updates = getattr(updates, 'updates', None) or [updates] + + # updateShort is the only update which cannot be dispatched directly but doesn't have 'updates' field + updates = getattr(updates, 'updates', None) or [updates.update if isinstance(updates, tl.UpdateShort) else updates] for u in updates: u._self_outgoing = self_outgoing @@ -487,7 +497,7 @@ # TODO store chats too? if pts.entry not in self.possible_gaps: self.possible_gaps[pts.entry] = PossibleGap( - deadline=asyncio.get_running_loop().time() + POSSIBLE_GAP_TIMEOUT, + deadline=get_running_loop().time() + POSSIBLE_GAP_TIMEOUT, updates=[] ) @@ -584,7 +594,7 @@ chat_hashes, ): state = getattr(diff, 'intermediate_state', None) or diff.state - self.set_state(state) + self.set_state(state, reset=False) # diff.other_updates can contain things like UpdateChannelTooLong and UpdateNewChannelMessage. # We need to process those as if they were socket updates to discard any we have already handled. @@ -609,6 +619,19 @@ return updates, diff.users, diff.chats + def end_difference(self): + account = ENTRY_ACCOUNT in self.getting_diff_for + secret = ENTRY_SECRET in self.getting_diff_for + + if not account and not secret: + raise RuntimeWarning('Should not be ending get difference when neither account or secret was diff was active') + + # Both may be active if both expired at the same time. + if account: + self.end_get_diff(ENTRY_ACCOUNT) + if secret: + self.end_get_diff(ENTRY_SECRET) + # endregion Getting and applying account difference. # region Getting and applying channel difference. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Telethon-1.25.0/telethon/client/auth.py new/Telethon-1.25.4/telethon/client/auth.py --- old/Telethon-1.25.0/telethon/client/auth.py 2022-08-30 12:57:34.000000000 +0200 +++ new/Telethon-1.25.4/telethon/client/auth.py 2022-10-14 18:43:44.000000000 +0200 @@ -586,6 +586,9 @@ # Important! You need to wait for the login to complete! await qr_login.wait() + + # If you have 2FA enabled, `wait` will raise `telethon.errors.SessionPasswordNeededError`. + # You should except that error and call `sign_in` with the password if this happens. """ qr_login = custom.QRLogin(self, ignored_ids or []) await qr_login.recreate() @@ -595,6 +598,8 @@ """ Logs out Telegram and deletes the current ``*.session`` file. + The client is unusable after logging out and a new instance should be created. + Returns `True` if the operation was successful. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Telethon-1.25.0/telethon/client/chats.py new/Telethon-1.25.4/telethon/client/chats.py --- old/Telethon-1.25.0/telethon/client/chats.py 2022-08-30 12:57:34.000000000 +0200 +++ new/Telethon-1.25.4/telethon/client/chats.py 2022-10-14 18:43:44.000000000 +0200 @@ -97,7 +97,7 @@ class _ParticipantsIter(RequestIter): - async def _init(self, entity, filter, search, aggressive): + async def _init(self, entity, filter, search): if isinstance(filter, type): if filter in (types.ChannelParticipantsBanned, types.ChannelParticipantsKicked, @@ -122,7 +122,8 @@ self.filter_entity = lambda ent: True # Only used for channels, but we should always set the attribute - self.requests = [] + # Called `requests` even though it's just one for legacy purposes. + self.requests = None if ty == helpers._EntityType.CHANNEL: if self.limit <= 0: @@ -133,22 +134,13 @@ raise StopAsyncIteration self.seen = set() - if aggressive and not filter: - self.requests.extend(functions.channels.GetParticipantsRequest( - channel=entity, - filter=types.ChannelParticipantsSearch(x), - offset=0, - limit=_MAX_PARTICIPANTS_CHUNK_SIZE, - hash=0 - ) for x in (search or string.ascii_lowercase)) - else: - self.requests.append(functions.channels.GetParticipantsRequest( - channel=entity, - filter=filter or types.ChannelParticipantsSearch(search), - offset=0, - limit=_MAX_PARTICIPANTS_CHUNK_SIZE, - hash=0 - )) + self.requests = functions.channels.GetParticipantsRequest( + channel=entity, + filter=filter or types.ChannelParticipantsSearch(search), + offset=0, + limit=_MAX_PARTICIPANTS_CHUNK_SIZE, + hash=0 + ) elif ty == helpers._EntityType.CHAT: full = await self.client( @@ -163,7 +155,10 @@ users = {user.id: user for user in full.users} for participant in full.full_chat.participants.participants: - if isinstance(participant, types.ChannelParticipantBanned): + if isinstance(participant, types.ChannelParticipantLeft): + # See issue #3231 to learn why this is ignored. + continue + elif isinstance(participant, types.ChannelParticipantBanned): user_id = participant.peer.user_id else: user_id = participant.user_id @@ -190,21 +185,14 @@ if not self.requests: return True - # Only care about the limit for the first request - # (small amount of people, won't be aggressive). - # - # Most people won't care about getting exactly 12,345 - # members so it doesn't really matter not to be 100% - # precise with being out of the offset/limit here. - self.requests[0].limit = min( - self.limit - self.requests[0].offset, _MAX_PARTICIPANTS_CHUNK_SIZE) + self.requests.limit = min(self.limit - self.requests.offset, _MAX_PARTICIPANTS_CHUNK_SIZE) - if self.requests[0].offset > self.limit: + if self.requests.offset > self.limit: return True if self.total is None: - f = self.requests[0].filter - if len(self.requests) > 1 or ( + f = self.requests.filter + if ( not isinstance(f, types.ChannelParticipantsRecent) and (not isinstance(f, types.ChannelParticipantsSearch) or f.q) ): @@ -212,42 +200,40 @@ # if there's a filter which would reduce the real total number. # getParticipants is cheaper than getFull. self.total = (await self.client(functions.channels.GetParticipantsRequest( - channel=self.requests[0].channel, + channel=self.requests.channel, filter=types.ChannelParticipantsRecent(), offset=0, limit=1, hash=0 ))).count - results = await self.client(self.requests) - for i in reversed(range(len(self.requests))): - participants = results[i] - if self.total is None: - # Will only get here if there was one request with a filter that matched all users. - self.total = participants.count - if not participants.users: - self.requests.pop(i) - continue - - self.requests[i].offset += len(participants.participants) - users = {user.id: user for user in participants.users} - for participant in participants.participants: - - if isinstance(participant, types.ChannelParticipantBanned): - if not isinstance(participant.peer, types.PeerUser): - # May have the entire channel banned. See #3105. - continue - user_id = participant.peer.user_id - else: - user_id = participant.user_id - - user = users[user_id] - if not self.filter_entity(user) or user.id in self.seen: + participants = await self.client(self.requests) + if self.total is None: + # Will only get here if there was one request with a filter that matched all users. + self.total = participants.count + if not participants.users: + self.requests = None + return + + self.requests.offset += len(participants.participants) + users = {user.id: user for user in participants.users} + for participant in participants.participants: + + if isinstance(participant, types.ChannelParticipantBanned): + if not isinstance(participant.peer, types.PeerUser): + # May have the entire channel banned. See #3105. continue - self.seen.add(user_id) - user = users[user_id] - user.participant = participant - self.buffer.append(user) + user_id = participant.peer.user_id + else: + user_id = participant.user_id + + user = users[user_id] + if not self.filter_entity(user) or user.id in self.seen: + continue + self.seen.add(user_id) + user = users[user_id] + user.participant = participant + self.buffer.append(user) class _AdminLogIter(RequestIter): @@ -431,9 +417,6 @@ search (`str`, optional): Look for participants with this string in name/username. - If ``aggressive is True``, the symbols from this string will - be used. - filter (:tl:`ChannelParticipantsFilter`, optional): The filter to be used, if you want e.g. only admins Note that you might not have permissions for some filter. @@ -446,14 +429,11 @@ use :tl:`ChannelParticipantsKicked` instead. aggressive (`bool`, optional): - Aggressively looks for all participants in the chat. - - This is useful for channels since 20 July 2018, - Telegram added a server-side limit where only the - first 200 members can be retrieved. With this flag - set, more than 200 will be often be retrieved. + Does nothing. This is kept for backwards-compatibility. - This has no effect if a ``filter`` is given. + There have been several changes to Telegram's API that limits + the amount of members that can be retrieved, and this was a + hack that no longer works. Yields The :tl:`User` objects returned by :tl:`GetParticipantsRequest` @@ -482,8 +462,7 @@ limit, entity=entity, filter=filter, - search=search, - aggressive=aggressive + search=search ) async def get_participants( @@ -987,7 +966,7 @@ is_admin = any(locals()[x] for x in perm_names) return await self(functions.messages.EditChatAdminRequest( - entity, user, is_admin=is_admin)) + entity.chat_id, user, is_admin=is_admin)) else: raise ValueError( @@ -1259,7 +1238,7 @@ if isinstance(entity, types.Channel): FullChat = await self(functions.channels.GetFullChannelRequest(entity)) elif isinstance(entity, types.Chat): - FullChat = await self(functions.messages.GetFullChatRequest(entity)) + FullChat = await self(functions.messages.GetFullChatRequest(entity.id)) else: return return FullChat.chats[0].default_banned_rights @@ -1276,7 +1255,7 @@ return custom.ParticipantPermissions(participant.participant, False) elif helpers._entity_type(entity) == helpers._EntityType.CHAT: chat = await self(functions.messages.GetFullChatRequest( - entity + entity.chat_id )) if isinstance(user, types.InputPeerSelf): user = await self.get_me(input_peer=True) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Telethon-1.25.0/telethon/client/dialogs.py new/Telethon-1.25.4/telethon/client/dialogs.py --- old/Telethon-1.25.0/telethon/client/dialogs.py 2022-08-30 12:57:34.000000000 +0200 +++ new/Telethon-1.25.4/telethon/client/dialogs.py 2022-10-14 18:43:44.000000000 +0200 @@ -58,6 +58,8 @@ for x in itertools.chain(r.users, r.chats) if not isinstance(x, (types.UserEmpty, types.ChatEmpty))} + self.client._mb_entity_cache.extend(r.users, r.chats) + messages = {} for m in r.messages: m._finish_init(self.client, entities, None) @@ -82,7 +84,8 @@ cd = custom.Dialog(self.client, d, entities, message) if cd.dialog.pts: - self.client._channel_pts[cd.id] = cd.dialog.pts + self.client._message_box.try_set_channel_state( + utils.get_peer_id(d.peer, add_mark=False), cd.dialog.pts) if not self.ignore_migrated or getattr( cd.entity, 'migrated_to', None) is None: diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Telethon-1.25.0/telethon/client/downloads.py new/Telethon-1.25.4/telethon/client/downloads.py --- old/Telethon-1.25.0/telethon/client/downloads.py 2022-08-30 12:57:34.000000000 +0200 +++ new/Telethon-1.25.4/telethon/client/downloads.py 2022-10-14 18:43:44.000000000 +0200 @@ -272,7 +272,9 @@ if isinstance(photo, (types.UserProfilePhoto, types.ChatPhoto)): dc_id = photo.dc_id loc = types.InputPeerPhotoFileLocation( - peer=await self.get_input_entity(entity), + # min users can be used to download profile photos + # self.get_input_entity would otherwise not accept those + peer=utils.get_input_peer(entity, check_hash=False), photo_id=photo.photo_id, big=download_big ) @@ -402,7 +404,7 @@ if isinstance(message.action, types.MessageActionChatEditPhoto): media = media.photo - + if isinstance(media, types.MessageMediaWebPage): if isinstance(media.webpage, types.WebPage): media = media.webpage.document or media.webpage.photo diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Telethon-1.25.0/telethon/client/messageparse.py new/Telethon-1.25.4/telethon/client/messageparse.py --- old/Telethon-1.25.0/telethon/client/messageparse.py 2022-08-30 12:57:34.000000000 +0200 +++ new/Telethon-1.25.4/telethon/client/messageparse.py 2022-10-14 18:43:44.000000000 +0200 @@ -87,10 +87,15 @@ message, msg_entities = parse_mode.parse(message) if original_message and not message and not msg_entities: raise ValueError("Failed to parse message") - + for i in reversed(range(len(msg_entities))): e = msg_entities[i] - if isinstance(e, types.MessageEntityTextUrl): + if not e.length: + # 0-length MessageEntity is no longer valid #3884. + # Because the user can provide their own parser (with reasonable 0-length + # entities), strip them here rather than fixing the built-in parsers. + del msg_entities[i] + elif isinstance(e, types.MessageEntityTextUrl): m = re.match(r'^@|\+|tg://user\?id=(\d+)', e.url) if m: user = int(m.group(1)) if m.group(1) else e.url diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Telethon-1.25.0/telethon/client/messages.py new/Telethon-1.25.4/telethon/client/messages.py --- old/Telethon-1.25.0/telethon/client/messages.py 2022-08-30 12:57:34.000000000 +0200 +++ new/Telethon-1.25.4/telethon/client/messages.py 2022-10-14 18:43:44.000000000 +0200 @@ -204,7 +204,20 @@ message._finish_init(self.client, entities, self.entity) self.buffer.append(message) - if len(r.messages) < self.request.limit: + # Some channels are "buggy" and may return less messages than + # requested (apparently, the messages excluded are, for example, + # "not displayable due to local laws"). + # + # This means it's not safe to rely on `len(r.messages) < req.limit` as + # the stop condition. Unfortunately more requests must be made. + # + # However we can still check if the highest ID is equal to or lower + # than the limit, in which case there won't be any more messages + # because the lowest message ID is 1. + # + # We also assume the API will always return, at least, one message if + # there is more to fetch. + if not r.messages or r.messages[0].id <= self.request.limit: return True # Get the last message that's not empty (in some rare cases @@ -618,7 +631,7 @@ thumb: 'hints.FileLike' = None, force_document: bool = False, clear_draft: bool = False, - buttons: 'hints.MarkupLike' = None, + buttons: typing.Optional['hints.MarkupLike'] = None, silent: bool = None, background: bool = None, supports_streaming: bool = False, @@ -880,7 +893,8 @@ media=result.media, entities=result.entities, reply_markup=request.reply_markup, - ttl_period=result.ttl_period + ttl_period=result.ttl_period, + reply_to=types.MessageReplyHeader(request.reply_to_msg_id) ) message._finish_init(self, {}, entity) return message @@ -1029,7 +1043,7 @@ file: 'hints.FileLike' = None, thumb: 'hints.FileLike' = None, force_document: bool = False, - buttons: 'hints.MarkupLike' = None, + buttons: typing.Optional['hints.MarkupLike'] = None, supports_streaming: bool = False, schedule: 'hints.DateLike' = None ) -> 'types.Message': diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Telethon-1.25.0/telethon/client/telegrambaseclient.py new/Telethon-1.25.4/telethon/client/telegrambaseclient.py --- old/Telethon-1.25.0/telethon/client/telegrambaseclient.py 2022-08-30 12:57:34.000000000 +0200 +++ new/Telethon-1.25.4/telethon/client/telegrambaseclient.py 2022-10-14 18:43:44.000000000 +0200 @@ -386,10 +386,10 @@ self._borrowed_senders = {} self._borrow_sender_lock = asyncio.Lock() + self._updates_error = None self._updates_handle = None self._keepalive_handle = None self._last_request = time.time() - self._channel_pts = {} self._no_updates = not receive_updates # Used for non-sequential updates, in order to terminate all pending tasks on disconnect. @@ -591,6 +591,12 @@ coroutine that you should await on your own code; otherwise the loop is ran until said coroutine completes. + Event handlers which are currently running will be cancelled before + this function returns (in order to properly clean-up their tasks). + In particular, this means that using ``disconnect`` in a handler + will cause code after the ``disconnect`` to never run. If this is + needed, consider spawning a separate task to do the remaining work. + Example .. code-block:: python @@ -598,7 +604,11 @@ await client.disconnect() """ if self.loop.is_running(): - return self._disconnect_coro() + # Disconnect may be called from an event handler, which would + # cancel itself during itself and never actually complete the + # disconnection. Shield the task to prevent disconnect itself + # from being cancelled. See issue #3942 for more details. + return asyncio.shield(self.loop.create_task(self._disconnect_coro())) else: try: self.loop.run_until_complete(self._disconnect_coro()) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Telethon-1.25.0/telethon/client/updates.py new/Telethon-1.25.4/telethon/client/updates.py --- old/Telethon-1.25.0/telethon/client/updates.py 2022-08-30 12:57:34.000000000 +0200 +++ new/Telethon-1.25.4/telethon/client/updates.py 2022-10-14 18:43:44.000000000 +0200 @@ -13,6 +13,8 @@ from ..events.common import EventBuilder, EventCommon from ..tl import types, functions from .._updates import GapError, PrematureEndReason +from ..helpers import get_running_loop + if typing.TYPE_CHECKING: from .telegramclient import TelegramClient @@ -28,7 +30,10 @@ try: # Make a high-level request to notify that we want updates await self(functions.updates.GetStateRequest()) - return await self.disconnected + result = await self.disconnected + if self._updates_error is not None: + raise self._updates_error + return result except KeyboardInterrupt: pass finally: @@ -51,6 +56,8 @@ It also notifies Telegram that we want to receive updates as described in https://core.telegram.org/api/updates. + If an unexpected error occurs during update handling, + the client will disconnect and said error will be raised. Manual disconnections can be made by calling `disconnect() <telethon.client.telegrambaseclient.TelegramBaseClient.disconnect>` @@ -246,6 +253,7 @@ # region Private methods async def _update_loop(self: 'TelegramClient'): + self._updates_error = None try: if self._catch_up: # User wants to catch up as soon as the client is up and running, @@ -260,6 +268,7 @@ await self._dispatch_update(updates_to_dispatch.popleft()) else: while updates_to_dispatch: + # TODO if _dispatch_update fails for whatever reason, it's not logged! this should be fixed task = self.loop.create_task(self._dispatch_update(updates_to_dispatch.popleft())) self._event_handler_tasks.add(task) task.add_done_callback(lambda _: self._event_handler_tasks.discard(task)) @@ -268,18 +277,39 @@ get_diff = self._message_box.get_difference() if get_diff: - self._log[__name__].info('Getting difference for account updates') - diff = await self(get_diff) + self._log[__name__].debug('Getting difference for account updates') + try: + diff = await self(get_diff) + except (errors.ServerError, ValueError) as e: + # Telegram is having issues + self._log[__name__].info('Cannot get difference since Telegram is having issues: %s', type(e).__name__) + self._message_box.end_difference() + continue + except (errors.UnauthorizedError, errors.AuthKeyError) as e: + # Not logged in or broken authorization key, can't get difference + self._log[__name__].info('Cannot get difference since the account is not logged in: %s', type(e).__name__) + self._message_box.end_difference() + continue updates, users, chats = self._message_box.apply_difference(diff, self._mb_entity_cache) + if updates: + self._log[__name__].info('Got difference for account updates') + updates_to_dispatch.extend(self._preprocess_updates(updates, users, chats)) continue get_diff = self._message_box.get_channel_difference(self._mb_entity_cache) if get_diff: - self._log[__name__].info('Getting difference for channel updates') + self._log[__name__].debug('Getting difference for channel %s updates', get_diff.channel.channel_id) try: diff = await self(get_diff) - except (errors.PersistentTimestampOutdatedError, errors.PersistentTimestampInvalidError, ValueError) as e: + except ( + errors.PersistentTimestampOutdatedError, + errors.PersistentTimestampInvalidError, + errors.ServerError, + errors.UnauthorizedError, + errors.AuthKeyError, + ValueError + ) as e: # According to Telegram's docs: # "Channel internal replication issues, try again later (treat this like an RPC_CALL_FAIL)." # We can treat this as "empty difference" and not update the local pts. @@ -296,15 +326,10 @@ # Somehow our pts is either too new or the server does not know about this. # We treat this as PersistentTimestampOutdatedError for now. # TODO investigate why/when this happens and if this is the proper solution - if isinstance(e, errors.PersistentTimestampOutdatedError): - reason = 'caused PersistentTimestampOutdated' - elif isinstance(e, errors.PersistentTimestampInvalidError): - reason = 'caused PersistentTimestampInvalidError' - else: - reason = 'is failing' self._log[__name__].warning( - 'Getting difference for channel updates %s;' - ' ending getting difference prematurely until server issues are resolved', reason + 'Getting difference for channel updates %s caused %s;' + ' ending getting difference prematurely until server issues are resolved', + get_diff.channel.channel_id, type(e).__name__ ) self._message_box.end_channel_difference( get_diff, @@ -328,17 +353,20 @@ continue updates, users, chats = self._message_box.apply_channel_difference(get_diff, diff, self._mb_entity_cache) + if updates: + self._log[__name__].info('Got difference for channel %d updates', get_diff.channel.channel_id) + updates_to_dispatch.extend(self._preprocess_updates(updates, users, chats)) continue deadline = self._message_box.check_deadlines() - deadline_delay = deadline - asyncio.get_running_loop().time() + deadline_delay = deadline - get_running_loop().time() if deadline_delay > 0: # Don't bother sleeping and timing out if the delay is already 0 (pollutes the logs). try: updates = await asyncio.wait_for(self._updates_queue.get(), deadline_delay) except asyncio.TimeoutError: - self._log[__name__].info('Timeout waiting for updates expired') + self._log[__name__].debug('Timeout waiting for updates expired') continue else: continue @@ -350,8 +378,12 @@ continue # get(_channel)_difference will start returning requests updates_to_dispatch.extend(self._preprocess_updates(processed, users, chats)) - except Exception: + except asyncio.CancelledError: + pass + except Exception as e: self._log[__name__].exception('Fatal error handling updates (this is a bug in Telethon, please report it)') + self._updates_error = e + await self.disconnect() def _preprocess_updates(self, updates, users, chats): self._mb_entity_cache.extend(users, chats) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Telethon-1.25.0/telethon/client/uploads.py new/Telethon-1.25.4/telethon/client/uploads.py --- old/Telethon-1.25.0/telethon/client/uploads.py 2022-08-30 12:57:34.000000000 +0200 +++ new/Telethon-1.25.4/telethon/client/uploads.py 2022-10-14 18:43:44.000000000 +0200 @@ -110,7 +110,7 @@ formatting_entities: typing.Optional[typing.List[types.TypeMessageEntity]] = None, voice_note: bool = False, video_note: bool = False, - buttons: 'hints.MarkupLike' = None, + buttons: typing.Optional['hints.MarkupLike'] = None, silent: bool = None, background: bool = None, supports_streaming: bool = False, diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Telethon-1.25.0/telethon/custom.py new/Telethon-1.25.4/telethon/custom.py --- old/Telethon-1.25.0/telethon/custom.py 1970-01-01 01:00:00.000000000 +0100 +++ new/Telethon-1.25.4/telethon/custom.py 2022-10-14 18:43:44.000000000 +0200 @@ -0,0 +1 @@ +from .tl.custom import * diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Telethon-1.25.0/telethon/events/album.py new/Telethon-1.25.4/telethon/events/album.py --- old/Telethon-1.25.0/telethon/events/album.py 2022-08-30 12:57:34.000000000 +0200 +++ new/Telethon-1.25.4/telethon/events/album.py 2022-10-14 18:43:44.000000000 +0200 @@ -97,8 +97,10 @@ @classmethod def build(cls, update, others=None, self_id=None): - if not others: - return # We only care about albums which come inside the same Updates + # TODO normally we'd only check updates if they come with other updates + # but MessageBox is not designed for this so others will always be None. + # In essence we always rely on AlbumHack rather than returning early if not others. + others = [update] if isinstance(update, (types.UpdateNewMessage, types.UpdateNewChannelMessage)): @@ -150,16 +152,8 @@ """ def __init__(self, messages): message = messages[0] - if not message.out and isinstance(message.peer_id, types.PeerUser): - # Incoming message (e.g. from a bot) has peer_id=us, and - # from_id=bot (the actual "chat" from a user's perspective). - chat_peer = message.from_id - else: - chat_peer = message.peer_id - - super().__init__(chat_peer=chat_peer, + super().__init__(chat_peer=message.peer_id, msg_id=message.id, broadcast=bool(message.post)) - SenderGetter.__init__(self, message.sender_id) self.messages = messages diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Telethon-1.25.0/telethon/extensions/html.py new/Telethon-1.25.4/telethon/extensions/html.py --- old/Telethon-1.25.0/telethon/extensions/html.py 2022-08-30 12:57:34.000000000 +0200 +++ new/Telethon-1.25.4/telethon/extensions/html.py 2022-10-14 18:43:44.000000000 +0200 @@ -86,7 +86,7 @@ EntityType = MessageEntityUrl else: EntityType = MessageEntityTextUrl - args['url'] = url + args['url'] = _del_surrogate(url) url = None self._open_tags_meta.popleft() self._open_tags_meta.appendleft(url) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Telethon-1.25.0/telethon/extensions/markdown.py new/Telethon-1.25.4/telethon/extensions/markdown.py --- old/Telethon-1.25.0/telethon/extensions/markdown.py 2022-08-30 12:57:34.000000000 +0200 +++ new/Telethon-1.25.4/telethon/extensions/markdown.py 2022-10-14 18:43:44.000000000 +0200 @@ -22,7 +22,7 @@ '```': MessageEntityPre } -DEFAULT_URL_RE = re.compile(r'\[([\S\s]+?)\]\((.+?)\)') +DEFAULT_URL_RE = re.compile(r'\[([^\]]+)\]\(([^)]+)\)') DEFAULT_URL_FORMAT = '[{0}]({1})' diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Telethon-1.25.0/telethon/functions.py new/Telethon-1.25.4/telethon/functions.py --- old/Telethon-1.25.0/telethon/functions.py 1970-01-01 01:00:00.000000000 +0100 +++ new/Telethon-1.25.4/telethon/functions.py 2022-10-14 18:43:44.000000000 +0200 @@ -0,0 +1 @@ +from .tl.functions import * diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Telethon-1.25.0/telethon/helpers.py new/Telethon-1.25.4/telethon/helpers.py --- old/Telethon-1.25.0/telethon/helpers.py 2022-08-30 12:57:34.000000000 +0200 +++ new/Telethon-1.25.4/telethon/helpers.py 2022-10-14 18:43:44.000000000 +0200 @@ -7,6 +7,7 @@ import inspect import logging import functools +import sys from pathlib import Path from hashlib import sha1 @@ -423,3 +424,9 @@ pass # endregion + +def get_running_loop(): + if sys.version_info[:2] <= (3, 6): + return asyncio._get_running_loop() + + return asyncio.get_running_loop() diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Telethon-1.25.0/telethon/network/connection/connection.py new/Telethon-1.25.4/telethon/network/connection/connection.py --- old/Telethon-1.25.0/telethon/network/connection/connection.py 2022-08-30 12:57:34.000000000 +0200 +++ new/Telethon-1.25.4/telethon/network/connection/connection.py 2022-10-14 18:43:44.000000000 +0200 @@ -265,7 +265,12 @@ self._writer.close() if sys.version_info >= (3, 7): try: - await self._writer.wait_closed() + await asyncio.wait_for(self._writer.wait_closed(), timeout=10) + except asyncio.TimeoutError: + # See issue #3917. For some users, this line was hanging indefinitely. + # The hard timeout is not ideal (connection won't be properly closed), + # but the code will at least be able to procceed. + self._log.warning('Graceful disconnection timed out, forcibly ignoring cleanup') except Exception as e: # Disconnecting should never raise. Seen: # * OSError: No route to host and diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Telethon-1.25.0/telethon/tl/custom/sendergetter.py new/Telethon-1.25.4/telethon/tl/custom/sendergetter.py --- old/Telethon-1.25.0/telethon/tl/custom/sendergetter.py 2022-08-30 12:57:34.000000000 +0200 +++ new/Telethon-1.25.4/telethon/tl/custom/sendergetter.py 2022-10-14 18:43:44.000000000 +0200 @@ -46,11 +46,14 @@ # cached information, they may use the property instead. if (self._sender is None or getattr(self._sender, 'min', None)) \ and await self.get_input_sender(): - try: - self._sender =\ - await self._client.get_entity(self._input_sender) - except ValueError: - await self._refetch_sender() + # self.get_input_sender may refresh in which case the sender may no longer be min + # However it could still incur a cost so the cheap check is done twice instead. + if self._sender is None or getattr(self._sender, 'min', None): + try: + self._sender =\ + await self._client.get_entity(self._input_sender) + except ValueError: + await self._refetch_sender() return self._sender @property diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Telethon-1.25.0/telethon/types.py new/Telethon-1.25.4/telethon/types.py --- old/Telethon-1.25.0/telethon/types.py 1970-01-01 01:00:00.000000000 +0100 +++ new/Telethon-1.25.4/telethon/types.py 2022-10-14 18:43:44.000000000 +0200 @@ -0,0 +1 @@ +from .tl.types import * diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Telethon-1.25.0/telethon/utils.py new/Telethon-1.25.4/telethon/utils.py --- old/Telethon-1.25.0/telethon/utils.py 2022-08-30 12:57:34.000000000 +0200 +++ new/Telethon-1.25.4/telethon/utils.py 2022-10-14 18:43:44.000000000 +0200 @@ -54,7 +54,7 @@ mimetypes.add_type('application/x-tgsticker', '.tgs') USERNAME_RE = re.compile( - r'@|(?:https?://)?(?:www\.)?(?:telegram\.(?:me|dog)|t\.me)/(@|joinchat/)?' + r'@|(?:https?://)?(?:www\.)?(?:telegram\.(?:me|dog)|t\.me)/(@|\+|joinchat/)?' ) TG_JOIN_RE = re.compile( r'tg://(join)\?invite=' diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Telethon-1.25.0/telethon/version.py new/Telethon-1.25.4/telethon/version.py --- old/Telethon-1.25.0/telethon/version.py 2022-08-30 12:57:34.000000000 +0200 +++ new/Telethon-1.25.4/telethon/version.py 2022-10-14 18:43:44.000000000 +0200 @@ -1,3 +1,3 @@ # Versions should comply with PEP440. # This line is parsed in setup.py: -__version__ = '1.25.0' +__version__ = '1.25.4' diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Telethon-1.25.0/telethon_examples/README.md new/Telethon-1.25.4/telethon_examples/README.md --- old/Telethon-1.25.0/telethon_examples/README.md 2022-08-30 12:57:34.000000000 +0200 +++ new/Telethon-1.25.4/telethon_examples/README.md 2022-10-14 18:43:44.000000000 +0200 @@ -136,7 +136,7 @@ ![Screenshot of the tkinter GUI][tkinter GUI] -### [`payment.py`](https://raw.githubusercontent.com/LonamiWebs/Telethon/master/telethon_examples/payment.py) +### [`payment.py`](https://raw.githubusercontent.com/LonamiWebs/Telethon/v1/telethon_examples/payment.py) * Usable as: **bot**. * Difficulty: **medium**. @@ -150,18 +150,18 @@ [Telethon]: https://github.com/LonamiWebs/Telethon -[CC0 License]: https://github.com/LonamiWebs/Telethon/blob/master/telethon_examples/LICENSE +[CC0 License]: https://github.com/LonamiWebs/Telethon/blob/v1/telethon_examples/LICENSE [@BotFather]: https://t.me/BotFather -[`assistant.py`]: https://raw.githubusercontent.com/LonamiWebs/Telethon/master/telethon_examples/assistant.py -[`quart_login.py`]: https://raw.githubusercontent.com/LonamiWebs/Telethon/master/telethon_examples/quart_login.py -[`gui.py`]: https://raw.githubusercontent.com/LonamiWebs/Telethon/master/telethon_examples/gui.py -[`interactive_telegram_client.py`]: https://raw.githubusercontent.com/LonamiWebs/Telethon/master/telethon_examples/interactive_telegram_client.py -[`print_messages.py`]: https://raw.githubusercontent.com/LonamiWebs/Telethon/master/telethon_examples/print_messages.py -[`print_updates.py`]: https://raw.githubusercontent.com/LonamiWebs/Telethon/master/telethon_examples/print_updates.py -[`replier.py`]: https://raw.githubusercontent.com/LonamiWebs/Telethon/master/telethon_examples/replier.py +[`assistant.py`]: https://raw.githubusercontent.com/LonamiWebs/Telethon/v1/telethon_examples/assistant.py +[`quart_login.py`]: https://raw.githubusercontent.com/LonamiWebs/Telethon/v1/telethon_examples/quart_login.py +[`gui.py`]: https://raw.githubusercontent.com/LonamiWebs/Telethon/v1/telethon_examples/gui.py +[`interactive_telegram_client.py`]: https://raw.githubusercontent.com/LonamiWebs/Telethon/v1/telethon_examples/interactive_telegram_client.py +[`print_messages.py`]: https://raw.githubusercontent.com/LonamiWebs/Telethon/v1/telethon_examples/print_messages.py +[`print_updates.py`]: https://raw.githubusercontent.com/LonamiWebs/Telethon/v1/telethon_examples/print_updates.py +[`replier.py`]: https://raw.githubusercontent.com/LonamiWebs/Telethon/v1/telethon_examples/replier.py [@TelethonianBot]: https://t.me/TelethonianBot [official Telethon's chat]: https://t.me/TelethonChat [`asyncio`]: https://docs.python.org/3/library/asyncio.html [`tkinter`]: https://docs.python.org/3/library/tkinter.html -[tkinter GUI]: https://raw.githubusercontent.com/LonamiWebs/Telethon/master/telethon_examples/screenshot-gui.jpg +[tkinter GUI]: https://raw.githubusercontent.com/LonamiWebs/Telethon/v1/telethon_examples/screenshot-gui.jpg [`events.NewMessage`]: https://docs.telethon.dev/en/stable/modules/events.html#telethon.events.newmessage.NewMessage diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Telethon-1.25.0/telethon_generator/data/errors.csv new/Telethon-1.25.4/telethon_generator/data/errors.csv --- old/Telethon-1.25.0/telethon_generator/data/errors.csv 2022-08-30 12:57:34.000000000 +0200 +++ new/Telethon-1.25.4/telethon_generator/data/errors.csv 2022-10-14 18:43:44.000000000 +0200 @@ -22,6 +22,7 @@ AUTH_TOKEN_ALREADY_ACCEPTED,400,The authorization token was already used AUTH_TOKEN_EXPIRED,400,The provided authorization token has expired and the updated QR-code must be re-scanned AUTH_TOKEN_INVALID,400,An invalid authorization token was provided +AUTH_TOKEN_INVALID2,400,An invalid authorization token was provided AUTOARCHIVE_NOT_AVAILABLE,400,You cannot use this feature yet BANK_CARD_NUMBER_INVALID,400,Incorrect credit card number BASE_PORT_LOC_INVALID,400,Base port location invalid @@ -67,6 +68,7 @@ CHAT_ADMIN_INVITE_REQUIRED,403,You do not have the rights to do this CHAT_ADMIN_REQUIRED,400,"Chat admin privileges are required to do that in the specified chat (for example, to send a message in a channel which is not yours), or invalid permissions used for the channel or group" CHAT_FORBIDDEN,403,You cannot write in this chat +CHAT_FORWARDS_RESTRICTED,400, CHAT_ID_EMPTY,400,The provided chat ID is empty CHAT_ID_INVALID,400,"Invalid object ID for a chat. Make sure to pass the right types, for instance making sure that the request is designed for chats (not channels/megagroups) or otherwise look for a different one more suited\nAn example working with a megagroup and AddChatUserRequest, it will fail because megagroups are channels. Use InviteToChannelRequest instead" CHAT_INVALID,400,The chat is invalid for this request @@ -282,6 +284,7 @@ POLL_UNSUPPORTED,400,This layer does not support polls in the issued method POLL_VOTE_REQUIRED,403, POSTPONED_TIMEOUT,500,The postponed call has timed out +PREMIUM_ACCOUNT_REQUIRED,403, PREVIOUS_CHAT_IMPORT_ACTIVE_WAIT_XMIN,406,"Similar to a flood wait, must wait {minutes} minutes" PRIVACY_KEY_INVALID,400,The privacy key is invalid PRIVACY_TOO_LONG,400,Cannot add that many entities in a single request @@ -338,6 +341,7 @@ SRP_ID_INVALID,400, START_PARAM_EMPTY,400,The start parameter is empty START_PARAM_INVALID,400,Start parameter invalid +START_PARAM_TOO_LONG,400, STATS_MIGRATE_X,303,The channel statistics must be fetched from DC {dc} STICKERSET_INVALID,400,The provided sticker set is invalid STICKERSET_OWNER_ANONYMOUS,406,This sticker set can't be used as the group's official stickers because it was created by one of its anonymous admins diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Telethon-1.25.0/telethon_generator/docswriter.py new/Telethon-1.25.4/telethon_generator/docswriter.py --- old/Telethon-1.25.0/telethon_generator/docswriter.py 2022-08-30 12:57:34.000000000 +0200 +++ new/Telethon-1.25.4/telethon_generator/docswriter.py 2022-10-14 18:43:44.000000000 +0200 @@ -142,8 +142,8 @@ self.write(':') # "Opening" modifiers - if arg.is_flag: - self.write('flags.{}?', arg.flag_index) + if arg.flag: + self.write('{}.{}?', arg.flag, arg.flag_index) if arg.is_generic: self.write('!') diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Telethon-1.25.0/update-docs.sh new/Telethon-1.25.4/update-docs.sh --- old/Telethon-1.25.0/update-docs.sh 2022-08-30 12:57:34.000000000 +0200 +++ new/Telethon-1.25.4/update-docs.sh 2022-10-14 18:43:44.000000000 +0200 @@ -11,4 +11,4 @@ git add constructors/ types/ methods/ index.html js/search.js css/ img/ git commit --amend -m "Update documentation" git push --force -git checkout master +git checkout v1