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

Issue:
[Type Hinting] _log function is not properly annotated
### Steps to Reproduce

1. Create a `test.py` like:
```
import asyncio
import telegram

bot = telegram.Bot(token="some-token")
async def send_msg():
    await bot.send_message(chat_id="channel-id", text="Hello World")  # Argument missing for parameter "self"

asyncio.run(send_msg())
```
2. Run
```
pyright test.py
```

You'll see:
```
test.py:6:11 - error: Argument missing for parameter "self" (reportGeneralTypeIssues)
```

Fix is described in pyright discussion, see https://github.com/microsoft/pyright/discussions/6669#discussioncomment-7781395

### Expected behaviour

Code is properly annotated so pyright doesn't throw any error.

### Actual behaviour

Pyright complains _Argument missing for parameter "self"_

### Operating System

Ubuntu 23.10

### Version of Python, python-telegram-bot & dependencies

```shell
python-telegram-bot 20.7
Bot API 6.9
Python 3.11.6 (main, Oct  8 2023, 05:06:43) [GCC 13.2.0]
```


### Relevant log output

_No response_

### Additional Context

_No response_


Discussion:
Thanks for reaching out. This is in fact not the first time we had issues with the typing for this decorator, as it came up in #2677 before, which was adressed in #2686. I strongly suggest that we manually check compatability of a new fix with VSCode and PyCharm before merging.

