Repository: LonamiWebs/Telethon (language: python)

Issue:
There is no caption extraction from types.Message when using TelegramClient.send_message with a file
### Code that causes the issue

```python
from telethon import TelegramClient
from telethon.tl.types import Message, PeerChannel, Photo, MessageMediaPhoto


WRITE_TO_CHANNEL_NAME = NotImplemented
API_ID = NotImplemented
API_HASH = NotImplemented


async def example(client):
    message = Message(
        id=23,
        peer_id=PeerChannel(1078071132),
        date=None,
        message='message',
    )
    photo = Photo(
        dc_id=5,
        id=1358272180771727307,
        access_hash=4856299325127254003,
        file_reference=b'\x02@B\x0f\\\x00\x00\x00\x17g\x1a\x8e\xe7\xae\xe5\xd2\x7fl\xc7\x16\xc7@7\xab\x1bu\x0cr\x1f',
        sizes=[],
        date=None,
    )
    msg_media_photo = MessageMediaPhoto(photo=photo)

    await client.send_message(
        entity=WRITE_TO_CHANNEL_NAME,
        message=message,
        file=msg_media_photo,
    )

if __name__ == '__main__':
    client = TelegramClient('session_name', API_ID, API_HASH)
    client.start()
    client.loop.run_until_complete(example(client))
```

### Expected behavior

1. Run the script
2. A new post with the photo and the message successfully added
<img width="383" alt="Captura de pantalla 2024-10-24 a la(s) 3 26 30 p m" src="https://github.com/user-attachments/assets/d014da56-acce-4963-b153-34407caecb66">


### Actual behavior

The error _**TypeError: 'Message' object is not iterable**_ occurs

### Traceback

```
Traceback (most recent call last):
  File "/Users/greg/Documents/code/python/poc_repost_tg/main.py", line 97, in <module>
    client = TelegramClient('session_name', API_ID, API_HASH)
  File "/Users/greg/Documents/code/python/poc_repost_tg/.venv/lib/python3.13/site-packages/telethon/client/telegrambaseclient.py", line 328, in __init__
    self.api_id = int(api_id)
                  ~~~^^^^^^^^
TypeError: int() argument must be a string, a bytes-like object or a real number, not 'NotImplementedType'
(.venv) ➜  poc_repost_tg python main.py
Traceback (most recent call last):
  File "/Users/greg/Documents/code/python/poc_repost_tg/main.py", line 96, in <module>
    client.loop.run_until_complete(example(client))
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^
  File "/usr/local/Cellar/python@3.13/3.13.0_1/Frameworks/Python.framework/Versions/3.13/lib/python3.13/asyncio/base_events.py", line 721, in run_until_complete
    return future.result()
           ~~~~~~~~~~~~~^^
  File "/Users/greg/Documents/code/python/poc_repost_tg/main.py", line 87, in example
    await client.send_message(
    ...<3 lines>...
    )
  File "/Users/greg/Documents/code/python/poc_repost_tg/.venv/lib/python3.13/site-packages/telethon/client/messages.py", line 831, in send_message
    return await self.send_file(
           ^^^^^^^^^^^^^^^^^^^^^
    ...<8 lines>...
    )
    ^
  File "/Users/greg/Documents/code/python/poc_repost_tg/.venv/lib/python3.13/site-packages/telethon/client/uploads.py", line 406, in send_file
    await self._parse_message_text(caption, parse_mode)
  File "/Users/greg/Documents/code/python/poc_repost_tg/.venv/lib/python3.13/site-packages/telethon/client/messageparse.py", line 87, in _parse_message_text
    message, msg_entities = parse_mode.parse(message)
                            ~~~~~~~~~~~~~~~~^^^^^^^^^
  File "/Users/greg/Documents/code/python/poc_repost_tg/.venv/lib/python3.13/site-packages/telethon/extensions/markdown.py", line 68, in parse
    message = add_surrogate(message)
  File "/Users/greg/Documents/code/python/poc_repost_tg/.venv/lib/python3.13/site-packages/telethon/helpers.py", line 44, in add_surrogate
    if (0x10000 <= ord(x) <= 0x10FFFF) else x for x in text
                                                       ^^^^
TypeError: 'Message' object is not iterable
```

