docs: async def send_file(
              self, entity, file, *, caption=None, force_document=False,
              progress_callback=None, reply_to=None, attributes=None,
              thumb=None, allow_cache=True, parse_mode=(),
              voice_note=False, video_note=False, buttons=None, silent=None,
              supports_streaming=False, **kwargs):
          """
          Sends a file to the specified entity.
  
          Args:
              entity (`entity`):
                  Who will receive the file.
  
              file (`str` | `bytes` | `file` | `media`):
                  The file to send, which can be one of:
  
                  * A local file path to an in-disk file. The file name
                    will be the path's base name.
  
                  * A `bytes` byte array with the file's data to send
                    (for example, by using ``text.encode('utf-8')``).
                    A default file name will be used.
  
                  * A bytes `io.IOBase` stream over the file to send
                    (for example, by using ``open(file, 'rb')``).
                    Its ``.name`` property will be used for the file name,
                    or a default if it doesn't have one.
  
                  * An external URL to a file over the internet. This will
                    send the file as "external" media, and Telegram is the
                    one that will fetch the media and send it.
  
                  * A Bot API-like ``file_id``. You can convert previously
                    sent media to file IDs for later reusing with
                    `telethon.utils.pack_bot_file_id`.
  
                  * A handle to an existing file (for example, if you sent a
                    message with media before, you can use its ``message.media``
                    as a file here).
  
                  * A handle to an uploaded file (from `upload_file`).
  
                  To send an album, you should provide a list in this parameter.
  
                  If a list or similar is provided, the files in it will be
                  sent as an album in the order in which they appear, sliced
                  in chunks of 10 if more than 10 are given.
  
              caption (`str`, optional):
                  Optional caption for the sent media message. When sending an
                  album, the caption may be a list of strings, which will be
                  assigned to the files pairwise.
  
              force_document (`bool`, optional):
                  If left to ``False`` and the file is a path that ends with
                  the extension of an image file or a video file, it will be
                  sent as such. Otherwise always as a document.
  
              progress_callback (`callable`, optional):
                  A callback function accepting two parameters:
                  ``(sent bytes, total)``.
  
              reply_to (`int` | `Message <telethon.tl.custom.message.Message>`):
                  Same as `reply_to` from `send_message`.
  
              attributes (`list`, optional):
                  Optional attributes that override the inferred ones, like
                  :tl:`DocumentAttributeFilename` and so on.
  
              thumb (`str` | `bytes` | `file`, optional):
                  Optional JPEG thumbnail (for documents). **Telegram will
                  ignore this parameter** unless you pass a ``.jpg`` file!
  
                  The file must also be small in dimensions and in-disk size.
                  Successful thumbnails were files below 20kb and 200x200px.
                  Width/height and dimensions/size ratios may be important.
  
              allow_cache (`bool`, optional):
                  Whether to allow using the cached version stored in the
                  database or not. Defaults to ``True`` to avoid re-uploads.
                  Must be ``False`` if you wish to use different attributes
                  or thumb than those that were used when the file was cached.
  
              parse_mode (`object`, optional):
                  See the `TelegramClient.parse_mode
                  <telethon.client.messageparse.MessageParseMethods.parse_mode>`
                  property for allowed values. Markdown parsing will be used by
                  default.
  
              voice_note (`bool`, optional):
                  If ``True`` the audio will be sent as a voice note.
  
                  Set `allow_cache` to ``False`` if you sent the same file
                  without this setting before for it to work.
  
              video_note (`bool`, optional):
                  If ``True`` the video will be sent as a video note,
                  also known as a round video message.
  
                  Set `allow_cache` to ``False`` if you sent the same file
                  without this setting before for it to work.
  
              buttons (`list`, `custom.Button <telethon.tl.custom.button.Button>`, :tl:`KeyboardButton`):
                  The matrix (list of lists), row list or button to be shown
                  after sending the message. This parameter will only work if
                  you have signed in as a bot. You can also pass your own
                  :tl:`ReplyMarkup` here.
  
              silent (`bool`, optional):
                  Whether the message should notify people in a broadcast
                  channel or not. Defaults to ``False``, which means it will
                  notify them. Set it to ``True`` to alter this behaviour.
  
              supports_streaming (`bool`, optional):
                  Whether the sent video supports streaming or not. Note that
                  Telegram only recognizes as streamable some formats like MP4,
                  and others like AVI or MKV will not work. You should convert
                  these to MP4 before sending if you want them to be streamable.
                  Unsupported formats will result in ``VideoContentTypeError``.
  
          Notes:
              If the ``hachoir3`` package (``hachoir`` module) is installed,
              it will be used to determine metadata from audio and video files.
  
              If the `pillow` package is installed and you are sending a photo,
              it will be resized to fit within the maximum dimensions allowed
              by Telegram to avoid ``errors.PhotoInvalidDimensionsError``. This
              cannot be done if you are sending :tl:`InputFile`, however.
  
          Returns:
              The `telethon.tl.custom.message.Message` (or messages) containing
              the sent file, or messages if a list of them was passed.
          """
          # i.e. ``None`` was used
          if not file:
              raise TypeError('Cannot use {!r} as file'.format(file))
  
          if not caption:
              caption = ''
  
          # First check if the user passed an iterable, in which case
          # we may want to send as an album if all are photo files.
          if utils.is_list_like(file):
              # TODO Fix progress_callback
              images = []
              if force_document:
                  documents = file
              else:
                  documents = []
                  for x in file:
                      if utils.is_image(x):
                          images.append(x)
                      else:
                          documents.append(x)
  
              result = []
              while images:
                  result += await self._send_album(
                      entity, images[:10], caption=caption,
                      progress_callback=progress_callback, reply_to=reply_to,
                      parse_mode=parse_mode, silent=silent
                  )
                  images = images[10:]
  
              for x in documents:
                  result.append(await self.send_file(
                      entity, x, allow_cache=allow_cache,
                      caption=caption, force_document=force_document,
                      progress_callback=progress_callback, reply_to=reply_to,
                      attributes=attributes, thumb=thumb, voice_note=voice_note,
                      video_note=video_note, buttons=buttons, silent=silent,
                      supports_streaming=supports_streaming,
                      **kwargs
                  ))
  
              return result
  
          entity = await self.get_input_entity(entity)
          reply_to = utils.get_message_id(reply_to)
  
          # Not document since it's subject to change.
          # Needed when a Message is passed to send_message and it has media.
          if 'entities' in kwargs:
              msg_entities = kwargs['entities']
          else:
              caption, msg_entities =\
                  await self._parse_message_text(caption, parse_mode)
  
          file_handle, media, image = await self._file_to_media(
              file, force_document=force_document,
              progress_callback=progress_callback,
              attributes=attributes,  allow_cache=allow_cache, thumb=thumb,
              voice_note=voice_note, video_note=video_note,
              supports_streaming=supports_streaming
          )
  
          # e.g. invalid cast from :tl:`MessageMediaWebPage`
          if not media:
              raise TypeError('Cannot use {!r} as file'.format(file))
  
          markup = self.build_reply_markup(buttons)
          request = functions.messages.SendMediaRequest(
              entity, media, reply_to_msg_id=reply_to, message=caption,
              entities=msg_entities, reply_markup=markup, silent=silent
          )
          msg = self._get_response_message(request, await self(request), entity)
          await self._cache_media(msg, file, file_handle, image=image)
  
          return msg