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

Issue:
[BUG] Type Hinting of reply_markups
* `stop_poll` allows ReplyKeyboard, but only Inline is accepted. Same for a bunch of other methods
* ~`disable_web_page_preview` is falsely typed as `str`~ that already was fixed …
* `edit_message_reply_markup` should accept `None` for `reply_markup`


Discussion:

Resolving patch:
diff --git a/telegram/bot.py b/telegram/bot.py
--- a/telegram/bot.py
+++ b/telegram/bot.py
@@ -89,6 +89,7 @@
     InputMediaDocument,
     InputMediaPhoto,
     InputMediaVideo,
+    InlineKeyboardMarkup,
 )
 from telegram.constants import MAX_INLINE_QUERY_RESULTS
 from telegram.error import InvalidToken, TelegramError
@@ -1459,7 +1460,7 @@ def edit_message_live_location(
         latitude: float = None,
         longitude: float = None,
         location: Location = None,
-        reply_markup: ReplyMarkup = None,
+        reply_markup: InlineKeyboardMarkup = None,
         timeout: float = None,
         api_kwargs: JSONDict = None,
         horizontal_accuracy: float = None,
@@ -1545,7 +1546,7 @@ def stop_message_live_location(
         chat_id: Union[str, int] = None,
         message_id: Union[str, int] = None,
         inline_message_id: Union[str, int] = None,
-        reply_markup: ReplyMarkup = None,
+        reply_markup: InlineKeyboardMarkup = None,
         timeout: float = None,
         api_kwargs: JSONDict = None,
     ) -> Union[Optional[Message], bool]:
@@ -1794,7 +1795,7 @@ def send_game(
         game_short_name: str,
         disable_notification: bool = False,
         reply_to_message_id: Union[int, str] = None,
-        reply_markup: ReplyMarkup = None,
+        reply_markup: InlineKeyboardMarkup = None,
         timeout: float = None,
         api_kwargs: JSONDict = None,
         allow_sending_without_reply: bool = None,
@@ -2303,7 +2304,7 @@ def edit_message_text(
         inline_message_id: Union[str, int] = None,
         parse_mode: str = None,
         disable_web_page_preview: bool = None,
-        reply_markup: ReplyMarkup = None,
+        reply_markup: InlineKeyboardMarkup = None,
         timeout: float = None,
         api_kwargs: JSONDict = None,
         entities: Union[List[MessageEntity], Tuple[MessageEntity, ...]] = None,
@@ -2373,7 +2374,7 @@ def edit_message_caption(
         message_id: Union[str, int] = None,
         inline_message_id: Union[str, int] = None,
         caption: str = None,
-        reply_markup: ReplyMarkup = None,
+        reply_markup: InlineKeyboardMarkup = None,
         timeout: float = None,
         parse_mode: str = None,
         api_kwargs: JSONDict = None,
@@ -2450,7 +2451,7 @@ def edit_message_media(
         message_id: Union[str, int] = None,
         inline_message_id: Union[str, int] = None,
         media: InputMedia = None,
-        reply_markup: ReplyMarkup = None,
+        reply_markup: InlineKeyboardMarkup = None,
         timeout: float = None,
         api_kwargs: JSONDict = None,
     ) -> Union[Message, bool]:
@@ -2516,7 +2517,7 @@ def edit_message_reply_markup(
         chat_id: Union[str, int] = None,
         message_id: Union[str, int] = None,
         inline_message_id: Union[str, int] = None,
-        reply_markup: ReplyMarkup = None,
+        reply_markup: Optional[InlineKeyboardMarkup] = None,
         timeout: float = None,
         api_kwargs: JSONDict = None,
     ) -> Union[Message, bool]:
@@ -3144,7 +3145,7 @@ def send_invoice(
         is_flexible: bool = None,
         disable_notification: bool = False,
         reply_to_message_id: Union[int, str] = None,
-        reply_markup: ReplyMarkup = None,
+        reply_markup: InlineKeyboardMarkup = None,
         provider_data: Union[str, object] = None,
         send_phone_number_to_provider: bool = None,
         send_email_to_provider: bool = None,
@@ -4400,7 +4401,7 @@ def stop_poll(
         self,
         chat_id: Union[int, str],
         message_id: Union[int, str],
-        reply_markup: ReplyMarkup = None,
+        reply_markup: InlineKeyboardMarkup = None,
         timeout: float = None,
         api_kwargs: JSONDict = None,
     ) -> Poll:
diff --git a/telegram/utils/helpers.py b/telegram/utils/helpers.py
--- a/telegram/utils/helpers.py
+++ b/telegram/utils/helpers.py
@@ -35,7 +35,7 @@
 from telegram.utils.types import JSONDict, FileInput
 
 if TYPE_CHECKING:
-    from telegram import MessageEntity, TelegramObject, InputFile
+    from telegram import Message, Update, TelegramObject, InputFile
 
 try:
     import ujson as json
@@ -320,7 +320,7 @@ def mention_markdown(user_id: Union[int, str], name: str, version: int = 1) -> s
     return u'[{}](tg://user?id={})'.format(escape_markdown(name, version=version), user_id)
 
 
-def effective_message_type(entity: 'MessageEntity') -> Optional[str]:
+def effective_message_type(entity: Union['Message', 'Update']) -> Optional[str]:
     """
     Extracts the type of message as a string identifier from a :class:`telegram.Message` or a
     :class:`telegram.Update`.
@@ -339,7 +339,7 @@ def effective_message_type(entity: 'MessageEntity') -> Optional[str]:
     if isinstance(entity, Message):
         message = entity
     elif isinstance(entity, Update):
-        message = entity.effective_message
+        message = entity.effective_message  # type: ignore[assignment]
     else:
         raise TypeError(f"entity is not Message or Update (got: {type(entity)})")
 


Test patch: