mirror of
https://github.com/python-telegram-bot/python-telegram-bot.git
synced 2024-12-22 06:25:12 +01:00
Empower ruff
(#3594)
This commit is contained in:
parent
4aedb33d37
commit
9997a9f47e
111 changed files with 776 additions and 896 deletions
|
@ -80,11 +80,11 @@ repos:
|
|||
- --diff
|
||||
- --check
|
||||
- repo: https://github.com/charliermarsh/ruff-pre-commit
|
||||
rev: 'v0.0.254'
|
||||
rev: 'v0.0.259'
|
||||
hooks:
|
||||
- id: ruff
|
||||
name: ruff
|
||||
files: ^(telegram|examples)/.*\.py$
|
||||
files: ^(telegram|examples|tests)/.*\.py$
|
||||
additional_dependencies:
|
||||
- httpx~=0.23.3
|
||||
- tornado~=6.2
|
||||
|
|
|
@ -103,13 +103,12 @@ async def track_chats(update: Update, context: ContextTypes.DEFAULT_TYPE) -> Non
|
|||
elif was_member and not is_member:
|
||||
logger.info("%s removed the bot from the group %s", cause_name, chat.title)
|
||||
context.bot_data.setdefault("group_ids", set()).discard(chat.id)
|
||||
else:
|
||||
if not was_member and is_member:
|
||||
logger.info("%s added the bot to the channel %s", cause_name, chat.title)
|
||||
context.bot_data.setdefault("channel_ids", set()).add(chat.id)
|
||||
elif was_member and not is_member:
|
||||
logger.info("%s removed the bot from the channel %s", cause_name, chat.title)
|
||||
context.bot_data.setdefault("channel_ids", set()).discard(chat.id)
|
||||
elif not was_member and is_member:
|
||||
logger.info("%s added the bot to the channel %s", cause_name, chat.title)
|
||||
context.bot_data.setdefault("channel_ids", set()).add(chat.id)
|
||||
elif was_member and not is_member:
|
||||
logger.info("%s removed the bot from the channel %s", cause_name, chat.title)
|
||||
context.bot_data.setdefault("channel_ids", set()).discard(chat.id)
|
||||
|
||||
|
||||
async def show_chats(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
|
||||
|
|
|
@ -39,7 +39,7 @@ DEVELOPER_CHAT_ID = 123456789
|
|||
async def error_handler(update: object, context: ContextTypes.DEFAULT_TYPE) -> None:
|
||||
"""Log the error and send a telegram message to notify the developer."""
|
||||
# Log the error before we do anything else, so we can see it even if something breaks.
|
||||
logger.error(msg="Exception while handling an update:", exc_info=context.error)
|
||||
logger.error("Exception while handling an update:", exc_info=context.error)
|
||||
|
||||
# traceback.format_exception returns the usual python message about an exception, but as a
|
||||
# list of strings rather than a single string, so we have to join them together.
|
||||
|
|
|
@ -58,7 +58,7 @@ async def inline_query(update: Update, context: ContextTypes.DEFAULT_TYPE) -> No
|
|||
"""Handle the inline query. This is run when you type: @botusername <query>"""
|
||||
query = update.inline_query.query
|
||||
|
||||
if query == "":
|
||||
if not query: # empty query should not be handled
|
||||
return
|
||||
|
||||
results = [
|
||||
|
|
|
@ -48,6 +48,9 @@ logging.basicConfig(
|
|||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
TOTAL_VOTER_COUNT = 3
|
||||
|
||||
|
||||
async def start(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
|
||||
"""Inform user about what this bot can do"""
|
||||
await update.message.reply_text(
|
||||
|
@ -101,7 +104,7 @@ async def receive_poll_answer(update: Update, context: ContextTypes.DEFAULT_TYPE
|
|||
)
|
||||
answered_poll["answers"] += 1
|
||||
# Close poll after three participants voted
|
||||
if answered_poll["answers"] == 3:
|
||||
if answered_poll["answers"] == TOTAL_VOTER_COUNT:
|
||||
await context.bot.stop_poll(answered_poll["chat_id"], answered_poll["message_id"])
|
||||
|
||||
|
||||
|
@ -123,7 +126,7 @@ async def receive_quiz_answer(update: Update, context: ContextTypes.DEFAULT_TYPE
|
|||
# the bot can receive closed poll updates we don't care about
|
||||
if update.poll.is_closed:
|
||||
return
|
||||
if update.poll.total_voter_count == 3:
|
||||
if update.poll.total_voter_count == TOTAL_VOTER_COUNT:
|
||||
try:
|
||||
quiz_data = context.bot_data[update.poll.id]
|
||||
# this means this poll answer update is from an old poll, we can't stop it then
|
||||
|
|
|
@ -7,6 +7,7 @@ on the telegram.ext bot framework.
|
|||
This program is dedicated to the public domain under the CC0 license.
|
||||
"""
|
||||
import asyncio
|
||||
import contextlib
|
||||
import logging
|
||||
from typing import NoReturn
|
||||
|
||||
|
@ -72,7 +73,5 @@ async def echo(bot: Bot, update_id: int) -> int:
|
|||
|
||||
|
||||
if __name__ == "__main__":
|
||||
try:
|
||||
with contextlib.suppress(KeyboardInterrupt): # Ignore exception when Ctrl-C is pressed
|
||||
asyncio.run(main())
|
||||
except KeyboardInterrupt: # Ignore exception when Ctrl-C is pressed
|
||||
pass
|
||||
|
|
|
@ -9,3 +9,7 @@ line_length = 99
|
|||
[tool.ruff]
|
||||
line-length = 99
|
||||
target-version = "py37"
|
||||
show-fixes = true
|
||||
ignore = ["PLR2004", "PLR0911", "PLR0912", "PLR0913", "PLR0915"]
|
||||
select = ["E", "F", "I", "PL", "UP", "RUF", "PTH", "C4", "B", "PIE", "SIM", "RET", "RSE",
|
||||
"G", "ISC", "PT"]
|
||||
|
|
195
telegram/_bot.py
195
telegram/_bot.py
|
@ -19,6 +19,7 @@
|
|||
# along with this program. If not, see [http://www.gnu.org/licenses/].
|
||||
"""This module contains an object that represents a Telegram Bot."""
|
||||
import asyncio
|
||||
import contextlib
|
||||
import copy
|
||||
import functools
|
||||
import logging
|
||||
|
@ -152,7 +153,7 @@ class Bot(TelegramObject, AsyncContextManager["Bot"]):
|
|||
Examples:
|
||||
:any:`Raw API Bot <examples.rawapibot>`
|
||||
|
||||
.. seealso:: :wiki:`Your First Bot <Extensions-–-Your-first-Bot>`,
|
||||
.. seealso:: :wiki:`Your First Bot <Extensions---Your-first-Bot>`,
|
||||
:wiki:`Builder Pattern <Builder-Pattern>`
|
||||
|
||||
.. versionadded:: 13.2
|
||||
|
@ -411,10 +412,10 @@ class Bot(TelegramObject, AsyncContextManager["Bot"]):
|
|||
# 1)
|
||||
if isinstance(val, InputMedia):
|
||||
# Copy object as not to edit it in-place
|
||||
val = copy.copy(val)
|
||||
with val._unfrozen():
|
||||
val.parse_mode = DefaultValue.get_value(val.parse_mode)
|
||||
data[key] = val
|
||||
new = copy.copy(val)
|
||||
with new._unfrozen():
|
||||
new.parse_mode = DefaultValue.get_value(new.parse_mode)
|
||||
data[key] = new
|
||||
elif key == "media" and isinstance(val, Sequence):
|
||||
# Copy objects as not to edit them in-place
|
||||
copy_list = [copy.copy(media) for media in val]
|
||||
|
@ -479,10 +480,7 @@ class Bot(TelegramObject, AsyncContextManager["Bot"]):
|
|||
parameters=[RequestParameter.from_input(key, value) for key, value in data.items()],
|
||||
)
|
||||
|
||||
if endpoint == "getUpdates":
|
||||
request = self._request[0]
|
||||
else:
|
||||
request = self._request[1]
|
||||
request = self._request[0] if endpoint == "getUpdates" else self._request[1]
|
||||
|
||||
return await request.post(
|
||||
url=f"{self._base_url}/{endpoint}",
|
||||
|
@ -861,7 +859,7 @@ class Bot(TelegramObject, AsyncContextManager["Bot"]):
|
|||
|
||||
"""
|
||||
data: JSONDict = {"chat_id": chat_id, "message_id": message_id}
|
||||
result = await self._post(
|
||||
return await self._post(
|
||||
"deleteMessage",
|
||||
data,
|
||||
read_timeout=read_timeout,
|
||||
|
@ -870,7 +868,6 @@ class Bot(TelegramObject, AsyncContextManager["Bot"]):
|
|||
pool_timeout=pool_timeout,
|
||||
api_kwargs=api_kwargs,
|
||||
)
|
||||
return result
|
||||
|
||||
@_log
|
||||
async def forward_message(
|
||||
|
@ -1998,7 +1995,7 @@ class Bot(TelegramObject, AsyncContextManager["Bot"]):
|
|||
:class:`telegram.InputMediaDocument`, :class:`telegram.InputMediaPhoto`,\
|
||||
:class:`telegram.InputMediaVideo`]): An array
|
||||
describing messages to be sent, must include
|
||||
:tg-const:`telegram.constants.MediaGroupLimit.MIN_MEDIA_LENGTH`–
|
||||
:tg-const:`telegram.constants.MediaGroupLimit.MIN_MEDIA_LENGTH`-
|
||||
:tg-const:`telegram.constants.MediaGroupLimit.MAX_MEDIA_LENGTH` items.
|
||||
|
||||
.. versionchanged:: 20.0
|
||||
|
@ -2676,7 +2673,7 @@ class Bot(TelegramObject, AsyncContextManager["Bot"]):
|
|||
"action": action,
|
||||
"message_thread_id": message_thread_id,
|
||||
}
|
||||
result = await self._post(
|
||||
return await self._post(
|
||||
"sendChatAction",
|
||||
data,
|
||||
read_timeout=read_timeout,
|
||||
|
@ -2685,7 +2682,6 @@ class Bot(TelegramObject, AsyncContextManager["Bot"]):
|
|||
pool_timeout=pool_timeout,
|
||||
api_kwargs=api_kwargs,
|
||||
)
|
||||
return result
|
||||
|
||||
def _effective_inline_results( # skipcq: PYL-R0201
|
||||
self,
|
||||
|
@ -2708,10 +2704,7 @@ class Bot(TelegramObject, AsyncContextManager["Bot"]):
|
|||
|
||||
if current_offset is not None:
|
||||
# Convert the string input to integer
|
||||
if current_offset == "":
|
||||
current_offset_int = 0
|
||||
else:
|
||||
current_offset_int = int(current_offset)
|
||||
current_offset_int = 0 if not current_offset else int(current_offset)
|
||||
|
||||
# for now set to empty string, stating that there are no more results
|
||||
# might change later
|
||||
|
@ -2726,18 +2719,18 @@ class Bot(TelegramObject, AsyncContextManager["Bot"]):
|
|||
# the callback *might* return more results on the next call, so we increment
|
||||
# the page count
|
||||
next_offset = str(current_offset_int + 1)
|
||||
|
||||
elif len(results) > (current_offset_int + 1) * InlineQueryLimit.RESULTS:
|
||||
# we expect more results for the next page
|
||||
next_offset_int = current_offset_int + 1
|
||||
next_offset = str(next_offset_int)
|
||||
effective_results = results[
|
||||
current_offset_int
|
||||
* InlineQueryLimit.RESULTS : next_offset_int
|
||||
* InlineQueryLimit.RESULTS
|
||||
]
|
||||
else:
|
||||
if len(results) > (current_offset_int + 1) * InlineQueryLimit.RESULTS:
|
||||
# we expect more results for the next page
|
||||
next_offset_int = current_offset_int + 1
|
||||
next_offset = str(next_offset_int)
|
||||
effective_results = results[
|
||||
current_offset_int
|
||||
* InlineQueryLimit.RESULTS : next_offset_int
|
||||
* InlineQueryLimit.RESULTS
|
||||
]
|
||||
else:
|
||||
effective_results = results[current_offset_int * InlineQueryLimit.RESULTS :]
|
||||
effective_results = results[current_offset_int * InlineQueryLimit.RESULTS :]
|
||||
else:
|
||||
effective_results = results # type: ignore[assignment]
|
||||
|
||||
|
@ -2982,10 +2975,9 @@ class Bot(TelegramObject, AsyncContextManager["Bot"]):
|
|||
:class:`telegram.error.TelegramError`
|
||||
|
||||
"""
|
||||
try: # Try to get the file_id from the object
|
||||
# Try to get the file_id from the object, if it fails, assume it's a string
|
||||
with contextlib.suppress(AttributeError):
|
||||
file_id = file_id.file_id # type: ignore[union-attr]
|
||||
except AttributeError: # If it fails, assume it's a string
|
||||
pass
|
||||
|
||||
data: JSONDict = {"file_id": file_id}
|
||||
|
||||
|
@ -3059,7 +3051,7 @@ class Bot(TelegramObject, AsyncContextManager["Bot"]):
|
|||
"until_date": until_date,
|
||||
}
|
||||
|
||||
result = await self._post(
|
||||
return await self._post(
|
||||
"banChatMember",
|
||||
data,
|
||||
read_timeout=read_timeout,
|
||||
|
@ -3069,8 +3061,6 @@ class Bot(TelegramObject, AsyncContextManager["Bot"]):
|
|||
api_kwargs=api_kwargs,
|
||||
)
|
||||
|
||||
return result
|
||||
|
||||
@_log
|
||||
async def ban_chat_sender_chat(
|
||||
self,
|
||||
|
@ -3105,7 +3095,7 @@ class Bot(TelegramObject, AsyncContextManager["Bot"]):
|
|||
"""
|
||||
data: JSONDict = {"chat_id": chat_id, "sender_chat_id": sender_chat_id}
|
||||
|
||||
result = await self._post(
|
||||
return await self._post(
|
||||
"banChatSenderChat",
|
||||
data,
|
||||
read_timeout=read_timeout,
|
||||
|
@ -3115,8 +3105,6 @@ class Bot(TelegramObject, AsyncContextManager["Bot"]):
|
|||
api_kwargs=api_kwargs,
|
||||
)
|
||||
|
||||
return result
|
||||
|
||||
@_log
|
||||
async def unban_chat_member(
|
||||
self,
|
||||
|
@ -3152,7 +3140,7 @@ class Bot(TelegramObject, AsyncContextManager["Bot"]):
|
|||
"""
|
||||
data: JSONDict = {"chat_id": chat_id, "user_id": user_id, "only_if_banned": only_if_banned}
|
||||
|
||||
result = await self._post(
|
||||
return await self._post(
|
||||
"unbanChatMember",
|
||||
data,
|
||||
read_timeout=read_timeout,
|
||||
|
@ -3162,8 +3150,6 @@ class Bot(TelegramObject, AsyncContextManager["Bot"]):
|
|||
api_kwargs=api_kwargs,
|
||||
)
|
||||
|
||||
return result
|
||||
|
||||
@_log
|
||||
async def unban_chat_sender_chat(
|
||||
self,
|
||||
|
@ -3195,7 +3181,7 @@ class Bot(TelegramObject, AsyncContextManager["Bot"]):
|
|||
"""
|
||||
data: JSONDict = {"chat_id": chat_id, "sender_chat_id": sender_chat_id}
|
||||
|
||||
result = await self._post(
|
||||
return await self._post(
|
||||
"unbanChatSenderChat",
|
||||
data,
|
||||
read_timeout=read_timeout,
|
||||
|
@ -3205,8 +3191,6 @@ class Bot(TelegramObject, AsyncContextManager["Bot"]):
|
|||
api_kwargs=api_kwargs,
|
||||
)
|
||||
|
||||
return result
|
||||
|
||||
@_log
|
||||
async def answer_callback_query(
|
||||
self,
|
||||
|
@ -3263,7 +3247,7 @@ class Bot(TelegramObject, AsyncContextManager["Bot"]):
|
|||
"url": url,
|
||||
}
|
||||
|
||||
result = await self._post(
|
||||
return await self._post(
|
||||
"answerCallbackQuery",
|
||||
data,
|
||||
read_timeout=read_timeout,
|
||||
|
@ -3273,8 +3257,6 @@ class Bot(TelegramObject, AsyncContextManager["Bot"]):
|
|||
api_kwargs=api_kwargs,
|
||||
)
|
||||
|
||||
return result
|
||||
|
||||
@_log
|
||||
async def edit_message_text(
|
||||
self,
|
||||
|
@ -3753,7 +3735,7 @@ class Bot(TelegramObject, AsyncContextManager["Bot"]):
|
|||
"certificate": self._parse_file_input(certificate), # type: ignore[arg-type]
|
||||
}
|
||||
|
||||
result = await self._post(
|
||||
return await self._post(
|
||||
"setWebhook",
|
||||
data,
|
||||
read_timeout=read_timeout,
|
||||
|
@ -3763,8 +3745,6 @@ class Bot(TelegramObject, AsyncContextManager["Bot"]):
|
|||
api_kwargs=api_kwargs,
|
||||
)
|
||||
|
||||
return result
|
||||
|
||||
@_log
|
||||
async def delete_webhook(
|
||||
self,
|
||||
|
@ -3793,7 +3773,7 @@ class Bot(TelegramObject, AsyncContextManager["Bot"]):
|
|||
"""
|
||||
data = {"drop_pending_updates": drop_pending_updates}
|
||||
|
||||
result = await self._post(
|
||||
return await self._post(
|
||||
"deleteWebhook",
|
||||
data,
|
||||
read_timeout=read_timeout,
|
||||
|
@ -3803,8 +3783,6 @@ class Bot(TelegramObject, AsyncContextManager["Bot"]):
|
|||
api_kwargs=api_kwargs,
|
||||
)
|
||||
|
||||
return result
|
||||
|
||||
@_log
|
||||
async def leave_chat(
|
||||
self,
|
||||
|
@ -3830,7 +3808,7 @@ class Bot(TelegramObject, AsyncContextManager["Bot"]):
|
|||
"""
|
||||
data: JSONDict = {"chat_id": chat_id}
|
||||
|
||||
result = await self._post(
|
||||
return await self._post(
|
||||
"leaveChat",
|
||||
data,
|
||||
read_timeout=read_timeout,
|
||||
|
@ -3840,8 +3818,6 @@ class Bot(TelegramObject, AsyncContextManager["Bot"]):
|
|||
api_kwargs=api_kwargs,
|
||||
)
|
||||
|
||||
return result
|
||||
|
||||
@_log
|
||||
async def get_chat(
|
||||
self,
|
||||
|
@ -3949,7 +3925,7 @@ class Bot(TelegramObject, AsyncContextManager["Bot"]):
|
|||
|
||||
"""
|
||||
data: JSONDict = {"chat_id": chat_id}
|
||||
result = await self._post(
|
||||
return await self._post(
|
||||
"getChatMemberCount",
|
||||
data,
|
||||
read_timeout=read_timeout,
|
||||
|
@ -3958,7 +3934,6 @@ class Bot(TelegramObject, AsyncContextManager["Bot"]):
|
|||
pool_timeout=pool_timeout,
|
||||
api_kwargs=api_kwargs,
|
||||
)
|
||||
return result
|
||||
|
||||
@_log
|
||||
async def get_chat_member(
|
||||
|
@ -4024,7 +3999,7 @@ class Bot(TelegramObject, AsyncContextManager["Bot"]):
|
|||
:obj:`bool`: On success, :obj:`True` is returned.
|
||||
"""
|
||||
data: JSONDict = {"chat_id": chat_id, "sticker_set_name": sticker_set_name}
|
||||
result = await self._post(
|
||||
return await self._post(
|
||||
"setChatStickerSet",
|
||||
data,
|
||||
read_timeout=read_timeout,
|
||||
|
@ -4033,7 +4008,6 @@ class Bot(TelegramObject, AsyncContextManager["Bot"]):
|
|||
pool_timeout=pool_timeout,
|
||||
api_kwargs=api_kwargs,
|
||||
)
|
||||
return result
|
||||
|
||||
@_log
|
||||
async def delete_chat_sticker_set(
|
||||
|
@ -4058,7 +4032,7 @@ class Bot(TelegramObject, AsyncContextManager["Bot"]):
|
|||
:obj:`bool`: On success, :obj:`True` is returned.
|
||||
"""
|
||||
data: JSONDict = {"chat_id": chat_id}
|
||||
result = await self._post(
|
||||
return await self._post(
|
||||
"deleteChatStickerSet",
|
||||
data,
|
||||
read_timeout=read_timeout,
|
||||
|
@ -4067,7 +4041,6 @@ class Bot(TelegramObject, AsyncContextManager["Bot"]):
|
|||
pool_timeout=pool_timeout,
|
||||
api_kwargs=api_kwargs,
|
||||
)
|
||||
return result
|
||||
|
||||
@_log
|
||||
async def get_webhook_info(
|
||||
|
@ -4455,7 +4428,7 @@ class Bot(TelegramObject, AsyncContextManager["Bot"]):
|
|||
"error_message": error_message,
|
||||
}
|
||||
|
||||
result = await self._post(
|
||||
return await self._post(
|
||||
"answerShippingQuery",
|
||||
data,
|
||||
read_timeout=read_timeout,
|
||||
|
@ -4465,8 +4438,6 @@ class Bot(TelegramObject, AsyncContextManager["Bot"]):
|
|||
api_kwargs=api_kwargs,
|
||||
)
|
||||
|
||||
return result
|
||||
|
||||
@_log
|
||||
async def answer_pre_checkout_query( # pylint: disable=invalid-name
|
||||
self,
|
||||
|
@ -4514,7 +4485,7 @@ class Bot(TelegramObject, AsyncContextManager["Bot"]):
|
|||
"error_message": error_message,
|
||||
}
|
||||
|
||||
result = await self._post(
|
||||
return await self._post(
|
||||
"answerPreCheckoutQuery",
|
||||
data,
|
||||
read_timeout=read_timeout,
|
||||
|
@ -4524,8 +4495,6 @@ class Bot(TelegramObject, AsyncContextManager["Bot"]):
|
|||
api_kwargs=api_kwargs,
|
||||
)
|
||||
|
||||
return result
|
||||
|
||||
@_log
|
||||
async def answer_web_app_query(
|
||||
self,
|
||||
|
@ -4637,7 +4606,7 @@ class Bot(TelegramObject, AsyncContextManager["Bot"]):
|
|||
"use_independent_chat_permissions": use_independent_chat_permissions,
|
||||
}
|
||||
|
||||
result = await self._post(
|
||||
return await self._post(
|
||||
"restrictChatMember",
|
||||
data,
|
||||
read_timeout=read_timeout,
|
||||
|
@ -4647,8 +4616,6 @@ class Bot(TelegramObject, AsyncContextManager["Bot"]):
|
|||
api_kwargs=api_kwargs,
|
||||
)
|
||||
|
||||
return result
|
||||
|
||||
@_log
|
||||
async def promote_chat_member(
|
||||
self,
|
||||
|
@ -4746,7 +4713,7 @@ class Bot(TelegramObject, AsyncContextManager["Bot"]):
|
|||
"can_manage_topics": can_manage_topics,
|
||||
}
|
||||
|
||||
result = await self._post(
|
||||
return await self._post(
|
||||
"promoteChatMember",
|
||||
data,
|
||||
read_timeout=read_timeout,
|
||||
|
@ -4756,8 +4723,6 @@ class Bot(TelegramObject, AsyncContextManager["Bot"]):
|
|||
api_kwargs=api_kwargs,
|
||||
)
|
||||
|
||||
return result
|
||||
|
||||
@_log
|
||||
async def set_chat_permissions(
|
||||
self,
|
||||
|
@ -4807,7 +4772,7 @@ class Bot(TelegramObject, AsyncContextManager["Bot"]):
|
|||
"permissions": permissions,
|
||||
"use_independent_chat_permissions": use_independent_chat_permissions,
|
||||
}
|
||||
result = await self._post(
|
||||
return await self._post(
|
||||
"setChatPermissions",
|
||||
data,
|
||||
read_timeout=read_timeout,
|
||||
|
@ -4816,7 +4781,6 @@ class Bot(TelegramObject, AsyncContextManager["Bot"]):
|
|||
pool_timeout=pool_timeout,
|
||||
api_kwargs=api_kwargs,
|
||||
)
|
||||
return result
|
||||
|
||||
@_log
|
||||
async def set_chat_administrator_custom_title(
|
||||
|
@ -4851,7 +4815,7 @@ class Bot(TelegramObject, AsyncContextManager["Bot"]):
|
|||
"""
|
||||
data: JSONDict = {"chat_id": chat_id, "user_id": user_id, "custom_title": custom_title}
|
||||
|
||||
result = await self._post(
|
||||
return await self._post(
|
||||
"setChatAdministratorCustomTitle",
|
||||
data,
|
||||
read_timeout=read_timeout,
|
||||
|
@ -4861,8 +4825,6 @@ class Bot(TelegramObject, AsyncContextManager["Bot"]):
|
|||
api_kwargs=api_kwargs,
|
||||
)
|
||||
|
||||
return result
|
||||
|
||||
@_log
|
||||
async def export_chat_invite_link(
|
||||
self,
|
||||
|
@ -4897,7 +4859,7 @@ class Bot(TelegramObject, AsyncContextManager["Bot"]):
|
|||
|
||||
"""
|
||||
data: JSONDict = {"chat_id": chat_id}
|
||||
result = await self._post(
|
||||
return await self._post(
|
||||
"exportChatInviteLink",
|
||||
data,
|
||||
read_timeout=read_timeout,
|
||||
|
@ -4906,7 +4868,6 @@ class Bot(TelegramObject, AsyncContextManager["Bot"]):
|
|||
pool_timeout=pool_timeout,
|
||||
api_kwargs=api_kwargs,
|
||||
)
|
||||
return result
|
||||
|
||||
@_log
|
||||
async def create_chat_invite_link(
|
||||
|
@ -5139,7 +5100,7 @@ class Bot(TelegramObject, AsyncContextManager["Bot"]):
|
|||
"""
|
||||
data: JSONDict = {"chat_id": chat_id, "user_id": user_id}
|
||||
|
||||
result = await self._post(
|
||||
return await self._post(
|
||||
"approveChatJoinRequest",
|
||||
data,
|
||||
read_timeout=read_timeout,
|
||||
|
@ -5149,8 +5110,6 @@ class Bot(TelegramObject, AsyncContextManager["Bot"]):
|
|||
api_kwargs=api_kwargs,
|
||||
)
|
||||
|
||||
return result
|
||||
|
||||
@_log
|
||||
async def decline_chat_join_request(
|
||||
self,
|
||||
|
@ -5182,7 +5141,7 @@ class Bot(TelegramObject, AsyncContextManager["Bot"]):
|
|||
"""
|
||||
data: JSONDict = {"chat_id": chat_id, "user_id": user_id}
|
||||
|
||||
result = await self._post(
|
||||
return await self._post(
|
||||
"declineChatJoinRequest",
|
||||
data,
|
||||
read_timeout=read_timeout,
|
||||
|
@ -5192,8 +5151,6 @@ class Bot(TelegramObject, AsyncContextManager["Bot"]):
|
|||
api_kwargs=api_kwargs,
|
||||
)
|
||||
|
||||
return result
|
||||
|
||||
@_log
|
||||
async def set_chat_photo(
|
||||
self,
|
||||
|
@ -5231,7 +5188,7 @@ class Bot(TelegramObject, AsyncContextManager["Bot"]):
|
|||
|
||||
"""
|
||||
data: JSONDict = {"chat_id": chat_id, "photo": self._parse_file_input(photo)}
|
||||
result = await self._post(
|
||||
return await self._post(
|
||||
"setChatPhoto",
|
||||
data,
|
||||
read_timeout=read_timeout,
|
||||
|
@ -5240,7 +5197,6 @@ class Bot(TelegramObject, AsyncContextManager["Bot"]):
|
|||
pool_timeout=pool_timeout,
|
||||
api_kwargs=api_kwargs,
|
||||
)
|
||||
return result
|
||||
|
||||
@_log
|
||||
async def delete_chat_photo(
|
||||
|
@ -5269,7 +5225,7 @@ class Bot(TelegramObject, AsyncContextManager["Bot"]):
|
|||
|
||||
"""
|
||||
data: JSONDict = {"chat_id": chat_id}
|
||||
result = await self._post(
|
||||
return await self._post(
|
||||
"deleteChatPhoto",
|
||||
data,
|
||||
read_timeout=read_timeout,
|
||||
|
@ -5278,7 +5234,6 @@ class Bot(TelegramObject, AsyncContextManager["Bot"]):
|
|||
pool_timeout=pool_timeout,
|
||||
api_kwargs=api_kwargs,
|
||||
)
|
||||
return result
|
||||
|
||||
@_log
|
||||
async def set_chat_title(
|
||||
|
@ -5311,7 +5266,7 @@ class Bot(TelegramObject, AsyncContextManager["Bot"]):
|
|||
|
||||
"""
|
||||
data: JSONDict = {"chat_id": chat_id, "title": title}
|
||||
result = await self._post(
|
||||
return await self._post(
|
||||
"setChatTitle",
|
||||
data,
|
||||
read_timeout=read_timeout,
|
||||
|
@ -5320,7 +5275,6 @@ class Bot(TelegramObject, AsyncContextManager["Bot"]):
|
|||
pool_timeout=pool_timeout,
|
||||
api_kwargs=api_kwargs,
|
||||
)
|
||||
return result
|
||||
|
||||
@_log
|
||||
async def set_chat_description(
|
||||
|
@ -5354,7 +5308,7 @@ class Bot(TelegramObject, AsyncContextManager["Bot"]):
|
|||
"""
|
||||
data: JSONDict = {"chat_id": chat_id, "description": description}
|
||||
|
||||
result = await self._post(
|
||||
return await self._post(
|
||||
"setChatDescription",
|
||||
data,
|
||||
read_timeout=read_timeout,
|
||||
|
@ -5363,7 +5317,6 @@ class Bot(TelegramObject, AsyncContextManager["Bot"]):
|
|||
pool_timeout=pool_timeout,
|
||||
api_kwargs=api_kwargs,
|
||||
)
|
||||
return result
|
||||
|
||||
@_log
|
||||
async def pin_chat_message(
|
||||
|
@ -5882,7 +5835,7 @@ CUSTOM_EMOJI_IDENTIFIER_LIMIT` custom emoji identifiers can be specified.
|
|||
"mask_position": mask_position,
|
||||
}
|
||||
|
||||
result = await self._post(
|
||||
return await self._post(
|
||||
"createNewStickerSet",
|
||||
data,
|
||||
read_timeout=read_timeout,
|
||||
|
@ -5892,8 +5845,6 @@ CUSTOM_EMOJI_IDENTIFIER_LIMIT` custom emoji identifiers can be specified.
|
|||
api_kwargs=api_kwargs,
|
||||
)
|
||||
|
||||
return result
|
||||
|
||||
@_log
|
||||
async def add_sticker_to_set(
|
||||
self,
|
||||
|
@ -6051,7 +6002,7 @@ CUSTOM_EMOJI_IDENTIFIER_LIMIT` custom emoji identifiers can be specified.
|
|||
"mask_position": mask_position,
|
||||
}
|
||||
|
||||
result = await self._post(
|
||||
return await self._post(
|
||||
"addStickerToSet",
|
||||
data,
|
||||
read_timeout=read_timeout,
|
||||
|
@ -6061,8 +6012,6 @@ CUSTOM_EMOJI_IDENTIFIER_LIMIT` custom emoji identifiers can be specified.
|
|||
api_kwargs=api_kwargs,
|
||||
)
|
||||
|
||||
return result
|
||||
|
||||
@_log
|
||||
async def set_sticker_position_in_set(
|
||||
self,
|
||||
|
@ -6089,7 +6038,7 @@ CUSTOM_EMOJI_IDENTIFIER_LIMIT` custom emoji identifiers can be specified.
|
|||
|
||||
"""
|
||||
data: JSONDict = {"sticker": sticker, "position": position}
|
||||
result = await self._post(
|
||||
return await self._post(
|
||||
"setStickerPositionInSet",
|
||||
data,
|
||||
read_timeout=read_timeout,
|
||||
|
@ -6098,7 +6047,6 @@ CUSTOM_EMOJI_IDENTIFIER_LIMIT` custom emoji identifiers can be specified.
|
|||
pool_timeout=pool_timeout,
|
||||
api_kwargs=api_kwargs,
|
||||
)
|
||||
return result
|
||||
|
||||
@_log
|
||||
async def delete_sticker_from_set(
|
||||
|
@ -6124,7 +6072,7 @@ CUSTOM_EMOJI_IDENTIFIER_LIMIT` custom emoji identifiers can be specified.
|
|||
|
||||
"""
|
||||
data: JSONDict = {"sticker": sticker}
|
||||
result = await self._post(
|
||||
return await self._post(
|
||||
"deleteStickerFromSet",
|
||||
data,
|
||||
read_timeout=read_timeout,
|
||||
|
@ -6133,7 +6081,6 @@ CUSTOM_EMOJI_IDENTIFIER_LIMIT` custom emoji identifiers can be specified.
|
|||
pool_timeout=pool_timeout,
|
||||
api_kwargs=api_kwargs,
|
||||
)
|
||||
return result
|
||||
|
||||
@_log
|
||||
async def delete_sticker_set(
|
||||
|
@ -6162,7 +6109,7 @@ CUSTOM_EMOJI_IDENTIFIER_LIMIT` custom emoji identifiers can be specified.
|
|||
|
||||
"""
|
||||
data: JSONDict = {"name": name}
|
||||
result = await self._post(
|
||||
return await self._post(
|
||||
"deleteStickerSet",
|
||||
data,
|
||||
read_timeout=read_timeout,
|
||||
|
@ -6171,7 +6118,6 @@ CUSTOM_EMOJI_IDENTIFIER_LIMIT` custom emoji identifiers can be specified.
|
|||
pool_timeout=pool_timeout,
|
||||
api_kwargs=api_kwargs,
|
||||
)
|
||||
return result
|
||||
|
||||
@_log
|
||||
async def set_sticker_set_thumbnail(
|
||||
|
@ -6317,7 +6263,7 @@ CUSTOM_EMOJI_IDENTIFIER_LIMIT` custom emoji identifiers can be specified.
|
|||
"thumbnail": self._parse_file_input(thumbnail) if thumbnail else None,
|
||||
}
|
||||
|
||||
result = await self._post(
|
||||
return await self._post(
|
||||
"setStickerSetThumbnail",
|
||||
data,
|
||||
read_timeout=read_timeout,
|
||||
|
@ -6327,8 +6273,6 @@ CUSTOM_EMOJI_IDENTIFIER_LIMIT` custom emoji identifiers can be specified.
|
|||
api_kwargs=api_kwargs,
|
||||
)
|
||||
|
||||
return result
|
||||
|
||||
@_log
|
||||
async def set_sticker_set_title(
|
||||
self,
|
||||
|
@ -6360,7 +6304,7 @@ CUSTOM_EMOJI_IDENTIFIER_LIMIT` custom emoji identifiers can be specified.
|
|||
|
||||
"""
|
||||
data: JSONDict = {"name": name, "title": title}
|
||||
result = await self._post(
|
||||
return await self._post(
|
||||
"setStickerSetTitle",
|
||||
data,
|
||||
read_timeout=read_timeout,
|
||||
|
@ -6369,7 +6313,6 @@ CUSTOM_EMOJI_IDENTIFIER_LIMIT` custom emoji identifiers can be specified.
|
|||
pool_timeout=pool_timeout,
|
||||
api_kwargs=api_kwargs,
|
||||
)
|
||||
return result
|
||||
|
||||
@_log
|
||||
async def set_sticker_emoji_list(
|
||||
|
@ -6403,7 +6346,7 @@ CUSTOM_EMOJI_IDENTIFIER_LIMIT` custom emoji identifiers can be specified.
|
|||
:class:`telegram.error.TelegramError`
|
||||
"""
|
||||
data: JSONDict = {"sticker": sticker, "emoji_list": emoji_list}
|
||||
result = await self._post(
|
||||
return await self._post(
|
||||
"setStickerEmojiList",
|
||||
data,
|
||||
read_timeout=read_timeout,
|
||||
|
@ -6412,7 +6355,6 @@ CUSTOM_EMOJI_IDENTIFIER_LIMIT` custom emoji identifiers can be specified.
|
|||
pool_timeout=pool_timeout,
|
||||
api_kwargs=api_kwargs,
|
||||
)
|
||||
return result
|
||||
|
||||
@_log
|
||||
async def set_sticker_keywords(
|
||||
|
@ -6446,7 +6388,7 @@ CUSTOM_EMOJI_IDENTIFIER_LIMIT` custom emoji identifiers can be specified.
|
|||
:class:`telegram.error.TelegramError`
|
||||
"""
|
||||
data: JSONDict = {"sticker": sticker, "keywords": keywords}
|
||||
result = await self._post(
|
||||
return await self._post(
|
||||
"setStickerKeywords",
|
||||
data,
|
||||
read_timeout=read_timeout,
|
||||
|
@ -6455,7 +6397,6 @@ CUSTOM_EMOJI_IDENTIFIER_LIMIT` custom emoji identifiers can be specified.
|
|||
pool_timeout=pool_timeout,
|
||||
api_kwargs=api_kwargs,
|
||||
)
|
||||
return result
|
||||
|
||||
@_log
|
||||
async def set_sticker_mask_position(
|
||||
|
@ -6488,7 +6429,7 @@ CUSTOM_EMOJI_IDENTIFIER_LIMIT` custom emoji identifiers can be specified.
|
|||
:class:`telegram.error.TelegramError`
|
||||
"""
|
||||
data: JSONDict = {"sticker": sticker, "mask_position": mask_position}
|
||||
result = await self._post(
|
||||
return await self._post(
|
||||
"setStickerMaskPosition",
|
||||
data,
|
||||
read_timeout=read_timeout,
|
||||
|
@ -6497,7 +6438,6 @@ CUSTOM_EMOJI_IDENTIFIER_LIMIT` custom emoji identifiers can be specified.
|
|||
pool_timeout=pool_timeout,
|
||||
api_kwargs=api_kwargs,
|
||||
)
|
||||
return result
|
||||
|
||||
@_log
|
||||
async def set_custom_emoji_sticker_set_thumbnail(
|
||||
|
@ -6531,7 +6471,7 @@ CUSTOM_EMOJI_IDENTIFIER_LIMIT` custom emoji identifiers can be specified.
|
|||
"""
|
||||
data: JSONDict = {"name": name, "custom_emoji_id": custom_emoji_id}
|
||||
|
||||
result = await self._post(
|
||||
return await self._post(
|
||||
"setCustomEmojiStickerSetThumbnail",
|
||||
data,
|
||||
read_timeout=read_timeout,
|
||||
|
@ -6541,8 +6481,6 @@ CUSTOM_EMOJI_IDENTIFIER_LIMIT` custom emoji identifiers can be specified.
|
|||
api_kwargs=api_kwargs,
|
||||
)
|
||||
|
||||
return result
|
||||
|
||||
@_log
|
||||
async def set_passport_data_errors(
|
||||
self,
|
||||
|
@ -6580,7 +6518,7 @@ CUSTOM_EMOJI_IDENTIFIER_LIMIT` custom emoji identifiers can be specified.
|
|||
|
||||
"""
|
||||
data: JSONDict = {"user_id": user_id, "errors": errors}
|
||||
result = await self._post(
|
||||
return await self._post(
|
||||
"setPassportDataErrors",
|
||||
data,
|
||||
read_timeout=read_timeout,
|
||||
|
@ -6589,7 +6527,6 @@ CUSTOM_EMOJI_IDENTIFIER_LIMIT` custom emoji identifiers can be specified.
|
|||
pool_timeout=pool_timeout,
|
||||
api_kwargs=api_kwargs,
|
||||
)
|
||||
return result
|
||||
|
||||
@_log
|
||||
async def send_poll(
|
||||
|
@ -6926,7 +6863,7 @@ CUSTOM_EMOJI_IDENTIFIER_LIMIT` custom emoji identifiers can be specified.
|
|||
"""
|
||||
data: JSONDict = {"rights": rights, "for_channels": for_channels}
|
||||
|
||||
result = await self._post(
|
||||
return await self._post(
|
||||
"setMyDefaultAdministratorRights",
|
||||
data,
|
||||
read_timeout=read_timeout,
|
||||
|
@ -6936,8 +6873,6 @@ CUSTOM_EMOJI_IDENTIFIER_LIMIT` custom emoji identifiers can be specified.
|
|||
api_kwargs=api_kwargs,
|
||||
)
|
||||
|
||||
return result
|
||||
|
||||
@_log
|
||||
async def get_my_commands(
|
||||
self,
|
||||
|
@ -7047,7 +6982,7 @@ CUSTOM_EMOJI_IDENTIFIER_LIMIT` custom emoji identifiers can be specified.
|
|||
cmds = [c if isinstance(c, BotCommand) else BotCommand(c[0], c[1]) for c in commands]
|
||||
data: JSONDict = {"commands": cmds, "scope": scope, "language_code": language_code}
|
||||
|
||||
result = await self._post(
|
||||
return await self._post(
|
||||
"setMyCommands",
|
||||
data,
|
||||
read_timeout=read_timeout,
|
||||
|
@ -7057,8 +6992,6 @@ CUSTOM_EMOJI_IDENTIFIER_LIMIT` custom emoji identifiers can be specified.
|
|||
api_kwargs=api_kwargs,
|
||||
)
|
||||
|
||||
return result
|
||||
|
||||
@_log
|
||||
async def delete_my_commands(
|
||||
self,
|
||||
|
@ -7097,7 +7030,7 @@ CUSTOM_EMOJI_IDENTIFIER_LIMIT` custom emoji identifiers can be specified.
|
|||
"""
|
||||
data: JSONDict = {"scope": scope, "language_code": language_code}
|
||||
|
||||
result = await self._post(
|
||||
return await self._post(
|
||||
"deleteMyCommands",
|
||||
data,
|
||||
read_timeout=read_timeout,
|
||||
|
@ -7107,8 +7040,6 @@ CUSTOM_EMOJI_IDENTIFIER_LIMIT` custom emoji identifiers can be specified.
|
|||
api_kwargs=api_kwargs,
|
||||
)
|
||||
|
||||
return result
|
||||
|
||||
@_log
|
||||
async def log_out(
|
||||
self,
|
||||
|
|
|
@ -41,7 +41,7 @@ class ChatJoinRequest(TelegramObject):
|
|||
Note:
|
||||
* Since Bot API 5.5, bots are allowed to contact users who sent a join request to a chat
|
||||
where the bot is an administrator with the
|
||||
:attr:`~telegram.ChatMemberAdministrator.can_invite_users` administrator right – even
|
||||
:attr:`~telegram.ChatMemberAdministrator.can_invite_users` administrator right - even
|
||||
if the user never interacted with the bot before.
|
||||
* Telegram does not guarantee that :attr:`from_user.id <from_user>` coincides with the
|
||||
``chat_id`` of the user. Please use :attr:`user_chat_id` to contact the user in
|
||||
|
|
|
@ -93,8 +93,7 @@ class MenuButton(TelegramObject):
|
|||
|
||||
if cls is MenuButton and data.get("type") in _class_mapping:
|
||||
return _class_mapping[data.pop("type")].de_json(data, bot=bot)
|
||||
out = super().de_json(data=data, bot=bot)
|
||||
return out
|
||||
return super().de_json(data=data, bot=bot)
|
||||
|
||||
COMMANDS: ClassVar[str] = constants.MenuButtonType.COMMANDS
|
||||
""":const:`telegram.constants.MenuButtonType.COMMANDS`"""
|
||||
|
|
|
@ -829,11 +829,8 @@ class Message(TelegramObject):
|
|||
a private chat or normal group, returns a t.me link of the message.
|
||||
"""
|
||||
if self.chat.type not in [Chat.PRIVATE, Chat.GROUP]:
|
||||
if self.chat.username:
|
||||
to_link = self.chat.username
|
||||
else:
|
||||
# Get rid of leading -100 for supergroups
|
||||
to_link = f"c/{str(self.chat.id)[4:]}"
|
||||
# the else block gets rid of leading -100 for supergroups:
|
||||
to_link = self.chat.username if self.chat.username else f"c/{str(self.chat.id)[4:]}"
|
||||
return f"https://t.me/{to_link}/{self.message_id}"
|
||||
return None
|
||||
|
||||
|
@ -3268,38 +3265,40 @@ class Message(TelegramObject):
|
|||
parsed_entities.extend(list(nested_entities.keys()))
|
||||
|
||||
orig_text = text
|
||||
text = escape(text)
|
||||
escaped_text = escape(text)
|
||||
|
||||
if nested_entities:
|
||||
text = Message._parse_html(
|
||||
escaped_text = Message._parse_html(
|
||||
orig_text, nested_entities, urled=urled, offset=entity.offset
|
||||
)
|
||||
|
||||
if entity.type == MessageEntity.TEXT_LINK:
|
||||
insert = f'<a href="{entity.url}">{text}</a>'
|
||||
insert = f'<a href="{entity.url}">{escaped_text}</a>'
|
||||
elif entity.type == MessageEntity.TEXT_MENTION and entity.user:
|
||||
insert = f'<a href="tg://user?id={entity.user.id}">{text}</a>'
|
||||
insert = f'<a href="tg://user?id={entity.user.id}">{escaped_text}</a>'
|
||||
elif entity.type == MessageEntity.URL and urled:
|
||||
insert = f'<a href="{text}">{text}</a>'
|
||||
insert = f'<a href="{escaped_text}">{escaped_text}</a>'
|
||||
elif entity.type == MessageEntity.BOLD:
|
||||
insert = f"<b>{text}</b>"
|
||||
insert = f"<b>{escaped_text}</b>"
|
||||
elif entity.type == MessageEntity.ITALIC:
|
||||
insert = f"<i>{text}</i>"
|
||||
insert = f"<i>{escaped_text}</i>"
|
||||
elif entity.type == MessageEntity.CODE:
|
||||
insert = f"<code>{text}</code>"
|
||||
insert = f"<code>{escaped_text}</code>"
|
||||
elif entity.type == MessageEntity.PRE:
|
||||
if entity.language:
|
||||
insert = f'<pre><code class="{entity.language}">{text}</code></pre>'
|
||||
insert = (
|
||||
f'<pre><code class="{entity.language}">{escaped_text}</code></pre>'
|
||||
)
|
||||
else:
|
||||
insert = f"<pre>{text}</pre>"
|
||||
insert = f"<pre>{escaped_text}</pre>"
|
||||
elif entity.type == MessageEntity.UNDERLINE:
|
||||
insert = f"<u>{text}</u>"
|
||||
insert = f"<u>{escaped_text}</u>"
|
||||
elif entity.type == MessageEntity.STRIKETHROUGH:
|
||||
insert = f"<s>{text}</s>"
|
||||
insert = f"<s>{escaped_text}</s>"
|
||||
elif entity.type == MessageEntity.SPOILER:
|
||||
insert = f'<span class="tg-spoiler">{text}</span>'
|
||||
insert = f'<span class="tg-spoiler">{escaped_text}</span>'
|
||||
else:
|
||||
insert = text
|
||||
insert = escaped_text
|
||||
|
||||
if offset == 0:
|
||||
if sys.maxunicode == 0xFFFF:
|
||||
|
@ -3315,16 +3314,15 @@ class Message(TelegramObject):
|
|||
)
|
||||
+ insert
|
||||
)
|
||||
elif sys.maxunicode == 0xFFFF:
|
||||
html_text += message_text[last_offset : entity.offset - offset] + insert
|
||||
else:
|
||||
if sys.maxunicode == 0xFFFF:
|
||||
html_text += message_text[last_offset : entity.offset - offset] + insert
|
||||
else:
|
||||
html_text += (
|
||||
message_text[ # type: ignore
|
||||
last_offset * 2 : (entity.offset - offset) * 2
|
||||
].decode("utf-16-le")
|
||||
+ insert
|
||||
)
|
||||
html_text += (
|
||||
message_text[ # type: ignore
|
||||
last_offset * 2 : (entity.offset - offset) * 2
|
||||
].decode("utf-16-le")
|
||||
+ insert
|
||||
)
|
||||
|
||||
last_offset = entity.offset - offset + entity.length
|
||||
|
||||
|
@ -3335,11 +3333,10 @@ class Message(TelegramObject):
|
|||
html_text += escape(
|
||||
message_text[last_offset * 2 :].decode("utf-16-le") # type: ignore
|
||||
)
|
||||
elif sys.maxunicode == 0xFFFF:
|
||||
html_text += message_text[last_offset:]
|
||||
else:
|
||||
if sys.maxunicode == 0xFFFF:
|
||||
html_text += message_text[last_offset:]
|
||||
else:
|
||||
html_text += message_text[last_offset * 2 :].decode("utf-16-le") # type: ignore
|
||||
html_text += message_text[last_offset * 2 :].decode("utf-16-le") # type: ignore
|
||||
|
||||
return html_text
|
||||
|
||||
|
@ -3452,8 +3449,7 @@ class Message(TelegramObject):
|
|||
}
|
||||
parsed_entities.extend(list(nested_entities.keys()))
|
||||
|
||||
orig_text = text
|
||||
text = escape_markdown(text, version=version)
|
||||
escaped_text = escape_markdown(text, version=version)
|
||||
|
||||
if nested_entities:
|
||||
if version < 2:
|
||||
|
@ -3461,8 +3457,8 @@ class Message(TelegramObject):
|
|||
"Nested entities are not supported for Markdown version 1"
|
||||
)
|
||||
|
||||
text = Message._parse_markdown(
|
||||
orig_text,
|
||||
escaped_text = Message._parse_markdown(
|
||||
text,
|
||||
nested_entities,
|
||||
urled=urled,
|
||||
offset=entity.offset,
|
||||
|
@ -3477,56 +3473,50 @@ class Message(TelegramObject):
|
|||
url = escape_markdown(
|
||||
entity.url, version=version, entity_type=MessageEntity.TEXT_LINK
|
||||
)
|
||||
insert = f"[{text}]({url})"
|
||||
insert = f"[{escaped_text}]({url})"
|
||||
elif entity.type == MessageEntity.TEXT_MENTION and entity.user:
|
||||
insert = f"[{text}](tg://user?id={entity.user.id})"
|
||||
insert = f"[{escaped_text}](tg://user?id={entity.user.id})"
|
||||
elif entity.type == MessageEntity.URL and urled:
|
||||
if version == 1:
|
||||
link = orig_text
|
||||
else:
|
||||
link = text
|
||||
insert = f"[{link}]({orig_text})"
|
||||
link = text if version == 1 else escaped_text
|
||||
insert = f"[{link}]({text})"
|
||||
elif entity.type == MessageEntity.BOLD:
|
||||
insert = f"*{text}*"
|
||||
insert = f"*{escaped_text}*"
|
||||
elif entity.type == MessageEntity.ITALIC:
|
||||
insert = f"_{text}_"
|
||||
insert = f"_{escaped_text}_"
|
||||
elif entity.type == MessageEntity.CODE:
|
||||
# Monospace needs special escaping. Also can't have entities nested within
|
||||
insert = f"`{escape_markdown(orig_text, version, MessageEntity.CODE)}`"
|
||||
insert = f"`{escape_markdown(text, version, MessageEntity.CODE)}`"
|
||||
|
||||
elif entity.type == MessageEntity.PRE:
|
||||
# Monospace needs special escaping. Also can't have entities nested within
|
||||
code = escape_markdown(
|
||||
orig_text, version=version, entity_type=MessageEntity.PRE
|
||||
)
|
||||
code = escape_markdown(text, version=version, entity_type=MessageEntity.PRE)
|
||||
if entity.language:
|
||||
prefix = f"```{entity.language}\n"
|
||||
elif code.startswith("\\"):
|
||||
prefix = "```"
|
||||
else:
|
||||
if code.startswith("\\"):
|
||||
prefix = "```"
|
||||
else:
|
||||
prefix = "```\n"
|
||||
prefix = "```\n"
|
||||
insert = f"{prefix}{code}```"
|
||||
elif entity.type == MessageEntity.UNDERLINE:
|
||||
if version == 1:
|
||||
raise ValueError(
|
||||
"Underline entities are not supported for Markdown version 1"
|
||||
)
|
||||
insert = f"__{text}__"
|
||||
insert = f"__{escaped_text}__"
|
||||
elif entity.type == MessageEntity.STRIKETHROUGH:
|
||||
if version == 1:
|
||||
raise ValueError(
|
||||
"Strikethrough entities are not supported for Markdown version 1"
|
||||
)
|
||||
insert = f"~{text}~"
|
||||
insert = f"~{escaped_text}~"
|
||||
elif entity.type == MessageEntity.SPOILER:
|
||||
if version == 1:
|
||||
raise ValueError(
|
||||
"Spoiler entities are not supported for Markdown version 1"
|
||||
)
|
||||
insert = f"||{text}||"
|
||||
insert = f"||{escaped_text}||"
|
||||
else:
|
||||
insert = text
|
||||
insert = escaped_text
|
||||
|
||||
if offset == 0:
|
||||
if sys.maxunicode == 0xFFFF:
|
||||
|
@ -3546,18 +3536,15 @@ class Message(TelegramObject):
|
|||
)
|
||||
+ insert
|
||||
)
|
||||
elif sys.maxunicode == 0xFFFF:
|
||||
markdown_text += message_text[last_offset : entity.offset - offset] + insert
|
||||
else:
|
||||
if sys.maxunicode == 0xFFFF:
|
||||
markdown_text += (
|
||||
message_text[last_offset : entity.offset - offset] + insert
|
||||
)
|
||||
else:
|
||||
markdown_text += (
|
||||
message_text[ # type: ignore
|
||||
last_offset * 2 : (entity.offset - offset) * 2
|
||||
].decode("utf-16-le")
|
||||
+ insert
|
||||
)
|
||||
markdown_text += (
|
||||
message_text[ # type: ignore
|
||||
last_offset * 2 : (entity.offset - offset) * 2
|
||||
].decode("utf-16-le")
|
||||
+ insert
|
||||
)
|
||||
|
||||
last_offset = entity.offset - offset + entity.length
|
||||
|
||||
|
@ -3569,13 +3556,10 @@ class Message(TelegramObject):
|
|||
message_text[last_offset * 2 :].decode("utf-16-le"), # type: ignore
|
||||
version=version,
|
||||
)
|
||||
elif sys.maxunicode == 0xFFFF:
|
||||
markdown_text += message_text[last_offset:]
|
||||
else:
|
||||
if sys.maxunicode == 0xFFFF:
|
||||
markdown_text += message_text[last_offset:]
|
||||
else:
|
||||
markdown_text += message_text[last_offset * 2 :].decode( # type: ignore
|
||||
"utf-16-le"
|
||||
)
|
||||
markdown_text += message_text[last_offset * 2 :].decode("utf-16-le") # type: ignore
|
||||
|
||||
return markdown_text
|
||||
|
||||
|
|
|
@ -180,7 +180,7 @@ class PassportElementErrorFiles(PassportElementError):
|
|||
with self._unfrozen():
|
||||
self.file_hashes: str = file_hashes
|
||||
|
||||
self._id_attrs = (self.source, self.type, self.message) + tuple(file_hashes)
|
||||
self._id_attrs = (self.source, self.type, self.message, *tuple(file_hashes))
|
||||
|
||||
|
||||
class PassportElementErrorFrontSide(PassportElementError):
|
||||
|
@ -362,7 +362,7 @@ class PassportElementErrorTranslationFiles(PassportElementError):
|
|||
with self._unfrozen():
|
||||
self.file_hashes: str = file_hashes
|
||||
|
||||
self._id_attrs = (self.source, self.type, self.message) + tuple(file_hashes)
|
||||
self._id_attrs = (self.source, self.type, self.message, *tuple(file_hashes))
|
||||
|
||||
|
||||
class PassportElementErrorUnspecified(PassportElementError):
|
||||
|
|
|
@ -24,7 +24,7 @@ from telegram._utils.argumentparsing import parse_sequence_arg
|
|||
from telegram._utils.types import JSONDict
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from telegram import LabeledPrice # noqa
|
||||
from telegram import LabeledPrice
|
||||
|
||||
|
||||
class ShippingOption(TelegramObject):
|
||||
|
|
|
@ -281,7 +281,7 @@ class TelegramObject:
|
|||
|
||||
# Make sure that we have a `_bot` attribute. This is necessary, since __getstate__ omits
|
||||
# this as Bots are not pickable.
|
||||
setattr(self, "_bot", None)
|
||||
self._bot = None
|
||||
|
||||
# get api_kwargs first because we may need to add entries to it (see try-except below)
|
||||
api_kwargs = cast(Dict[str, object], state.pop("api_kwargs", {}))
|
||||
|
@ -299,7 +299,7 @@ class TelegramObject:
|
|||
# and then set the rest as MappingProxyType attribute. Converting to MappingProxyType
|
||||
# is necessary, since __getstate__ converts it to a dict as MPT is not pickable.
|
||||
self._apply_api_kwargs(api_kwargs)
|
||||
setattr(self, "api_kwargs", MappingProxyType(api_kwargs))
|
||||
self.api_kwargs = MappingProxyType(api_kwargs)
|
||||
|
||||
# Apply freezing if necessary
|
||||
# we .get(…) the setting for backwards compatibility with objects that were pickled
|
||||
|
@ -328,7 +328,7 @@ class TelegramObject:
|
|||
result = cls.__new__(cls) # create a new instance
|
||||
memodict[id(self)] = result # save the id of the object in the dict
|
||||
|
||||
setattr(result, "_frozen", False) # unfreeze the new object for setting the attributes
|
||||
result._frozen = False # unfreeze the new object for setting the attributes
|
||||
|
||||
# now we set the attributes in the deepcopied object
|
||||
for k in self._get_attrs_names(include_private=True):
|
||||
|
|
|
@ -34,7 +34,7 @@ from telegram._telegramobject import TelegramObject
|
|||
from telegram._utils.types import JSONDict
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from telegram import Bot, Chat, User # noqa
|
||||
from telegram import Bot, Chat, User
|
||||
|
||||
|
||||
class Update(TelegramObject):
|
||||
|
@ -46,7 +46,7 @@ class Update(TelegramObject):
|
|||
Note:
|
||||
At most one of the optional parameters can be present in any given update.
|
||||
|
||||
.. seealso:: :wiki:`Your First Bot <Extensions-–-Your-first-Bot>`
|
||||
.. seealso:: :wiki:`Your First Bot <Extensions---Your-first-Bot>`
|
||||
|
||||
Args:
|
||||
update_id (:obj:`int`): The update's unique identifier. Update identifiers start from a
|
||||
|
|
|
@ -48,11 +48,7 @@ def _lstrip_str(in_s: str, lstr: str) -> str:
|
|||
:obj:`str`: The stripped string.
|
||||
|
||||
"""
|
||||
if in_s.startswith(lstr):
|
||||
res = in_s[len(lstr) :]
|
||||
else:
|
||||
res = in_s
|
||||
return res
|
||||
return in_s[len(lstr) :] if in_s.startswith(lstr) else in_s
|
||||
|
||||
|
||||
class TelegramError(Exception):
|
||||
|
|
|
@ -203,7 +203,7 @@ class AIORateLimiter(BaseRateLimiter[int]):
|
|||
return await callback(*args, **kwargs)
|
||||
|
||||
# mypy doesn't understand that the last run of the for loop raises an exception
|
||||
async def process_request( # type: ignore[return]
|
||||
async def process_request(
|
||||
self,
|
||||
callback: Callable[..., Coroutine[Any, Any, Union[bool, JSONDict, List[JSONDict]]]],
|
||||
args: Any,
|
||||
|
@ -232,10 +232,8 @@ class AIORateLimiter(BaseRateLimiter[int]):
|
|||
chat = True
|
||||
|
||||
# In case user passes integer chat id as string
|
||||
try:
|
||||
with contextlib.suppress(ValueError, TypeError):
|
||||
chat_id = int(chat_id)
|
||||
except (ValueError, TypeError):
|
||||
pass
|
||||
|
||||
if (isinstance(chat_id, int) and chat_id < 0) or isinstance(chat_id, str):
|
||||
# string chat_id only works for channels and supergroups
|
||||
|
@ -262,3 +260,4 @@ class AIORateLimiter(BaseRateLimiter[int]):
|
|||
finally:
|
||||
# Allow other requests to be processed
|
||||
self._retry_after_event.set()
|
||||
return None # type: ignore[return-value]
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
# along with this program. If not, see [http://www.gnu.org/licenses/].
|
||||
"""This module contains the Application class."""
|
||||
import asyncio
|
||||
import contextlib
|
||||
import inspect
|
||||
import itertools
|
||||
import logging
|
||||
|
@ -74,6 +75,7 @@ DEFAULT_GROUP: int = 0
|
|||
|
||||
_AppType = TypeVar("_AppType", bound="Application") # pylint: disable=invalid-name
|
||||
_STOP_SIGNAL = object()
|
||||
_DEFAULT_0 = DefaultValue(0)
|
||||
|
||||
_logger = logging.getLogger(__name__)
|
||||
|
||||
|
@ -137,7 +139,7 @@ class Application(Generic[BT, CCT, UD, CD, BD, JQ], AsyncContextManager["Applica
|
|||
Examples:
|
||||
:any:`Echo Bot <examples.echobot>`
|
||||
|
||||
.. seealso:: :wiki:`Your First Bot <Extensions-–-Your-first-Bot>`,
|
||||
.. seealso:: :wiki:`Your First Bot <Extensions---Your-first-Bot>`,
|
||||
:wiki:`Architecture Overview <Architecture>`
|
||||
|
||||
.. versionchanged:: 20.0
|
||||
|
@ -997,10 +999,8 @@ class Application(Generic[BT, CCT, UD, CD, BD, JQ], AsyncContextManager["Applica
|
|||
self.__create_task_tasks.discard(task) # Discard from our set since we are done with it
|
||||
# We just retrieve the eventual exception so that asyncio doesn't complain in case
|
||||
# it's not retrieved somewhere else
|
||||
try:
|
||||
with contextlib.suppress(asyncio.CancelledError, asyncio.InvalidStateError):
|
||||
task.exception()
|
||||
except (asyncio.CancelledError, asyncio.InvalidStateError):
|
||||
pass
|
||||
|
||||
async def __create_task_callback(
|
||||
self,
|
||||
|
@ -1200,7 +1200,7 @@ class Application(Generic[BT, CCT, UD, CD, BD, JQ], AsyncContextManager["Applica
|
|||
Union[List[BaseHandler[Any, CCT]], Tuple[BaseHandler[Any, CCT]]],
|
||||
Dict[int, Union[List[BaseHandler[Any, CCT]], Tuple[BaseHandler[Any, CCT]]]],
|
||||
],
|
||||
group: Union[int, DefaultValue[int]] = DefaultValue(0),
|
||||
group: Union[int, DefaultValue[int]] = _DEFAULT_0,
|
||||
) -> None:
|
||||
"""Registers multiple handlers at once. The order of the handlers in the passed
|
||||
sequence(s) matters. See :meth:`add_handler` for details.
|
||||
|
|
|
@ -114,7 +114,7 @@ class ApplicationBuilder(Generic[BT, CCT, UD, CD, BD, JQ]):
|
|||
* Unless a custom :class:`telegram.Bot` instance is set via :meth:`bot`, :meth:`build` will
|
||||
use :class:`telegram.ext.ExtBot` for the bot.
|
||||
|
||||
.. seealso:: :wiki:`Your First Bot <Extensions-–-Your-first-Bot>`,
|
||||
.. seealso:: :wiki:`Your First Bot <Extensions---Your-first-Bot>`,
|
||||
:wiki:`Builder Pattern <Builder-Pattern>`
|
||||
|
||||
.. _`builder pattern`: https://en.wikipedia.org/wiki/Builder_pattern
|
||||
|
|
|
@ -41,7 +41,7 @@ from telegram.ext._utils.types import BD, BT, CD, UD
|
|||
if TYPE_CHECKING:
|
||||
from asyncio import Future, Queue
|
||||
|
||||
from telegram.ext import Application, Job, JobQueue # noqa: F401
|
||||
from telegram.ext import Application, Job, JobQueue
|
||||
from telegram.ext._utils.types import CCT
|
||||
|
||||
_STORING_DATA_WIKI = (
|
||||
|
|
|
@ -654,7 +654,7 @@ class ConversationHandler(BaseHandler[Update, CCT]):
|
|||
"timeout.",
|
||||
exc_info=exc,
|
||||
)
|
||||
return
|
||||
return None
|
||||
return self._schedule_job(
|
||||
new_state=effective_new_state,
|
||||
application=application,
|
||||
|
@ -813,13 +813,12 @@ class ConversationHandler(BaseHandler[Update, CCT]):
|
|||
# 3. Default values of the bot
|
||||
if handler.block is not DEFAULT_TRUE:
|
||||
block = handler.block
|
||||
elif self._block is not DEFAULT_TRUE:
|
||||
block = self._block
|
||||
elif isinstance(application.bot, ExtBot) and application.bot.defaults is not None:
|
||||
block = application.bot.defaults.block
|
||||
else:
|
||||
if self._block is not DEFAULT_TRUE:
|
||||
block = self._block
|
||||
elif isinstance(application.bot, ExtBot) and application.bot.defaults is not None:
|
||||
block = application.bot.defaults.block
|
||||
else:
|
||||
block = DefaultValue.get_value(handler.block)
|
||||
block = DefaultValue.get_value(handler.block)
|
||||
|
||||
try: # Now create task or await the callback
|
||||
if block:
|
||||
|
@ -847,20 +846,17 @@ class ConversationHandler(BaseHandler[Update, CCT]):
|
|||
"Ignoring `conversation_timeout` because the Applications JobQueue is "
|
||||
"not running.",
|
||||
)
|
||||
else:
|
||||
# Add the new timeout job
|
||||
# checking if the new state is self.END is done in _schedule_job
|
||||
if isinstance(new_state, asyncio.Task):
|
||||
application.create_task(
|
||||
self._schedule_job_delayed(
|
||||
new_state, application, update, context, conversation_key
|
||||
),
|
||||
update=update,
|
||||
)
|
||||
else:
|
||||
self._schedule_job(
|
||||
# Add the new timeout job
|
||||
# checking if the new state is self.END is done in _schedule_job
|
||||
elif isinstance(new_state, asyncio.Task):
|
||||
application.create_task(
|
||||
self._schedule_job_delayed(
|
||||
new_state, application, update, context, conversation_key
|
||||
)
|
||||
),
|
||||
update=update,
|
||||
)
|
||||
else:
|
||||
self._schedule_job(new_state, application, update, context, conversation_key)
|
||||
|
||||
if isinstance(self.map_to_parent, dict) and new_state in self.map_to_parent:
|
||||
self._update_state(self.END, conversation_key, handler)
|
||||
|
@ -874,7 +870,7 @@ class ConversationHandler(BaseHandler[Update, CCT]):
|
|||
if raise_dp_handler_stop:
|
||||
# Don't pass the new state here. If we're in a nested conversation, the parent is
|
||||
# expecting None as return value.
|
||||
raise ApplicationHandlerStop()
|
||||
raise ApplicationHandlerStop
|
||||
# Signals a possible parent conversation to stay in the current state
|
||||
return None
|
||||
|
||||
|
|
|
@ -468,12 +468,12 @@ class DictPersistence(BasePersistence[Dict[Any, Any], Dict[Any, Any], Dict[Any,
|
|||
tmp: Dict[int, Dict[object, object]] = {}
|
||||
decoded_data = json.loads(data)
|
||||
for user, user_data in decoded_data.items():
|
||||
user = int(user)
|
||||
tmp[user] = {}
|
||||
int_user_id = int(user)
|
||||
tmp[int_user_id] = {}
|
||||
for key, value in user_data.items():
|
||||
try:
|
||||
key = int(key)
|
||||
_id = int(key)
|
||||
except ValueError:
|
||||
pass
|
||||
tmp[user][key] = value
|
||||
_id = key
|
||||
tmp[int_user_id][_id] = value
|
||||
return tmp
|
||||
|
|
|
@ -385,10 +385,10 @@ class ExtBot(Bot, Generic[RLARGS]):
|
|||
# 3)
|
||||
elif isinstance(val, InputMedia) and val.parse_mode is DEFAULT_NONE:
|
||||
# Copy object as not to edit it in-place
|
||||
val = copy(val)
|
||||
with val._unfrozen():
|
||||
val.parse_mode = self.defaults.parse_mode if self.defaults else None
|
||||
data[key] = val
|
||||
copied_val = copy(val)
|
||||
with copied_val._unfrozen():
|
||||
copied_val.parse_mode = self.defaults.parse_mode if self.defaults else None
|
||||
data[key] = copied_val
|
||||
elif key == "media" and isinstance(val, Sequence):
|
||||
# Copy objects as not to edit them in-place
|
||||
copy_list = [copy(media) for media in val]
|
||||
|
|
|
@ -41,6 +41,9 @@ if TYPE_CHECKING:
|
|||
from telegram.ext import Application
|
||||
|
||||
|
||||
_ALL_DAYS = tuple(range(7))
|
||||
|
||||
|
||||
class JobQueue(Generic[CCT]):
|
||||
"""This class allows you to periodically perform tasks with the bot. It is a convenience
|
||||
wrapper for the APScheduler library.
|
||||
|
@ -436,7 +439,7 @@ class JobQueue(Generic[CCT]):
|
|||
self,
|
||||
callback: JobCallback[CCT],
|
||||
time: datetime.time,
|
||||
days: Tuple[int, ...] = tuple(range(7)),
|
||||
days: Tuple[int, ...] = _ALL_DAYS,
|
||||
data: object = None,
|
||||
name: str = None,
|
||||
chat_id: int = None,
|
||||
|
|
|
@ -47,7 +47,7 @@ class MessageHandler(BaseHandler[Update, CCT]):
|
|||
operators (& for and, | for or, ~ for not). Passing :obj:`None` is a shortcut
|
||||
to passing :class:`telegram.ext.filters.ALL`.
|
||||
|
||||
.. seealso:: :wiki:`Advanced Filters <Extensions-–-Advanced-Filters>`
|
||||
.. seealso:: :wiki:`Advanced Filters <Extensions---Advanced-Filters>`
|
||||
callback (:term:`coroutine function`): The callback function for this handler. Will be
|
||||
called when :meth:`check_update` has determined that an update should be processed by
|
||||
this handler. Callback signature::
|
||||
|
|
|
@ -132,15 +132,9 @@ class PrefixHandler(BaseHandler[Update, CCT]):
|
|||
):
|
||||
super().__init__(callback=callback, block=block)
|
||||
|
||||
if isinstance(prefix, str):
|
||||
prefixes = {prefix.lower()}
|
||||
else:
|
||||
prefixes = {x.lower() for x in prefix}
|
||||
prefixes = {prefix.lower()} if isinstance(prefix, str) else {x.lower() for x in prefix}
|
||||
|
||||
if isinstance(command, str):
|
||||
commands = {command.lower()}
|
||||
else:
|
||||
commands = {x.lower() for x in command}
|
||||
commands = {command.lower()} if isinstance(command, str) else {x.lower() for x in command}
|
||||
|
||||
self.commands: FrozenSet[str] = frozenset(
|
||||
p + c for p, c in itertools.product(prefixes, commands)
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
# along with this program. If not, see [http://www.gnu.org/licenses/].
|
||||
"""This module contains the class Updater, which tries to make creating Telegram bots intuitive."""
|
||||
import asyncio
|
||||
import contextlib
|
||||
import logging
|
||||
import ssl
|
||||
from pathlib import Path
|
||||
|
@ -746,11 +747,9 @@ class Updater(AsyncContextManager["Updater"]):
|
|||
self._logger.debug("Waiting background polling task to finish up.")
|
||||
self.__polling_task.cancel()
|
||||
|
||||
try:
|
||||
with contextlib.suppress(asyncio.CancelledError):
|
||||
await self.__polling_task
|
||||
except asyncio.CancelledError:
|
||||
# This only happens in rare edge-cases, e.g. when `stop()` is called directly
|
||||
# It only fails in rare edge-cases, e.g. when `stop()` is called directly
|
||||
# after start_polling(), but lets better be safe than sorry ...
|
||||
pass
|
||||
|
||||
self.__polling_task = None
|
||||
|
|
|
@ -93,7 +93,7 @@ class WebhookAppClass(tornado.web.Application):
|
|||
"update_queue": update_queue,
|
||||
"secret_token": secret_token,
|
||||
}
|
||||
handlers = [(rf"{webhook_path}/?", TelegramHandler, self.shared_objects)] # noqa
|
||||
handlers = [(rf"{webhook_path}/?", TelegramHandler, self.shared_objects)]
|
||||
tornado.web.Application.__init__(self, handlers) # type: ignore
|
||||
|
||||
def log_request(self, handler: tornado.web.RequestHandler) -> None:
|
||||
|
|
|
@ -244,7 +244,7 @@ class MessageFilter(BaseFilter):
|
|||
|
||||
Please see :class:`BaseFilter` for details on how to create custom filters.
|
||||
|
||||
.. seealso:: :wiki:`Advanced Filters <Extensions-–-Advanced-Filters>`
|
||||
.. seealso:: :wiki:`Advanced Filters <Extensions---Advanced-Filters>`
|
||||
|
||||
"""
|
||||
|
||||
|
@ -379,7 +379,7 @@ class _MergedFilter(UpdateFilter):
|
|||
def _merge(base_output: Union[bool, Dict], comp_output: Union[bool, Dict]) -> FilterDataDict:
|
||||
base = base_output if isinstance(base_output, dict) else {}
|
||||
comp = comp_output if isinstance(comp_output, dict) else {}
|
||||
for k in comp.keys():
|
||||
for k in comp:
|
||||
# Make sure comp values are lists
|
||||
comp_value = comp[k] if isinstance(comp[k], list) else []
|
||||
try:
|
||||
|
@ -387,7 +387,7 @@ class _MergedFilter(UpdateFilter):
|
|||
if isinstance(base[k], list):
|
||||
base[k] += comp_value
|
||||
else:
|
||||
base[k] = [base[k]] + comp_value
|
||||
base[k] = [base[k], *comp_value]
|
||||
except KeyError:
|
||||
base[k] = comp_value
|
||||
return base
|
||||
|
|
|
@ -162,6 +162,11 @@ def create_deep_linked_url(bot_username: str, payload: str = None, group: bool =
|
|||
|
||||
Returns:
|
||||
:obj:`str`: An URL to start the bot with specific parameters.
|
||||
|
||||
Raises:
|
||||
:exc:`ValueError`: If the length of the :paramref:`payload` exceeds 64 characters,
|
||||
contains invalid characters, or if the :paramref:`bot_username` is less than 4
|
||||
characters.
|
||||
"""
|
||||
if bot_username is None or len(bot_username) <= 3:
|
||||
raise ValueError("You must provide a valid bot_username.")
|
||||
|
@ -179,9 +184,6 @@ def create_deep_linked_url(bot_username: str, payload: str = None, group: bool =
|
|||
"URLs: A-Z, a-z, 0-9, _ and -"
|
||||
)
|
||||
|
||||
if group:
|
||||
key = "startgroup"
|
||||
else:
|
||||
key = "start"
|
||||
key = "startgroup" if group else "start"
|
||||
|
||||
return f"{base_url}?{key}={payload}"
|
||||
|
|
|
@ -296,10 +296,7 @@ class BaseRequest(
|
|||
response_data = self.parse_json_payload(payload)
|
||||
|
||||
description = response_data.get("description")
|
||||
if description:
|
||||
message = description
|
||||
else:
|
||||
message = "Unknown HTTPError"
|
||||
message = description if description else "Unknown HTTPError"
|
||||
|
||||
# In some special cases, we can raise more informative exceptions:
|
||||
# see https://core.telegram.org/bots/api#responseparameters and
|
||||
|
|
|
@ -122,7 +122,7 @@ class HTTPXRequest(BaseRequest):
|
|||
|
||||
# See https://github.com/python-telegram-bot/python-telegram-bot/pull/3542
|
||||
# for why we need to use `dict()` here.
|
||||
self._client_kwargs = dict( # pylint: disable=use-dict-literal
|
||||
self._client_kwargs = dict( # pylint: disable=use-dict-literal # noqa: C408
|
||||
timeout=timeout,
|
||||
proxies=proxy_url,
|
||||
limits=limits,
|
||||
|
|
|
@ -36,7 +36,7 @@ from tests.auxil.files import data_file
|
|||
from tests.auxil.slots import mro_slots
|
||||
|
||||
|
||||
@pytest.fixture(scope="function")
|
||||
@pytest.fixture()
|
||||
def animation_file():
|
||||
with data_file("game.gif").open("rb") as f:
|
||||
yield f
|
||||
|
@ -75,8 +75,8 @@ class TestAnimationWithoutRequest(TestAnimationBase):
|
|||
assert isinstance(animation, Animation)
|
||||
assert isinstance(animation.file_id, str)
|
||||
assert isinstance(animation.file_unique_id, str)
|
||||
assert animation.file_id != ""
|
||||
assert animation.file_unique_id != ""
|
||||
assert animation.file_id
|
||||
assert animation.file_unique_id
|
||||
|
||||
def test_expected_values(self, animation):
|
||||
assert animation.mime_type == self.mime_type
|
||||
|
@ -231,8 +231,8 @@ class TestAnimationWithRequest(TestAnimationBase):
|
|||
assert isinstance(message.animation, Animation)
|
||||
assert isinstance(message.animation.file_id, str)
|
||||
assert isinstance(message.animation.file_unique_id, str)
|
||||
assert message.animation.file_id != ""
|
||||
assert message.animation.file_unique_id != ""
|
||||
assert message.animation.file_id
|
||||
assert message.animation.file_unique_id
|
||||
assert message.animation.file_name == animation.file_name
|
||||
assert message.animation.mime_type == animation.mime_type
|
||||
assert message.animation.file_size == animation.file_size
|
||||
|
@ -266,8 +266,8 @@ class TestAnimationWithRequest(TestAnimationBase):
|
|||
assert isinstance(message.animation, Animation)
|
||||
assert isinstance(message.animation.file_id, str)
|
||||
assert isinstance(message.animation.file_unique_id, str)
|
||||
assert message.animation.file_id != ""
|
||||
assert message.animation.file_unique_id != ""
|
||||
assert message.animation.file_id
|
||||
assert message.animation.file_unique_id
|
||||
|
||||
assert message.animation.duration == animation.duration
|
||||
assert message.animation.file_name.startswith(
|
||||
|
@ -321,7 +321,7 @@ class TestAnimationWithRequest(TestAnimationBase):
|
|||
assert message.caption_markdown == escape_markdown(test_markdown_string)
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"default_bot,custom",
|
||||
("default_bot", "custom"),
|
||||
[
|
||||
({"allow_sending_without_reply": True}, None),
|
||||
({"allow_sending_without_reply": False}, None),
|
||||
|
@ -368,9 +368,7 @@ class TestAnimationWithRequest(TestAnimationBase):
|
|||
assert message.animation == animation
|
||||
|
||||
async def test_error_send_empty_file(self, bot, chat_id):
|
||||
animation_file = open(os.devnull, "rb")
|
||||
|
||||
with pytest.raises(TelegramError):
|
||||
with Path(os.devnull).open("rb") as animation_file, pytest.raises(TelegramError):
|
||||
await bot.send_animation(chat_id=chat_id, animation=animation_file)
|
||||
|
||||
async def test_error_send_empty_file_id(self, bot, chat_id):
|
||||
|
|
|
@ -36,7 +36,7 @@ from tests.auxil.files import data_file
|
|||
from tests.auxil.slots import mro_slots
|
||||
|
||||
|
||||
@pytest.fixture(scope="function")
|
||||
@pytest.fixture()
|
||||
def audio_file():
|
||||
with data_file("telegram.mp3").open("rb") as f:
|
||||
yield f
|
||||
|
@ -77,8 +77,8 @@ class TestAudioWithoutRequest(TestAudioBase):
|
|||
assert isinstance(audio, Audio)
|
||||
assert isinstance(audio.file_id, str)
|
||||
assert isinstance(audio.file_unique_id, str)
|
||||
assert audio.file_id != ""
|
||||
assert audio.file_unique_id != ""
|
||||
assert audio.file_id
|
||||
assert audio.file_unique_id
|
||||
|
||||
def test_expected_values(self, audio):
|
||||
assert audio.duration == self.duration
|
||||
|
@ -331,9 +331,7 @@ class TestAudioWithRequest(TestAudioBase):
|
|||
assert message.audio == audio
|
||||
|
||||
async def test_error_send_empty_file(self, bot, chat_id):
|
||||
audio_file = open(os.devnull, "rb")
|
||||
|
||||
with pytest.raises(TelegramError):
|
||||
with Path(os.devnull).open("rb") as audio_file, pytest.raises(TelegramError):
|
||||
await bot.send_audio(chat_id=chat_id, audio=audio_file)
|
||||
|
||||
async def test_error_send_empty_file_id(self, bot, chat_id):
|
||||
|
|
|
@ -36,7 +36,7 @@ from tests.auxil.networking import expect_bad_request
|
|||
from tests.auxil.slots import mro_slots
|
||||
|
||||
|
||||
@pytest.fixture(scope="function")
|
||||
@pytest.fixture()
|
||||
def chatphoto_file():
|
||||
with data_file("telegram.jpg").open("rb") as f:
|
||||
yield f
|
||||
|
@ -174,7 +174,8 @@ class TestChatPhotoWithRequest:
|
|||
await file.download_to_drive(jpg_file)
|
||||
assert jpg_file.is_file()
|
||||
|
||||
assert "small" in asserts and "big" in asserts
|
||||
assert "small" in asserts
|
||||
assert "big" in asserts
|
||||
|
||||
async def test_send_all_args(self, bot, super_group_id, chatphoto_file):
|
||||
async def func():
|
||||
|
@ -185,9 +186,7 @@ class TestChatPhotoWithRequest:
|
|||
)
|
||||
|
||||
async def test_error_send_empty_file(self, bot, super_group_id):
|
||||
chatphoto_file = open(os.devnull, "rb")
|
||||
|
||||
with pytest.raises(TelegramError):
|
||||
with Path(os.devnull).open("rb") as chatphoto_file, pytest.raises(TelegramError):
|
||||
await bot.set_chat_photo(chat_id=super_group_id, photo=chatphoto_file)
|
||||
|
||||
async def test_error_send_empty_file_id(self, bot, super_group_id):
|
||||
|
|
|
@ -129,7 +129,7 @@ class TestContactWithoutRequest(TestContactBase):
|
|||
|
||||
class TestContactWithRequest(TestContactBase):
|
||||
@pytest.mark.parametrize(
|
||||
"default_bot,custom",
|
||||
("default_bot", "custom"),
|
||||
[
|
||||
({"allow_sending_without_reply": True}, None),
|
||||
({"allow_sending_without_reply": False}, None),
|
||||
|
|
|
@ -36,7 +36,7 @@ from tests.auxil.files import data_file
|
|||
from tests.auxil.slots import mro_slots
|
||||
|
||||
|
||||
@pytest.fixture(scope="function")
|
||||
@pytest.fixture()
|
||||
def document_file():
|
||||
with data_file("telegram.png").open("rb") as f:
|
||||
yield f
|
||||
|
@ -71,8 +71,8 @@ class TestDocumentWithoutRequest(TestDocumentBase):
|
|||
assert isinstance(document, Document)
|
||||
assert isinstance(document.file_id, str)
|
||||
assert isinstance(document.file_unique_id, str)
|
||||
assert document.file_id != ""
|
||||
assert document.file_unique_id != ""
|
||||
assert document.file_id
|
||||
assert document.file_unique_id
|
||||
|
||||
def test_expected_values(self, document):
|
||||
assert document.file_size == self.file_size
|
||||
|
@ -206,9 +206,8 @@ class TestDocumentWithoutRequest(TestDocumentBase):
|
|||
|
||||
class TestDocumentWithRequest(TestDocumentBase):
|
||||
async def test_error_send_empty_file(self, bot, chat_id):
|
||||
with open(os.devnull, "rb") as f:
|
||||
with pytest.raises(TelegramError):
|
||||
await bot.send_document(chat_id=chat_id, document=f)
|
||||
with Path(os.devnull).open("rb") as f, pytest.raises(TelegramError):
|
||||
await bot.send_document(chat_id=chat_id, document=f)
|
||||
|
||||
async def test_error_send_empty_file_id(self, bot, chat_id):
|
||||
with pytest.raises(TelegramError):
|
||||
|
@ -247,9 +246,9 @@ class TestDocumentWithRequest(TestDocumentBase):
|
|||
|
||||
assert isinstance(message.document, Document)
|
||||
assert isinstance(message.document.file_id, str)
|
||||
assert message.document.file_id != ""
|
||||
assert message.document.file_id
|
||||
assert isinstance(message.document.file_unique_id, str)
|
||||
assert message.document.file_unique_id != ""
|
||||
assert message.document.file_unique_id
|
||||
assert isinstance(message.document.thumbnail, PhotoSize)
|
||||
assert message.document.file_name == "telegram_custom.png"
|
||||
assert message.document.mime_type == document.mime_type
|
||||
|
@ -266,9 +265,9 @@ class TestDocumentWithRequest(TestDocumentBase):
|
|||
|
||||
assert isinstance(document, Document)
|
||||
assert isinstance(document.file_id, str)
|
||||
assert document.file_id != ""
|
||||
assert document.file_id
|
||||
assert isinstance(message.document.file_unique_id, str)
|
||||
assert message.document.file_unique_id != ""
|
||||
assert message.document.file_unique_id
|
||||
assert isinstance(document.thumbnail, PhotoSize)
|
||||
assert document.file_name == "telegram.gif"
|
||||
assert document.mime_type == "image/gif"
|
||||
|
@ -328,7 +327,7 @@ class TestDocumentWithRequest(TestDocumentBase):
|
|||
assert message.caption_markdown == escape_markdown(test_markdown_string)
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"default_bot,custom",
|
||||
("default_bot", "custom"),
|
||||
[
|
||||
({"allow_sending_without_reply": True}, None),
|
||||
({"allow_sending_without_reply": False}, None),
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
#
|
||||
# You should have received a copy of the GNU Lesser Public License
|
||||
# along with this program. If not, see [http://www.gnu.org/licenses/].
|
||||
import contextlib
|
||||
import subprocess
|
||||
import sys
|
||||
from io import BytesIO
|
||||
|
@ -49,12 +50,10 @@ class TestInputFileWithoutRequest:
|
|||
assert in_file.mimetype == "application/octet-stream"
|
||||
assert in_file.filename == "application.octet-stream"
|
||||
|
||||
try:
|
||||
with contextlib.suppress(ProcessLookupError):
|
||||
proc.kill()
|
||||
except ProcessLookupError:
|
||||
# This exception may be thrown if the process has finished before we had the chance
|
||||
# to kill it.
|
||||
pass
|
||||
|
||||
@pytest.mark.parametrize("attach", [True, False])
|
||||
def test_attach(self, attach):
|
||||
|
|
|
@ -54,7 +54,7 @@ from .test_audio import audio, audio_file # noqa: F401
|
|||
from .test_document import document, document_file # noqa: F401
|
||||
|
||||
# noinspection PyUnresolvedReferences
|
||||
from .test_photo import _photo, photo, photo_file, thumb # noqa: F401
|
||||
from .test_photo import photo, photo_file, photolist, thumb # noqa: F401
|
||||
|
||||
# noinspection PyUnresolvedReferences
|
||||
from .test_video import video, video_file # noqa: F401
|
||||
|
@ -211,7 +211,7 @@ class TestInputMediaVideoWithoutRequest(TestInputMediaVideoBase):
|
|||
assert input_media_video.thumbnail == data_file("telegram.jpg").as_uri()
|
||||
|
||||
def test_with_local_files_throws_exception_with_different_thumb_and_thumbnail(self):
|
||||
with pytest.raises(ValueError):
|
||||
with pytest.raises(ValueError, match="You passed different entities as 'thumb' and "):
|
||||
InputMediaVideo(
|
||||
data_file("telegram.mp4"),
|
||||
thumbnail=data_file("telegram.jpg"),
|
||||
|
@ -351,7 +351,7 @@ class TestInputMediaAnimationWithoutRequest(TestInputMediaAnimationBase):
|
|||
assert input_media_animation.thumbnail == data_file("telegram.jpg").as_uri()
|
||||
|
||||
def test_with_local_files_throws_exception_with_different_thumb_and_thumbnail(self):
|
||||
with pytest.raises(ValueError):
|
||||
with pytest.raises(ValueError, match="You passed different entities as 'thumb' and "):
|
||||
InputMediaAnimation(
|
||||
data_file("telegram.mp4"),
|
||||
thumbnail=data_file("telegram.jpg"),
|
||||
|
@ -436,7 +436,7 @@ class TestInputMediaAudioWithoutRequest(TestInputMediaAudioBase):
|
|||
assert input_media_audio.thumbnail == data_file("telegram.jpg").as_uri()
|
||||
|
||||
def test_with_local_files_throws_exception_with_different_thumb_and_thumbnail(self):
|
||||
with pytest.raises(ValueError):
|
||||
with pytest.raises(ValueError, match="You passed different entities as 'thumb' and "):
|
||||
InputMediaAudio(
|
||||
data_file("telegram.mp4"),
|
||||
thumbnail=data_file("telegram.jpg"),
|
||||
|
@ -518,7 +518,7 @@ class TestInputMediaDocumentWithoutRequest(TestInputMediaDocumentBase):
|
|||
assert input_media_document.thumbnail == data_file("telegram.jpg").as_uri()
|
||||
|
||||
def test_with_local_files_throws_exception_with_different_thumb_and_thumbnail(self):
|
||||
with pytest.raises(ValueError):
|
||||
with pytest.raises(ValueError, match="You passed different entities as 'thumb' and "):
|
||||
InputMediaDocument(
|
||||
data_file("telegram.mp4"),
|
||||
thumbnail=data_file("telegram.jpg"),
|
||||
|
@ -526,7 +526,7 @@ class TestInputMediaDocumentWithoutRequest(TestInputMediaDocumentBase):
|
|||
)
|
||||
|
||||
|
||||
@pytest.fixture(scope="module") # noqa: F811
|
||||
@pytest.fixture(scope="module")
|
||||
def media_group(photo, thumb): # noqa: F811
|
||||
return [
|
||||
InputMediaPhoto(photo, caption="*photo* 1", parse_mode="Markdown"),
|
||||
|
@ -537,12 +537,12 @@ def media_group(photo, thumb): # noqa: F811
|
|||
]
|
||||
|
||||
|
||||
@pytest.fixture(scope="module") # noqa: F811
|
||||
@pytest.fixture(scope="module")
|
||||
def media_group_no_caption_args(photo, thumb): # noqa: F811
|
||||
return [InputMediaPhoto(photo), InputMediaPhoto(thumb), InputMediaPhoto(photo)]
|
||||
|
||||
|
||||
@pytest.fixture(scope="module") # noqa: F811
|
||||
@pytest.fixture(scope="module")
|
||||
def media_group_no_caption_only_caption_entities(photo, thumb): # noqa: F811
|
||||
return [
|
||||
InputMediaPhoto(photo, caption_entities=[MessageEntity(MessageEntity.BOLD, 0, 5)]),
|
||||
|
@ -550,7 +550,7 @@ def media_group_no_caption_only_caption_entities(photo, thumb): # noqa: F811
|
|||
]
|
||||
|
||||
|
||||
@pytest.fixture(scope="module") # noqa: F811
|
||||
@pytest.fixture(scope="module")
|
||||
def media_group_no_caption_only_parse_mode(photo, thumb): # noqa: F811
|
||||
return [
|
||||
InputMediaPhoto(photo, parse_mode="Markdown"),
|
||||
|
@ -720,7 +720,7 @@ class TestSendMediaGroupWithRequest:
|
|||
assert all(i.message_thread_id == real_topic.message_thread_id for i in messages)
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"caption, parse_mode, caption_entities",
|
||||
("caption", "parse_mode", "caption_entities"),
|
||||
[
|
||||
# same combinations of caption options as in media_group fixture
|
||||
("*photo* 1", "Markdown", None),
|
||||
|
@ -852,7 +852,7 @@ class TestSendMediaGroupWithRequest:
|
|||
assert isinstance(new_message, Message)
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"default_bot,custom",
|
||||
("default_bot", "custom"),
|
||||
[
|
||||
({"allow_sending_without_reply": True}, None),
|
||||
({"allow_sending_without_reply": False}, None),
|
||||
|
@ -984,6 +984,7 @@ class TestSendMediaGroupWithRequest:
|
|||
return InputMediaPhoto(photo, **kwargs)
|
||||
if med_type == "video":
|
||||
return InputMediaVideo(video, **kwargs)
|
||||
return None
|
||||
|
||||
message = await default_bot.send_photo(chat_id, photo)
|
||||
|
||||
|
|
|
@ -51,7 +51,8 @@ class TestInputStickerNoRequest(TestInputStickerBase):
|
|||
assert len(mro_slots(inst)) == len(set(mro_slots(inst))), "duplicate slot"
|
||||
|
||||
def test_expected_values(self, input_sticker):
|
||||
assert input_sticker.sticker == self.sticker and isinstance(input_sticker.sticker, str)
|
||||
assert input_sticker.sticker == self.sticker
|
||||
assert isinstance(input_sticker.sticker, str)
|
||||
assert input_sticker.emoji_list == self.emoji_list
|
||||
assert input_sticker.mask_position == self.mask_position
|
||||
assert input_sticker.keywords == self.keywords
|
||||
|
@ -60,7 +61,8 @@ class TestInputStickerNoRequest(TestInputStickerBase):
|
|||
assert isinstance(input_sticker.keywords, tuple)
|
||||
assert isinstance(input_sticker.emoji_list, tuple)
|
||||
a = InputSticker("sticker", ["emoji"])
|
||||
assert isinstance(a.emoji_list, tuple) and a.keywords == ()
|
||||
assert isinstance(a.emoji_list, tuple)
|
||||
assert a.keywords == ()
|
||||
|
||||
def test_to_dict(self, input_sticker):
|
||||
input_sticker_dict = input_sticker.to_dict()
|
||||
|
|
|
@ -136,8 +136,7 @@ class TestLocationWithoutRequest(TestLocationBase):
|
|||
# TODO: Needs improvement with in inline sent live location.
|
||||
async def test_stop_live_inline_message(self, monkeypatch, bot):
|
||||
async def make_assertion(url, request_data: RequestData, *args, **kwargs):
|
||||
id_ = request_data.json_parameters["inline_message_id"] == "1234"
|
||||
return id_
|
||||
return request_data.json_parameters["inline_message_id"] == "1234"
|
||||
|
||||
monkeypatch.setattr(bot.request, "post", make_assertion)
|
||||
assert await bot.stop_message_live_location(inline_message_id=1234)
|
||||
|
@ -163,7 +162,7 @@ class TestLocationWithoutRequest(TestLocationBase):
|
|||
|
||||
class TestLocationWithRequest:
|
||||
@pytest.mark.parametrize(
|
||||
"default_bot,custom",
|
||||
("default_bot", "custom"),
|
||||
[
|
||||
({"allow_sending_without_reply": True}, None),
|
||||
({"allow_sending_without_reply": False}, None),
|
||||
|
@ -205,7 +204,7 @@ class TestLocationWithRequest:
|
|||
assert protected.has_protected_content
|
||||
assert not unprotected.has_protected_content
|
||||
|
||||
@pytest.mark.xfail
|
||||
@pytest.mark.xfail()
|
||||
async def test_send_live_location(self, bot, chat_id):
|
||||
message = await bot.send_location(
|
||||
chat_id=chat_id,
|
||||
|
@ -218,8 +217,8 @@ class TestLocationWithRequest:
|
|||
protect_content=True,
|
||||
)
|
||||
assert message.location
|
||||
assert 52.223880 == pytest.approx(message.location.latitude, rel=1e-5)
|
||||
assert 5.166146 == pytest.approx(message.location.longitude, rel=1e-5)
|
||||
assert pytest.approx(message.location.latitude, rel=1e-5) == 52.223880
|
||||
assert pytest.approx(message.location.longitude, rel=1e-5) == 5.166146
|
||||
assert message.location.live_period == 80
|
||||
assert message.location.horizontal_accuracy == 50
|
||||
assert message.location.heading == 90
|
||||
|
@ -236,8 +235,8 @@ class TestLocationWithRequest:
|
|||
proximity_alert_radius=500,
|
||||
)
|
||||
|
||||
assert 52.223098 == pytest.approx(message2.location.latitude, rel=1e-5)
|
||||
assert 5.164306 == pytest.approx(message2.location.longitude, rel=1e-5)
|
||||
assert pytest.approx(message2.location.latitude, rel=1e-5) == 52.223098
|
||||
assert pytest.approx(message2.location.longitude, rel=1e-5) == 5.164306
|
||||
assert message2.location.horizontal_accuracy == 30
|
||||
assert message2.location.heading == 10
|
||||
assert message2.location.proximity_alert_radius == 500
|
||||
|
|
|
@ -36,14 +36,14 @@ from tests.auxil.networking import expect_bad_request
|
|||
from tests.auxil.slots import mro_slots
|
||||
|
||||
|
||||
@pytest.fixture(scope="function")
|
||||
@pytest.fixture()
|
||||
def photo_file():
|
||||
with data_file("telegram.jpg").open("rb") as f:
|
||||
yield f
|
||||
|
||||
|
||||
@pytest.fixture(scope="module")
|
||||
async def _photo(bot, chat_id):
|
||||
async def photolist(bot, chat_id):
|
||||
async def func():
|
||||
with data_file("telegram.jpg").open("rb") as f:
|
||||
return (await bot.send_photo(chat_id, photo=f, read_timeout=50)).photo
|
||||
|
@ -54,13 +54,13 @@ async def _photo(bot, chat_id):
|
|||
|
||||
|
||||
@pytest.fixture(scope="module")
|
||||
def thumb(_photo):
|
||||
return _photo[0]
|
||||
def thumb(photolist):
|
||||
return photolist[0]
|
||||
|
||||
|
||||
@pytest.fixture(scope="module")
|
||||
def photo(_photo):
|
||||
return _photo[-1]
|
||||
def photo(photolist):
|
||||
return photolist[-1]
|
||||
|
||||
|
||||
class TestPhotoBase:
|
||||
|
@ -84,14 +84,14 @@ class TestPhotoWithoutRequest(TestPhotoBase):
|
|||
assert isinstance(photo, PhotoSize)
|
||||
assert isinstance(photo.file_id, str)
|
||||
assert isinstance(photo.file_unique_id, str)
|
||||
assert photo.file_id != ""
|
||||
assert photo.file_unique_id != ""
|
||||
assert photo.file_id
|
||||
assert photo.file_unique_id
|
||||
|
||||
assert isinstance(thumb, PhotoSize)
|
||||
assert isinstance(thumb.file_id, str)
|
||||
assert isinstance(thumb.file_unique_id, str)
|
||||
assert thumb.file_id != ""
|
||||
assert thumb.file_unique_id != ""
|
||||
assert thumb.file_id
|
||||
assert thumb.file_unique_id
|
||||
|
||||
def test_expected_values(self, photo, thumb):
|
||||
assert photo.width == self.width
|
||||
|
@ -223,14 +223,14 @@ class TestPhotoWithRequest(TestPhotoBase):
|
|||
assert isinstance(message.photo[-2], PhotoSize)
|
||||
assert isinstance(message.photo[-2].file_id, str)
|
||||
assert isinstance(message.photo[-2].file_unique_id, str)
|
||||
assert message.photo[-2].file_id != ""
|
||||
assert message.photo[-2].file_unique_id != ""
|
||||
assert message.photo[-2].file_id
|
||||
assert message.photo[-2].file_unique_id
|
||||
|
||||
assert isinstance(message.photo[-1], PhotoSize)
|
||||
assert isinstance(message.photo[-1].file_id, str)
|
||||
assert isinstance(message.photo[-1].file_unique_id, str)
|
||||
assert message.photo[-1].file_id != ""
|
||||
assert message.photo[-1].file_unique_id != ""
|
||||
assert message.photo[-1].file_id
|
||||
assert message.photo[-1].file_unique_id
|
||||
|
||||
assert message.caption == self.caption.replace("*", "")
|
||||
assert message.has_protected_content
|
||||
|
@ -243,14 +243,14 @@ class TestPhotoWithRequest(TestPhotoBase):
|
|||
assert isinstance(message.photo[-2], PhotoSize)
|
||||
assert isinstance(message.photo[-2].file_id, str)
|
||||
assert isinstance(message.photo[-2].file_unique_id, str)
|
||||
assert message.photo[-2].file_id != ""
|
||||
assert message.photo[-2].file_unique_id != ""
|
||||
assert message.photo[-2].file_id
|
||||
assert message.photo[-2].file_unique_id
|
||||
|
||||
assert isinstance(message.photo[-1], PhotoSize)
|
||||
assert isinstance(message.photo[-1].file_id, str)
|
||||
assert isinstance(message.photo[-1].file_unique_id, str)
|
||||
assert message.photo[-1].file_id != ""
|
||||
assert message.photo[-1].file_unique_id != ""
|
||||
assert message.photo[-1].file_id
|
||||
assert message.photo[-1].file_unique_id
|
||||
|
||||
assert message.caption == self.caption.replace("*", "")
|
||||
assert len(message.caption_entities) == 1
|
||||
|
@ -262,14 +262,14 @@ class TestPhotoWithRequest(TestPhotoBase):
|
|||
assert isinstance(message.photo[-2], PhotoSize)
|
||||
assert isinstance(message.photo[-2].file_id, str)
|
||||
assert isinstance(message.photo[-2].file_unique_id, str)
|
||||
assert message.photo[-2].file_id != ""
|
||||
assert message.photo[-2].file_unique_id != ""
|
||||
assert message.photo[-2].file_id
|
||||
assert message.photo[-2].file_unique_id
|
||||
|
||||
assert isinstance(message.photo[-1], PhotoSize)
|
||||
assert isinstance(message.photo[-1].file_id, str)
|
||||
assert isinstance(message.photo[-1].file_unique_id, str)
|
||||
assert message.photo[-1].file_id != ""
|
||||
assert message.photo[-1].file_unique_id != ""
|
||||
assert message.photo[-1].file_id
|
||||
assert message.photo[-1].file_unique_id
|
||||
|
||||
assert message.caption == self.caption.replace("<b>", "").replace("</b>", "")
|
||||
assert len(message.caption_entities) == 1
|
||||
|
@ -328,7 +328,7 @@ class TestPhotoWithRequest(TestPhotoBase):
|
|||
assert not unprotected.has_protected_content
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"default_bot,custom",
|
||||
("default_bot", "custom"),
|
||||
[
|
||||
({"allow_sending_without_reply": True}, None),
|
||||
({"allow_sending_without_reply": False}, None),
|
||||
|
@ -381,14 +381,14 @@ class TestPhotoWithRequest(TestPhotoBase):
|
|||
assert isinstance(message.photo[-2], PhotoSize)
|
||||
assert isinstance(message.photo[-2].file_id, str)
|
||||
assert isinstance(message.photo[-2].file_unique_id, str)
|
||||
assert message.photo[-2].file_id != ""
|
||||
assert message.photo[-2].file_unique_id != ""
|
||||
assert message.photo[-2].file_id
|
||||
assert message.photo[-2].file_unique_id
|
||||
|
||||
assert isinstance(message.photo[-1], PhotoSize)
|
||||
assert isinstance(message.photo[-1].file_id, str)
|
||||
assert isinstance(message.photo[-1].file_unique_id, str)
|
||||
assert message.photo[-1].file_id != ""
|
||||
assert message.photo[-1].file_unique_id != ""
|
||||
assert message.photo[-1].file_id
|
||||
assert message.photo[-1].file_unique_id
|
||||
|
||||
async def test_send_url_png_file(self, bot, chat_id):
|
||||
message = await bot.send_photo(
|
||||
|
@ -400,8 +400,8 @@ class TestPhotoWithRequest(TestPhotoBase):
|
|||
assert isinstance(photo, PhotoSize)
|
||||
assert isinstance(photo.file_id, str)
|
||||
assert isinstance(photo.file_unique_id, str)
|
||||
assert photo.file_id != ""
|
||||
assert photo.file_unique_id != ""
|
||||
assert photo.file_id
|
||||
assert photo.file_unique_id
|
||||
|
||||
async def test_send_file_unicode_filename(self, bot, chat_id):
|
||||
"""
|
||||
|
@ -415,8 +415,8 @@ class TestPhotoWithRequest(TestPhotoBase):
|
|||
assert isinstance(photo, PhotoSize)
|
||||
assert isinstance(photo.file_id, str)
|
||||
assert isinstance(photo.file_unique_id, str)
|
||||
assert photo.file_id != ""
|
||||
assert photo.file_unique_id != ""
|
||||
assert photo.file_id
|
||||
assert photo.file_unique_id
|
||||
|
||||
async def test_send_bytesio_jpg_file(self, bot, chat_id):
|
||||
filepath = data_file("telegram_no_standard_header.jpg")
|
||||
|
@ -438,8 +438,8 @@ class TestPhotoWithRequest(TestPhotoBase):
|
|||
photo = message.photo[-1]
|
||||
assert isinstance(photo.file_id, str)
|
||||
assert isinstance(photo.file_unique_id, str)
|
||||
assert photo.file_id != ""
|
||||
assert photo.file_unique_id != ""
|
||||
assert photo.file_id
|
||||
assert photo.file_unique_id
|
||||
assert isinstance(photo, PhotoSize)
|
||||
assert photo.width == 1280
|
||||
assert photo.height == 720
|
||||
|
@ -451,18 +451,18 @@ class TestPhotoWithRequest(TestPhotoBase):
|
|||
assert isinstance(message.photo[-2], PhotoSize)
|
||||
assert isinstance(message.photo[-2].file_id, str)
|
||||
assert isinstance(message.photo[-2].file_unique_id, str)
|
||||
assert message.photo[-2].file_id != ""
|
||||
assert message.photo[-2].file_unique_id != ""
|
||||
assert message.photo[-2].file_id
|
||||
assert message.photo[-2].file_unique_id
|
||||
|
||||
assert isinstance(message.photo[-1], PhotoSize)
|
||||
assert isinstance(message.photo[-1].file_id, str)
|
||||
assert isinstance(message.photo[-1].file_unique_id, str)
|
||||
assert message.photo[-1].file_id != ""
|
||||
assert message.photo[-1].file_unique_id != ""
|
||||
assert message.photo[-1].file_id
|
||||
assert message.photo[-1].file_unique_id
|
||||
|
||||
async def test_error_send_empty_file(self, bot, chat_id):
|
||||
with pytest.raises(TelegramError):
|
||||
await bot.send_photo(chat_id=chat_id, photo=open(os.devnull, "rb"))
|
||||
with Path(os.devnull).open("rb") as file, pytest.raises(TelegramError):
|
||||
await bot.send_photo(chat_id=chat_id, photo=file)
|
||||
|
||||
async def test_error_send_empty_file_id(self, bot, chat_id):
|
||||
with pytest.raises(TelegramError):
|
||||
|
|
|
@ -48,7 +48,7 @@ from tests.auxil.files import data_file
|
|||
from tests.auxil.slots import mro_slots
|
||||
|
||||
|
||||
@pytest.fixture(scope="function")
|
||||
@pytest.fixture()
|
||||
def sticker_file():
|
||||
with data_file("telegram.webp").open("rb") as file:
|
||||
yield file
|
||||
|
@ -64,7 +64,7 @@ async def sticker(bot, chat_id):
|
|||
return sticker
|
||||
|
||||
|
||||
@pytest.fixture(scope="function")
|
||||
@pytest.fixture()
|
||||
def animated_sticker_file():
|
||||
with data_file("telegram_animated_sticker.tgs").open("rb") as f:
|
||||
yield f
|
||||
|
@ -76,7 +76,7 @@ async def animated_sticker(bot, chat_id):
|
|||
return (await bot.send_sticker(chat_id, sticker=f, read_timeout=50)).sticker
|
||||
|
||||
|
||||
@pytest.fixture(scope="function")
|
||||
@pytest.fixture()
|
||||
def video_sticker_file():
|
||||
with data_file("telegram_video_sticker.webm").open("rb") as f:
|
||||
yield f
|
||||
|
@ -126,13 +126,13 @@ class TestStickerWithoutRequest(TestStickerBase):
|
|||
assert isinstance(sticker, Sticker)
|
||||
assert isinstance(sticker.file_id, str)
|
||||
assert isinstance(sticker.file_unique_id, str)
|
||||
assert sticker.file_id != ""
|
||||
assert sticker.file_unique_id != ""
|
||||
assert sticker.file_id
|
||||
assert sticker.file_unique_id
|
||||
assert isinstance(sticker.thumbnail, PhotoSize)
|
||||
assert isinstance(sticker.thumbnail.file_id, str)
|
||||
assert isinstance(sticker.thumbnail.file_unique_id, str)
|
||||
assert sticker.thumbnail.file_id != ""
|
||||
assert sticker.thumbnail.file_unique_id != ""
|
||||
assert sticker.thumbnail.file_id
|
||||
assert sticker.thumbnail.file_unique_id
|
||||
assert isinstance(sticker.needs_repainting, bool)
|
||||
|
||||
def test_expected_values(self, sticker):
|
||||
|
@ -312,8 +312,8 @@ class TestStickerWithRequest(TestStickerBase):
|
|||
assert isinstance(message.sticker, Sticker)
|
||||
assert isinstance(message.sticker.file_id, str)
|
||||
assert isinstance(message.sticker.file_unique_id, str)
|
||||
assert message.sticker.file_id != ""
|
||||
assert message.sticker.file_unique_id != ""
|
||||
assert message.sticker.file_id
|
||||
assert message.sticker.file_unique_id
|
||||
assert message.sticker.width == sticker.width
|
||||
assert message.sticker.height == sticker.height
|
||||
assert message.sticker.is_animated == sticker.is_animated
|
||||
|
@ -327,8 +327,8 @@ class TestStickerWithRequest(TestStickerBase):
|
|||
assert isinstance(message.sticker.thumbnail, PhotoSize)
|
||||
assert isinstance(message.sticker.thumbnail.file_id, str)
|
||||
assert isinstance(message.sticker.thumbnail.file_unique_id, str)
|
||||
assert message.sticker.thumbnail.file_id != ""
|
||||
assert message.sticker.thumbnail.file_unique_id != ""
|
||||
assert message.sticker.thumbnail.file_id
|
||||
assert message.sticker.thumbnail.file_unique_id
|
||||
assert message.sticker.thumbnail.width == sticker.thumbnail.width
|
||||
assert message.sticker.thumbnail.height == sticker.thumbnail.height
|
||||
assert message.sticker.thumbnail.file_size == sticker.thumbnail.file_size
|
||||
|
@ -372,8 +372,8 @@ class TestStickerWithRequest(TestStickerBase):
|
|||
assert isinstance(message.sticker, Sticker)
|
||||
assert isinstance(message.sticker.file_id, str)
|
||||
assert isinstance(message.sticker.file_unique_id, str)
|
||||
assert message.sticker.file_id != ""
|
||||
assert message.sticker.file_unique_id != ""
|
||||
assert message.sticker.file_id
|
||||
assert message.sticker.file_unique_id
|
||||
assert message.sticker.width == sticker.width
|
||||
assert message.sticker.height == sticker.height
|
||||
assert message.sticker.is_animated == sticker.is_animated
|
||||
|
@ -384,14 +384,14 @@ class TestStickerWithRequest(TestStickerBase):
|
|||
assert isinstance(message.sticker.thumbnail, PhotoSize)
|
||||
assert isinstance(message.sticker.thumbnail.file_id, str)
|
||||
assert isinstance(message.sticker.thumbnail.file_unique_id, str)
|
||||
assert message.sticker.thumbnail.file_id != ""
|
||||
assert message.sticker.thumbnail.file_unique_id != ""
|
||||
assert message.sticker.thumbnail.file_id
|
||||
assert message.sticker.thumbnail.file_unique_id
|
||||
assert message.sticker.thumbnail.width == sticker.thumbnail.width
|
||||
assert message.sticker.thumbnail.height == sticker.thumbnail.height
|
||||
assert message.sticker.thumbnail.file_size == sticker.thumbnail.file_size
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"default_bot,custom",
|
||||
("default_bot", "custom"),
|
||||
[
|
||||
({"allow_sending_without_reply": True}, None),
|
||||
({"allow_sending_without_reply": False}, None),
|
||||
|
@ -442,7 +442,7 @@ class TestStickerWithRequest(TestStickerBase):
|
|||
premium_sticker = premium_sticker_set.stickers[20]
|
||||
assert premium_sticker.premium_animation.file_unique_id == "AQADOBwAAifPOElr"
|
||||
assert isinstance(premium_sticker.premium_animation.file_id, str)
|
||||
assert premium_sticker.premium_animation.file_id != ""
|
||||
assert premium_sticker.premium_animation.file_id
|
||||
premium_sticker_dict = {
|
||||
"file_unique_id": "AQADOBwAAifPOElr",
|
||||
"file_id": premium_sticker.premium_animation.file_id,
|
||||
|
@ -478,15 +478,15 @@ class TestStickerWithRequest(TestStickerBase):
|
|||
assert emoji_sticker_list[0].file_unique_id == "AgAD6gwAAoY06FM"
|
||||
|
||||
async def test_error_send_empty_file(self, bot, chat_id):
|
||||
with pytest.raises(TelegramError):
|
||||
await bot.send_sticker(chat_id, open(os.devnull, "rb"))
|
||||
with Path(os.devnull).open("rb") as file, pytest.raises(TelegramError):
|
||||
await bot.send_sticker(chat_id, file)
|
||||
|
||||
async def test_error_send_empty_file_id(self, bot, chat_id):
|
||||
with pytest.raises(TelegramError):
|
||||
await bot.send_sticker(chat_id, "")
|
||||
|
||||
|
||||
@pytest.fixture(scope="function")
|
||||
@pytest.fixture()
|
||||
async def sticker_set(bot):
|
||||
ss = await bot.get_sticker_set(f"test_by_{bot.username}")
|
||||
if len(ss.stickers) > 100:
|
||||
|
@ -496,11 +496,11 @@ async def sticker_set(bot):
|
|||
except BadRequest as e:
|
||||
if e.message == "Stickerset_not_modified":
|
||||
return ss
|
||||
raise Exception("stickerset is growing too large.")
|
||||
raise Exception("stickerset is growing too large.") from None
|
||||
return ss
|
||||
|
||||
|
||||
@pytest.fixture(scope="function")
|
||||
@pytest.fixture()
|
||||
async def animated_sticker_set(bot):
|
||||
ss = await bot.get_sticker_set(f"animated_test_by_{bot.username}")
|
||||
if len(ss.stickers) > 100:
|
||||
|
@ -510,11 +510,11 @@ async def animated_sticker_set(bot):
|
|||
except BadRequest as e:
|
||||
if e.message == "Stickerset_not_modified":
|
||||
return ss
|
||||
raise Exception("stickerset is growing too large.")
|
||||
raise Exception("stickerset is growing too large.") from None
|
||||
return ss
|
||||
|
||||
|
||||
@pytest.fixture(scope="function")
|
||||
@pytest.fixture()
|
||||
async def video_sticker_set(bot):
|
||||
ss = await bot.get_sticker_set(f"video_test_by_{bot.username}")
|
||||
if len(ss.stickers) > 100:
|
||||
|
@ -524,11 +524,11 @@ async def video_sticker_set(bot):
|
|||
except BadRequest as e:
|
||||
if e.message == "Stickerset_not_modified":
|
||||
return ss
|
||||
raise Exception("stickerset is growing too large.")
|
||||
raise Exception("stickerset is growing too large.") from None
|
||||
return ss
|
||||
|
||||
|
||||
@pytest.fixture(scope="function")
|
||||
@pytest.fixture()
|
||||
def sticker_set_thumb_file():
|
||||
with data_file("sticker_set_thumb.png").open("rb") as file:
|
||||
yield file
|
||||
|
|
|
@ -144,7 +144,7 @@ class TestVenueWithoutRequest(TestVenueBase):
|
|||
|
||||
class TestVenueWithRequest(TestVenueBase):
|
||||
@pytest.mark.parametrize(
|
||||
"default_bot,custom",
|
||||
("default_bot", "custom"),
|
||||
[
|
||||
({"allow_sending_without_reply": True}, None),
|
||||
({"allow_sending_without_reply": False}, None),
|
||||
|
|
|
@ -36,7 +36,7 @@ from tests.auxil.files import data_file
|
|||
from tests.auxil.slots import mro_slots
|
||||
|
||||
|
||||
@pytest.fixture(scope="function")
|
||||
@pytest.fixture()
|
||||
def video_file():
|
||||
with data_file("telegram.mp4").open("rb") as f:
|
||||
yield f
|
||||
|
@ -76,14 +76,14 @@ class TestVideoWithoutRequest(TestVideoBase):
|
|||
assert isinstance(video, Video)
|
||||
assert isinstance(video.file_id, str)
|
||||
assert isinstance(video.file_unique_id, str)
|
||||
assert video.file_id != ""
|
||||
assert video.file_unique_id != ""
|
||||
assert video.file_id
|
||||
assert video.file_unique_id
|
||||
|
||||
assert isinstance(video.thumbnail, PhotoSize)
|
||||
assert isinstance(video.thumbnail.file_id, str)
|
||||
assert isinstance(video.thumbnail.file_unique_id, str)
|
||||
assert video.thumbnail.file_id != ""
|
||||
assert video.thumbnail.file_unique_id != ""
|
||||
assert video.thumbnail.file_id
|
||||
assert video.thumbnail.file_unique_id
|
||||
|
||||
def test_expected_values(self, video):
|
||||
assert video.width == self.width
|
||||
|
@ -244,8 +244,8 @@ class TestVideoWithRequest(TestVideoBase):
|
|||
assert isinstance(message.video, Video)
|
||||
assert isinstance(message.video.file_id, str)
|
||||
assert isinstance(message.video.file_unique_id, str)
|
||||
assert message.video.file_id != ""
|
||||
assert message.video.file_unique_id != ""
|
||||
assert message.video.file_id
|
||||
assert message.video.file_unique_id
|
||||
assert message.video.width == video.width
|
||||
assert message.video.height == video.height
|
||||
assert message.video.duration == video.duration
|
||||
|
@ -282,8 +282,8 @@ class TestVideoWithRequest(TestVideoBase):
|
|||
assert isinstance(message.video, Video)
|
||||
assert isinstance(message.video.file_id, str)
|
||||
assert isinstance(message.video.file_unique_id, str)
|
||||
assert message.video.file_id != ""
|
||||
assert message.video.file_unique_id != ""
|
||||
assert message.video.file_id
|
||||
assert message.video.file_unique_id
|
||||
assert message.video.width == video.width
|
||||
assert message.video.height == video.height
|
||||
assert message.video.duration == video.duration
|
||||
|
@ -292,8 +292,8 @@ class TestVideoWithRequest(TestVideoBase):
|
|||
assert isinstance(message.video.thumbnail, PhotoSize)
|
||||
assert isinstance(message.video.thumbnail.file_id, str)
|
||||
assert isinstance(message.video.thumbnail.file_unique_id, str)
|
||||
assert message.video.thumbnail.file_id != ""
|
||||
assert message.video.thumbnail.file_unique_id != ""
|
||||
assert message.video.thumbnail.file_id
|
||||
assert message.video.thumbnail.file_unique_id
|
||||
assert message.video.thumbnail.width == 51 # This seems odd that it's not self.thumb_width
|
||||
assert message.video.thumbnail.height == 90 # Ditto
|
||||
assert message.video.thumbnail.file_size == 645 # same
|
||||
|
@ -358,7 +358,7 @@ class TestVideoWithRequest(TestVideoBase):
|
|||
assert not unprotected.has_protected_content
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"default_bot,custom",
|
||||
("default_bot", "custom"),
|
||||
[
|
||||
({"allow_sending_without_reply": True}, None),
|
||||
({"allow_sending_without_reply": False}, None),
|
||||
|
@ -391,8 +391,8 @@ class TestVideoWithRequest(TestVideoBase):
|
|||
)
|
||||
|
||||
async def test_error_send_empty_file(self, bot, chat_id):
|
||||
with pytest.raises(TelegramError):
|
||||
await bot.send_video(chat_id, open(os.devnull, "rb"))
|
||||
with Path(os.devnull).open("rb") as file, pytest.raises(TelegramError):
|
||||
await bot.send_video(chat_id, file)
|
||||
|
||||
async def test_error_send_empty_file_id(self, bot, chat_id):
|
||||
with pytest.raises(TelegramError):
|
||||
|
|
|
@ -35,7 +35,7 @@ from tests.auxil.files import data_file
|
|||
from tests.auxil.slots import mro_slots
|
||||
|
||||
|
||||
@pytest.fixture(scope="function")
|
||||
@pytest.fixture()
|
||||
def video_note_file():
|
||||
with data_file("telegram2.mp4").open("rb") as f:
|
||||
yield f
|
||||
|
@ -70,14 +70,14 @@ class TestVideoNoteWithoutRequest(TestVideoNoteBase):
|
|||
assert isinstance(video_note, VideoNote)
|
||||
assert isinstance(video_note.file_id, str)
|
||||
assert isinstance(video_note.file_unique_id, str)
|
||||
assert video_note.file_id != ""
|
||||
assert video_note.file_unique_id != ""
|
||||
assert video_note.file_id
|
||||
assert video_note.file_unique_id
|
||||
|
||||
assert isinstance(video_note.thumbnail, PhotoSize)
|
||||
assert isinstance(video_note.thumbnail.file_id, str)
|
||||
assert isinstance(video_note.thumbnail.file_unique_id, str)
|
||||
assert video_note.thumbnail.file_id != ""
|
||||
assert video_note.thumbnail.file_unique_id != ""
|
||||
assert video_note.thumbnail.file_id
|
||||
assert video_note.thumbnail.file_unique_id
|
||||
|
||||
def test_expected_values(self, video_note):
|
||||
assert video_note.length == self.length
|
||||
|
@ -221,8 +221,8 @@ class TestVideoNoteWithRequest(TestVideoNoteBase):
|
|||
assert isinstance(message.video_note, VideoNote)
|
||||
assert isinstance(message.video_note.file_id, str)
|
||||
assert isinstance(message.video_note.file_unique_id, str)
|
||||
assert message.video_note.file_id != ""
|
||||
assert message.video_note.file_unique_id != ""
|
||||
assert message.video_note.file_id
|
||||
assert message.video_note.file_unique_id
|
||||
assert message.video_note.length == video_note.length
|
||||
assert message.video_note.duration == video_note.duration
|
||||
assert message.video_note.file_size == video_note.file_size
|
||||
|
@ -252,7 +252,7 @@ class TestVideoNoteWithRequest(TestVideoNoteBase):
|
|||
assert message.video_note == video_note
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"default_bot,custom",
|
||||
("default_bot", "custom"),
|
||||
[
|
||||
({"allow_sending_without_reply": True}, None),
|
||||
({"allow_sending_without_reply": False}, None),
|
||||
|
@ -295,8 +295,8 @@ class TestVideoNoteWithRequest(TestVideoNoteBase):
|
|||
assert not unprotected.has_protected_content
|
||||
|
||||
async def test_error_send_empty_file(self, bot, chat_id):
|
||||
with pytest.raises(TelegramError):
|
||||
await bot.send_video_note(chat_id, open(os.devnull, "rb"))
|
||||
with Path(os.devnull).open("rb") as file, pytest.raises(TelegramError):
|
||||
await bot.send_video_note(chat_id, file)
|
||||
|
||||
async def test_error_send_empty_file_id(self, bot, chat_id):
|
||||
with pytest.raises(TelegramError):
|
||||
|
|
|
@ -35,7 +35,7 @@ from tests.auxil.files import data_file
|
|||
from tests.auxil.slots import mro_slots
|
||||
|
||||
|
||||
@pytest.fixture(scope="function")
|
||||
@pytest.fixture()
|
||||
def voice_file():
|
||||
with data_file("telegram.ogg").open("rb") as f:
|
||||
yield f
|
||||
|
@ -68,8 +68,8 @@ class TestVoiceWithoutRequest(TestVoiceBase):
|
|||
assert isinstance(voice, Voice)
|
||||
assert isinstance(voice.file_id, str)
|
||||
assert isinstance(voice.file_unique_id, str)
|
||||
assert voice.file_id != ""
|
||||
assert voice.file_unique_id != ""
|
||||
assert voice.file_id
|
||||
assert voice.file_unique_id
|
||||
|
||||
def test_expected_values(self, voice):
|
||||
assert voice.duration == self.duration
|
||||
|
@ -191,8 +191,8 @@ class TestVoiceWithRequest(TestVoiceBase):
|
|||
assert isinstance(message.voice, Voice)
|
||||
assert isinstance(message.voice.file_id, str)
|
||||
assert isinstance(message.voice.file_unique_id, str)
|
||||
assert message.voice.file_id != ""
|
||||
assert message.voice.file_unique_id != ""
|
||||
assert message.voice.file_id
|
||||
assert message.voice.file_unique_id
|
||||
assert message.voice.duration == voice.duration
|
||||
assert message.voice.mime_type == voice.mime_type
|
||||
assert message.voice.file_size == voice.file_size
|
||||
|
@ -220,8 +220,8 @@ class TestVoiceWithRequest(TestVoiceBase):
|
|||
assert isinstance(message.voice, Voice)
|
||||
assert isinstance(message.voice.file_id, str)
|
||||
assert isinstance(message.voice.file_unique_id, str)
|
||||
assert message.voice.file_id != ""
|
||||
assert message.voice.file_unique_id != ""
|
||||
assert message.voice.file_id
|
||||
assert message.voice.file_unique_id
|
||||
assert message.voice.duration == voice.duration
|
||||
assert message.voice.mime_type == voice.mime_type
|
||||
assert message.voice.file_size == voice.file_size
|
||||
|
@ -285,7 +285,7 @@ class TestVoiceWithRequest(TestVoiceBase):
|
|||
assert not unprotected.has_protected_content
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"default_bot,custom",
|
||||
("default_bot", "custom"),
|
||||
[
|
||||
({"allow_sending_without_reply": True}, None),
|
||||
({"allow_sending_without_reply": False}, None),
|
||||
|
@ -318,8 +318,8 @@ class TestVoiceWithRequest(TestVoiceBase):
|
|||
)
|
||||
|
||||
async def test_error_send_empty_file(self, bot, chat_id):
|
||||
with pytest.raises(TelegramError):
|
||||
await bot.sendVoice(chat_id, open(os.devnull, "rb"))
|
||||
with Path(os.devnull).open("rb") as file, pytest.raises(TelegramError):
|
||||
await bot.sendVoice(chat_id, file)
|
||||
|
||||
async def test_error_send_empty_file_id(self, bot, chat_id):
|
||||
with pytest.raises(TelegramError):
|
||||
|
|
|
@ -93,7 +93,7 @@ class TestInlineKeyboardButtonWithoutRequest(TestInlineKeyboardButtonBase):
|
|||
assert inline_keyboard_button_dict["pay"] == inline_keyboard_button.pay
|
||||
assert (
|
||||
inline_keyboard_button_dict["login_url"] == inline_keyboard_button.login_url.to_dict()
|
||||
) # NOQA: E127
|
||||
)
|
||||
assert inline_keyboard_button_dict["web_app"] == inline_keyboard_button.web_app.to_dict()
|
||||
|
||||
def test_de_json(self, bot):
|
||||
|
|
|
@ -179,17 +179,17 @@ class TestInlineKeyboardMarkupWithoutRequest(TestInlineKeyboardMarkupBase):
|
|||
)
|
||||
|
||||
def test_wrong_keyboard_inputs(self):
|
||||
with pytest.raises(ValueError):
|
||||
with pytest.raises(ValueError, match="should be a sequence of sequences"):
|
||||
InlineKeyboardMarkup(
|
||||
[[InlineKeyboardButton("b1", "1")], InlineKeyboardButton("b2", "2")]
|
||||
)
|
||||
with pytest.raises(ValueError):
|
||||
with pytest.raises(ValueError, match="should be a sequence of sequences"):
|
||||
InlineKeyboardMarkup("strings_are_not_allowed")
|
||||
with pytest.raises(ValueError):
|
||||
with pytest.raises(ValueError, match="should be a sequence of sequences"):
|
||||
InlineKeyboardMarkup(["strings_are_not_allowed_in_the_rows_either"])
|
||||
with pytest.raises(ValueError):
|
||||
with pytest.raises(ValueError, match="should be a sequence of sequences"):
|
||||
InlineKeyboardMarkup(InlineKeyboardButton("b1", "1"))
|
||||
with pytest.raises(ValueError):
|
||||
with pytest.raises(ValueError, match="should be a sequence of sequences"):
|
||||
InlineKeyboardMarkup([[[InlineKeyboardButton("only_2d_array_is_allowed", "1")]]])
|
||||
|
||||
async def test_expected_values_empty_switch(self, inline_keyboard_markup, bot, monkeypatch):
|
||||
|
|
|
@ -68,7 +68,7 @@ def false_update(request):
|
|||
return Update(update_id=2, **request.param)
|
||||
|
||||
|
||||
@pytest.fixture(scope="function")
|
||||
@pytest.fixture()
|
||||
def inline_query(bot):
|
||||
update = Update(
|
||||
0,
|
||||
|
@ -95,7 +95,7 @@ class TestInlineQueryHandler:
|
|||
assert len(mro_slots(handler)) == len(set(mro_slots(handler))), "duplicate slot"
|
||||
|
||||
@pytest.fixture(autouse=True)
|
||||
def reset(self):
|
||||
def _reset(self):
|
||||
self.test_flag = False
|
||||
|
||||
async def callback(self, update, context):
|
||||
|
@ -154,7 +154,7 @@ class TestInlineQueryHandler:
|
|||
|
||||
@pytest.mark.parametrize("chat_types", [[Chat.SENDER], [Chat.SENDER, Chat.SUPERGROUP], []])
|
||||
@pytest.mark.parametrize(
|
||||
"chat_type,result", [(Chat.SENDER, True), (Chat.CHANNEL, False), (None, False)]
|
||||
("chat_type", "result"), [(Chat.SENDER, True), (Chat.CHANNEL, False), (None, False)]
|
||||
)
|
||||
async def test_chat_types(self, app, inline_query, chat_types, chat_type, result):
|
||||
try:
|
||||
|
|
|
@ -120,7 +120,7 @@ class TestInputInvoiceMessageContentWithoutRequest(TestInputInvoiceMessageConten
|
|||
currency=self.currency,
|
||||
prices=self.prices,
|
||||
)
|
||||
assert input_invoice_message_content.suggested_tip_amounts == tuple()
|
||||
assert input_invoice_message_content.suggested_tip_amounts == ()
|
||||
|
||||
def test_to_dict(self, input_invoice_message_content):
|
||||
input_invoice_message_content_dict = input_invoice_message_content.to_dict()
|
||||
|
|
|
@ -29,7 +29,7 @@ with the TEST_WITH_OPT_DEPS environment variable set to False in addition to the
|
|||
import pytest
|
||||
|
||||
from telegram import _bot as bot
|
||||
from telegram._passport import credentials as credentials
|
||||
from telegram._passport import credentials
|
||||
from tests.auxil.envvars import TEST_WITH_OPT_DEPS
|
||||
|
||||
|
||||
|
|
|
@ -90,7 +90,7 @@ class TestInvoiceWithoutRequest(TestInvoiceBase):
|
|||
# parameters correctly because #2526 went unnoticed for 3 years …
|
||||
async def make_assertion(*args, **_):
|
||||
kwargs = args[1]
|
||||
return all([kwargs[key] == key for key in kwargs])
|
||||
return all(kwargs[key] == key for key in kwargs)
|
||||
|
||||
monkeypatch.setattr(bot, "_send_message", make_assertion)
|
||||
assert await bot.send_invoice(
|
||||
|
@ -123,7 +123,7 @@ class TestInvoiceWithoutRequest(TestInvoiceBase):
|
|||
async def test_send_all_args_create_invoice_link(self, bot, monkeypatch):
|
||||
async def make_assertion(*args, **_):
|
||||
kwargs = args[1]
|
||||
return all([kwargs[i] == i for i in kwargs])
|
||||
return all(kwargs[i] == i for i in kwargs)
|
||||
|
||||
monkeypatch.setattr(bot, "_post", make_assertion)
|
||||
assert await bot.create_invoice_link(
|
||||
|
@ -196,7 +196,7 @@ class TestInvoiceWithRequest(TestInvoiceBase):
|
|||
)
|
||||
|
||||
assert message.invoice.currency == self.currency
|
||||
assert message.invoice.start_parameter == ""
|
||||
assert not message.invoice.start_parameter
|
||||
assert message.invoice.description == self.description
|
||||
assert message.invoice.title == self.title
|
||||
assert message.invoice.total_amount == self.total_amount
|
||||
|
@ -211,7 +211,7 @@ class TestInvoiceWithRequest(TestInvoiceBase):
|
|||
)
|
||||
|
||||
assert isinstance(link, str)
|
||||
assert link != ""
|
||||
assert link
|
||||
|
||||
@pytest.mark.parametrize("default_bot", [{"protect_content": True}], indirect=True)
|
||||
async def test_send_invoice_default_protect_content(
|
||||
|
@ -237,7 +237,7 @@ class TestInvoiceWithRequest(TestInvoiceBase):
|
|||
assert not unprotected.has_protected_content
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"default_bot,custom",
|
||||
("default_bot", "custom"),
|
||||
[
|
||||
({"allow_sending_without_reply": True}, None),
|
||||
({"allow_sending_without_reply": False}, None),
|
||||
|
|
|
@ -96,7 +96,7 @@ class TestDatetime:
|
|||
|
||||
def test_to_float_timestamp_absolute_no_reference(self):
|
||||
"""A reference timestamp is only relevant for relative time specifications"""
|
||||
with pytest.raises(ValueError):
|
||||
with pytest.raises(ValueError, match="while reference_timestamp is not None"):
|
||||
tg_dtm.to_float_timestamp(dtm.datetime(2019, 11, 11), reference_timestamp=123)
|
||||
|
||||
# see note on parametrization at the top of this file
|
||||
|
|
|
@ -45,7 +45,7 @@ class TestDefault:
|
|||
def test_data_assignment(self):
|
||||
defaults = Defaults()
|
||||
|
||||
for name, val in inspect.getmembers(Defaults, lambda x: isinstance(x, property)):
|
||||
for name, _val in inspect.getmembers(Defaults, lambda x: isinstance(x, property)):
|
||||
with pytest.raises(AttributeError):
|
||||
setattr(defaults, name, True)
|
||||
|
||||
|
|
|
@ -37,7 +37,7 @@ class TestDefaultValue:
|
|||
assert df_1 != df_2
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"value,expected",
|
||||
("value", "expected"),
|
||||
[
|
||||
({}, False),
|
||||
({1: 2}, True),
|
||||
|
@ -67,8 +67,7 @@ class TestDefaultValue:
|
|||
def foo(arg=default_one):
|
||||
if arg is default_one:
|
||||
return 1
|
||||
else:
|
||||
return 2
|
||||
return 2
|
||||
|
||||
assert foo() == 1
|
||||
assert foo(None) == 2
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
#
|
||||
# You should have received a copy of the GNU Lesser Public License
|
||||
# along with this program. If not, see [http://www.gnu.org/licenses/].
|
||||
import contextlib
|
||||
import subprocess
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
@ -30,7 +31,7 @@ from tests.auxil.files import TEST_DATA_PATH, data_file
|
|||
|
||||
class TestFiles:
|
||||
@pytest.mark.parametrize(
|
||||
"string,expected",
|
||||
("string", "expected"),
|
||||
[
|
||||
(str(data_file("game.gif")), True),
|
||||
(str(TEST_DATA_PATH), False),
|
||||
|
@ -46,7 +47,7 @@ class TestFiles:
|
|||
assert telegram._utils.files.is_local_file(string) == expected
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"string,expected_local,expected_non_local",
|
||||
("string", "expected_local", "expected_non_local"),
|
||||
[
|
||||
(data_file("game.gif"), data_file("game.gif").as_uri(), InputFile),
|
||||
(TEST_DATA_PATH, TEST_DATA_PATH, TEST_DATA_PATH),
|
||||
|
@ -76,7 +77,7 @@ class TestFiles:
|
|||
telegram._utils.files.parse_file_input(string, local_mode=False), InputFile
|
||||
)
|
||||
elif expected_non_local is ValueError:
|
||||
with pytest.raises(ValueError):
|
||||
with pytest.raises(ValueError, match="but local mode is not enabled."):
|
||||
telegram._utils.files.parse_file_input(string, local_mode=False)
|
||||
else:
|
||||
assert (
|
||||
|
@ -153,9 +154,7 @@ class TestFiles:
|
|||
assert out[0] is None
|
||||
assert out[1] == png_file.read_bytes()
|
||||
|
||||
try:
|
||||
with contextlib.suppress(ProcessLookupError):
|
||||
proc.kill()
|
||||
except ProcessLookupError:
|
||||
# This exception may be thrown if the process has finished before we had the chance
|
||||
# to kill it.
|
||||
pass
|
||||
|
|
|
@ -19,7 +19,6 @@
|
|||
import datetime
|
||||
import functools
|
||||
import inspect
|
||||
import os
|
||||
from typing import Any, Callable, Dict, Iterable, List
|
||||
|
||||
import pytest
|
||||
|
@ -38,9 +37,8 @@ from telegram._utils.defaultvalue import DEFAULT_NONE, DefaultValue
|
|||
from telegram.constants import InputMediaType
|
||||
from telegram.ext import Defaults, ExtBot
|
||||
from telegram.request import RequestData
|
||||
from tests.auxil.envvars import env_var_2_bool
|
||||
from tests.auxil.envvars import TEST_WITH_OPT_DEPS
|
||||
|
||||
TEST_WITH_OPT_DEPS = env_var_2_bool(os.getenv("TEST_WITH_OPT_DEPS", True))
|
||||
if TEST_WITH_OPT_DEPS:
|
||||
import pytz
|
||||
|
||||
|
@ -138,15 +136,9 @@ async def check_shortcut_call(
|
|||
Returns:
|
||||
:obj:`bool`
|
||||
"""
|
||||
if not skip_params:
|
||||
skip_params = set()
|
||||
else:
|
||||
skip_params = set(skip_params)
|
||||
skip_params = set() if not skip_params else set(skip_params)
|
||||
skip_params.add("rate_limit_args")
|
||||
if not shortcut_kwargs:
|
||||
shortcut_kwargs = set()
|
||||
else:
|
||||
shortcut_kwargs = set(shortcut_kwargs)
|
||||
shortcut_kwargs = set() if not shortcut_kwargs else set(shortcut_kwargs)
|
||||
|
||||
orig_bot_method = getattr(bot, bot_method_name)
|
||||
bot_signature = inspect.signature(orig_bot_method)
|
||||
|
@ -278,7 +270,7 @@ async def check_defaults_handling(
|
|||
kwargs_need_default.remove("parse_mode")
|
||||
|
||||
defaults_no_custom_defaults = Defaults()
|
||||
kwargs = {kwarg: "custom_default" for kwarg in inspect.signature(Defaults).parameters.keys()}
|
||||
kwargs = {kwarg: "custom_default" for kwarg in inspect.signature(Defaults).parameters}
|
||||
kwargs["tzinfo"] = pytz.timezone("America/New_York")
|
||||
defaults_custom_defaults = Defaults(**kwargs)
|
||||
|
||||
|
@ -351,15 +343,12 @@ async def check_defaults_handling(
|
|||
# Check datetime conversion
|
||||
until_date = data.pop("until_date", None)
|
||||
if until_date:
|
||||
if df_value == "non-None-value":
|
||||
if until_date != 946681200:
|
||||
pytest.fail("Non-naive until_date was interpreted as Europe/Berlin.")
|
||||
if df_value is DEFAULT_NONE:
|
||||
if until_date != 946684800:
|
||||
pytest.fail("Naive until_date was not interpreted as UTC")
|
||||
if df_value == "custom_default":
|
||||
if until_date != 946702800:
|
||||
pytest.fail("Naive until_date was not interpreted as America/New_York")
|
||||
if df_value == "non-None-value" and until_date != 946681200:
|
||||
pytest.fail("Non-naive until_date was interpreted as Europe/Berlin.")
|
||||
if df_value is DEFAULT_NONE and until_date != 946684800:
|
||||
pytest.fail("Naive until_date was not interpreted as UTC")
|
||||
if df_value == "custom_default" and until_date != 946702800:
|
||||
pytest.fail("Naive until_date was not interpreted as America/New_York")
|
||||
|
||||
if method.__name__ in ["get_file", "get_small_file", "get_big_file"]:
|
||||
# This is here mainly for PassportFile.get_file, which calls .set_credentials on the
|
||||
|
@ -397,13 +386,13 @@ async def check_defaults_handling(
|
|||
kwargs_need_default,
|
||||
)
|
||||
assertion_callback = functools.partial(make_assertion, df_value=default_value)
|
||||
setattr(request, "post", assertion_callback)
|
||||
request.post = assertion_callback
|
||||
assert await method(**kwargs) in expected_return_values
|
||||
|
||||
# 2: test that we get the manually passed non-None value
|
||||
kwargs = build_kwargs(shortcut_signature, kwargs_need_default, dfv="non-None-value")
|
||||
assertion_callback = functools.partial(make_assertion, df_value="non-None-value")
|
||||
setattr(request, "post", assertion_callback)
|
||||
request.post = assertion_callback
|
||||
assert await method(**kwargs) in expected_return_values
|
||||
|
||||
# 3: test that we get the manually passed None value
|
||||
|
@ -413,12 +402,12 @@ async def check_defaults_handling(
|
|||
dfv=None,
|
||||
)
|
||||
assertion_callback = functools.partial(make_assertion, df_value=None)
|
||||
setattr(request, "post", assertion_callback)
|
||||
request.post = assertion_callback
|
||||
assert await method(**kwargs) in expected_return_values
|
||||
except Exception as exc:
|
||||
raise exc
|
||||
finally:
|
||||
setattr(request, "post", orig_post)
|
||||
request.post = orig_post
|
||||
if not raw_bot:
|
||||
bot._defaults = None
|
||||
|
||||
|
|
|
@ -27,5 +27,5 @@ def env_var_2_bool(env_var: object) -> bool:
|
|||
return env_var.lower().strip() == "true"
|
||||
|
||||
|
||||
GITHUB_ACTION = os.getenv("GITHUB_ACTION", False)
|
||||
TEST_WITH_OPT_DEPS = env_var_2_bool(os.getenv("TEST_WITH_OPT_DEPS", True))
|
||||
GITHUB_ACTION = os.getenv("GITHUB_ACTION", "")
|
||||
TEST_WITH_OPT_DEPS = env_var_2_bool(os.getenv("TEST_WITH_OPT_DEPS", "true"))
|
||||
|
|
|
@ -33,15 +33,16 @@ def terminal_summary_wrapper(original, plugin_name):
|
|||
return pytest_terminal_summary
|
||||
|
||||
|
||||
@pytest.mark.trylast
|
||||
@pytest.mark.trylast()
|
||||
def pytest_configure(config):
|
||||
for hookimpl in config.pluginmanager.hook.pytest_terminal_summary._nonwrappers:
|
||||
if hookimpl.plugin_name in fold_plugins:
|
||||
hookimpl.function = terminal_summary_wrapper(hookimpl.function, hookimpl.plugin_name)
|
||||
|
||||
|
||||
terminal = None
|
||||
previous_name = None
|
||||
class PytestPluginHelpers:
|
||||
terminal = None
|
||||
previous_name = None
|
||||
|
||||
|
||||
def _get_name(location):
|
||||
|
@ -50,7 +51,7 @@ def _get_name(location):
|
|||
return location[0]
|
||||
|
||||
|
||||
@pytest.mark.trylast
|
||||
@pytest.mark.trylast()
|
||||
def pytest_itemcollected(item):
|
||||
item._nodeid = item._nodeid.split("::", 1)[1]
|
||||
|
||||
|
@ -58,19 +59,16 @@ def pytest_itemcollected(item):
|
|||
@pytest.hookimpl(hookwrapper=True, tryfirst=True)
|
||||
def pytest_runtest_protocol(item, nextitem):
|
||||
# This is naughty but pytests' own plugins does something similar too, so who cares
|
||||
global terminal
|
||||
if terminal is None:
|
||||
terminal = _pytest.config.create_terminal_writer(item.config)
|
||||
|
||||
global previous_name
|
||||
if PytestPluginHelpers.terminal is None:
|
||||
PytestPluginHelpers.terminal = _pytest.config.create_terminal_writer(item.config)
|
||||
|
||||
name = _get_name(item.location)
|
||||
|
||||
if previous_name is None or previous_name != name:
|
||||
previous_name = name
|
||||
terminal.write(f"\n##[group] {name}")
|
||||
if PytestPluginHelpers.previous_name is None or PytestPluginHelpers.previous_name != name:
|
||||
PytestPluginHelpers.previous_name = name
|
||||
PytestPluginHelpers.terminal.write(f"\n##[group] {name}")
|
||||
|
||||
yield
|
||||
|
||||
if nextitem is None or _get_name(nextitem.location) != name:
|
||||
terminal.write("\n##[endgroup]")
|
||||
PytestPluginHelpers.terminal.write("\n##[endgroup]")
|
||||
|
|
|
@ -92,11 +92,10 @@ def make_bot(bot_info=None, **kwargs):
|
|||
token = kwargs.pop("token", (bot_info or {}).get("token"))
|
||||
private_key = kwargs.pop("private_key", PRIVATE_KEY)
|
||||
kwargs.pop("token", None)
|
||||
_bot = PytestExtBot(
|
||||
return PytestExtBot(
|
||||
token=token,
|
||||
private_key=private_key if TEST_WITH_OPT_DEPS else None,
|
||||
request=NonchalantHttpxRequest(8),
|
||||
get_updates_request=NonchalantHttpxRequest(1),
|
||||
**kwargs,
|
||||
)
|
||||
return _bot
|
||||
|
|
|
@ -28,10 +28,7 @@ def mro_slots(obj, only_parents: bool = False):
|
|||
"""
|
||||
cls = obj if inspect.isclass(obj) else obj.__class__
|
||||
|
||||
if only_parents:
|
||||
classes = cls.__mro__[1:]
|
||||
else:
|
||||
classes = cls.__mro__
|
||||
classes = cls.__mro__[1:] if only_parents else cls.__mro__
|
||||
|
||||
return [
|
||||
attr
|
||||
|
|
|
@ -100,8 +100,7 @@ def event_loop(request):
|
|||
# https://github.com/python/cpython/issues/83413, https://github.com/encode/httpx/issues/914
|
||||
if sys.version_info[0] == 3 and sys.version_info[1] >= 8 and sys.platform.startswith("win"):
|
||||
asyncio.set_event_loop_policy(asyncio.WindowsSelectorEventLoopPolicy())
|
||||
loop = asyncio.get_event_loop_policy().new_event_loop()
|
||||
yield loop
|
||||
return asyncio.get_event_loop_policy().new_event_loop()
|
||||
# loop.close() # instead of closing here, do that at the every end of the test session
|
||||
|
||||
|
||||
|
@ -117,7 +116,7 @@ async def bot(bot_info):
|
|||
yield _bot
|
||||
|
||||
|
||||
@pytest.fixture(scope="function")
|
||||
@pytest.fixture()
|
||||
def one_time_bot(bot_info):
|
||||
"""A function scoped bot since the session bot would shutdown when `async with app` finishes"""
|
||||
return make_bot(bot_info)
|
||||
|
@ -199,7 +198,7 @@ def provider_token(bot_info):
|
|||
return bot_info["payment_provider_token"]
|
||||
|
||||
|
||||
@pytest.fixture(scope="function")
|
||||
@pytest.fixture()
|
||||
async def app(bot_info):
|
||||
# We build a new bot each time so that we use `app` in a context manager without problems
|
||||
application = (
|
||||
|
@ -211,7 +210,7 @@ async def app(bot_info):
|
|||
await application.shutdown()
|
||||
|
||||
|
||||
@pytest.fixture(scope="function")
|
||||
@pytest.fixture()
|
||||
async def updater(bot_info):
|
||||
# We build a new bot each time so that we use `updater` in a context manager without problems
|
||||
up = Updater(bot=make_bot(bot_info), update_queue=asyncio.Queue())
|
||||
|
@ -221,7 +220,7 @@ async def updater(bot_info):
|
|||
await up.shutdown()
|
||||
|
||||
|
||||
@pytest.fixture(scope="function")
|
||||
@pytest.fixture()
|
||||
def thumb_file():
|
||||
with data_file("thumb.jpg").open("rb") as f:
|
||||
yield f
|
||||
|
@ -266,7 +265,7 @@ def _get_false_update_fixture_decorator_params():
|
|||
return {"params": params, "ids": ids}
|
||||
|
||||
|
||||
@pytest.fixture(scope="function", **_get_false_update_fixture_decorator_params())
|
||||
@pytest.fixture(**_get_false_update_fixture_decorator_params())
|
||||
def false_update(request):
|
||||
return Update(update_id=1, **request.param)
|
||||
|
||||
|
@ -275,9 +274,8 @@ def false_update(request):
|
|||
def tzinfo(request):
|
||||
if TEST_WITH_OPT_DEPS:
|
||||
return pytz.timezone(request.param)
|
||||
else:
|
||||
hours_offset = {"Europe/Berlin": 2, "Asia/Singapore": 8, "UTC": 0}[request.param]
|
||||
return BasicTimezone(offset=datetime.timedelta(hours=hours_offset), name=request.param)
|
||||
hours_offset = {"Europe/Berlin": 2, "Asia/Singapore": 8, "UTC": 0}[request.param]
|
||||
return BasicTimezone(offset=datetime.timedelta(hours=hours_offset), name=request.param)
|
||||
|
||||
|
||||
@pytest.fixture(scope="session")
|
||||
|
|
|
@ -81,8 +81,8 @@ class TestAdmonitionInserter:
|
|||
)
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"admonition_type, cls, link",
|
||||
(
|
||||
("admonition_type", "cls", "link"),
|
||||
[
|
||||
(
|
||||
"available_in",
|
||||
telegram.ChatMember,
|
||||
|
@ -171,7 +171,7 @@ class TestAdmonitionInserter:
|
|||
telegram.ext.PicklePersistence, # subclass
|
||||
":meth:`telegram.ext.ApplicationBuilder.persistence`",
|
||||
),
|
||||
),
|
||||
],
|
||||
)
|
||||
def test_check_presence(self, admonition_inserter, admonition_type, cls, link):
|
||||
"""Checks if a given link is present in the admonition of a given type for a given
|
||||
|
@ -199,8 +199,8 @@ class TestAdmonitionInserter:
|
|||
)
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"admonition_type, cls, link",
|
||||
(
|
||||
("admonition_type", "cls", "link"),
|
||||
[
|
||||
(
|
||||
"returned_in",
|
||||
telegram.ext.CallbackContext,
|
||||
|
@ -208,7 +208,7 @@ class TestAdmonitionInserter:
|
|||
# In this case classes inside square brackets must not be parsed
|
||||
":meth:`telegram.ext.ApplicationBuilder.build`",
|
||||
),
|
||||
),
|
||||
],
|
||||
)
|
||||
def test_check_absence(self, admonition_inserter, admonition_type, cls, link):
|
||||
"""Checks if a given link is **absent** in the admonition of a given type for a given
|
||||
|
|
|
@ -23,14 +23,14 @@ from telegram.ext._utils.trackingdict import TrackingDict
|
|||
from tests.auxil.slots import mro_slots
|
||||
|
||||
|
||||
@pytest.fixture(scope="function")
|
||||
@pytest.fixture()
|
||||
def td() -> TrackingDict:
|
||||
td = TrackingDict()
|
||||
td.update_no_track({1: 1})
|
||||
return td
|
||||
|
||||
|
||||
@pytest.fixture(scope="function")
|
||||
@pytest.fixture()
|
||||
def data() -> dict:
|
||||
return {1: 1}
|
||||
|
||||
|
@ -62,9 +62,9 @@ class TestTrackingDict:
|
|||
assert td != td_2
|
||||
assert td_2 != td
|
||||
assert td != 1
|
||||
assert 1 != td
|
||||
assert td != 1
|
||||
assert td != 5
|
||||
assert td != 5
|
||||
assert 5 != td
|
||||
|
||||
def test_getitem(self, td):
|
||||
assert td[1] == 1
|
||||
|
|
|
@ -75,7 +75,7 @@ class TestApplication:
|
|||
count = 0
|
||||
|
||||
@pytest.fixture(autouse=True, name="reset")
|
||||
def reset_fixture(self):
|
||||
def _reset_fixture(self):
|
||||
self.reset()
|
||||
|
||||
def reset(self):
|
||||
|
@ -121,8 +121,8 @@ class TestApplication:
|
|||
async def test_slot_behaviour(self, one_time_bot):
|
||||
async with ApplicationBuilder().bot(one_time_bot).build() as app:
|
||||
for at in app.__slots__:
|
||||
at = f"_Application{at}" if at.startswith("__") and not at.endswith("__") else at
|
||||
assert getattr(app, at, "err") != "err", f"got extra slot '{at}'"
|
||||
attr = f"_Application{at}" if at.startswith("__") and not at.endswith("__") else at
|
||||
assert getattr(app, attr, "err") != "err", f"got extra slot '{attr}'"
|
||||
assert len(mro_slots(app)) == len(set(mro_slots(app))), "duplicate slot"
|
||||
|
||||
def test_manual_init_warning(self, recwarn, updater):
|
||||
|
@ -146,7 +146,7 @@ class TestApplication:
|
|||
assert recwarn[0].filename == __file__, "stacklevel is incorrect!"
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"concurrent_updates, expected", [(0, 0), (4, 4), (False, 0), (True, 256)]
|
||||
("concurrent_updates", "expected"), [(0, 0), (4, 4), (False, 0), (True, 256)]
|
||||
)
|
||||
@pytest.mark.filterwarnings("ignore: `Application` instances should")
|
||||
def test_init(self, one_time_bot, concurrent_updates, expected):
|
||||
|
@ -239,7 +239,7 @@ class TestApplication:
|
|||
assert isinstance(application.chat_data[1], float)
|
||||
assert isinstance(application.bot_data, complex)
|
||||
|
||||
@pytest.mark.parametrize("updater", (True, False))
|
||||
@pytest.mark.parametrize("updater", [True, False])
|
||||
async def test_initialize(self, one_time_bot, monkeypatch, updater):
|
||||
"""Initialization of persistence is tested test_basepersistence"""
|
||||
self.test_flag = set()
|
||||
|
@ -266,7 +266,7 @@ class TestApplication:
|
|||
assert self.test_flag == {"bot"}
|
||||
await app.shutdown()
|
||||
|
||||
@pytest.mark.parametrize("updater", (True, False))
|
||||
@pytest.mark.parametrize("updater", [True, False])
|
||||
async def test_shutdown(self, one_time_bot, monkeypatch, updater):
|
||||
"""Shutdown of persistence is tested in test_basepersistence"""
|
||||
self.test_flag = set()
|
||||
|
@ -408,7 +408,7 @@ class TestApplication:
|
|||
builder_1.token(app.bot.token)
|
||||
builder_2.token(app.bot.token)
|
||||
|
||||
@pytest.mark.parametrize("job_queue", (True, False))
|
||||
@pytest.mark.parametrize("job_queue", [True, False])
|
||||
@pytest.mark.filterwarnings("ignore::telegram.warnings.PTBUserWarning")
|
||||
async def test_start_stop_processing_updates(self, one_time_bot, job_queue):
|
||||
# TODO: repeat a similar test for create_task, persistence processing and job queue
|
||||
|
@ -488,9 +488,8 @@ class TestApplication:
|
|||
if update.message.text == "test":
|
||||
if context is not self.received:
|
||||
pytest.fail("Expected same context object, got different")
|
||||
else:
|
||||
if context is self.received:
|
||||
pytest.fail("First handler was wrongly called")
|
||||
elif context is self.received:
|
||||
pytest.fail("First handler was wrongly called")
|
||||
|
||||
async with app:
|
||||
app.add_handler(MessageHandler(filters.Regex("test"), one), group=1)
|
||||
|
@ -510,7 +509,7 @@ class TestApplication:
|
|||
with pytest.raises(TypeError, match="group is not int"):
|
||||
app.add_handler(handler, "one")
|
||||
|
||||
@pytest.mark.parametrize("group_empty", (True, False))
|
||||
@pytest.mark.parametrize("group_empty", [True, False])
|
||||
async def test_add_remove_handler(self, app, group_empty):
|
||||
handler = MessageHandler(filters.ALL, self.callback_increase_count)
|
||||
app.add_handler(handler)
|
||||
|
@ -578,11 +577,9 @@ class TestApplication:
|
|||
await asyncio.sleep(0.05) # sleep is required otherwise there is random behaviour
|
||||
|
||||
# Test if handler was added to correct group with correct order-
|
||||
assert (
|
||||
self.count == 2
|
||||
and len(app.handlers[1]) == 3
|
||||
and app.handlers[1][0] is msg_handler_set_count
|
||||
)
|
||||
assert self.count == 2
|
||||
assert len(app.handlers[1]) == 3
|
||||
assert app.handlers[1][0] is msg_handler_set_count
|
||||
|
||||
# Now lets test add_handlers when `handlers` is a dict-
|
||||
voice_filter_handler_to_check = MessageHandler(
|
||||
|
@ -606,18 +603,17 @@ class TestApplication:
|
|||
await app.update_queue.put(voice_update)
|
||||
await asyncio.sleep(0.05)
|
||||
|
||||
assert (
|
||||
self.count == 4
|
||||
and len(app.handlers[1]) == 5
|
||||
and app.handlers[1][-1] is voice_filter_handler_to_check
|
||||
)
|
||||
assert self.count == 4
|
||||
assert len(app.handlers[1]) == 5
|
||||
assert app.handlers[1][-1] is voice_filter_handler_to_check
|
||||
|
||||
await app.update_queue.put(
|
||||
make_message_update(message=Message(5, None, None, caption="cap"))
|
||||
)
|
||||
await asyncio.sleep(0.05)
|
||||
|
||||
assert self.count == 2 and len(app.handlers[-1]) == 1
|
||||
assert self.count == 2
|
||||
assert len(app.handlers[-1]) == 1
|
||||
|
||||
# Now lets test the errors which can be produced-
|
||||
with pytest.raises(ValueError, match="The `group` argument"):
|
||||
|
@ -781,7 +777,7 @@ class TestApplication:
|
|||
await app.process_update(update)
|
||||
assert passed == ["start1", "error", err, "start3"]
|
||||
|
||||
@pytest.mark.parametrize("block", (True, False))
|
||||
@pytest.mark.parametrize("block", [True, False])
|
||||
async def test_error_handler(self, app, block):
|
||||
app.add_error_handler(self.error_handler_context)
|
||||
app.add_handler(TypeHandler(object, self.callback_raise_error("TestError"), block=block))
|
||||
|
@ -903,7 +899,7 @@ class TestApplication:
|
|||
assert self.received == (CustomContext, float, complex, int)
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"check,expected",
|
||||
("check", "expected"),
|
||||
[(True, True), (None, False), (False, False), ({}, True), ("", True), ("check", True)],
|
||||
)
|
||||
async def test_check_update_handling(self, app, check, expected):
|
||||
|
@ -994,7 +990,7 @@ class TestApplication:
|
|||
)
|
||||
await app.stop()
|
||||
|
||||
@pytest.mark.parametrize("handler_block", (True, False))
|
||||
@pytest.mark.parametrize("handler_block", [True, False])
|
||||
async def test_non_blocking_error_handler(self, app, handler_block):
|
||||
event = asyncio.Event()
|
||||
|
||||
|
@ -1021,12 +1017,12 @@ class TestApplication:
|
|||
assert self.received == "done"
|
||||
assert task.done()
|
||||
|
||||
@pytest.mark.parametrize("handler_block", (True, False))
|
||||
@pytest.mark.parametrize("handler_block", [True, False])
|
||||
async def test_non_blocking_error_handler_applicationhandlerstop(
|
||||
self, app, recwarn, handler_block
|
||||
):
|
||||
async def callback(update, context):
|
||||
raise RuntimeError()
|
||||
raise RuntimeError
|
||||
|
||||
async def error_handler(update, context):
|
||||
raise ApplicationHandlerStop
|
||||
|
@ -1050,7 +1046,7 @@ class TestApplication:
|
|||
Path(recwarn[0].filename) == PROJECT_ROOT_PATH / "telegram" / "ext" / "_application.py"
|
||||
), "incorrect stacklevel!"
|
||||
|
||||
@pytest.mark.parametrize(["block", "expected_output"], [(False, 0), (True, 5)])
|
||||
@pytest.mark.parametrize(("block", "expected_output"), [(False, 0), (True, 5)])
|
||||
async def test_default_block_error_handler(self, bot_info, block, expected_output):
|
||||
async def error_handler(*args, **kwargs):
|
||||
await asyncio.sleep(0.1)
|
||||
|
@ -1067,7 +1063,7 @@ class TestApplication:
|
|||
await asyncio.sleep(0.1)
|
||||
assert self.count == 5
|
||||
|
||||
@pytest.mark.parametrize(["block", "expected_output"], [(False, 0), (True, 5)])
|
||||
@pytest.mark.parametrize(("block", "expected_output"), [(False, 0), (True, 5)])
|
||||
async def test_default_block_handler(self, bot_info, block, expected_output):
|
||||
bot = make_bot(bot_info, defaults=Defaults(block=block))
|
||||
app = Application.builder().bot(bot).build()
|
||||
|
@ -1079,8 +1075,8 @@ class TestApplication:
|
|||
await asyncio.sleep(0.15)
|
||||
assert self.count == 5
|
||||
|
||||
@pytest.mark.parametrize("handler_block", (True, False))
|
||||
@pytest.mark.parametrize("error_handler_block", (True, False))
|
||||
@pytest.mark.parametrize("handler_block", [True, False])
|
||||
@pytest.mark.parametrize("error_handler_block", [True, False])
|
||||
async def test_nonblocking_handler_raises_and_non_blocking_error_handler_raises(
|
||||
self, app, caplog, handler_block, error_handler_block
|
||||
):
|
||||
|
@ -1155,7 +1151,7 @@ class TestApplication:
|
|||
assert app.chat_data[effective_new_chat_id]["key"] == "test"
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"c_id,expected",
|
||||
("c_id", "expected"),
|
||||
[(321, {222: "remove_me"}), (111, {321: {"not_empty": "no"}, 222: "remove_me"})],
|
||||
ids=["test chat_id removal", "test no key in data (no error)"],
|
||||
)
|
||||
|
@ -1165,7 +1161,7 @@ class TestApplication:
|
|||
assert app.chat_data == expected
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"u_id,expected",
|
||||
("u_id", "expected"),
|
||||
[(321, {222: "remove_me"}), (111, {321: {"not_empty": "no"}, 222: "remove_me"})],
|
||||
ids=["test user_id removal", "test no key in data (no error)"],
|
||||
)
|
||||
|
@ -1188,7 +1184,7 @@ class TestApplication:
|
|||
assert self.count == 42
|
||||
assert out == 43
|
||||
|
||||
@pytest.mark.parametrize("running", (True, False))
|
||||
@pytest.mark.parametrize("running", [True, False])
|
||||
async def test_create_task_awaiting_warning(self, app, running, recwarn):
|
||||
async def callback():
|
||||
await asyncio.sleep(0.1)
|
||||
|
@ -1213,7 +1209,7 @@ class TestApplication:
|
|||
assert not task.done()
|
||||
await task
|
||||
|
||||
@pytest.mark.parametrize("update", (None, object()))
|
||||
@pytest.mark.parametrize("update", [None, object()])
|
||||
async def test_create_task_error_handling(self, app, update):
|
||||
exception = RuntimeError("TestError")
|
||||
|
||||
|
@ -1334,7 +1330,7 @@ class TestApplication:
|
|||
|
||||
await app.stop()
|
||||
|
||||
@pytest.mark.parametrize("concurrent_updates", (15, 50, 100))
|
||||
@pytest.mark.parametrize("concurrent_updates", [15, 50, 100])
|
||||
async def test_concurrent_updates(self, one_time_bot, concurrent_updates):
|
||||
# We don't test with `True` since the large number of parallel coroutines quickly leads
|
||||
# to test instabilities
|
||||
|
@ -2042,7 +2038,7 @@ class TestApplication:
|
|||
Updater, "shutdown", call_after(Updater.shutdown, after_shutdown("updater"))
|
||||
)
|
||||
app = ApplicationBuilder().bot(one_time_bot).build()
|
||||
with pytest.raises(RuntimeError, match="Test Exception"):
|
||||
with pytest.raises(RuntimeError, match="Test Exception"): # noqa: PT012
|
||||
if "polling" in method:
|
||||
app.run_polling(close_loop=False)
|
||||
else:
|
||||
|
@ -2064,7 +2060,7 @@ class TestApplication:
|
|||
monkeypatch.setattr(Application, "initialize", raise_method)
|
||||
app = ApplicationBuilder().bot(one_time_bot).build()
|
||||
|
||||
with pytest.raises(RuntimeError, match="Prevent Actually Running"):
|
||||
with pytest.raises(RuntimeError, match="Prevent Actually Running"): # noqa: PT012
|
||||
if "polling" in method:
|
||||
app.run_polling(close_loop=False, stop_signals=(signal.SIGINT,))
|
||||
else:
|
||||
|
@ -2080,7 +2076,7 @@ class TestApplication:
|
|||
assert found
|
||||
|
||||
recwarn.clear()
|
||||
with pytest.raises(RuntimeError, match="Prevent Actually Running"):
|
||||
with pytest.raises(RuntimeError, match="Prevent Actually Running"): # noqa: PT012
|
||||
if "polling" in method:
|
||||
app.run_polling(close_loop=False, stop_signals=None)
|
||||
else:
|
||||
|
|
|
@ -42,7 +42,7 @@ from tests.auxil.files import data_file
|
|||
from tests.auxil.slots import mro_slots
|
||||
|
||||
|
||||
@pytest.fixture(scope="function")
|
||||
@pytest.fixture()
|
||||
def builder():
|
||||
return ApplicationBuilder()
|
||||
|
||||
|
@ -142,7 +142,7 @@ class TestApplicationBuilder:
|
|||
assert app.post_stop is None
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"method, description", _BOT_CHECKS, ids=[entry[0] for entry in _BOT_CHECKS]
|
||||
("method", "description"), _BOT_CHECKS, ids=[entry[0] for entry in _BOT_CHECKS]
|
||||
)
|
||||
def test_mutually_exclusive_for_bot(self, builder, method, description):
|
||||
# First test that e.g. `bot` can't be set if `request` was already set
|
||||
|
@ -160,7 +160,7 @@ class TestApplicationBuilder:
|
|||
|
||||
@pytest.mark.parametrize(
|
||||
"method",
|
||||
(
|
||||
[
|
||||
"connection_pool_size",
|
||||
"connect_timeout",
|
||||
"pool_timeout",
|
||||
|
@ -170,7 +170,7 @@ class TestApplicationBuilder:
|
|||
"bot",
|
||||
"updater",
|
||||
"http_version",
|
||||
),
|
||||
],
|
||||
)
|
||||
def test_mutually_exclusive_for_request(self, builder, method):
|
||||
builder.request(1)
|
||||
|
@ -187,7 +187,7 @@ class TestApplicationBuilder:
|
|||
|
||||
@pytest.mark.parametrize(
|
||||
"method",
|
||||
(
|
||||
[
|
||||
"get_updates_connection_pool_size",
|
||||
"get_updates_connect_timeout",
|
||||
"get_updates_pool_timeout",
|
||||
|
@ -197,7 +197,7 @@ class TestApplicationBuilder:
|
|||
"get_updates_http_version",
|
||||
"bot",
|
||||
"updater",
|
||||
),
|
||||
],
|
||||
)
|
||||
def test_mutually_exclusive_for_get_updates_request(self, builder, method):
|
||||
builder.get_updates_request(1)
|
||||
|
@ -415,7 +415,7 @@ class TestApplicationBuilder:
|
|||
assert app.bot is updater.bot
|
||||
assert app.update_queue is updater.update_queue
|
||||
|
||||
@pytest.mark.parametrize("input_type", ("bytes", "str", "Path"))
|
||||
@pytest.mark.parametrize("input_type", ["bytes", "str", "Path"])
|
||||
def test_all_private_key_input_types(self, builder, bot, input_type):
|
||||
private_key = data_file("private.key")
|
||||
password = data_file("private_key.password")
|
||||
|
|
|
@ -260,7 +260,7 @@ def build_conversation_handler(name: str, persistent: bool = True) -> BaseHandle
|
|||
return TrackingConversationHandler(name=name, persistent=persistent)
|
||||
|
||||
|
||||
@pytest.fixture(scope="function")
|
||||
@pytest.fixture()
|
||||
def papp(request, bot_info) -> Application:
|
||||
papp_input = request.param
|
||||
store_data = {}
|
||||
|
@ -359,10 +359,10 @@ class TestBasePersistence:
|
|||
slots = mro_slots(inst, only_parents=True)
|
||||
assert len(slots) == len(set(slots)), "duplicate slot"
|
||||
|
||||
@pytest.mark.parametrize("bot_data", (True, False))
|
||||
@pytest.mark.parametrize("chat_data", (True, False))
|
||||
@pytest.mark.parametrize("user_data", (True, False))
|
||||
@pytest.mark.parametrize("callback_data", (True, False))
|
||||
@pytest.mark.parametrize("bot_data", [True, False])
|
||||
@pytest.mark.parametrize("chat_data", [True, False])
|
||||
@pytest.mark.parametrize("user_data", [True, False])
|
||||
@pytest.mark.parametrize("callback_data", [True, False])
|
||||
def test_init_store_data_update_interval(self, bot_data, chat_data, user_data, callback_data):
|
||||
store_data = PersistenceInput(
|
||||
bot_data=bot_data,
|
||||
|
@ -503,7 +503,7 @@ class TestBasePersistence:
|
|||
[PappInput(fill_data=True)],
|
||||
indirect=True,
|
||||
)
|
||||
@pytest.mark.parametrize("callback_data", ("invalid", (1, 2, 3)))
|
||||
@pytest.mark.parametrize("callback_data", ["invalid", (1, 2, 3)])
|
||||
async def test_initialization_invalid_callback_data(
|
||||
self, papp: Application, callback_data, monkeypatch
|
||||
):
|
||||
|
@ -897,7 +897,7 @@ class TestBasePersistence:
|
|||
assert not papp.persistence.conversations
|
||||
|
||||
@default_papp
|
||||
@pytest.mark.parametrize("delay_type", ("job", "handler", "task"))
|
||||
@pytest.mark.parametrize("delay_type", ["job", "handler", "task"])
|
||||
async def test_update_persistence_loop_async_logic(
|
||||
self, papp: Application, delay_type: str, chat_id
|
||||
):
|
||||
|
@ -1069,7 +1069,7 @@ class TestBasePersistence:
|
|||
|
||||
@default_papp
|
||||
@pytest.mark.parametrize(
|
||||
"delay_type", ("job", "blocking_handler", "nonblocking_handler", "task")
|
||||
"delay_type", ["job", "blocking_handler", "nonblocking_handler", "task"]
|
||||
)
|
||||
async def test_update_persistence_after_exception(
|
||||
self, papp: Application, delay_type: str, chat_id
|
||||
|
|
|
@ -31,7 +31,7 @@ from tests.auxil.envvars import TEST_WITH_OPT_DEPS
|
|||
from tests.auxil.slots import mro_slots
|
||||
|
||||
|
||||
@pytest.fixture(scope="function")
|
||||
@pytest.fixture()
|
||||
def callback_data_cache(bot):
|
||||
return CallbackDataCache(bot)
|
||||
|
||||
|
@ -80,12 +80,12 @@ class TestKeyboardData:
|
|||
class TestCallbackDataCache:
|
||||
def test_slot_behaviour(self, callback_data_cache):
|
||||
for attr in callback_data_cache.__slots__:
|
||||
attr = (
|
||||
at = (
|
||||
f"_CallbackDataCache{attr}"
|
||||
if attr.startswith("__") and not attr.endswith("__")
|
||||
else attr
|
||||
)
|
||||
assert getattr(callback_data_cache, attr, "err") != "err", f"got extra slot '{attr}'"
|
||||
assert getattr(callback_data_cache, at, "err") != "err", f"got extra slot '{at}'"
|
||||
assert len(mro_slots(callback_data_cache)) == len(
|
||||
set(mro_slots(callback_data_cache))
|
||||
), "duplicate slot"
|
||||
|
@ -327,7 +327,7 @@ class TestCallbackDataCache:
|
|||
callback_data_cache.drop_data(callback_query)
|
||||
assert callback_data_cache.persistence_data == ([], {})
|
||||
|
||||
@pytest.mark.parametrize("method", ("callback_data", "callback_queries"))
|
||||
@pytest.mark.parametrize("method", ["callback_data", "callback_queries"])
|
||||
def test_clear_all(self, callback_data_cache, method):
|
||||
changing_button_1 = InlineKeyboardButton("changing", callback_data="some data 1")
|
||||
changing_button_2 = InlineKeyboardButton("changing", callback_data="some data 2")
|
||||
|
@ -401,4 +401,4 @@ class TestCallbackDataCache:
|
|||
callback_data = [
|
||||
list(data[2].values())[0] for data in callback_data_cache.persistence_data[0]
|
||||
]
|
||||
assert callback_data == list(str(i) for i in range(50, 100))
|
||||
assert callback_data == [str(i) for i in range(50, 100)]
|
||||
|
|
|
@ -65,7 +65,7 @@ def false_update(request):
|
|||
return Update(update_id=2, **request.param)
|
||||
|
||||
|
||||
@pytest.fixture(scope="function")
|
||||
@pytest.fixture()
|
||||
def callback_query(bot):
|
||||
update = Update(0, callback_query=CallbackQuery(2, User(1, "", False), None, data="test data"))
|
||||
update._unfreeze()
|
||||
|
@ -83,7 +83,7 @@ class TestCallbackQueryHandler:
|
|||
assert len(mro_slots(handler)) == len(set(mro_slots(handler))), "duplicate slot"
|
||||
|
||||
@pytest.fixture(autouse=True)
|
||||
def reset(self):
|
||||
def _reset(self):
|
||||
self.test_flag = False
|
||||
|
||||
def callback_basic(self, update, context):
|
||||
|
|
|
@ -96,7 +96,7 @@ def chat_join_request(time, bot):
|
|||
return cjr
|
||||
|
||||
|
||||
@pytest.fixture(scope="function")
|
||||
@pytest.fixture()
|
||||
def chat_join_request_update(bot, chat_join_request):
|
||||
return Update(0, chat_join_request=chat_join_request)
|
||||
|
||||
|
@ -111,7 +111,7 @@ class TestChatJoinRequestHandler:
|
|||
assert len(mro_slots(action)) == len(set(mro_slots(action))), "duplicate slot"
|
||||
|
||||
@pytest.fixture(autouse=True)
|
||||
def reset(self):
|
||||
def _reset(self):
|
||||
self.test_flag = False
|
||||
|
||||
async def callback(self, update, context):
|
||||
|
|
|
@ -81,7 +81,7 @@ def chat_member_updated():
|
|||
)
|
||||
|
||||
|
||||
@pytest.fixture(scope="function")
|
||||
@pytest.fixture()
|
||||
def chat_member(bot, chat_member_updated):
|
||||
update = Update(0, my_chat_member=chat_member_updated)
|
||||
update._unfreeze()
|
||||
|
@ -98,7 +98,7 @@ class TestChatMemberHandler:
|
|||
assert len(mro_slots(action)) == len(set(mro_slots(action))), "duplicate slot"
|
||||
|
||||
@pytest.fixture(autouse=True)
|
||||
def reset(self):
|
||||
def _reset(self):
|
||||
self.test_flag = False
|
||||
|
||||
async def callback(self, update, context):
|
||||
|
|
|
@ -82,7 +82,7 @@ class TestChosenInlineResultHandler:
|
|||
test_flag = False
|
||||
|
||||
@pytest.fixture(autouse=True)
|
||||
def reset(self):
|
||||
def _reset(self):
|
||||
self.test_flag = False
|
||||
|
||||
def test_slot_behaviour(self):
|
||||
|
|
|
@ -51,7 +51,7 @@ class BaseTest:
|
|||
SRE_TYPE = type(re.match("", ""))
|
||||
|
||||
@pytest.fixture(autouse=True)
|
||||
def reset(self):
|
||||
def _reset(self):
|
||||
self.test_flag = False
|
||||
|
||||
async def response(self, application, update):
|
||||
|
|
|
@ -103,7 +103,7 @@ class TestConversationHandler:
|
|||
|
||||
# Test related
|
||||
@pytest.fixture(autouse=True)
|
||||
def reset(self):
|
||||
def _reset(self):
|
||||
self.raise_app_handler_stop = False
|
||||
self.test_flag = False
|
||||
self.current_state = {}
|
||||
|
@ -1106,7 +1106,7 @@ class TestConversationHandler:
|
|||
|
||||
async def raise_error(*a, **kw):
|
||||
if test_type == "none":
|
||||
return None
|
||||
return
|
||||
raise error
|
||||
|
||||
handler = ConversationHandler(
|
||||
|
@ -1316,7 +1316,7 @@ class TestConversationHandler:
|
|||
)
|
||||
|
||||
def timeout(*args, **kwargs):
|
||||
raise ApplicationHandlerStop()
|
||||
raise ApplicationHandlerStop
|
||||
|
||||
self.states.update({ConversationHandler.TIMEOUT: [TypeHandler(Update, timeout)]})
|
||||
app.add_handler(handler)
|
||||
|
@ -2130,10 +2130,7 @@ class TestConversationHandler:
|
|||
handler = CommandHandler("start", callback=callback)
|
||||
fallback = MessageHandler(filters.ALL, callback, block=handler_block)
|
||||
|
||||
if default_block is not None:
|
||||
defaults = Defaults(block=default_block)
|
||||
else:
|
||||
defaults = None
|
||||
defaults = Defaults(block=default_block) if default_block is not None else None
|
||||
|
||||
if ch_block is not None:
|
||||
conv_handler = ConversationHandler(
|
||||
|
|
|
@ -25,33 +25,33 @@ from tests.auxil.slots import mro_slots
|
|||
|
||||
|
||||
@pytest.fixture(autouse=True)
|
||||
def reset_callback_data_cache(cdc_bot):
|
||||
def _reset_callback_data_cache(cdc_bot):
|
||||
yield
|
||||
cdc_bot.callback_data_cache.clear_callback_data()
|
||||
cdc_bot.callback_data_cache.clear_callback_queries()
|
||||
|
||||
|
||||
@pytest.fixture(scope="function")
|
||||
@pytest.fixture()
|
||||
def bot_data():
|
||||
return {"test1": "test2", "test3": {"test4": "test5"}}
|
||||
|
||||
|
||||
@pytest.fixture(scope="function")
|
||||
@pytest.fixture()
|
||||
def chat_data():
|
||||
return {-12345: {"test1": "test2", "test3": {"test4": "test5"}}, -67890: {3: "test4"}}
|
||||
|
||||
|
||||
@pytest.fixture(scope="function")
|
||||
@pytest.fixture()
|
||||
def user_data():
|
||||
return {12345: {"test1": "test2", "test3": {"test4": "test5"}}, 67890: {3: "test4"}}
|
||||
|
||||
|
||||
@pytest.fixture(scope="function")
|
||||
@pytest.fixture()
|
||||
def callback_data():
|
||||
return [("test1", 1000, {"button1": "test0", "button2": "test1"})], {"test1": "test2"}
|
||||
|
||||
|
||||
@pytest.fixture(scope="function")
|
||||
@pytest.fixture()
|
||||
def conversations():
|
||||
return {
|
||||
"name1": {(123, 123): 3, (456, 654): 4},
|
||||
|
@ -60,27 +60,27 @@ def conversations():
|
|||
}
|
||||
|
||||
|
||||
@pytest.fixture(scope="function")
|
||||
@pytest.fixture()
|
||||
def user_data_json(user_data):
|
||||
return json.dumps(user_data)
|
||||
|
||||
|
||||
@pytest.fixture(scope="function")
|
||||
@pytest.fixture()
|
||||
def chat_data_json(chat_data):
|
||||
return json.dumps(chat_data)
|
||||
|
||||
|
||||
@pytest.fixture(scope="function")
|
||||
@pytest.fixture()
|
||||
def bot_data_json(bot_data):
|
||||
return json.dumps(bot_data)
|
||||
|
||||
|
||||
@pytest.fixture(scope="function")
|
||||
@pytest.fixture()
|
||||
def callback_data_json(callback_data):
|
||||
return json.dumps(callback_data)
|
||||
|
||||
|
||||
@pytest.fixture(scope="function")
|
||||
@pytest.fixture()
|
||||
def conversations_json(conversations):
|
||||
return """{"name1": {"[123, 123]": 3, "[456, 654]": 4}, "name2":
|
||||
{"[123, 321]": 1, "[890, 890]": 2}, "name3":
|
||||
|
@ -303,7 +303,7 @@ class TestDictPersistence:
|
|||
|
||||
conversation1 = await dict_persistence.get_conversations("name1")
|
||||
conversation1[(123, 123)] = 5
|
||||
assert not dict_persistence.conversations["name1"] == conversation1
|
||||
assert dict_persistence.conversations["name1"] != conversation1
|
||||
await dict_persistence.update_conversation("name1", (123, 123), 5)
|
||||
assert dict_persistence.conversations["name1"] == conversation1
|
||||
conversations["name1"][(123, 123)] = 5
|
||||
|
|
|
@ -38,7 +38,7 @@ from telegram.ext import filters
|
|||
from tests.auxil.slots import mro_slots
|
||||
|
||||
|
||||
@pytest.fixture(scope="function")
|
||||
@pytest.fixture()
|
||||
def update():
|
||||
update = Update(
|
||||
0,
|
||||
|
@ -64,7 +64,7 @@ def update():
|
|||
return update
|
||||
|
||||
|
||||
@pytest.fixture(scope="function", params=MessageEntity.ALL_TYPES)
|
||||
@pytest.fixture(params=MessageEntity.ALL_TYPES)
|
||||
def message_entity(request):
|
||||
return MessageEntity(request.param, 0, 0, url="", user=User(1, "first_name", False))
|
||||
|
||||
|
@ -87,7 +87,7 @@ class TestFilters:
|
|||
"""
|
||||
|
||||
def filter_class(obj):
|
||||
return True if inspect.isclass(obj) and "filters" in repr(obj) else False
|
||||
return bool(inspect.isclass(obj) and "filters" in repr(obj))
|
||||
|
||||
# The total no. of filters is about 72 as of 31/10/21.
|
||||
# Gather all the filters to test using DFS-
|
||||
|
@ -98,7 +98,7 @@ class TestFilters:
|
|||
cls = stack[-1][-1] # get last element and its class
|
||||
for inner_cls in inspect.getmembers(
|
||||
cls, # Get inner filters
|
||||
lambda a: inspect.isclass(a) and not issubclass(a, cls.__class__),
|
||||
lambda a: inspect.isclass(a) and not issubclass(a, cls.__class__), # noqa: B023
|
||||
):
|
||||
if inner_cls[1] not in visited:
|
||||
stack.append(inner_cls)
|
||||
|
@ -1096,7 +1096,7 @@ class TestFilters:
|
|||
assert not filters.Entity(message_entity.type).check_update(update)
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"chat_type, results",
|
||||
("chat_type", "results"),
|
||||
[
|
||||
(Chat.PRIVATE, (True, False, False, False, False)),
|
||||
(Chat.GROUP, (False, True, False, True, False)),
|
||||
|
@ -1252,7 +1252,8 @@ class TestFilters:
|
|||
f.add_usernames("@barfoo")
|
||||
assert str(f).startswith("filters.User(")
|
||||
# we don't know th exact order
|
||||
assert "barfoo" in str(f) and "foobar" in str(f)
|
||||
assert "barfoo" in str(f)
|
||||
assert "foobar" in str(f)
|
||||
|
||||
with pytest.raises(RuntimeError, match="Cannot set name"):
|
||||
f.name = "foo"
|
||||
|
@ -1411,7 +1412,8 @@ class TestFilters:
|
|||
f.add_usernames("@barfoo")
|
||||
assert str(f).startswith("filters.Chat(")
|
||||
# we don't know th exact order
|
||||
assert "barfoo" in str(f) and "foobar" in str(f)
|
||||
assert "barfoo" in str(f)
|
||||
assert "foobar" in str(f)
|
||||
|
||||
with pytest.raises(RuntimeError, match="Cannot set name"):
|
||||
f.name = "foo"
|
||||
|
@ -1661,7 +1663,8 @@ class TestFilters:
|
|||
f.add_usernames("@barfoo")
|
||||
assert str(f).startswith("filters.ForwardedFrom(")
|
||||
# we don't know the exact order
|
||||
assert "barfoo" in str(f) and "foobar" in str(f)
|
||||
assert "barfoo" in str(f)
|
||||
assert "foobar" in str(f)
|
||||
|
||||
with pytest.raises(RuntimeError, match="Cannot set name"):
|
||||
f.name = "foo"
|
||||
|
@ -1808,7 +1811,8 @@ class TestFilters:
|
|||
f.add_usernames("@barfoo")
|
||||
assert str(f).startswith("filters.SenderChat(")
|
||||
# we don't know th exact order
|
||||
assert "barfoo" in str(f) and "foobar" in str(f)
|
||||
assert "barfoo" in str(f)
|
||||
assert "foobar" in str(f)
|
||||
|
||||
with pytest.raises(RuntimeError, match="Cannot set name"):
|
||||
f.name = "foo"
|
||||
|
@ -1879,7 +1883,8 @@ class TestFilters:
|
|||
@pytest.mark.parametrize("emoji", Dice.ALL_EMOJI)
|
||||
def test_filters_dice(self, update, emoji):
|
||||
update.message.dice = Dice(4, emoji)
|
||||
assert filters.Dice.ALL.check_update(update) and filters.Dice().check_update(update)
|
||||
assert filters.Dice.ALL.check_update(update)
|
||||
assert filters.Dice().check_update(update)
|
||||
|
||||
to_camel = emoji.name.title().replace("_", "")
|
||||
assert repr(filters.Dice.ALL) == "filters.Dice.ALL"
|
||||
|
@ -2217,13 +2222,16 @@ class TestFilters:
|
|||
self.data = data
|
||||
|
||||
def filter(self, _):
|
||||
return {"test": [self.data]}
|
||||
return {"test": [self.data], "test2": {"test3": [self.data]}}
|
||||
|
||||
result = (filters.COMMAND & DataFilter("blah")).check_update(update)
|
||||
assert result["test"] == ["blah"]
|
||||
assert not result["test2"]
|
||||
|
||||
result = (DataFilter("blah1") & DataFilter("blah2")).check_update(update)
|
||||
assert result["test"] == ["blah1", "blah2"]
|
||||
assert isinstance(result["test2"], list)
|
||||
assert result["test2"][0]["test3"] == ["blah1"]
|
||||
|
||||
update.message.text = "test"
|
||||
update.message.entities = []
|
||||
|
@ -2390,7 +2398,8 @@ class TestFilters:
|
|||
f.add_usernames("@barfoo")
|
||||
assert str(f).startswith("filters.ViaBot(")
|
||||
# we don't know th exact order
|
||||
assert "barfoo" in str(f) and "foobar" in str(f)
|
||||
assert "barfoo" in str(f)
|
||||
assert "foobar" in str(f)
|
||||
|
||||
with pytest.raises(RuntimeError, match="Cannot set name"):
|
||||
f.name = "foo"
|
||||
|
|
|
@ -20,14 +20,13 @@ import asyncio
|
|||
import calendar
|
||||
import datetime as dtm
|
||||
import logging
|
||||
import os
|
||||
import platform
|
||||
import time
|
||||
|
||||
import pytest
|
||||
|
||||
from telegram.ext import ApplicationBuilder, CallbackContext, ContextTypes, Job, JobQueue
|
||||
from tests.auxil.envvars import TEST_WITH_OPT_DEPS
|
||||
from tests.auxil.envvars import GITHUB_ACTION, TEST_WITH_OPT_DEPS
|
||||
from tests.auxil.pytest_classes import make_bot
|
||||
from tests.auxil.slots import mro_slots
|
||||
|
||||
|
@ -45,7 +44,7 @@ class CustomContext(CallbackContext):
|
|||
pass
|
||||
|
||||
|
||||
@pytest.fixture(scope="function")
|
||||
@pytest.fixture()
|
||||
async def job_queue(app):
|
||||
jq = JobQueue()
|
||||
jq.set_application(app)
|
||||
|
@ -71,7 +70,7 @@ class TestNoJobQueue:
|
|||
not TEST_WITH_OPT_DEPS, reason="Only relevant if the optional dependency is installed"
|
||||
)
|
||||
@pytest.mark.skipif(
|
||||
os.getenv("GITHUB_ACTIONS", False) and platform.system() in ["Windows", "Darwin"],
|
||||
bool(GITHUB_ACTION and platform.system() in ["Windows", "Darwin"]),
|
||||
reason="On Windows & MacOS precise timings are not accurate.",
|
||||
)
|
||||
@pytest.mark.flaky(10, 1) # Timings aren't quite perfect
|
||||
|
@ -86,7 +85,7 @@ class TestJobQueue:
|
|||
)
|
||||
|
||||
@pytest.fixture(autouse=True)
|
||||
def reset(self):
|
||||
def _reset(self):
|
||||
self.result = 0
|
||||
self.job_time = 0
|
||||
self.received_error = None
|
||||
|
@ -362,7 +361,7 @@ class TestJobQueue:
|
|||
assert str(recwarn[0].message) == self.expected_warning
|
||||
assert recwarn[0].filename == __file__, "wrong stacklevel"
|
||||
|
||||
@pytest.mark.parametrize("weekday", (0, 1, 2, 3, 4, 5, 6))
|
||||
@pytest.mark.parametrize("weekday", [0, 1, 2, 3, 4, 5, 6])
|
||||
async def test_run_daily_days_of_week(self, job_queue, recwarn, weekday):
|
||||
delta, now = 1, dtm.datetime.now(UTC)
|
||||
time_of_day = (now + dtm.timedelta(seconds=delta)).time()
|
||||
|
@ -592,7 +591,7 @@ class TestJobQueue:
|
|||
):
|
||||
job.error
|
||||
|
||||
@pytest.mark.parametrize("wait", (True, False))
|
||||
@pytest.mark.parametrize("wait", [True, False])
|
||||
async def test_wait_on_shut_down(self, job_queue, wait):
|
||||
ready_event = asyncio.Event()
|
||||
|
||||
|
|
|
@ -83,7 +83,7 @@ class TestMessageHandler:
|
|||
assert len(mro_slots(handler)) == len(set(mro_slots(handler))), "duplicate slot"
|
||||
|
||||
@pytest.fixture(autouse=True)
|
||||
def reset(self):
|
||||
def _reset(self):
|
||||
self.test_flag = False
|
||||
|
||||
async def callback(self, update, context):
|
||||
|
|
|
@ -32,7 +32,7 @@ from tests.auxil.slots import mro_slots
|
|||
|
||||
|
||||
@pytest.fixture(autouse=True)
|
||||
def change_directory(tmp_path: Path):
|
||||
def _change_directory(tmp_path: Path):
|
||||
orig_dir = Path.cwd()
|
||||
# Switch to a temporary directory, so we don't have to worry about cleaning up files
|
||||
os.chdir(tmp_path)
|
||||
|
@ -42,33 +42,33 @@ def change_directory(tmp_path: Path):
|
|||
|
||||
|
||||
@pytest.fixture(autouse=True)
|
||||
def reset_callback_data_cache(cdc_bot):
|
||||
def _reset_callback_data_cache(cdc_bot):
|
||||
yield
|
||||
cdc_bot.callback_data_cache.clear_callback_data()
|
||||
cdc_bot.callback_data_cache.clear_callback_queries()
|
||||
|
||||
|
||||
@pytest.fixture(scope="function")
|
||||
@pytest.fixture()
|
||||
def bot_data():
|
||||
return {"test1": "test2", "test3": {"test4": "test5"}}
|
||||
|
||||
|
||||
@pytest.fixture(scope="function")
|
||||
@pytest.fixture()
|
||||
def chat_data():
|
||||
return {-12345: {"test1": "test2", "test3": {"test4": "test5"}}, -67890: {3: "test4"}}
|
||||
|
||||
|
||||
@pytest.fixture(scope="function")
|
||||
@pytest.fixture()
|
||||
def user_data():
|
||||
return {12345: {"test1": "test2", "test3": {"test4": "test5"}}, 67890: {3: "test4"}}
|
||||
|
||||
|
||||
@pytest.fixture(scope="function")
|
||||
@pytest.fixture()
|
||||
def callback_data():
|
||||
return [("test1", 1000, {"button1": "test0", "button2": "test1"})], {"test1": "test2"}
|
||||
|
||||
|
||||
@pytest.fixture(scope="function")
|
||||
@pytest.fixture()
|
||||
def conversations():
|
||||
return {
|
||||
"name1": {(123, 123): 3, (456, 654): 4},
|
||||
|
@ -77,7 +77,7 @@ def conversations():
|
|||
}
|
||||
|
||||
|
||||
@pytest.fixture(scope="function")
|
||||
@pytest.fixture()
|
||||
def pickle_persistence():
|
||||
return PicklePersistence(
|
||||
filepath="pickletest",
|
||||
|
@ -86,7 +86,7 @@ def pickle_persistence():
|
|||
)
|
||||
|
||||
|
||||
@pytest.fixture(scope="function")
|
||||
@pytest.fixture()
|
||||
def pickle_persistence_only_bot():
|
||||
return PicklePersistence(
|
||||
filepath="pickletest",
|
||||
|
@ -96,7 +96,7 @@ def pickle_persistence_only_bot():
|
|||
)
|
||||
|
||||
|
||||
@pytest.fixture(scope="function")
|
||||
@pytest.fixture()
|
||||
def pickle_persistence_only_chat():
|
||||
return PicklePersistence(
|
||||
filepath="pickletest",
|
||||
|
@ -106,7 +106,7 @@ def pickle_persistence_only_chat():
|
|||
)
|
||||
|
||||
|
||||
@pytest.fixture(scope="function")
|
||||
@pytest.fixture()
|
||||
def pickle_persistence_only_user():
|
||||
return PicklePersistence(
|
||||
filepath="pickletest",
|
||||
|
@ -116,7 +116,7 @@ def pickle_persistence_only_user():
|
|||
)
|
||||
|
||||
|
||||
@pytest.fixture(scope="function")
|
||||
@pytest.fixture()
|
||||
def pickle_persistence_only_callback():
|
||||
return PicklePersistence(
|
||||
filepath="pickletest",
|
||||
|
@ -126,7 +126,7 @@ def pickle_persistence_only_callback():
|
|||
)
|
||||
|
||||
|
||||
@pytest.fixture(scope="function")
|
||||
@pytest.fixture()
|
||||
def bad_pickle_files():
|
||||
for name in [
|
||||
"pickletest_user_data",
|
||||
|
@ -137,10 +137,10 @@ def bad_pickle_files():
|
|||
"pickletest",
|
||||
]:
|
||||
Path(name).write_text("(())")
|
||||
yield True
|
||||
return True
|
||||
|
||||
|
||||
@pytest.fixture(scope="function")
|
||||
@pytest.fixture()
|
||||
def invalid_pickle_files():
|
||||
for name in [
|
||||
"pickletest_user_data",
|
||||
|
@ -154,10 +154,10 @@ def invalid_pickle_files():
|
|||
# see https://stackoverflow.com/a/44422239/10606962
|
||||
with gzip.open(name, "wb") as file:
|
||||
pickle.dump([1, 2, 3], file)
|
||||
yield True
|
||||
return True
|
||||
|
||||
|
||||
@pytest.fixture(scope="function")
|
||||
@pytest.fixture()
|
||||
def good_pickle_files(user_data, chat_data, bot_data, callback_data, conversations):
|
||||
data = {
|
||||
"user_data": user_data,
|
||||
|
@ -178,10 +178,10 @@ def good_pickle_files(user_data, chat_data, bot_data, callback_data, conversatio
|
|||
pickle.dump(conversations, f)
|
||||
with Path("pickletest").open("wb") as f:
|
||||
pickle.dump(data, f)
|
||||
yield True
|
||||
return True
|
||||
|
||||
|
||||
@pytest.fixture(scope="function")
|
||||
@pytest.fixture()
|
||||
def pickle_files_wo_bot_data(user_data, chat_data, callback_data, conversations):
|
||||
data = {
|
||||
"user_data": user_data,
|
||||
|
@ -199,10 +199,10 @@ def pickle_files_wo_bot_data(user_data, chat_data, callback_data, conversations)
|
|||
pickle.dump(conversations, f)
|
||||
with Path("pickletest").open("wb") as f:
|
||||
pickle.dump(data, f)
|
||||
yield True
|
||||
return True
|
||||
|
||||
|
||||
@pytest.fixture(scope="function")
|
||||
@pytest.fixture()
|
||||
def pickle_files_wo_callback_data(user_data, chat_data, bot_data, conversations):
|
||||
data = {
|
||||
"user_data": user_data,
|
||||
|
@ -220,10 +220,10 @@ def pickle_files_wo_callback_data(user_data, chat_data, bot_data, conversations)
|
|||
pickle.dump(conversations, f)
|
||||
with Path("pickletest").open("wb") as f:
|
||||
pickle.dump(data, f)
|
||||
yield True
|
||||
return True
|
||||
|
||||
|
||||
@pytest.fixture(scope="function")
|
||||
@pytest.fixture()
|
||||
def update(bot):
|
||||
user = User(id=321, first_name="test_user", is_bot=False)
|
||||
chat = Chat(id=123, type="group")
|
||||
|
@ -261,7 +261,7 @@ class TestPicklePersistence:
|
|||
assert getattr(inst, attr, "err") != "err", f"got extra slot '{attr}'"
|
||||
assert len(mro_slots(inst)) == len(set(mro_slots(inst))), "duplicate slot"
|
||||
|
||||
@pytest.mark.parametrize("on_flush", (True, False))
|
||||
@pytest.mark.parametrize("on_flush", [True, False])
|
||||
async def test_on_flush(self, pickle_persistence, on_flush):
|
||||
pickle_persistence.on_flush = on_flush
|
||||
pickle_persistence.single_file = True
|
||||
|
@ -610,7 +610,7 @@ class TestPicklePersistence:
|
|||
|
||||
conversation1 = await pickle_persistence.get_conversations("name1")
|
||||
conversation1[(123, 123)] = 5
|
||||
assert not pickle_persistence.conversations["name1"] == conversation1
|
||||
assert pickle_persistence.conversations["name1"] != conversation1
|
||||
await pickle_persistence.update_conversation("name1", (123, 123), 5)
|
||||
assert pickle_persistence.conversations["name1"] == conversation1
|
||||
assert await pickle_persistence.get_conversations("name1") == conversation1
|
||||
|
@ -668,7 +668,7 @@ class TestPicklePersistence:
|
|||
|
||||
conversation1 = await pickle_persistence.get_conversations("name1")
|
||||
conversation1[(123, 123)] = 5
|
||||
assert not pickle_persistence.conversations["name1"] == conversation1
|
||||
assert pickle_persistence.conversations["name1"] != conversation1
|
||||
await pickle_persistence.update_conversation("name1", (123, 123), 5)
|
||||
assert pickle_persistence.conversations["name1"] == conversation1
|
||||
assert await pickle_persistence.get_conversations("name1") == conversation1
|
||||
|
@ -693,8 +693,8 @@ class TestPicklePersistence:
|
|||
]
|
||||
)
|
||||
await pickle_persistence.flush()
|
||||
with pytest.raises(FileNotFoundError, match="pickletest"):
|
||||
open("pickletest", "rb")
|
||||
with pytest.raises(FileNotFoundError, match="pickletest"), Path("pickletest").open("rb"):
|
||||
pass
|
||||
|
||||
async def test_save_on_flush_multi_files(self, pickle_persistence, good_pickle_files):
|
||||
# Should run without error
|
||||
|
@ -755,14 +755,14 @@ class TestPicklePersistence:
|
|||
|
||||
conversation1 = await pickle_persistence.get_conversations("name1")
|
||||
conversation1[(123, 123)] = 5
|
||||
assert not pickle_persistence.conversations["name1"] == conversation1
|
||||
assert pickle_persistence.conversations["name1"] != conversation1
|
||||
|
||||
await pickle_persistence.update_conversation("name1", (123, 123), 5)
|
||||
assert pickle_persistence.conversations["name1"] == conversation1
|
||||
|
||||
with Path("pickletest_conversations").open("rb") as f:
|
||||
conversations_test = dict(pickle.load(f))
|
||||
assert not conversations_test["name1"] == conversation1
|
||||
assert conversations_test["name1"] != conversation1
|
||||
|
||||
await pickle_persistence.flush()
|
||||
with Path("pickletest_user_data").open("rb") as f:
|
||||
|
@ -828,12 +828,12 @@ class TestPicklePersistence:
|
|||
|
||||
conversation1 = await pickle_persistence.get_conversations("name1")
|
||||
conversation1[(123, 123)] = 5
|
||||
assert not pickle_persistence.conversations["name1"] == conversation1
|
||||
assert pickle_persistence.conversations["name1"] != conversation1
|
||||
await pickle_persistence.update_conversation("name1", (123, 123), 5)
|
||||
assert pickle_persistence.conversations["name1"] == conversation1
|
||||
with Path("pickletest").open("rb") as f:
|
||||
conversations_test = dict(pickle.load(f))["conversations"]
|
||||
assert not conversations_test["name1"] == conversation1
|
||||
assert conversations_test["name1"] != conversation1
|
||||
|
||||
await pickle_persistence.flush()
|
||||
with Path("pickletest").open("rb") as f:
|
||||
|
@ -870,9 +870,10 @@ class TestPicklePersistence:
|
|||
"A load persistent id instruction was encountered,\nbut no persistent_load "
|
||||
"function was specified."
|
||||
)
|
||||
with pytest.raises(pickle.UnpicklingError, match=err_msg):
|
||||
with open("pickletest_chat_data", "rb") as f:
|
||||
pickle.load(f)
|
||||
with Path("pickletest_chat_data").open("rb") as f, pytest.raises(
|
||||
pickle.UnpicklingError, match=err_msg
|
||||
):
|
||||
pickle.load(f)
|
||||
|
||||
# Test that our custom unpickler works as intended -- inserts the current bot
|
||||
# We have to create a new instance otherwise unpickling is skipped
|
||||
|
|
|
@ -67,7 +67,7 @@ def false_update(request):
|
|||
return Update(update_id=2, **request.param)
|
||||
|
||||
|
||||
@pytest.fixture(scope="function")
|
||||
@pytest.fixture()
|
||||
def poll_answer(bot):
|
||||
return Update(0, poll_answer=PollAnswer(1, User(2, "test user", False), [0, 1]))
|
||||
|
||||
|
@ -82,7 +82,7 @@ class TestPollAnswerHandler:
|
|||
assert len(mro_slots(handler)) == len(set(mro_slots(handler))), "duplicate slot"
|
||||
|
||||
@pytest.fixture(autouse=True)
|
||||
def reset(self):
|
||||
def _reset(self):
|
||||
self.test_flag = False
|
||||
|
||||
async def callback(self, update, context):
|
||||
|
|
|
@ -87,7 +87,7 @@ class TestPreCheckoutQueryHandler:
|
|||
assert len(mro_slots(inst)) == len(set(mro_slots(inst))), "duplicate slot"
|
||||
|
||||
@pytest.fixture(autouse=True)
|
||||
def reset(self):
|
||||
def _reset(self):
|
||||
self.test_flag = False
|
||||
|
||||
async def callback(self, update, context):
|
||||
|
|
|
@ -23,7 +23,6 @@ notable
|
|||
"""
|
||||
import asyncio
|
||||
import json
|
||||
import os
|
||||
import platform
|
||||
import time
|
||||
from datetime import datetime
|
||||
|
@ -36,7 +35,7 @@ from telegram.constants import ParseMode
|
|||
from telegram.error import RetryAfter
|
||||
from telegram.ext import AIORateLimiter, BaseRateLimiter, Defaults, ExtBot
|
||||
from telegram.request import BaseRequest, RequestData
|
||||
from tests.auxil.envvars import TEST_WITH_OPT_DEPS
|
||||
from tests.auxil.envvars import GITHUB_ACTION, TEST_WITH_OPT_DEPS
|
||||
|
||||
|
||||
@pytest.mark.skipif(
|
||||
|
@ -120,7 +119,7 @@ class TestBaseRateLimiter:
|
|||
assert self.rl_received[0] == ("getMe", {}, None)
|
||||
assert self.rl_received[1] == (
|
||||
"setMyCommands",
|
||||
dict(commands=[BotCommand("test", "test")], language_code="en", api="kwargs"),
|
||||
{"commands": [BotCommand("test", "test")], "language_code": "en", "api": "kwargs"},
|
||||
(43, "test-1"),
|
||||
)
|
||||
assert len(self.request_received) == 4
|
||||
|
@ -143,7 +142,7 @@ class TestBaseRateLimiter:
|
|||
not TEST_WITH_OPT_DEPS, reason="Only relevant if the optional dependency is installed"
|
||||
)
|
||||
@pytest.mark.skipif(
|
||||
os.getenv("GITHUB_ACTIONS", False) and platform.system() == "Darwin",
|
||||
bool(GITHUB_ACTION and platform.system() == "Darwin"),
|
||||
reason="The timings are apparently rather inaccurate on MacOS.",
|
||||
)
|
||||
@pytest.mark.flaky(10, 1) # Timings aren't quite perfect
|
||||
|
@ -187,9 +186,10 @@ class TestAIORateLimiter:
|
|||
}
|
||||
).encode(),
|
||||
)
|
||||
return None
|
||||
|
||||
@pytest.fixture(autouse=True)
|
||||
def reset(self):
|
||||
def _reset(self):
|
||||
self.count = 0
|
||||
TestAIORateLimiter.count = 0
|
||||
self.call_times = []
|
||||
|
|
|
@ -91,7 +91,7 @@ class TestShippingQueryHandler:
|
|||
assert len(mro_slots(inst)) == len(set(mro_slots(inst))), "duplicate slot"
|
||||
|
||||
@pytest.fixture(autouse=True)
|
||||
def reset(self):
|
||||
def _reset(self):
|
||||
self.test_flag = False
|
||||
|
||||
async def callback(self, update, context):
|
||||
|
|
|
@ -79,7 +79,7 @@ class TestStringCommandHandler:
|
|||
assert len(mro_slots(inst)) == len(set(mro_slots(inst))), "duplicate slot"
|
||||
|
||||
@pytest.fixture(autouse=True)
|
||||
def reset(self):
|
||||
def _reset(self):
|
||||
self.test_flag = False
|
||||
|
||||
async def callback(self, update, context):
|
||||
|
|
|
@ -80,7 +80,7 @@ class TestStringRegexHandler:
|
|||
assert len(mro_slots(inst)) == len(set(mro_slots(inst))), "duplicate slot"
|
||||
|
||||
@pytest.fixture(autouse=True)
|
||||
def reset(self):
|
||||
def _reset(self):
|
||||
self.test_flag = False
|
||||
|
||||
async def callback(self, update, context):
|
||||
|
@ -98,7 +98,7 @@ class TestStringRegexHandler:
|
|||
if context.matches[0].groupdict():
|
||||
self.test_flag = context.matches[0].groupdict() == {"begin": "t", "end": " message"}
|
||||
|
||||
@pytest.mark.parametrize("compile", (True, False))
|
||||
@pytest.mark.parametrize("compile", [True, False])
|
||||
async def test_basic(self, app, compile):
|
||||
pattern = "(?P<begin>.*)est(?P<end>.*)"
|
||||
if compile:
|
||||
|
|
|
@ -36,7 +36,7 @@ class TestTypeHandler:
|
|||
assert len(mro_slots(inst)) == len(set(mro_slots(inst))), "duplicate slot"
|
||||
|
||||
@pytest.fixture(autouse=True)
|
||||
def reset(self):
|
||||
def _reset(self):
|
||||
self.test_flag = False
|
||||
|
||||
async def callback(self, update, context):
|
||||
|
|
|
@ -46,8 +46,8 @@ if TEST_WITH_OPT_DEPS:
|
|||
)
|
||||
class TestNoWebhooks:
|
||||
async def test_no_webhooks(self, bot):
|
||||
with pytest.raises(RuntimeError, match=r"python-telegram-bot\[webhooks\]"):
|
||||
async with Updater(bot=bot, update_queue=asyncio.Queue()) as updater:
|
||||
async with Updater(bot=bot, update_queue=asyncio.Queue()) as updater:
|
||||
with pytest.raises(RuntimeError, match=r"python-telegram-bot\[webhooks\]"):
|
||||
await updater.start_webhook()
|
||||
|
||||
|
||||
|
@ -65,7 +65,7 @@ class TestUpdater:
|
|||
test_flag = False
|
||||
|
||||
@pytest.fixture(autouse=True)
|
||||
def reset(self):
|
||||
def _reset(self):
|
||||
self.message_count = 0
|
||||
self.received = None
|
||||
self.attempts = 0
|
||||
|
@ -84,8 +84,8 @@ class TestUpdater:
|
|||
async def test_slot_behaviour(self, updater):
|
||||
async with updater:
|
||||
for at in updater.__slots__:
|
||||
at = f"_Updater{at}" if at.startswith("__") and not at.endswith("__") else at
|
||||
assert getattr(updater, at, "err") != "err", f"got extra slot '{at}'"
|
||||
attr = f"_Updater{at}" if at.startswith("__") and not at.endswith("__") else at
|
||||
assert getattr(updater, attr, "err") != "err", f"got extra slot '{attr}'"
|
||||
assert len(mro_slots(updater)) == len(set(mro_slots(updater))), "duplicate slot"
|
||||
|
||||
def test_init(self, bot):
|
||||
|
@ -207,7 +207,7 @@ class TestUpdater:
|
|||
|
||||
assert self.test_flag == "stop"
|
||||
|
||||
@pytest.mark.parametrize("drop_pending_updates", (True, False))
|
||||
@pytest.mark.parametrize("drop_pending_updates", [True, False])
|
||||
async def test_polling_basic(self, monkeypatch, updater, drop_pending_updates):
|
||||
updates = asyncio.Queue()
|
||||
await updates.put(Update(update_id=1))
|
||||
|
@ -277,15 +277,15 @@ class TestUpdater:
|
|||
update_queue = asyncio.Queue()
|
||||
await update_queue.put(Update(update_id=1))
|
||||
|
||||
expected = dict(
|
||||
timeout=10,
|
||||
read_timeout=2,
|
||||
write_timeout=DEFAULT_NONE,
|
||||
connect_timeout=DEFAULT_NONE,
|
||||
pool_timeout=DEFAULT_NONE,
|
||||
allowed_updates=None,
|
||||
api_kwargs=None,
|
||||
)
|
||||
expected = {
|
||||
"timeout": 10,
|
||||
"read_timeout": 2,
|
||||
"write_timeout": DEFAULT_NONE,
|
||||
"connect_timeout": DEFAULT_NONE,
|
||||
"pool_timeout": DEFAULT_NONE,
|
||||
"allowed_updates": None,
|
||||
"api_kwargs": None,
|
||||
}
|
||||
|
||||
async def get_updates(*args, **kwargs):
|
||||
for key, value in expected.items():
|
||||
|
@ -310,15 +310,15 @@ class TestUpdater:
|
|||
await update_queue.join()
|
||||
await updater.stop()
|
||||
|
||||
expected = dict(
|
||||
timeout=42,
|
||||
read_timeout=43,
|
||||
write_timeout=44,
|
||||
connect_timeout=45,
|
||||
pool_timeout=46,
|
||||
allowed_updates=["message"],
|
||||
api_kwargs=None,
|
||||
)
|
||||
expected = {
|
||||
"timeout": 42,
|
||||
"read_timeout": 43,
|
||||
"write_timeout": 44,
|
||||
"connect_timeout": 45,
|
||||
"pool_timeout": 46,
|
||||
"allowed_updates": ["message"],
|
||||
"api_kwargs": None,
|
||||
}
|
||||
|
||||
await update_queue.put(Update(update_id=2))
|
||||
await updater.start_polling(
|
||||
|
@ -332,8 +332,8 @@ class TestUpdater:
|
|||
await update_queue.join()
|
||||
await updater.stop()
|
||||
|
||||
@pytest.mark.parametrize("exception_class", (InvalidToken, TelegramError))
|
||||
@pytest.mark.parametrize("retries", (3, 0))
|
||||
@pytest.mark.parametrize("exception_class", [InvalidToken, TelegramError])
|
||||
@pytest.mark.parametrize("retries", [3, 0])
|
||||
async def test_start_polling_bootstrap_retries(
|
||||
self, updater, monkeypatch, exception_class, retries
|
||||
):
|
||||
|
@ -354,7 +354,7 @@ class TestUpdater:
|
|||
await updater.start_polling(bootstrap_retries=retries)
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"error,callback_should_be_called",
|
||||
("error", "callback_should_be_called"),
|
||||
argvalues=[
|
||||
(TelegramError("TestMessage"), True),
|
||||
(RetryAfter(1), False),
|
||||
|
@ -414,13 +414,12 @@ class TestUpdater:
|
|||
await get_updates_event.wait()
|
||||
|
||||
if callback_should_be_called:
|
||||
if callback_should_be_called:
|
||||
if custom_error_callback:
|
||||
assert self.received == error
|
||||
else:
|
||||
assert len(caplog.records) > 0
|
||||
records = (record.getMessage() for record in caplog.records)
|
||||
assert "Error while getting Updates: TestMessage" in records
|
||||
if custom_error_callback:
|
||||
assert self.received == error
|
||||
else:
|
||||
assert len(caplog.records) > 0
|
||||
records = (record.getMessage() for record in caplog.records)
|
||||
assert "Error while getting Updates: TestMessage" in records
|
||||
await updater.stop()
|
||||
|
||||
async def test_start_polling_unexpected_shutdown(self, updater, monkeypatch, caplog):
|
||||
|
@ -517,7 +516,7 @@ class TestUpdater:
|
|||
assert not updater.running
|
||||
|
||||
@pytest.mark.parametrize("ext_bot", [True, False])
|
||||
@pytest.mark.parametrize("drop_pending_updates", (True, False))
|
||||
@pytest.mark.parametrize("drop_pending_updates", [True, False])
|
||||
@pytest.mark.parametrize("secret_token", ["SecretToken", None])
|
||||
async def test_webhook_basic(
|
||||
self, monkeypatch, updater, drop_pending_updates, ext_bot, secret_token
|
||||
|
@ -627,9 +626,9 @@ class TestUpdater:
|
|||
await updater.stop()
|
||||
|
||||
async def test_start_webhook_parameters_passing(self, updater, monkeypatch):
|
||||
expected_delete_webhook = dict(
|
||||
drop_pending_updates=None,
|
||||
)
|
||||
expected_delete_webhook = {
|
||||
"drop_pending_updates": None,
|
||||
}
|
||||
|
||||
expected_set_webhook = dict(
|
||||
certificate=None,
|
||||
|
@ -668,10 +667,10 @@ class TestUpdater:
|
|||
async with updater:
|
||||
await updater.start_webhook()
|
||||
await updater.stop()
|
||||
expected_delete_webhook = dict(
|
||||
drop_pending_updates=True,
|
||||
api_kwargs=None,
|
||||
)
|
||||
expected_delete_webhook = {
|
||||
"drop_pending_updates": True,
|
||||
"api_kwargs": None,
|
||||
}
|
||||
|
||||
expected_set_webhook = dict(
|
||||
certificate=data_file("sslcert.pem").read_bytes(),
|
||||
|
@ -819,8 +818,8 @@ class TestUpdater:
|
|||
assert self.test_flag == [True, True]
|
||||
await updater.stop()
|
||||
|
||||
@pytest.mark.parametrize("exception_class", (InvalidToken, TelegramError))
|
||||
@pytest.mark.parametrize("retries", (3, 0))
|
||||
@pytest.mark.parametrize("exception_class", [InvalidToken, TelegramError])
|
||||
@pytest.mark.parametrize("retries", [3, 0])
|
||||
async def test_start_webhook_bootstrap_retries(
|
||||
self, updater, monkeypatch, exception_class, retries
|
||||
):
|
||||
|
|
|
@ -65,7 +65,7 @@ def mocker_factory(
|
|||
return make_assertion
|
||||
|
||||
|
||||
@pytest.fixture(scope="function")
|
||||
@pytest.fixture()
|
||||
async def httpx_request():
|
||||
async with HTTPXRequest() as rq:
|
||||
yield rq
|
||||
|
@ -102,7 +102,7 @@ class TestRequestWithoutRequest:
|
|||
test_flag = None
|
||||
|
||||
@pytest.fixture(autouse=True)
|
||||
def reset(self):
|
||||
def _reset(self):
|
||||
self.test_flag = None
|
||||
|
||||
async def test_init_import_errors(self, monkeypatch):
|
||||
|
@ -120,9 +120,8 @@ class TestRequestWithoutRequest:
|
|||
def test_slot_behaviour(self):
|
||||
inst = HTTPXRequest()
|
||||
for attr in inst.__slots__:
|
||||
if attr.startswith("__"):
|
||||
attr = f"_{inst.__class__.__name__}{attr}"
|
||||
assert getattr(inst, attr, "err") != "err", f"got extra slot '{attr}'"
|
||||
at = f"_{inst.__class__.__name__}{attr}" if attr.startswith("__") else attr
|
||||
assert getattr(inst, at, "err") != "err", f"got extra slot '{at}'"
|
||||
assert len(mro_slots(inst)) == len(set(mro_slots(inst))), "duplicate slot"
|
||||
|
||||
async def test_context_manager(self, monkeypatch):
|
||||
|
@ -257,7 +256,7 @@ class TestRequestWithoutRequest:
|
|||
await httpx_request.post(None, None, None)
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"code, exception_class",
|
||||
("code", "exception_class"),
|
||||
[
|
||||
(HTTPStatus.FORBIDDEN, Forbidden),
|
||||
(HTTPStatus.NOT_FOUND, InvalidToken),
|
||||
|
@ -283,7 +282,7 @@ class TestRequestWithoutRequest:
|
|||
await httpx_request.post("", None, None)
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
["exception", "catch_class", "match"],
|
||||
("exception", "catch_class", "match"),
|
||||
[
|
||||
(TelegramError("TelegramError"), TelegramError, "TelegramError"),
|
||||
(
|
||||
|
@ -344,7 +343,7 @@ class TestHTTPXRequestWithoutRequest:
|
|||
test_flag = None
|
||||
|
||||
@pytest.fixture(autouse=True)
|
||||
def reset(self):
|
||||
def _reset(self):
|
||||
self.test_flag = None
|
||||
|
||||
def test_init(self, monkeypatch):
|
||||
|
@ -564,7 +563,7 @@ class TestHTTPXRequestWithoutRequest:
|
|||
assert content == b"content"
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
["raised_class", "expected_class", "expected_message"],
|
||||
("raised_class", "expected_class", "expected_message"),
|
||||
[
|
||||
(httpx.TimeoutException, TimedOut, "Timed out"),
|
||||
(httpx.ReadError, NetworkError, "httpx.ReadError: message"),
|
||||
|
@ -594,8 +593,8 @@ class TestHTTPXRequestWithoutRequest:
|
|||
|
||||
monkeypatch.setattr(httpx.AsyncClient, "request", request)
|
||||
|
||||
with pytest.raises(TimedOut, match="Pool timeout"):
|
||||
async with HTTPXRequest(pool_timeout=0.02) as httpx_request:
|
||||
async with HTTPXRequest(pool_timeout=0.02) as httpx_request:
|
||||
with pytest.raises(TimedOut, match="Pool timeout"):
|
||||
await asyncio.gather(
|
||||
httpx_request.do_request(method="GET", url="URL"),
|
||||
httpx_request.do_request(method="GET", url="URL"),
|
||||
|
|
|
@ -47,7 +47,7 @@ class TestRequestParameterWithoutRequest:
|
|||
assert request_parameter.input_files is None
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"value, expected",
|
||||
("value", "expected"),
|
||||
[
|
||||
(1, "1"),
|
||||
("one", "one"),
|
||||
|
|
|
@ -93,7 +93,7 @@ def to_camel_case(snake_str):
|
|||
return components[0] + "".join(x.title() for x in components[1:])
|
||||
|
||||
|
||||
@pytest.fixture(scope="function")
|
||||
@pytest.fixture()
|
||||
async def message(bot, chat_id): # mostly used in tests for edit_message
|
||||
out = await bot.send_message(
|
||||
chat_id, "Text", disable_web_page_preview=True, disable_notification=True
|
||||
|
@ -200,8 +200,8 @@ class TestBotWithoutRequest:
|
|||
|
||||
test_flag = None
|
||||
|
||||
@pytest.fixture(scope="function", autouse=True)
|
||||
def reset(self):
|
||||
@pytest.fixture(autouse=True)
|
||||
def _reset(self):
|
||||
self.test_flag = None
|
||||
|
||||
@pytest.mark.parametrize("bot_class", [Bot, ExtBot])
|
||||
|
@ -447,12 +447,9 @@ class TestBotWithoutRequest:
|
|||
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("_", "") == "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
|
||||
# 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 if bot_method_name.lower().replace("_", "") == "getme" else None
|
||||
|
||||
# Check that ExtBot does the right thing
|
||||
bot_method = getattr(bot, bot_method_name)
|
||||
|
@ -526,8 +523,7 @@ class TestBotWithoutRequest:
|
|||
"id": "1",
|
||||
},
|
||||
}
|
||||
web_app_msg = SentWebAppMessage("321").to_dict()
|
||||
return web_app_msg
|
||||
return SentWebAppMessage("321").to_dict()
|
||||
|
||||
# We test different result types more thoroughly for answer_inline_query, so we just
|
||||
# use the one type here
|
||||
|
@ -558,7 +554,7 @@ class TestBotWithoutRequest:
|
|||
indirect=True,
|
||||
)
|
||||
@pytest.mark.parametrize(
|
||||
"ilq_result,expected_params",
|
||||
("ilq_result", "expected_params"),
|
||||
[
|
||||
(
|
||||
InlineQueryResultArticle("1", "title", InputTextMessageContent("text")),
|
||||
|
@ -632,8 +628,7 @@ class TestBotWithoutRequest:
|
|||
async def make_assertion(url, request_data: RequestData, *args, **kwargs):
|
||||
nonlocal params
|
||||
params = request_data.parameters == expected_params
|
||||
web_app_msg = SentWebAppMessage("321").to_dict()
|
||||
return web_app_msg
|
||||
return SentWebAppMessage("321").to_dict()
|
||||
|
||||
monkeypatch.setattr(bot.request, "post", make_assertion)
|
||||
|
||||
|
@ -908,7 +903,7 @@ class TestBotWithoutRequest:
|
|||
)
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"current_offset,num_results,id_offset,expected_next_offset",
|
||||
("current_offset", "num_results", "id_offset", "expected_next_offset"),
|
||||
[
|
||||
("", InlineQueryLimit.RESULTS, 1, 1),
|
||||
(1, InlineQueryLimit.RESULTS, 51, 2),
|
||||
|
@ -961,7 +956,7 @@ class TestBotWithoutRequest:
|
|||
results = data["results"]
|
||||
length_matches = len(results) == 30
|
||||
ids_match = all(int(res["id"]) == 1 + i for i, res in enumerate(results))
|
||||
next_offset_matches = data["next_offset"] == ""
|
||||
next_offset_matches = not data["next_offset"]
|
||||
return length_matches and ids_match and next_offset_matches
|
||||
|
||||
monkeypatch.setattr(bot.request, "post", make_assertion)
|
||||
|
@ -988,7 +983,7 @@ class TestBotWithoutRequest:
|
|||
data = request_data.parameters
|
||||
results = data["results"]
|
||||
length = results == []
|
||||
next_offset = data["next_offset"] == ""
|
||||
next_offset = not data["next_offset"]
|
||||
return length and next_offset
|
||||
|
||||
monkeypatch.setattr(bot.request, "post", make_assertion)
|
||||
|
@ -1411,7 +1406,7 @@ class TestBotWithoutRequest:
|
|||
# here we test more extensively.
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"acd_in,maxsize",
|
||||
("acd_in", "maxsize"),
|
||||
[(True, 1024), (False, 1024), (0, 0), (None, None)],
|
||||
)
|
||||
async def test_callback_data_maxsize(self, bot_info, acd_in, maxsize):
|
||||
|
@ -1909,10 +1904,11 @@ class TestBotWithRequest:
|
|||
assert message_quiz.poll.is_closed
|
||||
assert message_quiz.poll.explanation == "Here is a link"
|
||||
assert message_quiz.poll.explanation_entities == tuple(explanation_entities)
|
||||
assert poll_task.done() and quiz_task.done()
|
||||
assert poll_task.done()
|
||||
assert quiz_task.done()
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
["open_period", "close_date"], [(5, None), (None, True)], ids=["open_period", "close_date"]
|
||||
("open_period", "close_date"), [(5, None), (None, True)], ids=["open_period", "close_date"]
|
||||
)
|
||||
async def test_send_open_period(self, bot, super_group_id, open_period, close_date):
|
||||
question = "Is this a test?"
|
||||
|
@ -2034,7 +2030,7 @@ class TestBotWithRequest:
|
|||
assert message3.poll.explanation_entities == ()
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"default_bot,custom",
|
||||
("default_bot", "custom"),
|
||||
[
|
||||
({"allow_sending_without_reply": True}, None),
|
||||
({"allow_sending_without_reply": False}, None),
|
||||
|
@ -2085,7 +2081,7 @@ class TestBotWithRequest:
|
|||
assert protected_poll.has_protected_content
|
||||
assert not unprotect_poll.has_protected_content
|
||||
|
||||
@pytest.mark.parametrize("emoji", Dice.ALL_EMOJI + [None])
|
||||
@pytest.mark.parametrize("emoji", [*Dice.ALL_EMOJI, None])
|
||||
async def test_send_dice(self, bot, chat_id, emoji):
|
||||
message = await bot.send_dice(chat_id, emoji=emoji, protect_content=True)
|
||||
|
||||
|
@ -2097,7 +2093,7 @@ class TestBotWithRequest:
|
|||
assert message.dice.emoji == emoji
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"default_bot,custom",
|
||||
("default_bot", "custom"),
|
||||
[
|
||||
({"allow_sending_without_reply": True}, None),
|
||||
({"allow_sending_without_reply": False}, None),
|
||||
|
@ -2367,7 +2363,7 @@ class TestBotWithRequest:
|
|||
await bot.delete_webhook()
|
||||
await asyncio.sleep(1)
|
||||
info = await bot.get_webhook_info()
|
||||
assert info.url == ""
|
||||
assert not info.url
|
||||
assert info.ip_address is None
|
||||
assert info.has_custom_certificate is False
|
||||
|
||||
|
@ -2419,14 +2415,14 @@ class TestBotWithRequest:
|
|||
assert message.game.description == (
|
||||
"A no-op test game, for python-telegram-bot bot framework testing."
|
||||
)
|
||||
assert message.game.animation.file_id != ""
|
||||
assert message.game.animation.file_id
|
||||
# We added some test bots later and for some reason the file size is not the same for them
|
||||
# so we accept three different sizes here. Shouldn't be too much of
|
||||
assert message.game.photo[0].file_size in [851, 4928, 850]
|
||||
assert message.has_protected_content
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"default_bot,custom",
|
||||
("default_bot", "custom"),
|
||||
[
|
||||
({"allow_sending_without_reply": True}, None),
|
||||
({"allow_sending_without_reply": False}, None),
|
||||
|
@ -2462,7 +2458,7 @@ class TestBotWithRequest:
|
|||
)
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"default_bot,val",
|
||||
("default_bot", "val"),
|
||||
[({"protect_content": True}, True), ({"protect_content": False}, None)],
|
||||
indirect=["default_bot"],
|
||||
)
|
||||
|
@ -2629,7 +2625,7 @@ class TestBotWithRequest:
|
|||
# Each link is unique apparently
|
||||
invite_link = await bot.export_chat_invite_link(channel_id)
|
||||
assert isinstance(invite_link, str)
|
||||
assert invite_link != ""
|
||||
assert invite_link
|
||||
|
||||
async def test_edit_revoke_chat_invite_link_passing_link_objects(self, bot, channel_id):
|
||||
invite_link = await bot.create_chat_invite_link(chat_id=channel_id)
|
||||
|
@ -2683,7 +2679,7 @@ class TestBotWithRequest:
|
|||
invite_link = await bot.create_chat_invite_link(
|
||||
channel_id, expire_date=expire_time, member_limit=10
|
||||
)
|
||||
assert invite_link.invite_link != ""
|
||||
assert invite_link.invite_link
|
||||
assert not invite_link.invite_link.endswith("...")
|
||||
assert abs(invite_link.expire_date - aware_time_in_future) < dtm.timedelta(seconds=1)
|
||||
assert invite_link.member_limit == 10
|
||||
|
@ -2734,7 +2730,7 @@ class TestBotWithRequest:
|
|||
invite_link = await tz_bot.create_chat_invite_link(
|
||||
channel_id, expire_date=time_in_future, member_limit=10
|
||||
)
|
||||
assert invite_link.invite_link != ""
|
||||
assert invite_link.invite_link
|
||||
assert not invite_link.invite_link.endswith("...")
|
||||
assert abs(invite_link.expire_date - aware_expire_date) < dtm.timedelta(seconds=1)
|
||||
assert invite_link.member_limit == 10
|
||||
|
@ -2827,8 +2823,9 @@ class TestBotWithRequest:
|
|||
|
||||
assert len(messages) == 3 # Check if we sent 3 messages
|
||||
|
||||
assert all([await i for i in pinned_messages_tasks]) # Check if we pinned 3 messages
|
||||
assert all([i.done() for i in pinned_messages_tasks]) # Check if all tasks are done
|
||||
# Check if we pinned 3 messages
|
||||
assert all([await i for i in pinned_messages_tasks]) # noqa: PIE802
|
||||
assert all(i.done() for i in pinned_messages_tasks) # Check if all tasks are done
|
||||
|
||||
chat = await bot.get_chat(super_group_id) # get the chat to check the pinned message
|
||||
assert chat.pinned_message in messages
|
||||
|
@ -2848,7 +2845,7 @@ class TestBotWithRequest:
|
|||
bot.unpin_chat_message(chat_id=super_group_id, read_timeout=10), # unpins most recent
|
||||
)
|
||||
assert all(await tasks)
|
||||
assert all([i.done() for i in tasks])
|
||||
assert all(i.done() for i in tasks)
|
||||
assert await bot.unpin_all_chat_messages(super_group_id, read_timeout=10)
|
||||
|
||||
# get_sticker_set, upload_sticker_file, create_new_sticker_set, add_sticker_to_set,
|
||||
|
@ -2902,7 +2899,7 @@ class TestBotWithRequest:
|
|||
assert not no_protect.has_protected_content
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"default_bot,custom",
|
||||
("default_bot", "custom"),
|
||||
[
|
||||
({"allow_sending_without_reply": True}, None),
|
||||
({"allow_sending_without_reply": False}, None),
|
||||
|
|
|
@ -111,7 +111,7 @@ def scope_class_and_type(request):
|
|||
def bot_command_scope(scope_class_and_type, chat_id):
|
||||
# we use de_json here so that we don't have to worry about which class needs which arguments
|
||||
return scope_class_and_type[0].de_json(
|
||||
dict(type=scope_class_and_type[1], chat_id=chat_id, user_id=42), bot=None
|
||||
{"type": scope_class_and_type[1], "chat_id": chat_id, "user_id": 42}, bot=None
|
||||
)
|
||||
|
||||
|
||||
|
|
|
@ -30,7 +30,7 @@ from tests.auxil.bot_method_checks import (
|
|||
from tests.auxil.slots import mro_slots
|
||||
|
||||
|
||||
@pytest.fixture(scope="function", params=["message", "inline"])
|
||||
@pytest.fixture(params=["message", "inline"])
|
||||
def callback_query(bot, request):
|
||||
cbq = CallbackQuery(
|
||||
TestCallbackQueryBase.id_,
|
||||
|
@ -297,8 +297,7 @@ class TestCallbackQueryWithoutRequest(TestCallbackQueryBase):
|
|||
|
||||
async def test_stop_message_live_location(self, monkeypatch, callback_query):
|
||||
async def make_assertion(*_, **kwargs):
|
||||
ids = self.check_passed_ids(callback_query, kwargs)
|
||||
return ids
|
||||
return self.check_passed_ids(callback_query, kwargs)
|
||||
|
||||
assert check_shortcut_signature(
|
||||
CallbackQuery.stop_message_live_location,
|
||||
|
|
|
@ -486,8 +486,7 @@ class TestChatWithoutRequest(TestChatBase):
|
|||
|
||||
async def test_delete_photo(self, monkeypatch, chat):
|
||||
async def make_assertion(*_, **kwargs):
|
||||
chat_id = kwargs["chat_id"] == chat.id
|
||||
return chat_id
|
||||
return kwargs["chat_id"] == chat.id
|
||||
|
||||
assert check_shortcut_signature(Chat.delete_photo, Bot.delete_chat_photo, ["chat_id"], [])
|
||||
assert await check_shortcut_call(chat.delete_photo, chat.get_bot(), "delete_chat_photo")
|
||||
|
@ -1182,8 +1181,8 @@ class TestChatWithoutRequest(TestChatBase):
|
|||
assert await chat.unhide_general_forum_topic()
|
||||
|
||||
def test_mention_html(self):
|
||||
chat = Chat(id=1, type="foo")
|
||||
with pytest.raises(TypeError, match="Can not create a mention to a private group chat"):
|
||||
chat = Chat(id=1, type="foo")
|
||||
chat.mention_html()
|
||||
|
||||
expected = '<a href="tg://user?id={}">{}</a>'
|
||||
|
@ -1192,10 +1191,10 @@ class TestChatWithoutRequest(TestChatBase):
|
|||
)
|
||||
assert chat.mention_html("the_name*\u2022") == expected.format(chat.id, "the_name*\u2022")
|
||||
assert chat.mention_html() == expected.format(chat.id, chat.full_name)
|
||||
chat = Chat(id=1, type=Chat.PRIVATE, last_name="last\u2022name")
|
||||
with pytest.raises(
|
||||
TypeError, match="Can not create a mention to a private chat without first name"
|
||||
):
|
||||
chat = Chat(id=1, type=Chat.PRIVATE, last_name="last\u2022name")
|
||||
chat.mention_html()
|
||||
|
||||
expected = '<a href="https://t.me/{}">{}</a>'
|
||||
|
@ -1204,15 +1203,15 @@ class TestChatWithoutRequest(TestChatBase):
|
|||
chat.username, "the_name*\u2022"
|
||||
)
|
||||
assert chat.mention_html() == expected.format(chat.username, chat.title)
|
||||
chat = Chat(id=1, type="foo", username="user\u2022name")
|
||||
with pytest.raises(
|
||||
TypeError, match="Can not create a mention to a public chat without title"
|
||||
):
|
||||
chat = Chat(id=1, type="foo", username="user\u2022name")
|
||||
chat.mention_html()
|
||||
|
||||
def test_mention_markdown(self):
|
||||
chat = Chat(id=1, type="foo")
|
||||
with pytest.raises(TypeError, match="Can not create a mention to a private group chat"):
|
||||
chat = Chat(id=1, type="foo")
|
||||
chat.mention_markdown()
|
||||
|
||||
expected = "[{}](tg://user?id={})"
|
||||
|
@ -1223,10 +1222,10 @@ class TestChatWithoutRequest(TestChatBase):
|
|||
"the_name*\u2022", chat.id
|
||||
)
|
||||
assert chat.mention_markdown() == expected.format(chat.full_name, chat.id)
|
||||
chat = Chat(id=1, type=Chat.PRIVATE, last_name="last\u2022name")
|
||||
with pytest.raises(
|
||||
TypeError, match="Can not create a mention to a private chat without first name"
|
||||
):
|
||||
chat = Chat(id=1, type=Chat.PRIVATE, last_name="last\u2022name")
|
||||
chat.mention_markdown()
|
||||
|
||||
expected = "[{}](https://t.me/{})"
|
||||
|
@ -1235,15 +1234,15 @@ class TestChatWithoutRequest(TestChatBase):
|
|||
"the_name*\u2022", chat.username
|
||||
)
|
||||
assert chat.mention_markdown() == expected.format(chat.title, chat.username)
|
||||
chat = Chat(id=1, type="foo", username="user\u2022name")
|
||||
with pytest.raises(
|
||||
TypeError, match="Can not create a mention to a public chat without title"
|
||||
):
|
||||
chat = Chat(id=1, type="foo", username="user\u2022name")
|
||||
chat.mention_markdown()
|
||||
|
||||
def test_mention_markdown_v2(self):
|
||||
chat = Chat(id=1, type="foo")
|
||||
with pytest.raises(TypeError, match="Can not create a mention to a private group chat"):
|
||||
chat = Chat(id=1, type="foo")
|
||||
chat.mention_markdown_v2()
|
||||
|
||||
expected = "[{}](tg://user?id={})"
|
||||
|
@ -1254,10 +1253,10 @@ class TestChatWithoutRequest(TestChatBase):
|
|||
assert chat.mention_markdown_v2() == expected.format(
|
||||
escape_markdown(chat.full_name, version=2), chat.id
|
||||
)
|
||||
chat = Chat(id=1, type=Chat.PRIVATE, last_name="last_name")
|
||||
with pytest.raises(
|
||||
TypeError, match="Can not create a mention to a private chat without first name"
|
||||
):
|
||||
chat = Chat(id=1, type=Chat.PRIVATE, last_name="last_name")
|
||||
chat.mention_markdown_v2()
|
||||
|
||||
expected = "[{}](https://t.me/{})"
|
||||
|
@ -1268,8 +1267,8 @@ class TestChatWithoutRequest(TestChatBase):
|
|||
assert chat.mention_markdown_v2() == expected.format(
|
||||
escape_markdown(chat.title, version=2), chat.username
|
||||
)
|
||||
chat = Chat(id=1, type="foo", username="user\u2022name")
|
||||
with pytest.raises(
|
||||
TypeError, match="Can not create a mention to a public chat without title"
|
||||
):
|
||||
chat = Chat(id=1, type="foo", username="user\u2022name")
|
||||
chat.mention_markdown_v2()
|
||||
|
|
|
@ -165,13 +165,13 @@ def iter_args(instance: ChatMember, de_json_inst: ChatMember, include_optional:
|
|||
inst_at, json_at = getattr(instance, param.name), getattr(de_json_inst, param.name)
|
||||
if isinstance(json_at, datetime.datetime): # Convert datetime to int
|
||||
json_at = to_timestamp(json_at)
|
||||
if param.default is not inspect.Parameter.empty and include_optional:
|
||||
yield inst_at, json_at
|
||||
elif param.default is inspect.Parameter.empty:
|
||||
if (
|
||||
param.default is not inspect.Parameter.empty and include_optional
|
||||
) or param.default is inspect.Parameter.empty:
|
||||
yield inst_at, json_at
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
@pytest.fixture()
|
||||
def chat_member_type(request):
|
||||
return request.param()
|
||||
|
||||
|
|
|
@ -93,7 +93,7 @@ class TestConstantsWithoutRequest:
|
|||
assert StrEnumTest.FOO == "foo"
|
||||
assert StrEnumTest.FOO != StrEnumTest.BAR
|
||||
assert StrEnumTest.FOO != "bar"
|
||||
assert StrEnumTest.FOO != object()
|
||||
assert object() != StrEnumTest.FOO
|
||||
|
||||
assert hash(StrEnumTest.FOO) == hash("foo")
|
||||
|
||||
|
@ -105,14 +105,15 @@ class TestConstantsWithoutRequest:
|
|||
assert IntEnumTest.FOO == 1
|
||||
assert IntEnumTest.FOO != IntEnumTest.BAR
|
||||
assert IntEnumTest.FOO != 2
|
||||
assert IntEnumTest.FOO != object()
|
||||
assert object() != IntEnumTest.FOO
|
||||
|
||||
assert hash(IntEnumTest.FOO) == hash(1)
|
||||
|
||||
def test_bot_api_version_and_info(self):
|
||||
assert constants.BOT_API_VERSION == str(constants.BOT_API_VERSION_INFO)
|
||||
assert constants.BOT_API_VERSION_INFO == tuple(
|
||||
int(x) for x in constants.BOT_API_VERSION.split(".")
|
||||
assert str(constants.BOT_API_VERSION_INFO) == constants.BOT_API_VERSION
|
||||
assert (
|
||||
tuple(int(x) for x in constants.BOT_API_VERSION.split("."))
|
||||
== constants.BOT_API_VERSION_INFO
|
||||
)
|
||||
|
||||
def test_bot_api_version_info(self):
|
||||
|
@ -139,7 +140,8 @@ class TestConstantsWithRequest:
|
|||
)
|
||||
good_msg, bad_msg = await tasks
|
||||
assert good_msg.text == good_text
|
||||
assert isinstance(bad_msg, BadRequest) and "Message is too long" in str(bad_msg)
|
||||
assert isinstance(bad_msg, BadRequest)
|
||||
assert "Message is too long" in str(bad_msg)
|
||||
|
||||
async def test_max_caption_length(self, bot, chat_id):
|
||||
good_caption = "a" * constants.MessageLimit.CAPTION_LENGTH
|
||||
|
@ -151,4 +153,5 @@ class TestConstantsWithRequest:
|
|||
)
|
||||
good_msg, bad_msg = await tasks
|
||||
assert good_msg.caption == good_caption
|
||||
assert isinstance(bad_msg, BadRequest) and "Message caption is too long" in str(bad_msg)
|
||||
assert isinstance(bad_msg, BadRequest)
|
||||
assert "Message caption is too long" in str(bad_msg)
|
||||
|
|
|
@ -87,12 +87,9 @@ class TestErrors:
|
|||
raise TimedOut
|
||||
|
||||
def test_chat_migrated(self):
|
||||
with pytest.raises(ChatMigrated, match="Group migrated to supergroup. New chat id: 1234"):
|
||||
with pytest.raises(ChatMigrated, match="New chat id: 1234") as e:
|
||||
raise ChatMigrated(1234)
|
||||
try:
|
||||
raise ChatMigrated(1234)
|
||||
except ChatMigrated as e:
|
||||
assert e.new_chat_id == 1234
|
||||
assert e.value.new_chat_id == 1234
|
||||
|
||||
def test_retry_after(self):
|
||||
with pytest.raises(RetryAfter, match="Flood control exceeded. Retry in 12 seconds"):
|
||||
|
@ -103,7 +100,7 @@ class TestErrors:
|
|||
raise Conflict("Something something.")
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"exception, attributes",
|
||||
("exception", "attributes"),
|
||||
[
|
||||
(TelegramError("test message"), ["message"]),
|
||||
(Forbidden("test message"), ["message"]),
|
||||
|
|
|
@ -56,7 +56,7 @@ async def forum_topic_object(forum_group_id, emoji_id):
|
|||
)
|
||||
|
||||
|
||||
@pytest.fixture(scope="function")
|
||||
@pytest.fixture()
|
||||
async def real_topic(bot, emoji_id, forum_group_id):
|
||||
result = await bot.create_forum_topic(
|
||||
chat_id=forum_group_id,
|
||||
|
@ -247,7 +247,9 @@ class TestForumMethodsWithRequest:
|
|||
msg = await coro
|
||||
pin_msg_tasks.add(asyncio.create_task(msg.pin()))
|
||||
|
||||
assert all([await task for task in pin_msg_tasks]) is True, "Message(s) were not pinned"
|
||||
assert (
|
||||
all([await task for task in pin_msg_tasks]) is True # noqa: PIE802
|
||||
), "Message(s) were not pinned"
|
||||
|
||||
# We need 2 or more pinned msgs for this to work, else we get Chat_not_modified error
|
||||
result = await bot.unpin_all_forum_topic_messages(forum_group_id, message_thread_id)
|
||||
|
@ -420,7 +422,7 @@ class TestForumTopicEdited:
|
|||
# empty string
|
||||
json_dict = {"icon_custom_emoji_id": ""}
|
||||
action = ForumTopicEdited.de_json(json_dict, bot)
|
||||
assert action.icon_custom_emoji_id == ""
|
||||
assert not action.icon_custom_emoji_id
|
||||
|
||||
def test_to_dict(self, topic_edited, emoji_id):
|
||||
action_dict = topic_edited.to_dict()
|
||||
|
|
|
@ -26,7 +26,7 @@ from telegram.constants import MessageType
|
|||
|
||||
class TestHelpers:
|
||||
@pytest.mark.parametrize(
|
||||
"test_str,expected",
|
||||
("test_str", "expected"),
|
||||
[
|
||||
("*bold*", r"\*bold\*"),
|
||||
("_italic_", r"\_italic\_"),
|
||||
|
@ -39,7 +39,7 @@ class TestHelpers:
|
|||
assert expected == helpers.escape_markdown(test_str)
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"test_str, expected",
|
||||
("test_str", "expected"),
|
||||
[
|
||||
(r"a_b*c[d]e", r"a\_b\*c\[d\]e"),
|
||||
(r"(fg) ", r"\(fg\) "),
|
||||
|
@ -52,7 +52,7 @@ class TestHelpers:
|
|||
assert expected == helpers.escape_markdown(test_str, version=2)
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"test_str, expected",
|
||||
("test_str", "expected"),
|
||||
[
|
||||
(r"mono/pre:", r"mono/pre:"),
|
||||
("`abc`", r"\`abc\`"),
|
||||
|
@ -101,27 +101,27 @@ class TestHelpers:
|
|||
payload = None
|
||||
assert expected == helpers.create_deep_linked_url(username, payload)
|
||||
|
||||
with pytest.raises(ValueError):
|
||||
with pytest.raises(ValueError, match="Only the following characters"):
|
||||
helpers.create_deep_linked_url(username, "text with spaces")
|
||||
|
||||
with pytest.raises(ValueError):
|
||||
with pytest.raises(ValueError, match="must not exceed 64"):
|
||||
helpers.create_deep_linked_url(username, "0" * 65)
|
||||
|
||||
with pytest.raises(ValueError):
|
||||
with pytest.raises(ValueError, match="valid bot_username"):
|
||||
helpers.create_deep_linked_url(None, None)
|
||||
with pytest.raises(ValueError): # too short username (4 is minimum)
|
||||
with pytest.raises(ValueError, match="valid bot_username"): # too short username, 4 is min
|
||||
helpers.create_deep_linked_url("abc", None)
|
||||
|
||||
@pytest.mark.parametrize("message_type", list(MessageType))
|
||||
@pytest.mark.parametrize("entity_type", [Update, Message])
|
||||
def test_effective_message_type(self, message_type, entity_type):
|
||||
def build_test_message(kwargs):
|
||||
config = dict(
|
||||
message_id=1,
|
||||
from_user=None,
|
||||
date=None,
|
||||
chat=None,
|
||||
)
|
||||
config = {
|
||||
"message_id": 1,
|
||||
"from_user": None,
|
||||
"date": None,
|
||||
"chat": None,
|
||||
}
|
||||
config.update(**kwargs)
|
||||
return Message(**config)
|
||||
|
||||
|
@ -133,7 +133,7 @@ class TestHelpers:
|
|||
assert helpers.effective_message_type(empty_update) is None
|
||||
|
||||
def test_effective_message_type_wrong_type(self):
|
||||
entity = dict()
|
||||
entity = {}
|
||||
with pytest.raises(
|
||||
TypeError, match=re.escape(f"neither Message nor Update (got: {type(entity)})")
|
||||
):
|
||||
|
@ -145,7 +145,7 @@ class TestHelpers:
|
|||
assert expected == helpers.mention_html(1, "the name")
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"test_str, expected",
|
||||
("test_str", "expected"),
|
||||
[
|
||||
("the name", "[the name](tg://user?id=1)"),
|
||||
("under_score", "[under_score](tg://user?id=1)"),
|
||||
|
|
|
@ -81,11 +81,11 @@ def scope_class_and_type(request):
|
|||
def menu_button(scope_class_and_type):
|
||||
# We use de_json here so that we don't have to worry about which class gets which arguments
|
||||
return scope_class_and_type[0].de_json(
|
||||
dict(
|
||||
type=scope_class_and_type[1],
|
||||
text=TestMenuButtonselfBase.text,
|
||||
web_app=TestMenuButtonselfBase.web_app.to_dict(),
|
||||
),
|
||||
{
|
||||
"type": scope_class_and_type[1],
|
||||
"text": TestMenuButtonselfBase.text,
|
||||
"web_app": TestMenuButtonselfBase.web_app.to_dict(),
|
||||
},
|
||||
bot=None,
|
||||
)
|
||||
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue