From 74358f169fa73838dfc72ec207e0175534a83714 Mon Sep 17 00:00:00 2001 From: ai-ag2026 <261867348+ai-ag2026@users.noreply.github.com> Date: Fri, 31 Jul 2026 21:50:46 +0200 Subject: [PATCH] test(telegram): prefer the real PTB library over process-wide mocks MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The gateway conftest (and test_telegram_approval_buttons' file-local copy) install a permanent MagicMock for the telegram module family whenever the real library has not been imported yet. Collection order decides: when a gateway file collects first, every later test needing genuine PTB classes is poisoned — tests/test_telegram_polling_progress_ptb.py subclasses the real BaseRequest and fails 6/6 with 'object MagicMock can't be used in await expression'. Reproducible with just two files: pytest tests/gateway/test_telegram_approval_buttons.py \ tests/test_telegram_polling_progress_ptb.py Both _ensure_telegram_mock variants now import the real library first and install fakes only when PTB is genuinely absent. python-telegram-bot is a production dependency, so in a normal dev/CI venv tests now always run against real PTB semantics. Flip side: the real TelegramError capitalize()s its message where the mock did not — the token-redaction assertions in test_telegram_rich_messages now compare case-insensitively (the property under test is the redaction, not the URL casing). Full telegram test set (56 files): 524 passed, 0 failed; the two-file reproduction above goes 6-failed -> all-passed. --- tests/gateway/conftest.py | 17 +++++++++++++++++ tests/gateway/test_telegram_approval_buttons.py | 12 ++++++++++++ tests/gateway/test_telegram_rich_messages.py | 11 +++++++---- 3 files changed, 36 insertions(+), 4 deletions(-) diff --git a/tests/gateway/conftest.py b/tests/gateway/conftest.py index 7a21465dd3d7..13a94dee76df 100644 --- a/tests/gateway/conftest.py +++ b/tests/gateway/conftest.py @@ -94,6 +94,23 @@ def _ensure_telegram_mock() -> None: if "telegram" in sys.modules and hasattr(sys.modules["telegram"], "__file__"): return # Real library is installed — nothing to mock + # Prefer the REAL library whenever it is importable. The mock below is + # process-wide and permanent, and it poisons every later-collected test + # that needs genuine PTB classes (tests/test_telegram_polling_progress_ptb + # subclasses the real BaseRequest) whenever a gateway file collects + # first. PTB is a production dependency, so in a normal venv this branch + # always wins; the mock survives only for genuinely PTB-less environments. + try: + import telegram # noqa: F401 + import telegram.constants # noqa: F401 + import telegram.error # noqa: F401 + import telegram.ext # noqa: F401 + import telegram.request # noqa: F401 + if hasattr(sys.modules.get("telegram"), "__file__"): + return + except ImportError: + pass + mod = MagicMock() mod.ext.ContextTypes.DEFAULT_TYPE = type(None) # One shared PTB-faithful enum namespace per constant, attached to BOTH diff --git a/tests/gateway/test_telegram_approval_buttons.py b/tests/gateway/test_telegram_approval_buttons.py index 0f6ba60db35a..875c74c87b5f 100644 --- a/tests/gateway/test_telegram_approval_buttons.py +++ b/tests/gateway/test_telegram_approval_buttons.py @@ -24,6 +24,18 @@ def _ensure_telegram_mock(): if "telegram" in sys.modules and hasattr(sys.modules["telegram"], "__file__"): return + # Prefer the REAL library whenever it is importable — same rationale as + # the gateway conftest: the fakes below are process-wide and permanent. + try: + import telegram # noqa: F401 + import telegram.constants # noqa: F401 + import telegram.error # noqa: F401 + import telegram.ext # noqa: F401 + import telegram.request # noqa: F401 + return + except ImportError: + pass + mod = MagicMock() mod.ext.ContextTypes.DEFAULT_TYPE = type(None) mod.constants.ParseMode.MARKDOWN = "Markdown" diff --git a/tests/gateway/test_telegram_rich_messages.py b/tests/gateway/test_telegram_rich_messages.py index 5e46cbc35dd3..e330a5c3e703 100644 --- a/tests/gateway/test_telegram_rich_messages.py +++ b/tests/gateway/test_telegram_rich_messages.py @@ -312,9 +312,12 @@ async def test_legacy_send_error_redacts_bot_token_without_traceback(monkeypatch assert result.success is False assert result.error is not None assert token not in result.error - assert "bot123456789:***/sendMessage" in result.error + # Real PTB TelegramError capitalize()s its message (the mock did not) — + # assert the token redaction case-insensitively; the property under + # test is the redaction, not the URL casing. + assert "bot123456789:***/sendmessage" in result.error.lower() assert token not in caplog.text - assert "bot123456789:***/sendMessage" in caplog.text + assert "bot123456789:***/sendmessage" in caplog.text.lower() adapter._bot.do_api_request.assert_not_called() @@ -454,9 +457,9 @@ async def test_legacy_edit_error_logs_redacted_bot_token_without_traceback(monke assert result.success is False assert result.error is not None assert token not in result.error - assert "bot123456789:***/editMessageText" in result.error + assert "bot123456789:***/editmessagetext" in result.error.lower() assert token not in caplog.text - assert "bot123456789:***/editMessageText" in caplog.text + assert "bot123456789:***/editmessagetext" in caplog.text.lower() # --------------------------------------------------------------------------