It would also be good to use this chance to fix & improve our [type completeness check](https://github.com/python-telegram-bot/python-telegram-bot/blob/master/.github/workflows/type_completeness.yml) as we discovered through this issue that it [apparently fails silently](https://github.com/python-telegram-bot/python-telegram-bot/actions/runs/7200052287/job/19613114285).

It would be good to see if this check can automatically detect this shortcoming with a newer version of pyright. If it does not, we should reach out to pyright and ask for clarification.

Edit: The failing check is working again (see #4035) but does not report the issue.



Patch:
diff --git a/telegram/_bot.py b/telegram/_bot.py
index df498eb7a3e..a792e0f9490 100644
--- a/telegram/_bot.py
+++ b/telegram/_bot.py
@@ -21,7 +21,6 @@
 import asyncio
 import contextlib
 import copy
-import functools
 import pickle
 from datetime import datetime
 from types import TracebackType
@@ -531,20 +530,6 @@ def _warn(
         """
         warn(message=message, category=category, stacklevel=stacklevel + 1)
 
-    # TODO: After https://youtrack.jetbrains.com/issue/PY-50952 is fixed, we can revisit this and
-    # consider adding Paramspec from typing_extensions to properly fix this. Currently a workaround
-    def _log(func: Any):  # type: ignore[no-untyped-def] # skipcq: PY-D0003
-        @functools.wraps(func)
-        async def decorator(self: "Bot", *args: Any, **kwargs: Any) -> Any:
-            # pylint: disable=protected-access
-            self._LOGGER.debug("Entering: %s", func.__name__)
-            result = await func(self, *args, **kwargs)
-            self._LOGGER.debug(result)
-            self._LOGGER.debug("Exiting: %s", func.__name__)
-            return result
-
-        return decorator
-
     def _parse_file_input(
         self,
         file_input: Union[FileInput, "TelegramObject"],
@@ -654,7 +639,8 @@ async def _do_post(
 
         request = self._request[0] if endpoint == "getUpdates" else self._request[1]
 
-        return await request.post(
+        self._LOGGER.debug("Calling Bot API endpoint `%s` with parameters `%s`", endpoint, data)
+        result = await request.post(
             url=f"{self._base_url}/{endpoint}",
             request_data=request_data,
             read_timeout=read_timeout,
@@ -662,6 +648,11 @@ async def _do_post(
             connect_timeout=connect_timeout,
             pool_timeout=pool_timeout,
         )
+        self._LOGGER.debug(
+            "Call to Bot API endpoint `%s` finished with return value `%s`", endpoint, result
+        )
+
+        return result
 
     async def _send_message(
         self,
@@ -784,7 +775,6 @@ async def shutdown(self) -> None:
         await asyncio.gather(self._request[0].shutdown(), self._request[1].shutdown())
         self._initialized = False
 
-    @_log
     async def do_api_request(
         self,
         endpoint: str,
@@ -843,7 +833,7 @@ async def do_api_request(
                     f"'Bot.do_api_request(\"{endpoint}\", ...)'"
                 ),
                 PTBDeprecationWarning,
-                stacklevel=3,
+                stacklevel=2,
             )
 
         camel_case_endpoint = to_camel_case(endpoint)
@@ -879,7 +869,6 @@ async def do_api_request(
             return return_type.de_list(result, self)
         return return_type.de_json(result, self)
 
-    @_log
     async def get_me(
         self,
         *,
@@ -910,7 +899,6 @@ async def get_me(
         self._bot_user = User.de_json(result, self)
         return self._bot_user  # type: ignore[return-value]
 
-    @_log
     async def send_message(
         self,
         chat_id: Union[int, str],
@@ -1031,7 +1019,6 @@ async def send_message(
             api_kwargs=api_kwargs,
         )
 
-    @_log
     async def delete_message(
         self,
         chat_id: Union[str, int],
@@ -1090,7 +1077,6 @@ async def delete_message(
             api_kwargs=api_kwargs,
         )
 
-    @_log
     async def delete_messages(
         self,
         chat_id: Union[int, str],
@@ -1133,7 +1119,6 @@ async def delete_messages(
             api_kwargs=api_kwargs,
         )
 
-    @_log
     async def forward_message(
         self,
         chat_id: Union[int, str],
@@ -1199,7 +1184,6 @@ async def forward_message(
             api_kwargs=api_kwargs,
         )
 
-    @_log
     async def forward_messages(
         self,
         chat_id: Union[int, str],
@@ -1262,7 +1246,6 @@ async def forward_messages(
         )
         return MessageId.de_list(result, self)
 
-    @_log
     async def send_photo(
         self,
         chat_id: Union[int, str],
@@ -1395,7 +1378,6 @@ async def send_photo(
             api_kwargs=api_kwargs,
         )
 
-    @_log
     async def send_audio(
         self,
         chat_id: Union[int, str],
@@ -1543,7 +1525,6 @@ async def send_audio(
             api_kwargs=api_kwargs,
         )
 
-    @_log
     async def send_document(
         self,
         chat_id: Union[int, str],
@@ -1684,7 +1665,6 @@ async def send_document(
             api_kwargs=api_kwargs,
         )
 
-    @_log
     async def send_sticker(
         self,
         chat_id: Union[int, str],
@@ -1793,7 +1773,6 @@ async def send_sticker(
             api_kwargs=api_kwargs,
         )
 
-    @_log
     async def send_video(
         self,
         chat_id: Union[int, str],
@@ -1953,7 +1932,6 @@ async def send_video(
             api_kwargs=api_kwargs,
         )
 
-    @_log
     async def send_video_note(
         self,
         chat_id: Union[int, str],
@@ -2086,7 +2064,6 @@ async def send_video_note(
             api_kwargs=api_kwargs,
         )
 
-    @_log
     async def send_animation(
         self,
         chat_id: Union[int, str],
@@ -2238,7 +2215,6 @@ async def send_animation(
             api_kwargs=api_kwargs,
         )
 
-    @_log
     async def send_voice(
         self,
         chat_id: Union[int, str],
@@ -2375,7 +2351,6 @@ async def send_voice(
             api_kwargs=api_kwargs,
         )
 
-    @_log
     async def send_media_group(
         self,
         chat_id: Union[int, str],
@@ -2539,7 +2514,6 @@ async def send_media_group(
 
         return Message.de_list(result, self)
 
-    @_log
     async def send_location(
         self,
         chat_id: Union[int, str],
@@ -2675,7 +2649,6 @@ async def send_location(
             api_kwargs=api_kwargs,
         )
 
-    @_log
     async def edit_message_live_location(
         self,
         chat_id: Optional[Union[str, int]] = None,
@@ -2770,7 +2743,6 @@ async def edit_message_live_location(
             api_kwargs=api_kwargs,
         )
 
-    @_log
     async def stop_message_live_location(
         self,
         chat_id: Optional[Union[str, int]] = None,
@@ -2818,7 +2790,6 @@ async def stop_message_live_location(
             api_kwargs=api_kwargs,
         )
 
-    @_log
     async def send_venue(
         self,
         chat_id: Union[int, str],
@@ -2965,7 +2936,6 @@ async def send_venue(
             api_kwargs=api_kwargs,
         )
 
-    @_log
     async def send_contact(
         self,
         chat_id: Union[int, str],
@@ -3089,7 +3059,6 @@ async def send_contact(
             api_kwargs=api_kwargs,
         )
 
-    @_log
     async def send_game(
         self,
         chat_id: int,
@@ -3175,7 +3144,6 @@ async def send_game(
             api_kwargs=api_kwargs,
         )
 
-    @_log
     async def send_chat_action(
         self,
         chat_id: Union[str, int],
@@ -3319,7 +3287,6 @@ def _insert_defaults_for_ilq_results(self, res: "InlineQueryResult") -> "InlineQ
 
         return res
 
-    @_log
     async def answer_inline_query(
         self,
         inline_query_id: str,
@@ -3417,7 +3384,6 @@ async def answer_inline_query(
             api_kwargs=api_kwargs,
         )
 
-    @_log
     async def get_user_profile_photos(
         self,
         user_id: int,
@@ -3462,7 +3428,6 @@ async def get_user_profile_photos(
 
         return UserProfilePhotos.de_json(result, self)  # type: ignore[return-value]
 
-    @_log
     async def get_file(
         self,
         file_id: Union[
@@ -3528,7 +3493,6 @@ async def get_file(
 
         return File.de_json(result, self)  # type: ignore[return-value]
 
-    @_log
     async def ban_chat_member(
         self,
         chat_id: Union[str, int],
@@ -3592,7 +3556,6 @@ async def ban_chat_member(
             api_kwargs=api_kwargs,
         )
 
-    @_log
     async def ban_chat_sender_chat(
         self,
         chat_id: Union[str, int],
@@ -3636,7 +3599,6 @@ async def ban_chat_sender_chat(
             api_kwargs=api_kwargs,
         )
 
-    @_log
     async def unban_chat_member(
         self,
         chat_id: Union[str, int],
@@ -3681,7 +3643,6 @@ async def unban_chat_member(
             api_kwargs=api_kwargs,
         )
 
-    @_log
     async def unban_chat_sender_chat(
         self,
         chat_id: Union[str, int],
@@ -3722,7 +3683,6 @@ async def unban_chat_sender_chat(
             api_kwargs=api_kwargs,
         )
 
-    @_log
     async def answer_callback_query(
         self,
         callback_query_id: str,
@@ -3788,7 +3748,6 @@ async def answer_callback_query(
             api_kwargs=api_kwargs,
         )
 
-    @_log
     async def edit_message_text(
         self,
         text: str,
@@ -3890,7 +3849,6 @@ async def edit_message_text(
             api_kwargs=api_kwargs,
         )
 
-    @_log
     async def edit_message_caption(
         self,
         chat_id: Optional[Union[str, int]] = None,
@@ -3960,7 +3918,6 @@ async def edit_message_caption(
             api_kwargs=api_kwargs,
         )
 
-    @_log
     async def edit_message_media(
         self,
         media: "InputMedia",
@@ -4024,7 +3981,6 @@ async def edit_message_media(
             api_kwargs=api_kwargs,
         )
 
-    @_log
     async def edit_message_reply_markup(
         self,
         chat_id: Optional[Union[str, int]] = None,
@@ -4080,7 +4036,6 @@ async def edit_message_reply_markup(
             api_kwargs=api_kwargs,
         )
 
-    @_log
     async def get_updates(
         self,
         offset: Optional[int] = None,
@@ -4164,7 +4119,7 @@ async def get_updates(
                     "the property `read_timeout`. Overriding this property will be mandatory in "
                     "future versions. Using 2 seconds as fallback.",
                     PTBDeprecationWarning,
-                    stacklevel=3,
+                    stacklevel=2,
                 )
 
         # Ideally we'd use an aggressive read timeout for the polling. However,
@@ -4192,7 +4147,6 @@ async def get_updates(
 
         return Update.de_list(result, self)
 
-    @_log
     async def set_webhook(
         self,
         url: str,
@@ -4320,7 +4274,6 @@ async def set_webhook(
             api_kwargs=api_kwargs,
         )
 
-    @_log
     async def delete_webhook(
         self,
         drop_pending_updates: Optional[bool] = None,
@@ -4358,7 +4311,6 @@ async def delete_webhook(
             api_kwargs=api_kwargs,
         )
 
-    @_log
     async def leave_chat(
         self,
         chat_id: Union[str, int],
@@ -4393,7 +4345,6 @@ async def leave_chat(
             api_kwargs=api_kwargs,
         )
 
-    @_log
     async def get_chat(
         self,
         chat_id: Union[str, int],
@@ -4432,7 +4383,6 @@ async def get_chat(
 
         return Chat.de_json(result, self)  # type: ignore[return-value]
 
-    @_log
     async def get_chat_administrators(
         self,
         chat_id: Union[str, int],
@@ -4474,7 +4424,6 @@ async def get_chat_administrators(
         )
         return ChatMember.de_list(result, self)
 
-    @_log
     async def get_chat_member_count(
         self,
         chat_id: Union[str, int],
@@ -4510,7 +4459,6 @@ async def get_chat_member_count(
             api_kwargs=api_kwargs,
         )
 
-    @_log
     async def get_chat_member(
         self,
         chat_id: Union[str, int],
@@ -4548,7 +4496,6 @@ async def get_chat_member(
         )
         return ChatMember.de_json(result, self)  # type: ignore[return-value]
 
-    @_log
     async def set_chat_sticker_set(
         self,
         chat_id: Union[str, int],
@@ -4584,7 +4531,6 @@ async def set_chat_sticker_set(
             api_kwargs=api_kwargs,
         )
 
-    @_log
     async def delete_chat_sticker_set(
         self,
         chat_id: Union[str, int],
@@ -4617,7 +4563,6 @@ async def delete_chat_sticker_set(
             api_kwargs=api_kwargs,
         )
 
-    @_log
     async def get_webhook_info(
         self,
         *,
@@ -4646,7 +4591,6 @@ async def get_webhook_info(
         )
         return WebhookInfo.de_json(result, self)  # type: ignore[return-value]
 
-    @_log
     async def set_game_score(
         self,
         user_id: int,
@@ -4711,7 +4655,6 @@ async def set_game_score(
             api_kwargs=api_kwargs,
         )
 
-    @_log
     async def get_game_high_scores(
         self,
         user_id: int,
@@ -4772,7 +4715,6 @@ async def get_game_high_scores(
 
         return GameHighScore.de_list(result, self)
 
-    @_log
     async def send_invoice(
         self,
         chat_id: Union[int, str],
@@ -4977,7 +4919,6 @@ async def send_invoice(
             api_kwargs=api_kwargs,
         )
 
-    @_log
     async def answer_shipping_query(
         self,
         shipping_query_id: str,
@@ -5036,7 +4977,6 @@ async def answer_shipping_query(
             api_kwargs=api_kwargs,
         )
 
-    @_log
     async def answer_pre_checkout_query(
         self,
         pre_checkout_query_id: str,
@@ -5093,7 +5033,6 @@ async def answer_pre_checkout_query(
             api_kwargs=api_kwargs,
         )
 
-    @_log
     async def answer_web_app_query(
         self,
         web_app_query_id: str,
@@ -5140,7 +5079,6 @@ async def answer_web_app_query(
 
         return SentWebAppMessage.de_json(api_result, self)  # type: ignore[return-value]
 
-    @_log
     async def restrict_chat_member(
         self,
         chat_id: Union[str, int],
@@ -5214,7 +5152,6 @@ async def restrict_chat_member(
             api_kwargs=api_kwargs,
         )
 
-    @_log
     async def promote_chat_member(
         self,
         chat_id: Union[str, int],
@@ -5339,7 +5276,6 @@ async def promote_chat_member(
             api_kwargs=api_kwargs,
         )
 
-    @_log
     async def set_chat_permissions(
         self,
         chat_id: Union[str, int],
@@ -5398,7 +5334,6 @@ async def set_chat_permissions(
             api_kwargs=api_kwargs,
         )
 
-    @_log
     async def set_chat_administrator_custom_title(
         self,
         chat_id: Union[int, str],
@@ -5441,7 +5376,6 @@ async def set_chat_administrator_custom_title(
             api_kwargs=api_kwargs,
         )
 
-    @_log
     async def export_chat_invite_link(
         self,
         chat_id: Union[str, int],
@@ -5485,7 +5419,6 @@ async def export_chat_invite_link(
             api_kwargs=api_kwargs,
         )
 
-    @_log
     async def create_chat_invite_link(
         self,
         chat_id: Union[str, int],
@@ -5563,7 +5496,6 @@ async def create_chat_invite_link(
 
         return ChatInviteLink.de_json(result, self)  # type: ignore[return-value]
 
-    @_log
     async def edit_chat_invite_link(
         self,
         chat_id: Union[str, int],
@@ -5645,7 +5577,6 @@ async def edit_chat_invite_link(
 
         return ChatInviteLink.de_json(result, self)  # type: ignore[return-value]
 
-    @_log
     async def revoke_chat_invite_link(
         self,
         chat_id: Union[str, int],
@@ -5693,7 +5624,6 @@ async def revoke_chat_invite_link(
 
         return ChatInviteLink.de_json(result, self)  # type: ignore[return-value]
 
-    @_log
     async def approve_chat_join_request(
         self,
         chat_id: Union[str, int],
@@ -5734,7 +5664,6 @@ async def approve_chat_join_request(
             api_kwargs=api_kwargs,
         )
 
-    @_log
     async def decline_chat_join_request(
         self,
         chat_id: Union[str, int],
@@ -5775,7 +5704,6 @@ async def decline_chat_join_request(
             api_kwargs=api_kwargs,
         )
 
-    @_log
     async def set_chat_photo(
         self,
         chat_id: Union[str, int],
@@ -5822,7 +5750,6 @@ async def set_chat_photo(
             api_kwargs=api_kwargs,
         )
 
-    @_log
     async def delete_chat_photo(
         self,
         chat_id: Union[str, int],
@@ -5859,7 +5786,6 @@ async def delete_chat_photo(
             api_kwargs=api_kwargs,
         )
 
-    @_log
     async def set_chat_title(
         self,
         chat_id: Union[str, int],
@@ -5900,7 +5826,6 @@ async def set_chat_title(
             api_kwargs=api_kwargs,
         )
 
-    @_log
     async def set_chat_description(
         self,
         chat_id: Union[str, int],
@@ -5942,7 +5867,6 @@ async def set_chat_description(
             api_kwargs=api_kwargs,
         )
 
-    @_log
     async def pin_chat_message(
         self,
         chat_id: Union[str, int],
@@ -5992,7 +5916,6 @@ async def pin_chat_message(
             api_kwargs=api_kwargs,
         )
 
-    @_log
     async def unpin_chat_message(
         self,
         chat_id: Union[str, int],
@@ -6035,7 +5958,6 @@ async def unpin_chat_message(
             api_kwargs=api_kwargs,
         )
 
-    @_log
     async def unpin_all_chat_messages(
         self,
         chat_id: Union[str, int],
@@ -6074,7 +5996,6 @@ async def unpin_all_chat_messages(
             api_kwargs=api_kwargs,
         )
 
-    @_log
     async def get_sticker_set(
         self,
         name: str,
@@ -6109,7 +6030,6 @@ async def get_sticker_set(
         )
         return StickerSet.de_json(result, self)  # type: ignore[return-value]
 
-    @_log
     async def get_custom_emoji_stickers(
         self,
         custom_emoji_ids: Sequence[str],
@@ -6153,7 +6073,6 @@ async def get_custom_emoji_stickers(
         )
         return Sticker.de_list(result, self)
 
-    @_log
     async def upload_sticker_file(
         self,
         user_id: int,
@@ -6213,7 +6132,6 @@ async def upload_sticker_file(
         )
         return File.de_json(result, self)  # type: ignore[return-value]
 
-    @_log
     async def add_sticker_to_set(
         self,
         user_id: int,
@@ -6275,7 +6193,6 @@ async def add_sticker_to_set(
             api_kwargs=api_kwargs,
         )
 
-    @_log
     async def set_sticker_position_in_set(
         self,
         sticker: str,
@@ -6311,7 +6228,6 @@ async def set_sticker_position_in_set(
             api_kwargs=api_kwargs,
         )
 
-    @_log
     async def create_new_sticker_set(
         self,
         user_id: int,
@@ -6410,7 +6326,6 @@ async def create_new_sticker_set(
             api_kwargs=api_kwargs,
         )
 
-    @_log
     async def delete_sticker_from_set(
         self,
         sticker: str,
@@ -6444,7 +6359,6 @@ async def delete_sticker_from_set(
             api_kwargs=api_kwargs,
         )
 
-    @_log
     async def delete_sticker_set(
         self,
         name: str,
@@ -6481,7 +6395,6 @@ async def delete_sticker_set(
             api_kwargs=api_kwargs,
         )
 
-    @_log
     async def set_sticker_set_thumbnail(
         self,
         name: str,
@@ -6546,7 +6459,6 @@ async def set_sticker_set_thumbnail(
             api_kwargs=api_kwargs,
         )
 
-    @_log
     async def set_sticker_set_title(
         self,
         name: str,
@@ -6587,7 +6499,6 @@ async def set_sticker_set_title(
             api_kwargs=api_kwargs,
         )
 
-    @_log
     async def set_sticker_emoji_list(
         self,
         sticker: str,
@@ -6629,7 +6540,6 @@ async def set_sticker_emoji_list(
             api_kwargs=api_kwargs,
         )
 
-    @_log
     async def set_sticker_keywords(
         self,
         sticker: str,
@@ -6671,7 +6581,6 @@ async def set_sticker_keywords(
             api_kwargs=api_kwargs,
         )
 
-    @_log
     async def set_sticker_mask_position(
         self,
         sticker: str,
@@ -6712,7 +6621,6 @@ async def set_sticker_mask_position(
             api_kwargs=api_kwargs,
         )
 
-    @_log
     async def set_custom_emoji_sticker_set_thumbnail(
         self,
         name: str,
@@ -6754,7 +6662,6 @@ async def set_custom_emoji_sticker_set_thumbnail(
             api_kwargs=api_kwargs,
         )
 
-    @_log
     async def set_passport_data_errors(
         self,
         user_id: int,
@@ -6801,7 +6708,6 @@ async def set_passport_data_errors(
             api_kwargs=api_kwargs,
         )
 
-    @_log
     async def send_poll(
         self,
         chat_id: Union[int, str],
@@ -6958,7 +6864,6 @@ async def send_poll(
             api_kwargs=api_kwargs,
         )
 
-    @_log
     async def stop_poll(
         self,
         chat_id: Union[int, str],
@@ -7004,7 +6909,6 @@ async def stop_poll(
         )
         return Poll.de_json(result, self)  # type: ignore[return-value]
 
-    @_log
     async def send_dice(
         self,
         chat_id: Union[int, str],
@@ -7105,7 +7009,6 @@ async def send_dice(
             api_kwargs=api_kwargs,
         )
 
-    @_log
     async def get_my_default_administrator_rights(
         self,
         for_channels: Optional[bool] = None,
@@ -7147,7 +7050,6 @@ async def get_my_default_administrator_rights(
 
         return ChatAdministratorRights.de_json(result, self)  # type: ignore[return-value]
 
-    @_log
     async def set_my_default_administrator_rights(
         self,
         rights: Optional[ChatAdministratorRights] = None,
@@ -7193,7 +7095,6 @@ async def set_my_default_administrator_rights(
             api_kwargs=api_kwargs,
         )
 
-    @_log
     async def get_my_commands(
         self,
         scope: Optional[BotCommandScope] = None,
@@ -7247,7 +7148,6 @@ async def get_my_commands(
 
         return BotCommand.de_list(result, self)
 
-    @_log
     async def set_my_commands(
         self,
         commands: Sequence[Union[BotCommand, Tuple[str, str]]],
@@ -7312,7 +7212,6 @@ async def set_my_commands(
             api_kwargs=api_kwargs,
         )
 
-    @_log
     async def delete_my_commands(
         self,
         scope: Optional[BotCommandScope] = None,
@@ -7360,7 +7259,6 @@ async def delete_my_commands(
             api_kwargs=api_kwargs,
         )
 
-    @_log
     async def log_out(
         self,
         *,
@@ -7393,7 +7291,6 @@ async def log_out(
             api_kwargs=api_kwargs,
         )
 
-    @_log
     async def close(
         self,
         *,
@@ -7425,7 +7322,6 @@ async def close(
             api_kwargs=api_kwargs,
         )
 
-    @_log
     async def copy_message(
         self,
         chat_id: Union[int, str],
@@ -7551,7 +7447,6 @@ async def copy_message(
         )
         return MessageId.de_json(result, self)  # type: ignore[return-value]
 
-    @_log
     async def copy_messages(
         self,
         chat_id: Union[int, str],
@@ -7622,7 +7517,6 @@ async def copy_messages(
         )
         return MessageId.de_list(result, self)
 
-    @_log
     async def set_chat_menu_button(
         self,
         chat_id: Optional[int] = None,
@@ -7664,7 +7558,6 @@ async def set_chat_menu_button(
             api_kwargs=api_kwargs,
         )
 
-    @_log
     async def get_chat_menu_button(
         self,
         chat_id: Optional[int] = None,
@@ -7704,7 +7597,6 @@ async def get_chat_menu_button(
         )
         return MenuButton.de_json(result, bot=self)  # type: ignore[return-value]
 
-    @_log
     async def create_invoice_link(
         self,
         title: str,
@@ -7833,7 +7725,6 @@ async def create_invoice_link(
             api_kwargs=api_kwargs,
         )
 
-    @_log
     async def get_forum_topic_icon_stickers(
         self,
         *,
@@ -7865,7 +7756,6 @@ async def get_forum_topic_icon_stickers(
         )
         return Sticker.de_list(result, self)
 
-    @_log
     async def create_forum_topic(
         self,
         chat_id: Union[str, int],
@@ -7925,7 +7815,6 @@ async def create_forum_topic(
         )
         return ForumTopic.de_json(result, self)  # type: ignore[return-value]
 
-    @_log
     async def edit_forum_topic(
         self,
         chat_id: Union[str, int],
@@ -7982,7 +7871,6 @@ async def edit_forum_topic(
             api_kwargs=api_kwargs,
         )
 
-    @_log
     async def close_forum_topic(
         self,
         chat_id: Union[str, int],
@@ -8027,7 +7915,6 @@ async def close_forum_topic(
             api_kwargs=api_kwargs,
         )
 
-    @_log
     async def reopen_forum_topic(
         self,
         chat_id: Union[str, int],
@@ -8072,7 +7959,6 @@ async def reopen_forum_topic(
             api_kwargs=api_kwargs,
         )
 
-    @_log
     async def delete_forum_topic(
         self,
         chat_id: Union[str, int],
@@ -8116,7 +8002,6 @@ async def delete_forum_topic(
             api_kwargs=api_kwargs,
         )
 
-    @_log
     async def unpin_all_forum_topic_messages(
         self,
         chat_id: Union[str, int],
@@ -8161,7 +8046,6 @@ async def unpin_all_forum_topic_messages(
             api_kwargs=api_kwargs,
         )
 
-    @_log
     async def unpin_all_general_forum_topic_messages(
         self,
         chat_id: Union[str, int],
@@ -8201,7 +8085,6 @@ async def unpin_all_general_forum_topic_messages(
             api_kwargs=api_kwargs,
         )
 
-    @_log
     async def edit_general_forum_topic(
         self,
         chat_id: Union[str, int],
@@ -8245,7 +8128,6 @@ async def edit_general_forum_topic(
             api_kwargs=api_kwargs,
         )
 
-    @_log
     async def close_general_forum_topic(
         self,
         chat_id: Union[str, int],
@@ -8285,7 +8167,6 @@ async def close_general_forum_topic(
             api_kwargs=api_kwargs,
         )
 
-    @_log
     async def reopen_general_forum_topic(
         self,
         chat_id: Union[str, int],
@@ -8326,7 +8207,6 @@ async def reopen_general_forum_topic(
             api_kwargs=api_kwargs,
         )
 
-    @_log
     async def hide_general_forum_topic(
         self,
         chat_id: Union[str, int],
@@ -8367,7 +8247,6 @@ async def hide_general_forum_topic(
             api_kwargs=api_kwargs,
         )
 
-    @_log
     async def unhide_general_forum_topic(
         self,
         chat_id: Union[str, int],
@@ -8407,7 +8286,6 @@ async def unhide_general_forum_topic(
             api_kwargs=api_kwargs,
         )
 
-    @_log
     async def set_my_description(
         self,
         description: Optional[str] = None,
@@ -8453,7 +8331,6 @@ async def set_my_description(
             api_kwargs=api_kwargs,
         )
 
-    @_log
     async def set_my_short_description(
         self,
         short_description: Optional[str] = None,
@@ -8499,7 +8376,6 @@ async def set_my_short_description(
             api_kwargs=api_kwargs,
         )
 
-    @_log
     async def get_my_description(
         self,
         language_code: Optional[str] = None,
@@ -8538,7 +8414,6 @@ async def get_my_description(
             bot=self,
         )
 
-    @_log
     async def get_my_short_description(
         self,
         language_code: Optional[str] = None,
@@ -8578,7 +8453,6 @@ async def get_my_short_description(
             bot=self,
         )
 
-    @_log
     async def set_my_name(
         self,
         name: Optional[str] = None,
@@ -8627,7 +8501,6 @@ async def set_my_name(
             api_kwargs=api_kwargs,
         )
 
-    @_log
     async def get_my_name(
         self,
         language_code: Optional[str] = None,
@@ -8666,7 +8539,6 @@ async def get_my_name(
             bot=self,
         )
 
-    @_log
     async def get_user_chat_boosts(
         self,
         chat_id: Union[str, int],
@@ -8709,7 +8581,6 @@ async def get_user_chat_boosts(
             bot=self,
         )
 
-    @_log
     async def set_message_reaction(
         self,
         chat_id: Union[str, int],
diff --git a/telegram/_chat.py b/telegram/_chat.py
index c304be02def..915614bb6c8 100644
--- a/telegram/_chat.py
+++ b/telegram/_chat.py
@@ -1169,7 +1169,7 @@ async def set_permissions(
 
     async def set_administrator_custom_title(
         self,
-        user_id: Union[int, str],
+        user_id: int,
         custom_title: str,
         *,
         read_timeout: ODVInput[float] = DEFAULT_NONE,
diff --git a/telegram/_message.py b/telegram/_message.py
index eac0c748486..5e2f6024709 100644
--- a/telegram/_message.py
+++ b/telegram/_message.py
@@ -2871,7 +2871,7 @@ async def reply_game(
             do_quote, quote, reply_to_message_id, reply_parameters
         )
         return await self.get_bot().send_game(
-            chat_id=chat_id,
+            chat_id=chat_id,  # type: ignore[arg-type]
             game_short_name=game_short_name,
             disable_notification=disable_notification,
             reply_parameters=effective_reply_parameters,
diff --git a/telegram/_passport/passportfile.py b/telegram/_passport/passportfile.py
index 3d37910629c..12c0f6f049d 100644
--- a/telegram/_passport/passportfile.py
+++ b/telegram/_passport/passportfile.py
@@ -203,5 +203,6 @@ async def get_file(
             pool_timeout=pool_timeout,
             api_kwargs=api_kwargs,
         )
-        file.set_credentials(self._credentials)
+        if self._credentials:
+            file.set_credentials(self._credentials)
         return file
diff --git a/telegram/ext/_extbot.py b/telegram/ext/_extbot.py
index eefda3bf3d7..30ae0029999 100644
--- a/telegram/ext/_extbot.py
+++ b/telegram/ext/_extbot.py
@@ -113,6 +113,7 @@
     from telegram.ext import BaseRateLimiter, Defaults
 
 HandledTypes = TypeVar("HandledTypes", bound=Union[Message, CallbackQuery, Chat])
+KT = TypeVar("KT", bound=ReplyMarkup)
 
 
 class ExtBot(Bot, Generic[RLARGS]):
@@ -485,11 +486,14 @@ def _insert_defaults(self, data: Dict[str, object]) -> None:
 
                 data[key] = new_value
 
-    def _replace_keyboard(self, reply_markup: Optional[ReplyMarkup]) -> Optional[ReplyMarkup]:
+    def _replace_keyboard(self, reply_markup: Optional[KT]) -> Optional[KT]:
         # If the reply_markup is an inline keyboard and we allow arbitrary callback data, let the
         # CallbackDataCache build a new keyboard with the data replaced. Otherwise return the input
         if isinstance(reply_markup, InlineKeyboardMarkup) and self.callback_data_cache is not None:
-            return self.callback_data_cache.process_keyboard(reply_markup)
+            # for some reason mypy doesn't understand that IKB is a subtype of Optional[KT]
+            return self.callback_data_cache.process_keyboard(  # type: ignore[return-value]
+                reply_markup
+            )
 
         return reply_markup
 
diff --git a/telegram/ext/_updater.py b/telegram/ext/_updater.py
index 000176288ae..7279c9f8ab7 100644
--- a/telegram/ext/_updater.py
+++ b/telegram/ext/_updater.py
@@ -793,7 +793,7 @@ async def bootstrap_set_webhook() -> bool:
             if drop_pending_updates:
                 _LOGGER.debug("Dropping pending updates from Telegram server")
             await self.bot.set_webhook(
-                url=webhook_url,
+                url=webhook_url,  # type: ignore[arg-type]
                 certificate=cert,
                 allowed_updates=allowed_updates,
                 ip_address=ip_address,


Test patch:
diff --git a/tests/test_bot.py b/tests/test_bot.py
index 71e5b23041d..853d9c305a5 100644
--- a/tests/test_bot.py
+++ b/tests/test_bot.py
@@ -22,7 +22,6 @@
 import inspect
 import logging
 import pickle
-import re
 import socket
 import time
 from collections import defaultdict
@@ -388,22 +387,10 @@ def test_bot_deepcopy_error(self, bot):
         with pytest.raises(TypeError, match="Bot objects cannot be deepcopied"):
             copy.deepcopy(bot)
 
-    @bot_methods(ext_bot=False)
-    def test_api_methods_have_log_decorator(self, bot_class, bot_method_name, bot_method):
-        """Check that all bot methods have the log decorator ..."""
-        # not islower() skips the camelcase aliases
-        if not bot_method_name.islower():
-            return
-        source = inspect.getsource(bot_method)
-        assert (
-            # Use re.match to only match at *the beginning* of the string
-            re.match(rf"\s*\@\_log\s*async def {bot_method_name}", source)
-        ), f"{bot_method_name} is missing the @_log decorator"
-
     @pytest.mark.parametrize(
         ("cls", "logger_name"), [(Bot, "telegram.Bot"), (ExtBot, "telegram.ext.ExtBot")]
     )
-    async def test_log_decorator(self, bot: PytestExtBot, cls, logger_name, caplog):
+    async def test_bot_method_logging(self, bot: PytestExtBot, cls, logger_name, caplog):
         # Second argument makes sure that we ignore logs from e.g. httpx
         with caplog.at_level(logging.DEBUG, logger="telegram"):
             await cls(bot.token).get_me()
@@ -415,11 +402,19 @@ async def test_log_decorator(self, bot: PytestExtBot, cls, logger_name, caplog):
                         caplog.records.pop(idx)
                     if record.getMessage().startswith("Task exception was never retrieved"):
                         caplog.records.pop(idx)
-            assert len(caplog.records) == 3
+            assert len(caplog.records) == 2
 
             assert all(caplog.records[i].name == logger_name for i in [-1, 0])
-            assert caplog.records[0].getMessage().startswith("Entering: get_me")
-            assert caplog.records[-1].getMessage().startswith("Exiting: get_me")
+            assert (
+                caplog.records[0]
+                .getMessage()
+                .startswith("Calling Bot API endpoint `getMe` with parameters `{}`")
+            )
+            assert (
+                caplog.records[-1]
+                .getMessage()
+                .startswith("Call to Bot API endpoint `getMe` finished with return value")
+            )
 
     @bot_methods()
     def test_camel_case_aliases(self, bot_class, bot_method_name, bot_method):
diff --git a/tests/test_chat.py b/tests/test_chat.py
index 2755853e1f7..7db747146a8 100644
--- a/tests/test_chat.py
+++ b/tests/test_chat.py
@@ -576,6 +576,19 @@ async def make_assertion(*_, **kwargs):
             custom_title = kwargs["custom_title"] == "custom_title"
             return chat_id and user_id and custom_title
 
+        assert check_shortcut_signature(
+            Chat.set_administrator_custom_title,
+            Bot.set_chat_administrator_custom_title,
+            ["chat_id"],
+            [],
+        )
+        assert await check_shortcut_call(
+            chat.set_administrator_custom_title,
+            chat.get_bot(),
+            "set_chat_administrator_custom_title",
+        )
+        assert await check_defaults_handling(chat.set_administrator_custom_title, chat.get_bot())
+
         monkeypatch.setattr("telegram.Bot.set_chat_administrator_custom_title", make_assertion)
         assert await chat.set_administrator_custom_title(user_id=42, custom_title="custom_title")