### Telethon version

1.37

### Python version

3.10, 3.11, 3.12, 3.13

### Operating system (including distribution name and version)

Darwin 24.0.0 Darwin Kernel Version 24.0.0: Tue Sep 24 23:36:30 PDT 2024; root:xnu-11215.1.12~1/RELEASE_X86_64 x86_64

### Other details

_No response_

### Checklist

- [X] The error is in the library's code, and not in my own.
- [X] I have searched for this issue before posting it and there isn't an open duplicate.
- [X] I ran `pip install -U https://github.com/LonamiWebs/Telethon/archive/v1.zip` and triggered the bug in the latest version.


Discussion / hints:

Fix patch:
diff --git a/telethon/client/messages.py b/telethon/client/messages.py
index 0c61a9080..5dcd2ee63 100644
--- a/telethon/client/messages.py
+++ b/telethon/client/messages.py
@@ -826,6 +826,9 @@ async def callback(event):
                 await client.send_message(chat, 'Hi, future!', schedule=timedelta(minutes=5))
         """
         if file is not None:
+            if isinstance(message, types.Message):
+                formatting_entities = formatting_entities or message.entities
+                message = message.message
             return await self.send_file(
                 entity, file, caption=message, reply_to=reply_to,
                 attributes=attributes, parse_mode=parse_mode,


Test patch:
diff --git a/tests/telethon/client/test_messages.py b/tests/telethon/client/test_messages.py
index d47fcf459..2bdbb9e78 100644
--- a/tests/telethon/client/test_messages.py
+++ b/tests/telethon/client/test_messages.py
@@ -1,8 +1,12 @@
 import inspect
+from unittest import mock
+from unittest.mock import MagicMock
 
 import pytest
 
 from telethon import TelegramClient
+from telethon.client import MessageMethods
+from telethon.tl.types import PeerChat, MessageMediaDocument, Message, MessageEntityBold
 
 
 @pytest.mark.asyncio
@@ -38,3 +42,42 @@ async def send_file(self, entity, file, **kwargs):
 
     client = MockedClient()
     assert (await client.send_message('a', file='b', **arguments)) == sentinel
+
+
+class TestMessageMethods:
+    @pytest.mark.asyncio
+    @pytest.mark.parametrize(
+        'formatting_entities',
+        ([MessageEntityBold(offset=0, length=0)], None)
+    )
+    async def test_send_msg_and_file(self, formatting_entities):
+        async def async_func(result): # AsyncMock was added only in 3.8
+            return result
+        msg_methods = MessageMethods()
+        expected_result = Message(
+            id=0, peer_id=PeerChat(chat_id=0), message='', date=None,
+        )
+        entity = 'test_entity'
+        message = Message(
+            id=1, peer_id=PeerChat(chat_id=0), message='expected_caption', date=None,
+            entities=[MessageEntityBold(offset=9, length=9)],
+        )
+        media_file = MessageMediaDocument()
+
+        with mock.patch.object(
+            target=MessageMethods, attribute='send_file',
+            new=MagicMock(return_value=async_func(expected_result)), create=True,
+        ) as mock_obj:
+            result = await msg_methods.send_message(
+                entity=entity, message=message, file=media_file,
+                formatting_entities=formatting_entities,
+            )
+            mock_obj.assert_called_once_with(
+                entity, media_file, caption=message.message,
+                formatting_entities=formatting_entities or message.entities,
+                reply_to=None, silent=None, attributes=None, parse_mode=(),
+                force_document=False, thumb=None, buttons=None,
+                clear_draft=False, schedule=None, supports_streaming=False,
+                comment_to=None, background=None, nosound_video=None,
+            )
+            assert result == expected_result