From 22fcdeef7f8c7d3ab016b61ac3f7b99c41101575 Mon Sep 17 00:00:00 2001 From: Lonami Exo Date: Wed, 3 Apr 2019 09:36:58 +0200 Subject: [PATCH] Better get_input_entity code flow Plenty of unnecessary exceptions were being raised and caught when the input parameters were already correct. Furthermore, since 8abc7ade224620af76ebad1896424eeb5ae65fc7, the in-disk cache was no longer being used (so using usernames always reached out to memory). --- telethon/client/users.py | 29 +++++++++++++++++++---------- telethon/entitycache.py | 7 ++++--- 2 files changed, 23 insertions(+), 13 deletions(-) diff --git a/telethon/client/users.py b/telethon/client/users.py index 28b1df55..aa1cd273 100644 --- a/telethon/client/users.py +++ b/telethon/client/users.py @@ -303,26 +303,35 @@ class UserMethods(TelegramBaseClient): If you need to get the ID of yourself, you should use `get_me` with ``input_peer=True``) instead. """ + # Short-circuit if the input parameter directly maps to an InputPeer + try: + return utils.get_input_peer(peer) + except TypeError: + pass + + # Next in priority is having a peer (or its ID) cached in-memory + try: + # 0x2d45687 == crc32(b'Peer') + if isinstance(peer, int) or peer.SUBCLASS_OF_ID == 0x2d45687: + return self._entity_cache[peer] + except (AttributeError, KeyError): + pass + + # Then come known strings that take precedence if peer in ('me', 'self'): return types.InputPeerSelf() + # No InputPeer, cached peer, or known string. Fetch from disk cache try: - # First try to get the entity from cache, otherwise figure it out - return self._entity_cache[peer] - except KeyError: + return self.session.get_input_entity(peer) + except ValueError: pass + # Only network left to try if isinstance(peer, str): return utils.get_input_peer( await self._get_entity_from_string(peer)) - if not isinstance(peer, int) and (not isinstance(peer, TLObject) - or peer.SUBCLASS_OF_ID != 0x2d45687): - # Try casting the object into an input peer. Might TypeError. - # Don't do it if a not-found ID was given (instead ValueError). - # Also ignore Peer (0x2d45687 == crc32(b'Peer'))'s, lacking hash. - return utils.get_input_peer(peer) - # If we're a bot and the user has messaged us privately users.getUsers # will work with access_hash = 0. Similar for channels.getChannels. # If we're not a bot but the user is in our contacts, it seems to work diff --git a/telethon/entitycache.py b/telethon/entitycache.py index 0f94ae32..a87d787b 100644 --- a/telethon/entitycache.py +++ b/telethon/entitycache.py @@ -12,11 +12,12 @@ class EntityCache: Adds the given entities to the cache, if they weren't saved before. """ if not utils.is_list_like(entities): - # Invariant: all "chats" and "users" are always iterables + # Invariant: all "chats" and "users" are always iterables, + # and "user" never is (so we wrap it inside a list). entities = itertools.chain( - [getattr(entities, 'user', None)], getattr(entities, 'chats', []), - getattr(entities, 'users', []) + getattr(entities, 'users', []), + (hasattr(entities, 'user') and [entities.user]) or [] ) for entity in entities: