docs: async def get_input_entity(self, peer):
          """
          Turns the given peer into its input entity version. Most requests
          use this kind of :tl:`InputPeer`, so this is the most suitable call
          to make for those cases. **Generally you should let the library do
          its job** and don't worry about getting the input entity first, but
          if you're going to use an entity often, consider making the call:
  
          >>> import asyncio
          >>> rc = asyncio.get_event_loop().run_until_complete
          >>>
          >>> from telethon import TelegramClient
          >>> client = TelegramClient(...)
          >>> # If you're going to use "username" often in your code
          >>> # (make a lot of calls), consider getting its input entity
          >>> # once, and then using the "user" everywhere instead.
          >>> user = rc(client.get_input_entity('username'))
          >>> # The same applies to IDs, chats or channels.
          >>> chat = rc(client.get_input_entity(-123456789))
  
          entity (`str` | `int` | :tl:`Peer` | :tl:`InputPeer`):
              If a username or invite link is given, **the library will
              use the cache**. This means that it's possible to be using
              a username that *changed* or an old invite link (this only
              happens if an invite link for a small group chat is used
              after it was upgraded to a mega-group).
  
              If the username or ID from the invite link is not found in
              the cache, it will be fetched. The same rules apply to phone
              numbers (``'+34 123456789'``) from people in your contact list.
  
              If an exact name is given, it must be in the cache too. This
              is not reliable as different people can share the same name
              and which entity is returned is arbitrary, and should be used
              only for quick tests.
  
              If a positive integer ID is given, the entity will be searched
              in cached users, chats or channels, without making any call.
  
              If a negative integer ID is given, the entity will be searched
              exactly as either a chat (prefixed with ``-``) or as a channel
              (prefixed with ``-100``).
  
              If a :tl:`Peer` is given, it will be searched exactly in the
              cache as either a user, chat or channel.
  
              If the given object can be turned into an input entity directly,
              said operation will be done.
  
              Unsupported types will raise ``TypeError``.
  
              If the entity can't be found, ``ValueError`` will be raised.
  
          Returns:
              :tl:`InputPeerUser`, :tl:`InputPeerChat` or :tl:`InputPeerChannel`
              or :tl:`InputPeerSelf` if the parameter is ``'me'`` or ``'self'``.
  
              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:
              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 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
          # regardless. These are the only two special-cased requests.
          peer = utils.get_peer(peer)
          if isinstance(peer, types.PeerUser):
              users = await self(functions.users.GetUsersRequest([
                  types.InputUser(peer.user_id, access_hash=0)]))
              if users and not isinstance(users[0], types.UserEmpty):
                  # If the user passed a valid ID they expect to work for
                  # channels but would be valid for users, we get UserEmpty.
                  # Avoid returning the invalid empty input peer for that.
                  #
                  # We *could* try to guess if it's a channel first, and if
                  # it's not, work as a chat and try to validate it through
                  # another request, but that becomes too much work.
                  return utils.get_input_peer(users[0])
          elif isinstance(peer, types.PeerChat):
              return types.InputPeerChat(peer.chat_id)
          elif isinstance(peer, types.PeerChannel):
              try:
                  channels = await self(functions.channels.GetChannelsRequest([
                      types.InputChannel(peer.channel_id, access_hash=0)]))
                  return utils.get_input_peer(channels.chats[0])
              except errors.ChannelInvalidError:
                  pass
  
          raise ValueError(
              'Could not find the input entity for {!r}. Please read https://'
              'telethon.readthedocs.io/en/latest/extra/basic/entities.html to'
              ' find out more details.'
              .format(peer)
          )