Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Reduce code duplication in testing defaults handling #3419

Merged
merged 6 commits into from Dec 12, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
420 changes: 420 additions & 0 deletions tests/auxil/bot_method_checks.py

Large diffs are not rendered by default.

25 changes: 25 additions & 0 deletions tests/auxil/object_conversions.py
@@ -0,0 +1,25 @@
#
# A library that provides a Python interface to the Telegram Bot API
# Copyright (C) 2015-2022
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Lesser Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Lesser Public License for more details.
#
# You should have received a copy of the GNU Lesser Public License
# along with this program. If not, see [http://www.gnu.org/licenses/].


def env_var_2_bool(env_var: object) -> bool:
if isinstance(env_var, bool):
return env_var
if not isinstance(env_var, str):
return False
return env_var.lower().strip() == "true"
384 changes: 3 additions & 381 deletions tests/conftest.py

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions tests/test_animation.py
Expand Up @@ -25,12 +25,12 @@
from telegram.error import BadRequest, TelegramError
from telegram.helpers import escape_markdown
from telegram.request import RequestData
from tests.conftest import (
from tests.auxil.bot_method_checks import (
check_defaults_handling,
check_shortcut_call,
check_shortcut_signature,
data_file,
)
from tests.conftest import data_file


@pytest.fixture(scope="function")
Expand Down
3 changes: 2 additions & 1 deletion tests/test_applicationbuilder.py
Expand Up @@ -38,7 +38,8 @@
from telegram.ext._applicationbuilder import _BOT_CHECKS
from telegram.request import HTTPXRequest

from .conftest import PRIVATE_KEY, data_file, env_var_2_bool
from .auxil.object_conversions import env_var_2_bool
from .conftest import PRIVATE_KEY, data_file

TEST_WITH_OPT_DEPS = env_var_2_bool(os.getenv("TEST_WITH_OPT_DEPS", True))

Expand Down
4 changes: 2 additions & 2 deletions tests/test_audio.py
Expand Up @@ -25,12 +25,12 @@
from telegram.error import TelegramError
from telegram.helpers import escape_markdown
from telegram.request import RequestData
from tests.conftest import (
from tests.auxil.bot_method_checks import (
check_defaults_handling,
check_shortcut_call,
check_shortcut_signature,
data_file,
)
from tests.conftest import data_file


@pytest.fixture(scope="function")
Expand Down
95 changes: 14 additions & 81 deletions tests/test_bot.py
Expand Up @@ -38,14 +38,12 @@
ChatAdministratorRights,
ChatPermissions,
Dice,
File,
InlineKeyboardButton,
InlineKeyboardMarkup,
InlineQueryResultArticle,
InlineQueryResultDocument,
InlineQueryResultVoice,
InputFile,
InputMedia,
InputMessageContent,
InputTextMessageContent,
LabeledPrice,
Expand All @@ -64,7 +62,7 @@
WebAppInfo,
)
from telegram._utils.datetime import UTC, from_timestamp, to_timestamp
from telegram._utils.defaultvalue import DEFAULT_NONE, DefaultValue
from telegram._utils.defaultvalue import DEFAULT_NONE
from telegram.constants import (
ChatAction,
InlineQueryLimit,
Expand All @@ -76,15 +74,9 @@
from telegram.ext import ExtBot, InvalidCallbackData
from telegram.helpers import escape_markdown
from telegram.request import BaseRequest, HTTPXRequest, RequestData
from tests.auxil.bot_method_checks import check_defaults_handling
from tests.bots import FALLBACKS
from tests.conftest import (
GITHUB_ACTION,
build_kwargs,
check_defaults_handling,
data_file,
expect_bad_request,
make_bot,
)
from tests.conftest import GITHUB_ACTION, data_file, expect_bad_request, make_bot


def to_camel_case(snake_str):
Expand Down Expand Up @@ -449,77 +441,18 @@ async def test_defaults_handling(
Finally, there are some tests for Defaults.{parse_mode, quote, allow_sending_without_reply}
at the appropriate places, as those are the only things we can actually check.
"""
if bot_method_name.lower().replace("_", "") == "getupdates":
return
if bot_method_name.lower().replace("_", "") == "getme":
# Mocking get_me within check_defaults_handling messes with the cached values like
# Bot.{bot, username, id, …}` unless we return the expected User object.
return_value = bot.bot
else:
return_value = None

try:
# Check that ExtBot does the right thing
bot_method = getattr(bot, bot_method_name)
assert await check_defaults_handling(bot_method, bot)

# check that tg.Bot does the right thing
# make_assertion basically checks everything that happens in
# Bot._insert_defaults and Bot._insert_defaults_for_ilq_results
async def make_assertion(url, request_data: RequestData, *args, **kwargs):
json_data = request_data.parameters

# Check regular kwargs
for k, v in json_data.items():
if isinstance(v, DefaultValue):
pytest.fail(f"Parameter {k} was passed as DefaultValue to request")
elif isinstance(v, InputMedia) and isinstance(v.parse_mode, DefaultValue):
pytest.fail(f"Parameter {k} has a DefaultValue parse_mode")
# Check InputMedia
elif k == "media" and isinstance(v, list):
if any(isinstance(med.get("parse_mode"), DefaultValue) for med in v):
pytest.fail("One of the media items has a DefaultValue parse_mode")

# Check inline query results
if bot_method_name.lower().replace("_", "") == "answerinlinequery":
for result_dict in json_data["results"]:
if isinstance(result_dict.get("parse_mode"), DefaultValue):
pytest.fail("InlineQueryResult has DefaultValue parse_mode")
imc = result_dict.get("input_message_content")
if imc and isinstance(imc.get("parse_mode"), DefaultValue):
pytest.fail(
"InlineQueryResult is InputMessageContext with DefaultValue "
"parse_mode "
)
if imc and isinstance(imc.get("disable_web_page_preview"), DefaultValue):
pytest.fail(
"InlineQueryResult is InputMessageContext with DefaultValue "
"disable_web_page_preview "
)
# Check datetime conversion
until_date = json_data.pop("until_date", None)
if until_date and until_date != 946684800:
pytest.fail("Naive until_date was not interpreted as UTC")

if bot_method_name in ["get_file", "getFile"]:
# The get_file methods try to check if the result is a local file
return File(file_id="result", file_unique_id="result").to_dict()

method = getattr(raw_bot, bot_method_name)
signature = inspect.signature(method)
kwargs_need_default = [
kwarg
for kwarg, value in signature.parameters.items()
if isinstance(value.default, DefaultValue)
]
monkeypatch.setattr(raw_bot.request, "post", make_assertion)
await method(**build_kwargs(inspect.signature(method), kwargs_need_default))
finally:
await bot.get_me() # because running the mock-get_me messages with bot.bot & friends

method = getattr(raw_bot, bot_method_name)
signature = inspect.signature(method)
kwargs_need_default = [
kwarg
for kwarg, value in signature.parameters.items()
if isinstance(value.default, DefaultValue)
]
monkeypatch.setattr(raw_bot.request, "post", make_assertion)
await method(**build_kwargs(inspect.signature(method), kwargs_need_default))
# Check that ExtBot does the right thing
bot_method = getattr(bot, bot_method_name)
raw_bot_method = getattr(raw_bot, bot_method_name)
assert await check_defaults_handling(bot_method, bot, return_value=return_value)
assert await check_defaults_handling(raw_bot_method, raw_bot, return_value=return_value)

def test_ext_bot_signature(self):
"""
Expand Down
2 changes: 1 addition & 1 deletion tests/test_callbackdatacache.py
Expand Up @@ -28,7 +28,7 @@
from telegram._utils.datetime import UTC
from telegram.ext import ExtBot
from telegram.ext._callbackdatacache import CallbackDataCache, InvalidCallbackData, _KeyboardData
from tests.conftest import env_var_2_bool
from tests.auxil.object_conversions import env_var_2_bool


@pytest.fixture(scope="function")
Expand Down
6 changes: 5 additions & 1 deletion tests/test_callbackquery.py
Expand Up @@ -22,7 +22,11 @@
import pytest

from telegram import Audio, Bot, CallbackQuery, Chat, Message, User
from tests.conftest import check_defaults_handling, check_shortcut_call, check_shortcut_signature
from tests.auxil.bot_method_checks import (
check_defaults_handling,
check_shortcut_call,
check_shortcut_signature,
)


@pytest.fixture(scope="function", params=["message", "inline"])
Expand Down
6 changes: 5 additions & 1 deletion tests/test_chat.py
Expand Up @@ -22,7 +22,11 @@
from telegram import Bot, Chat, ChatLocation, ChatPermissions, Location, User
from telegram.constants import ChatAction, ChatType
from telegram.helpers import escape_markdown
from tests.conftest import check_defaults_handling, check_shortcut_call, check_shortcut_signature
from tests.auxil.bot_method_checks import (
check_defaults_handling,
check_shortcut_call,
check_shortcut_signature,
)


@pytest.fixture(scope="class")
Expand Down
6 changes: 5 additions & 1 deletion tests/test_chatjoinrequest.py
Expand Up @@ -22,7 +22,11 @@

from telegram import Bot, Chat, ChatInviteLink, ChatJoinRequest, User
from telegram._utils.datetime import UTC, to_timestamp
from tests.conftest import check_defaults_handling, check_shortcut_call, check_shortcut_signature
from tests.auxil.bot_method_checks import (
check_defaults_handling,
check_shortcut_call,
check_shortcut_signature,
)


@pytest.fixture(scope="class")
Expand Down
5 changes: 2 additions & 3 deletions tests/test_chatphoto.py
Expand Up @@ -25,13 +25,12 @@
from telegram import Bot, ChatPhoto, Voice
from telegram.error import TelegramError
from telegram.request import RequestData
from tests.conftest import (
from tests.auxil.bot_method_checks import (
check_defaults_handling,
check_shortcut_call,
check_shortcut_signature,
data_file,
expect_bad_request,
)
from tests.conftest import data_file, expect_bad_request


@pytest.fixture(scope="function")
Expand Down
2 changes: 1 addition & 1 deletion tests/test_datetime.py
Expand Up @@ -26,7 +26,7 @@
from telegram.ext import Defaults

# sample time specification values categorised into absolute / delta / time-of-day
from tests.conftest import env_var_2_bool
from tests.auxil.object_conversions import env_var_2_bool

ABSOLUTE_TIME_SPECS = [
dtm.datetime.now(tz=dtm.timezone(dtm.timedelta(hours=-7))).replace(second=0, microsecond=0),
Expand Down
2 changes: 1 addition & 1 deletion tests/test_defaults.py
Expand Up @@ -25,7 +25,7 @@

from telegram import User
from telegram.ext import Defaults
from tests.conftest import env_var_2_bool
from tests.auxil.object_conversions import env_var_2_bool

TEST_WITH_OPT_DEPS = env_var_2_bool(os.getenv("TEST_WITH_OPT_DEPS", True))

Expand Down
4 changes: 2 additions & 2 deletions tests/test_document.py
Expand Up @@ -25,12 +25,12 @@
from telegram.error import BadRequest, TelegramError
from telegram.helpers import escape_markdown
from telegram.request import RequestData
from tests.conftest import (
from tests.auxil.bot_method_checks import (
check_defaults_handling,
check_shortcut_call,
check_shortcut_signature,
data_file,
)
from tests.conftest import data_file


@pytest.fixture(scope="function")
Expand Down
6 changes: 5 additions & 1 deletion tests/test_inlinequery.py
Expand Up @@ -20,7 +20,11 @@
import pytest

from telegram import Bot, InlineQuery, Location, Update, User
from tests.conftest import check_defaults_handling, check_shortcut_call, check_shortcut_signature
from tests.auxil.bot_method_checks import (
check_defaults_handling,
check_shortcut_call,
check_shortcut_signature,
)


@pytest.fixture(scope="class")
Expand Down
2 changes: 1 addition & 1 deletion tests/test_jobqueue.py
Expand Up @@ -27,7 +27,7 @@
import pytest

from telegram.ext import ApplicationBuilder, CallbackContext, ContextTypes, Job, JobQueue
from tests.conftest import env_var_2_bool
from tests.auxil.object_conversions import env_var_2_bool

TEST_WITH_OPT_DEPS = env_var_2_bool(os.getenv("TEST_WITH_OPT_DEPS", True))

Expand Down
6 changes: 5 additions & 1 deletion tests/test_message.py
Expand Up @@ -55,7 +55,11 @@
)
from telegram.constants import ChatAction, ParseMode
from telegram.ext import Defaults
from tests.conftest import check_defaults_handling, check_shortcut_call, check_shortcut_signature
from tests.auxil.bot_method_checks import (
check_defaults_handling,
check_shortcut_call,
check_shortcut_signature,
)
from tests.test_passport import RAW_PASSPORT_DATA


Expand Down
2 changes: 1 addition & 1 deletion tests/test_meta.py
Expand Up @@ -20,7 +20,7 @@

import pytest

from tests.conftest import env_var_2_bool
from tests.auxil.object_conversions import env_var_2_bool

skip_disabled = pytest.mark.skipif(
not env_var_2_bool(os.getenv("TEST_BUILD", False)), reason="TEST_BUILD not enabled"
Expand Down
2 changes: 1 addition & 1 deletion tests/test_no_passport.py
Expand Up @@ -32,7 +32,7 @@

from telegram import _bot as bot
from telegram._passport import credentials as credentials
from tests.conftest import env_var_2_bool
from tests.auxil.object_conversions import env_var_2_bool

TEST_WITH_OPT_DEPS = env_var_2_bool(os.getenv("TEST_WITH_OPT_DEPS", True))

Expand Down
2 changes: 1 addition & 1 deletion tests/test_official.py
Expand Up @@ -26,7 +26,7 @@

import telegram
from telegram._utils.defaultvalue import DefaultValue
from tests.conftest import env_var_2_bool
from tests.auxil.object_conversions import env_var_2_bool

IGNORED_OBJECTS = ("ResponseParameters", "CallbackGame")
IGNORED_PARAMETERS = {
Expand Down
6 changes: 5 additions & 1 deletion tests/test_passportfile.py
Expand Up @@ -19,7 +19,11 @@
import pytest

from telegram import Bot, File, PassportElementError, PassportFile
from tests.conftest import check_defaults_handling, check_shortcut_call, check_shortcut_signature
from tests.auxil.bot_method_checks import (
check_defaults_handling,
check_shortcut_call,
check_shortcut_signature,
)


@pytest.fixture(scope="class")
Expand Down
5 changes: 2 additions & 3 deletions tests/test_photo.py
Expand Up @@ -25,13 +25,12 @@
from telegram.error import BadRequest, TelegramError
from telegram.helpers import escape_markdown
from telegram.request import RequestData
from tests.conftest import (
from tests.auxil.bot_method_checks import (
check_defaults_handling,
check_shortcut_call,
check_shortcut_signature,
data_file,
expect_bad_request,
)
from tests.conftest import data_file, expect_bad_request


@pytest.fixture(scope="function")
Expand Down
6 changes: 5 additions & 1 deletion tests/test_precheckoutquery.py
Expand Up @@ -20,7 +20,11 @@
import pytest

from telegram import Bot, OrderInfo, PreCheckoutQuery, Update, User
from tests.conftest import check_defaults_handling, check_shortcut_call, check_shortcut_signature
from tests.auxil.bot_method_checks import (
check_defaults_handling,
check_shortcut_call,
check_shortcut_signature,
)


@pytest.fixture(scope="class")
Expand Down