Repository: python-telegram-bot/python-telegram-bot

Issue:
[BUG] - error sending photo as file with inline keyboard
sending a photo as file with inline keyboard returns this error:


`Traceback (most recent call last):                                                 File "test.py", line 4, in                                                 bot.send_photo(4746004, photo=f, reply_markup=InlineKeyboardMarkup([[InlineK eyboardButton(text='1', url='2')]]))                                               File "", line 2, in send_photo                                  File "C:\Users\Dario\AppData\Local\Programs\Python\Python37-32\lib\site-packag es\telegram\bot.py", line 70, in decorator                                           result = func(*args, **kwargs)                                                 File "C:\Users\Dario\AppData\Local\Programs\Python\Python37-32\lib\site-packag es\telegram\bot.py", line 498, in send_photo                                         **kwargs)                                                                      File "C:\Users\Dario\AppData\Local\Programs\Python\Python37-32\lib\site-packag es\telegram\bot.py", line 176, in _message                                           result = self._request.post(url, data, timeout=timeout)                        File "C:\Users\Dario\AppData\Local\Programs\Python\Python37-32\lib\site-packag es\telegram\utils\request.py", line 329, in post                                     result = self._request_wrapper('POST', url, fields=data, **urlopen_kwargs)     File "C:\Users\Dario\AppData\Local\Programs\Python\Python37-32\lib\site-packag es\telegram\utils\request.py", line 225, in _request_wrapper                         resp = self._con_pool.request(*args, **kwargs)                                 File "C:\Users\Dario\AppData\Local\Programs\Python\Python37-32\lib\site-packag es\telegram\vendor\ptb_urllib3\urllib3\request.py", line 70, in request              **urlopen_kw)                                                                  File "C:\Users\Dario\AppData\Local\Programs\Python\Python37-32\lib\site-packag es\telegram\vendor\ptb_urllib3\urllib3\request.py", line 138, in request_encode_ body                                                                                 body, content_type = encode_multipart_formdata(fields, boundary=multipart_bo undary)                                                                            File "C:\Users\Dario\AppData\Local\Programs\Python\Python37-32\lib\site-packag es\telegram\vendor\ptb_urllib3\urllib3\filepost.py", line 86, in encode_multipar t_formdata                                                                           body.write(data)                                                             TypeError: a bytes-like object is required, not 'dict'`


this is the snippet use to reproduce the error (use a picture on the disk) :

```
from telegram import InlineKeyboardMarkup, InlineKeyboardButton, Bot
bot = Bot('token')
with open('test.png', 'rb') as f:
    bot.send_photo(TELEGRAM_ID, photo=f, reply_markup=InlineKeyboardMarkup([[InlineKeyboardButton(text='1', url='https://example.com')]]))
```

**the snippet works on ptb 12.5.1 version, but not on 12.6**


Discussion:
Seems to be introduced in d63e710784bc3eb654525335e3f750cc32df5cef, specifically by changing `reply_markup.to_json()` to `reply_markup.to_dict()` in `bot.py` in `Bot._message` https://github.com/python-telegram-bot/python-telegram-bot/blob/d63e710784bc3eb654525335e3f750cc32df5cef/telegram/bot.py#L166
Similar change was made in `Bot.stop_poll` but this one is not related to sending files
https://github.com/python-telegram-bot/python-telegram-bot/blob/d63e710784bc3eb654525335e3f750cc32df5cef/telegram/bot.py#L3716
Thanks for reporting! Can reproduce. When changing `to_json()` to `to_dict()`, I didn't account for the fact, that `InlineKeyboardMarkup` can be sent along with media messages, which are handled in a different way by `telegram.utils.request`. We'll have bug fix release ready soon.

Resolving patch:
diff --git a/telegram/bot.py b/telegram/bot.py
--- a/telegram/bot.py
+++ b/telegram/bot.py
@@ -163,7 +163,9 @@ def _message(self, url, data, reply_to_message_id=None, disable_notification=Non
 
         if reply_markup is not None:
             if isinstance(reply_markup, ReplyMarkup):
-                data['reply_markup'] = reply_markup.to_dict()
+                # We need to_json() instead of to_dict() here, because reply_markups may be
+                # attached to media messages, which aren't json dumped by utils.request
+                data['reply_markup'] = reply_markup.to_json()
             else:
                 data['reply_markup'] = reply_markup
 
@@ -3404,6 +3406,8 @@ def create_new_sticker_set(self, user_id, name, title, emojis, png_sticker=None,
         if contains_masks is not None:
             data['contains_masks'] = contains_masks
         if mask_position is not None:
+            # We need to_json() instead of to_dict() here, because we're sending a media
+            # message here, which isn't json dumped by utils.request
             data['mask_position'] = mask_position.to_json()
         data.update(kwargs)
 
@@ -3472,6 +3476,8 @@ def add_sticker_to_set(self, user_id, name, emojis, png_sticker=None, mask_posit
         if tgs_sticker is not None:
             data['tgs_sticker'] = tgs_sticker
         if mask_position is not None:
+            # We need to_json() instead of to_dict() here, because we're sending a media
+            # message here, which isn't json dumped by utils.request
             data['mask_position'] = mask_position.to_json()
         data.update(kwargs)
 
@@ -3726,7 +3732,9 @@ def stop_poll(self,
 
         if reply_markup:
             if isinstance(reply_markup, ReplyMarkup):
-                data['reply_markup'] = reply_markup.to_dict()
+                # We need to_json() instead of to_dict() here, because reply_markups may be
+                # attached to media messages, which aren't json dumped by utils.request
+                data['reply_markup'] = reply_markup.to_json()
             else:
                 data['reply_markup'] = reply_markup
 


Test patch: