mirror of
https://github.com/python-telegram-bot/python-telegram-bot.git
synced 2026-06-19 15:45:13 +00:00
Compare commits
9 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| e314e78d06 | |||
| 67a97ae5a7 | |||
| 9248c539d0 | |||
| 6b5e46cc08 | |||
| b3155b2e55 | |||
| ec909e62cf | |||
| 1223e851c3 | |||
| 0b352b043e | |||
| b9d2efdec5 |
@@ -0,0 +1,33 @@
|
||||
name: Check Type Completeness Monthly Run
|
||||
on:
|
||||
schedule:
|
||||
# Run first friday of the month at 03:17 - odd time to spread load on GitHub Actions
|
||||
- cron: '17 3 1-7 * 5'
|
||||
|
||||
jobs:
|
||||
test-type-completeness:
|
||||
name: test-type-completeness
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: Bibo-Joshi/pyright-type-completeness@1.0.0
|
||||
id: pyright-type-completeness
|
||||
with:
|
||||
package-name: telegram
|
||||
python-version: 3.12
|
||||
pyright-version: ~=1.1.367
|
||||
- name: Check Output
|
||||
uses: jannekem/run-python-script-action@v1
|
||||
env:
|
||||
TYPE_COMPLETENESS: ${{ steps.pyright-type-completeness.outputs.base-completeness-score }}
|
||||
with:
|
||||
script: |
|
||||
import os
|
||||
completeness = float(os.getenv("TYPE_COMPLETENESS"))
|
||||
|
||||
if completeness >= 1:
|
||||
exit(0)
|
||||
|
||||
text = f"Type Completeness Decreased to {completeness}. ❌"
|
||||
error(text)
|
||||
set_summary(text)
|
||||
exit(1)
|
||||
@@ -20,7 +20,7 @@ jobs:
|
||||
runs-on: ${{matrix.os}}
|
||||
strategy:
|
||||
matrix:
|
||||
python-version: ['3.8', '3.9', '3.10', '3.11', '3.12', '3.13.0-rc.1']
|
||||
python-version: ['3.8', '3.9', '3.10', '3.11', '3.12', '3.13.0-rc.2']
|
||||
os: [ubuntu-latest, windows-latest, macos-latest]
|
||||
fail-fast: False
|
||||
steps:
|
||||
|
||||
+31
@@ -4,6 +4,37 @@
|
||||
Changelog
|
||||
=========
|
||||
|
||||
Version 21.6
|
||||
============
|
||||
|
||||
*Released 2024-09-19*
|
||||
|
||||
This is the technical changelog for version 21.6. More elaborate release notes can be found in the news channel `@pythontelegrambotchannel <https://t.me/pythontelegrambotchannel>`_.
|
||||
|
||||
New Features
|
||||
------------
|
||||
|
||||
- Full Support for Bot API 7.10 (:pr:`4461` closes :issue:`4459`, :pr:`4460`, :pr:`4463` by `aelkheir <https://github.com/aelkheir>`_, :pr:`4464`)
|
||||
- Add Parameter ``httpx_kwargs`` to ``HTTPXRequest`` (:pr:`4451` closes :issue:`4424`)
|
||||
|
||||
Minor Changes
|
||||
-------------
|
||||
|
||||
- Improve Type Completeness (:pr:`4466`)
|
||||
|
||||
Internal Changes
|
||||
----------------
|
||||
|
||||
- Update Python 3.13 Test Suite to RC2 (:pr:`4471`)
|
||||
- Enforce the ``offline_bot`` Fixture in ``Test*WithoutRequest`` (:pr:`4465`)
|
||||
- Make Tests for ``telegram.ext`` Independent of Networking (:pr:`4454`)
|
||||
- Rename Testing Base Classes (:pr:`4453`)
|
||||
|
||||
Dependency Updates
|
||||
------------------
|
||||
|
||||
- Bump ``pytest`` from 8.3.2 to 8.3.3 (:pr:`4475`)
|
||||
|
||||
Version 21.5
|
||||
============
|
||||
|
||||
|
||||
+2
-2
@@ -11,7 +11,7 @@
|
||||
:target: https://pypi.org/project/python-telegram-bot/
|
||||
:alt: Supported Python versions
|
||||
|
||||
.. image:: https://img.shields.io/badge/Bot%20API-7.9-blue?logo=telegram
|
||||
.. image:: https://img.shields.io/badge/Bot%20API-7.10-blue?logo=telegram
|
||||
:target: https://core.telegram.org/bots/api-changelog
|
||||
:alt: Supported Bot API version
|
||||
|
||||
@@ -81,7 +81,7 @@ After installing_ the library, be sure to check out the section on `working with
|
||||
Telegram API support
|
||||
~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
All types and methods of the Telegram Bot API **7.9** are natively supported by this library.
|
||||
All types and methods of the Telegram Bot API **7.10** are natively supported by this library.
|
||||
In addition, Bot API functionality not yet natively included can still be used as described `in our wiki <https://github.com/python-telegram-bot/python-telegram-bot/wiki/Bot-API-Forward-Compatibility>`_.
|
||||
|
||||
Notable Features
|
||||
|
||||
@@ -120,6 +120,7 @@ Available Types
|
||||
telegram.paidmediainfo
|
||||
telegram.paidmediaphoto
|
||||
telegram.paidmediapreview
|
||||
telegram.paidmediapurchased
|
||||
telegram.paidmediavideo
|
||||
telegram.photosize
|
||||
telegram.poll
|
||||
|
||||
@@ -18,6 +18,7 @@ Handlers
|
||||
telegram.ext.inlinequeryhandler
|
||||
telegram.ext.messagehandler
|
||||
telegram.ext.messagereactionhandler
|
||||
telegram.ext.paidmediapurchasedhandler
|
||||
telegram.ext.pollanswerhandler
|
||||
telegram.ext.pollhandler
|
||||
telegram.ext.precheckoutqueryhandler
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
PaidMediaPurchasedHandler
|
||||
=========================
|
||||
|
||||
.. autoclass:: telegram.ext.PaidMediaPurchasedHandler
|
||||
:members:
|
||||
:show-inheritance:
|
||||
@@ -0,0 +1,6 @@
|
||||
PaidMediaPurchased
|
||||
==================
|
||||
|
||||
.. autoclass:: telegram.PaidMediaPurchased
|
||||
:members:
|
||||
:show-inheritance:
|
||||
@@ -371,8 +371,8 @@ def main() -> None:
|
||||
entry_points=[CommandHandler("start", start)],
|
||||
states={
|
||||
SHOWING: [CallbackQueryHandler(start, pattern="^" + str(END) + "$")],
|
||||
SELECTING_ACTION: selection_handlers,
|
||||
SELECTING_LEVEL: selection_handlers,
|
||||
SELECTING_ACTION: selection_handlers, # type: ignore[dict-item]
|
||||
SELECTING_LEVEL: selection_handlers, # type: ignore[dict-item]
|
||||
DESCRIBING_SELF: [description_conv],
|
||||
STOPPING: [CommandHandler("start", start)],
|
||||
},
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
build
|
||||
|
||||
# For the test suite
|
||||
pytest==8.3.2
|
||||
pytest==8.3.3
|
||||
|
||||
# needed because pytest doesn't come with native support for coroutines as tests
|
||||
pytest-asyncio==0.21.2
|
||||
|
||||
@@ -180,6 +180,7 @@ __all__ = (
|
||||
"PaidMediaInfo",
|
||||
"PaidMediaPhoto",
|
||||
"PaidMediaPreview",
|
||||
"PaidMediaPurchased",
|
||||
"PaidMediaVideo",
|
||||
"PassportData",
|
||||
"PassportElementError",
|
||||
@@ -419,7 +420,14 @@ from ._messageorigin import (
|
||||
MessageOriginUser,
|
||||
)
|
||||
from ._messagereactionupdated import MessageReactionCountUpdated, MessageReactionUpdated
|
||||
from ._paidmedia import PaidMedia, PaidMediaInfo, PaidMediaPhoto, PaidMediaPreview, PaidMediaVideo
|
||||
from ._paidmedia import (
|
||||
PaidMedia,
|
||||
PaidMediaInfo,
|
||||
PaidMediaPhoto,
|
||||
PaidMediaPreview,
|
||||
PaidMediaPurchased,
|
||||
PaidMediaVideo,
|
||||
)
|
||||
from ._passport.credentials import (
|
||||
Credentials,
|
||||
DataCredentials,
|
||||
|
||||
+9
-1
@@ -9193,6 +9193,7 @@ CUSTOM_EMOJI_IDENTIFIER_LIMIT` custom emoji identifiers can be specified.
|
||||
reply_parameters: Optional["ReplyParameters"] = None,
|
||||
reply_markup: Optional[ReplyMarkup] = None,
|
||||
business_connection_id: Optional[str] = None,
|
||||
payload: Optional[str] = None,
|
||||
*,
|
||||
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
|
||||
reply_to_message_id: Optional[int] = None,
|
||||
@@ -9211,9 +9212,15 @@ CUSTOM_EMOJI_IDENTIFIER_LIMIT` custom emoji identifiers can be specified.
|
||||
Telegram Star proceeds from this media will be credited to the chat's balance.
|
||||
Otherwise, they will be credited to the bot's balance.
|
||||
star_count (:obj:`int`): The number of Telegram Stars that must be paid to buy access
|
||||
to the media.
|
||||
to the media; :tg-const:`telegram.constants.InvoiceLimit.MIN_STAR_COUNT` -
|
||||
:tg-const:`telegram.constants.InvoiceLimit.MAX_STAR_COUNT`.
|
||||
media (Sequence[:class:`telegram.InputPaidMedia`]): A list describing the media to be
|
||||
sent; up to :tg-const:`telegram.constants.MediaGroupLimit.MAX_MEDIA_LENGTH` items.
|
||||
payload (:obj:`str`, optional): Bot-defined paid media payload,
|
||||
0-:tg-const:`telegram.constants.InvoiceLimit.MAX_PAYLOAD_LENGTH` bytes. This will
|
||||
not be displayed to the user, use it for your internal processes.
|
||||
|
||||
.. versionadded:: 21.6
|
||||
caption (:obj:`str`, optional): Caption of the media to be sent,
|
||||
0-:tg-const:`telegram.constants.MessageLimit.CAPTION_LENGTH` characters.
|
||||
parse_mode (:obj:`str`, optional): |parse_mode|
|
||||
@@ -9252,6 +9259,7 @@ CUSTOM_EMOJI_IDENTIFIER_LIMIT` custom emoji identifiers can be specified.
|
||||
"star_count": star_count,
|
||||
"media": media,
|
||||
"show_caption_above_media": show_caption_above_media,
|
||||
"payload": payload,
|
||||
}
|
||||
|
||||
return await self._send_message(
|
||||
|
||||
@@ -3350,6 +3350,7 @@ class _ChatBase(TelegramObject):
|
||||
reply_parameters: Optional["ReplyParameters"] = None,
|
||||
reply_markup: Optional[ReplyMarkup] = None,
|
||||
business_connection_id: Optional[str] = None,
|
||||
payload: Optional[str] = None,
|
||||
*,
|
||||
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
|
||||
reply_to_message_id: Optional[int] = None,
|
||||
@@ -3391,6 +3392,7 @@ class _ChatBase(TelegramObject):
|
||||
pool_timeout=pool_timeout,
|
||||
api_kwargs=api_kwargs,
|
||||
business_connection_id=business_connection_id,
|
||||
payload=payload,
|
||||
)
|
||||
|
||||
|
||||
|
||||
+17
-4
@@ -187,15 +187,22 @@ class ChatBoostSourceGiftCode(ChatBoostSource):
|
||||
|
||||
class ChatBoostSourceGiveaway(ChatBoostSource):
|
||||
"""
|
||||
The boost was obtained by the creation of a Telegram Premium giveaway. This boosts the chat 4
|
||||
times for the duration of the corresponding Telegram Premium subscription.
|
||||
The boost was obtained by the creation of a Telegram Premium giveaway or a Telegram Star.
|
||||
This boosts the chat 4 times for the duration of the corresponding Telegram Premium
|
||||
subscription for Telegram Premium giveaways and :attr:`prize_star_count` / 500 times for
|
||||
one year for Telegram Star giveaways.
|
||||
|
||||
.. versionadded:: 20.8
|
||||
|
||||
Args:
|
||||
giveaway_message_id (:obj:`int`): Identifier of a message in the chat with the giveaway;
|
||||
the message could have been deleted already. May be 0 if the message isn't sent yet.
|
||||
user (:class:`telegram.User`, optional): User that won the prize in the giveaway if any.
|
||||
user (:class:`telegram.User`, optional): User that won the prize in the giveaway if any;
|
||||
for Telegram Premium giveaways only.
|
||||
prize_star_count (:obj:`int`, optional): The number of Telegram Stars to be split between
|
||||
giveaway winners; for Telegram Star giveaways only.
|
||||
|
||||
.. versionadded:: 21.6
|
||||
is_unclaimed (:obj:`bool`, optional): :obj:`True`, if the giveaway was completed, but
|
||||
there was no user to win the prize.
|
||||
|
||||
@@ -205,17 +212,22 @@ class ChatBoostSourceGiveaway(ChatBoostSource):
|
||||
giveaway_message_id (:obj:`int`): Identifier of a message in the chat with the giveaway;
|
||||
the message could have been deleted already. May be 0 if the message isn't sent yet.
|
||||
user (:class:`telegram.User`): Optional. User that won the prize in the giveaway if any.
|
||||
prize_star_count (:obj:`int`): Optional. The number of Telegram Stars to be split between
|
||||
giveaway winners; for Telegram Star giveaways only.
|
||||
|
||||
.. versionadded:: 21.6
|
||||
is_unclaimed (:obj:`bool`): Optional. :obj:`True`, if the giveaway was completed, but
|
||||
there was no user to win the prize.
|
||||
"""
|
||||
|
||||
__slots__ = ("giveaway_message_id", "is_unclaimed", "user")
|
||||
__slots__ = ("giveaway_message_id", "is_unclaimed", "prize_star_count", "user")
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
giveaway_message_id: int,
|
||||
user: Optional[User] = None,
|
||||
is_unclaimed: Optional[bool] = None,
|
||||
prize_star_count: Optional[int] = None,
|
||||
*,
|
||||
api_kwargs: Optional[JSONDict] = None,
|
||||
):
|
||||
@@ -224,6 +236,7 @@ class ChatBoostSourceGiveaway(ChatBoostSource):
|
||||
with self._unfrozen():
|
||||
self.giveaway_message_id: int = giveaway_message_id
|
||||
self.user: Optional[User] = user
|
||||
self.prize_star_count: Optional[int] = prize_star_count
|
||||
self.is_unclaimed: Optional[bool] = is_unclaimed
|
||||
|
||||
|
||||
|
||||
+54
-6
@@ -56,8 +56,13 @@ class Giveaway(TelegramObject):
|
||||
country codes indicating the countries from which eligible users for the giveaway must
|
||||
come. If empty, then all users can participate in the giveaway. Users with a phone
|
||||
number that was bought on Fragment can always participate in giveaways.
|
||||
prize_star_count (:obj:`int`, optional): The number of Telegram Stars to be split between
|
||||
giveaway winners; for Telegram Star giveaways only.
|
||||
|
||||
.. versionadded:: 21.6
|
||||
premium_subscription_month_count (:obj:`int`, optional): The number of months the Telegram
|
||||
Premium subscription won from the giveaway will be active for.
|
||||
Premium subscription won from the giveaway will be active for; for Telegram Premium
|
||||
giveaways only.
|
||||
|
||||
Attributes:
|
||||
chats (Sequence[:class:`telegram.Chat`]): The list of chats which the user must join to
|
||||
@@ -75,8 +80,13 @@ class Giveaway(TelegramObject):
|
||||
country codes indicating the countries from which eligible users for the giveaway must
|
||||
come. If empty, then all users can participate in the giveaway. Users with a phone
|
||||
number that was bought on Fragment can always participate in giveaways.
|
||||
prize_star_count (:obj:`int`): Optional. The number of Telegram Stars to be split between
|
||||
giveaway winners; for Telegram Star giveaways only.
|
||||
|
||||
.. versionadded:: 21.6
|
||||
premium_subscription_month_count (:obj:`int`): Optional. The number of months the Telegram
|
||||
Premium subscription won from the giveaway will be active for.
|
||||
Premium subscription won from the giveaway will be active for; for Telegram Premium
|
||||
giveaways only.
|
||||
"""
|
||||
|
||||
__slots__ = (
|
||||
@@ -86,6 +96,7 @@ class Giveaway(TelegramObject):
|
||||
"only_new_members",
|
||||
"premium_subscription_month_count",
|
||||
"prize_description",
|
||||
"prize_star_count",
|
||||
"winner_count",
|
||||
"winners_selection_date",
|
||||
)
|
||||
@@ -100,6 +111,7 @@ class Giveaway(TelegramObject):
|
||||
prize_description: Optional[str] = None,
|
||||
country_codes: Optional[Sequence[str]] = None,
|
||||
premium_subscription_month_count: Optional[int] = None,
|
||||
prize_star_count: Optional[int] = None,
|
||||
*,
|
||||
api_kwargs: Optional[JSONDict] = None,
|
||||
):
|
||||
@@ -113,6 +125,7 @@ class Giveaway(TelegramObject):
|
||||
self.prize_description: Optional[str] = prize_description
|
||||
self.country_codes: Tuple[str, ...] = parse_sequence_arg(country_codes)
|
||||
self.premium_subscription_month_count: Optional[int] = premium_subscription_month_count
|
||||
self.prize_star_count: Optional[int] = prize_star_count
|
||||
|
||||
self._id_attrs = (
|
||||
self.chats,
|
||||
@@ -145,13 +158,28 @@ class Giveaway(TelegramObject):
|
||||
|
||||
class GiveawayCreated(TelegramObject):
|
||||
"""This object represents a service message about the creation of a scheduled giveaway.
|
||||
Currently holds no information.
|
||||
|
||||
Args:
|
||||
prize_star_count (:obj:`int`, optional): The number of Telegram Stars to be
|
||||
split between giveaway winners; for Telegram Star giveaways only.
|
||||
|
||||
.. versionadded:: 21.6
|
||||
|
||||
Attributes:
|
||||
prize_star_count (:obj:`int`): Optional. The number of Telegram Stars to be
|
||||
split between giveaway winners; for Telegram Star giveaways only.
|
||||
|
||||
.. versionadded:: 21.6
|
||||
|
||||
"""
|
||||
|
||||
__slots__ = ()
|
||||
__slots__ = ("prize_star_count",)
|
||||
|
||||
def __init__(self, *, api_kwargs: Optional[JSONDict] = None):
|
||||
def __init__(
|
||||
self, prize_star_count: Optional[int] = None, *, api_kwargs: Optional[JSONDict] = None
|
||||
):
|
||||
super().__init__(api_kwargs=api_kwargs)
|
||||
self.prize_star_count: Optional[int] = prize_star_count
|
||||
|
||||
self._freeze()
|
||||
|
||||
@@ -173,6 +201,10 @@ class GiveawayWinners(TelegramObject):
|
||||
winner_count (:obj:`int`): Total number of winners in the giveaway
|
||||
winners (Sequence[:class:`telegram.User`]): List of up to
|
||||
:tg-const:`telegram.constants.GiveawayLimit.MAX_WINNERS` winners of the giveaway
|
||||
prize_star_count (:obj:`int`, optional): The number of Telegram Stars to be split between
|
||||
giveaway winners; for Telegram Star giveaways only.
|
||||
|
||||
.. versionadded:: 21.6
|
||||
additional_chat_count (:obj:`int`, optional): The number of other chats the user had to
|
||||
join in order to be eligible for the giveaway
|
||||
premium_subscription_month_count (:obj:`int`, optional): The number of months the Telegram
|
||||
@@ -194,6 +226,10 @@ class GiveawayWinners(TelegramObject):
|
||||
:tg-const:`telegram.constants.GiveawayLimit.MAX_WINNERS` winners of the giveaway
|
||||
additional_chat_count (:obj:`int`): Optional. The number of other chats the user had to
|
||||
join in order to be eligible for the giveaway
|
||||
prize_star_count (:obj:`int`): Optional. The number of Telegram Stars to be split between
|
||||
giveaway winners; for Telegram Star giveaways only.
|
||||
|
||||
.. versionadded:: 21.6
|
||||
premium_subscription_month_count (:obj:`int`): Optional. The number of months the Telegram
|
||||
Premium subscription won from the giveaway will be active for
|
||||
unclaimed_prize_count (:obj:`int`): Optional. Number of undistributed prizes
|
||||
@@ -211,6 +247,7 @@ class GiveawayWinners(TelegramObject):
|
||||
"only_new_members",
|
||||
"premium_subscription_month_count",
|
||||
"prize_description",
|
||||
"prize_star_count",
|
||||
"unclaimed_prize_count",
|
||||
"was_refunded",
|
||||
"winner_count",
|
||||
@@ -231,6 +268,7 @@ class GiveawayWinners(TelegramObject):
|
||||
only_new_members: Optional[bool] = None,
|
||||
was_refunded: Optional[bool] = None,
|
||||
prize_description: Optional[str] = None,
|
||||
prize_star_count: Optional[int] = None,
|
||||
*,
|
||||
api_kwargs: Optional[JSONDict] = None,
|
||||
):
|
||||
@@ -247,6 +285,7 @@ class GiveawayWinners(TelegramObject):
|
||||
self.only_new_members: Optional[bool] = only_new_members
|
||||
self.was_refunded: Optional[bool] = was_refunded
|
||||
self.prize_description: Optional[str] = prize_description
|
||||
self.prize_star_count: Optional[int] = prize_star_count
|
||||
|
||||
self._id_attrs = (
|
||||
self.chat,
|
||||
@@ -295,21 +334,29 @@ class GiveawayCompleted(TelegramObject):
|
||||
unclaimed_prize_count (:obj:`int`, optional): Number of undistributed prizes
|
||||
giveaway_message (:class:`telegram.Message`, optional): Message with the giveaway that was
|
||||
completed, if it wasn't deleted
|
||||
is_star_giveaway (:obj:`bool`, optional): :obj:`True`, if the giveaway is a Telegram Star
|
||||
giveaway. Otherwise, currently, the giveaway is a Telegram Premium giveaway.
|
||||
|
||||
.. versionadded:: 21.6
|
||||
Attributes:
|
||||
winner_count (:obj:`int`): Number of winners in the giveaway
|
||||
unclaimed_prize_count (:obj:`int`): Optional. Number of undistributed prizes
|
||||
giveaway_message (:class:`telegram.Message`): Optional. Message with the giveaway that was
|
||||
completed, if it wasn't deleted
|
||||
is_star_giveaway (:obj:`bool`): Optional. :obj:`True`, if the giveaway is a Telegram Star
|
||||
giveaway. Otherwise, currently, the giveaway is a Telegram Premium giveaway.
|
||||
|
||||
.. versionadded:: 21.6
|
||||
"""
|
||||
|
||||
__slots__ = ("giveaway_message", "unclaimed_prize_count", "winner_count")
|
||||
__slots__ = ("giveaway_message", "is_star_giveaway", "unclaimed_prize_count", "winner_count")
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
winner_count: int,
|
||||
unclaimed_prize_count: Optional[int] = None,
|
||||
giveaway_message: Optional["Message"] = None,
|
||||
is_star_giveaway: Optional[bool] = None,
|
||||
*,
|
||||
api_kwargs: Optional[JSONDict] = None,
|
||||
):
|
||||
@@ -318,6 +365,7 @@ class GiveawayCompleted(TelegramObject):
|
||||
self.winner_count: int = winner_count
|
||||
self.unclaimed_prize_count: Optional[int] = unclaimed_prize_count
|
||||
self.giveaway_message: Optional[Message] = giveaway_message
|
||||
self.is_star_giveaway: Optional[bool] = is_star_giveaway
|
||||
|
||||
self._id_attrs = (
|
||||
self.winner_count,
|
||||
|
||||
@@ -24,6 +24,7 @@ from telegram import constants
|
||||
from telegram._files.photosize import PhotoSize
|
||||
from telegram._files.video import Video
|
||||
from telegram._telegramobject import TelegramObject
|
||||
from telegram._user import User
|
||||
from telegram._utils import enum
|
||||
from telegram._utils.argumentparsing import parse_sequence_arg
|
||||
from telegram._utils.types import JSONDict
|
||||
@@ -288,3 +289,52 @@ class PaidMediaInfo(TelegramObject):
|
||||
|
||||
data["paid_media"] = PaidMedia.de_list(data.get("paid_media"), bot=bot)
|
||||
return super().de_json(data=data, bot=bot)
|
||||
|
||||
|
||||
class PaidMediaPurchased(TelegramObject):
|
||||
"""This object contains information about a paid media purchase.
|
||||
|
||||
Objects of this class are comparable in terms of equality. Two objects of this class are
|
||||
considered equal, if their :attr:`from_user` and :attr:`paid_media_payload` are equal.
|
||||
|
||||
Note:
|
||||
In Python :keyword:`from` is a reserved word. Use :paramref:`from_user` instead.
|
||||
|
||||
.. versionadded:: 21.6
|
||||
|
||||
Args:
|
||||
from_user (:class:`telegram.User`): User who purchased the media.
|
||||
paid_media_payload (:obj:`str`): Bot-specified paid media payload.
|
||||
|
||||
Attributes:
|
||||
from_user (:class:`telegram.User`): User who purchased the media.
|
||||
paid_media_payload (:obj:`str`): Bot-specified paid media payload.
|
||||
"""
|
||||
|
||||
__slots__ = ("from_user", "paid_media_payload")
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
from_user: "User",
|
||||
paid_media_payload: str,
|
||||
*,
|
||||
api_kwargs: Optional[JSONDict] = None,
|
||||
) -> None:
|
||||
super().__init__(api_kwargs=api_kwargs)
|
||||
self.from_user: User = from_user
|
||||
self.paid_media_payload: str = paid_media_payload
|
||||
|
||||
self._id_attrs = (self.from_user, self.paid_media_payload)
|
||||
self._freeze()
|
||||
|
||||
@classmethod
|
||||
def de_json(
|
||||
cls, data: Optional[JSONDict], bot: Optional["Bot"] = None
|
||||
) -> Optional["PaidMediaPurchased"]:
|
||||
data = cls._parse_data(data)
|
||||
|
||||
if not data:
|
||||
return None
|
||||
|
||||
data["from_user"] = User.de_json(data=data.pop("from"), bot=bot)
|
||||
return super().de_json(data=data, bot=bot)
|
||||
|
||||
@@ -328,6 +328,9 @@ class TransactionPartnerUser(TransactionPartner):
|
||||
media bought by the user.
|
||||
|
||||
.. versionadded:: 21.5
|
||||
paid_media_payload (:obj:`str`, optional): Optional. Bot-specified paid media payload.
|
||||
|
||||
.. versionadded:: 21.6
|
||||
|
||||
Attributes:
|
||||
type (:obj:`str`): The type of the transaction partner,
|
||||
@@ -338,19 +341,20 @@ class TransactionPartnerUser(TransactionPartner):
|
||||
media bought by the user.
|
||||
|
||||
.. versionadded:: 21.5
|
||||
paid_media_payload (:obj:`str`): Optional. Optional. Bot-specified paid media payload.
|
||||
|
||||
.. versionadded:: 21.6
|
||||
|
||||
"""
|
||||
|
||||
__slots__ = (
|
||||
"invoice_payload",
|
||||
"paid_media",
|
||||
"user",
|
||||
)
|
||||
__slots__ = ("invoice_payload", "paid_media", "paid_media_payload", "user")
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
user: "User",
|
||||
invoice_payload: Optional[str] = None,
|
||||
paid_media: Optional[Sequence[PaidMedia]] = None,
|
||||
paid_media_payload: Optional[str] = None,
|
||||
*,
|
||||
api_kwargs: Optional[JSONDict] = None,
|
||||
) -> None:
|
||||
@@ -360,6 +364,7 @@ class TransactionPartnerUser(TransactionPartner):
|
||||
self.user: User = user
|
||||
self.invoice_payload: Optional[str] = invoice_payload
|
||||
self.paid_media: Optional[Tuple[PaidMedia, ...]] = parse_sequence_arg(paid_media)
|
||||
self.paid_media_payload: Optional[str] = paid_media_payload
|
||||
self._id_attrs = (
|
||||
self.type,
|
||||
self.user,
|
||||
|
||||
+32
-1
@@ -30,6 +30,7 @@ from telegram._choseninlineresult import ChosenInlineResult
|
||||
from telegram._inline.inlinequery import InlineQuery
|
||||
from telegram._message import Message
|
||||
from telegram._messagereactionupdated import MessageReactionCountUpdated, MessageReactionUpdated
|
||||
from telegram._paidmedia import PaidMediaPurchased
|
||||
from telegram._payment.precheckoutquery import PreCheckoutQuery
|
||||
from telegram._payment.shippingquery import ShippingQuery
|
||||
from telegram._poll import Poll, PollAnswer
|
||||
@@ -156,6 +157,11 @@ class Update(TelegramObject):
|
||||
|
||||
.. versionadded:: 21.1
|
||||
|
||||
purchased_paid_media (:class:`telegram.PaidMediaPurchased`, optional): A user purchased
|
||||
paid media with a non-empty payload sent by the bot in a non-channel chat.
|
||||
|
||||
.. versionadded:: 21.6
|
||||
|
||||
|
||||
Attributes:
|
||||
update_id (:obj:`int`): The update's unique identifier. Update identifiers start from a
|
||||
@@ -263,6 +269,11 @@ class Update(TelegramObject):
|
||||
were deleted from a connected business account.
|
||||
|
||||
.. versionadded:: 21.1
|
||||
|
||||
purchased_paid_media (:class:`telegram.PaidMediaPurchased`): Optional. A user purchased
|
||||
paid media with a non-empty payload sent by the bot in a non-channel chat.
|
||||
|
||||
.. versionadded:: 21.6
|
||||
"""
|
||||
|
||||
__slots__ = (
|
||||
@@ -290,6 +301,7 @@ class Update(TelegramObject):
|
||||
"poll",
|
||||
"poll_answer",
|
||||
"pre_checkout_query",
|
||||
"purchased_paid_media",
|
||||
"removed_chat_boost",
|
||||
"shipping_query",
|
||||
"update_id",
|
||||
@@ -383,6 +395,13 @@ class Update(TelegramObject):
|
||||
""":const:`telegram.constants.UpdateType.DELETED_BUSINESS_MESSAGES`
|
||||
|
||||
.. versionadded:: 21.1"""
|
||||
|
||||
PURCHASED_PAID_MEDIA: Final[str] = constants.UpdateType.PURCHASED_PAID_MEDIA
|
||||
""":const:`telegram.constants.UpdateType.PURCHASED_PAID_MEDIA`
|
||||
|
||||
.. versionadded:: 21.6
|
||||
"""
|
||||
|
||||
ALL_TYPES: Final[List[str]] = list(constants.UpdateType)
|
||||
"""List[:obj:`str`]: A list of all available update types.
|
||||
|
||||
@@ -413,6 +432,7 @@ class Update(TelegramObject):
|
||||
business_message: Optional[Message] = None,
|
||||
edited_business_message: Optional[Message] = None,
|
||||
deleted_business_messages: Optional[BusinessMessagesDeleted] = None,
|
||||
purchased_paid_media: Optional[PaidMediaPurchased] = None,
|
||||
*,
|
||||
api_kwargs: Optional[JSONDict] = None,
|
||||
):
|
||||
@@ -444,6 +464,7 @@ class Update(TelegramObject):
|
||||
self.deleted_business_messages: Optional[BusinessMessagesDeleted] = (
|
||||
deleted_business_messages
|
||||
)
|
||||
self.purchased_paid_media: Optional[PaidMediaPurchased] = purchased_paid_media
|
||||
|
||||
self._effective_user: Optional[User] = None
|
||||
self._effective_sender: Optional[Union[User, Chat]] = None
|
||||
@@ -475,6 +496,9 @@ class Update(TelegramObject):
|
||||
This property now also considers :attr:`business_connection`, :attr:`business_message`
|
||||
and :attr:`edited_business_message`.
|
||||
|
||||
.. versionchanged:: 21.6
|
||||
This property now also considers :attr:`purchased_paid_media`.
|
||||
|
||||
Example:
|
||||
* If :attr:`message` is present, this will give
|
||||
:attr:`telegram.Message.from_user`.
|
||||
@@ -531,6 +555,9 @@ class Update(TelegramObject):
|
||||
elif self.business_connection:
|
||||
user = self.business_connection.user
|
||||
|
||||
elif self.purchased_paid_media:
|
||||
user = self.purchased_paid_media.from_user
|
||||
|
||||
self._effective_user = user
|
||||
return user
|
||||
|
||||
@@ -601,7 +628,8 @@ class Update(TelegramObject):
|
||||
This is the case, if :attr:`inline_query`,
|
||||
:attr:`chosen_inline_result`, :attr:`callback_query` from inline messages,
|
||||
:attr:`shipping_query`, :attr:`pre_checkout_query`, :attr:`poll`,
|
||||
:attr:`poll_answer`, or :attr:`business_connection` is present.
|
||||
:attr:`poll_answer`, :attr:`business_connection`, or :attr:`purchased_paid_media`
|
||||
is present.
|
||||
|
||||
.. versionchanged:: 21.1
|
||||
This property now also considers :attr:`business_message`,
|
||||
@@ -768,5 +796,8 @@ class Update(TelegramObject):
|
||||
data["deleted_business_messages"] = BusinessMessagesDeleted.de_json(
|
||||
data.get("deleted_business_messages"), bot
|
||||
)
|
||||
data["purchased_paid_media"] = PaidMediaPurchased.de_json(
|
||||
data.get("purchased_paid_media"), bot
|
||||
)
|
||||
|
||||
return super().de_json(data=data, bot=bot)
|
||||
|
||||
@@ -51,6 +51,6 @@ class Version(NamedTuple):
|
||||
|
||||
|
||||
__version_info__: Final[Version] = Version(
|
||||
major=21, minor=5, micro=0, releaselevel="final", serial=0
|
||||
major=21, minor=6, micro=0, releaselevel="final", serial=0
|
||||
)
|
||||
__version__: Final[str] = str(__version_info__)
|
||||
|
||||
+77
-56
@@ -152,7 +152,7 @@ class _AccentColor(NamedTuple):
|
||||
#: :data:`telegram.__bot_api_version_info__`.
|
||||
#:
|
||||
#: .. versionadded:: 20.0
|
||||
BOT_API_VERSION_INFO: Final[_BotAPIVersion] = _BotAPIVersion(major=7, minor=9)
|
||||
BOT_API_VERSION_INFO: Final[_BotAPIVersion] = _BotAPIVersion(major=7, minor=10)
|
||||
#: :obj:`str`: Telegram Bot API
|
||||
#: version supported by this version of `python-telegram-bot`. Also available as
|
||||
#: :data:`telegram.__bot_api_version__`.
|
||||
@@ -552,6 +552,42 @@ class AccentColor(Enum):
|
||||
"""
|
||||
|
||||
|
||||
class BackgroundTypeType(StringEnum):
|
||||
"""This enum contains the available types of :class:`telegram.BackgroundType`. The enum
|
||||
members of this enumeration are instances of :class:`str` and can be treated as such.
|
||||
|
||||
.. versionadded:: 21.2
|
||||
"""
|
||||
|
||||
__slots__ = ()
|
||||
|
||||
FILL = "fill"
|
||||
""":obj:`str`: A :class:`telegram.BackgroundType` with fill background."""
|
||||
WALLPAPER = "wallpaper"
|
||||
""":obj:`str`: A :class:`telegram.BackgroundType` with wallpaper background."""
|
||||
PATTERN = "pattern"
|
||||
""":obj:`str`: A :class:`telegram.BackgroundType` with pattern background."""
|
||||
CHAT_THEME = "chat_theme"
|
||||
""":obj:`str`: A :class:`telegram.BackgroundType` with chat_theme background."""
|
||||
|
||||
|
||||
class BackgroundFillType(StringEnum):
|
||||
"""This enum contains the available types of :class:`telegram.BackgroundFill`. The enum
|
||||
members of this enumeration are instances of :class:`str` and can be treated as such.
|
||||
|
||||
.. versionadded:: 21.2
|
||||
"""
|
||||
|
||||
__slots__ = ()
|
||||
|
||||
SOLID = "solid"
|
||||
""":obj:`str`: A :class:`telegram.BackgroundFill` with solid fill."""
|
||||
GRADIENT = "gradient"
|
||||
""":obj:`str`: A :class:`telegram.BackgroundFill` with gradient fill."""
|
||||
FREEFORM_GRADIENT = "freeform_gradient"
|
||||
""":obj:`str`: A :class:`telegram.BackgroundFill` with freeform_gradient fill."""
|
||||
|
||||
|
||||
class BotCommandLimit(IntEnum):
|
||||
"""This enum contains limitations for :class:`telegram.BotCommand` and
|
||||
:meth:`telegram.Bot.set_my_commands`.
|
||||
@@ -833,6 +869,25 @@ class ChatLimit(IntEnum):
|
||||
"""
|
||||
|
||||
|
||||
class ChatSubscriptionLimit(IntEnum):
|
||||
"""This enum contains limitations for
|
||||
:paramref:`telegram.Bot.create_chat_subscription_invite_link.subscription_period` and
|
||||
:paramref:`telegram.Bot.create_chat_subscription_invite_link.subscription_price`.
|
||||
The enum members of this enumeration are instances of :class:`int` and can be treated as such.
|
||||
|
||||
.. versionadded:: 21.5
|
||||
"""
|
||||
|
||||
__slots__ = ()
|
||||
|
||||
SUBSCRIPTION_PERIOD = 2592000
|
||||
""":obj:`int`: The number of seconds the subscription will be active."""
|
||||
MIN_PRICE = 1
|
||||
""":obj:`int`: Amount of stars a user pays, minimum amount the subscription can be set to."""
|
||||
MAX_PRICE = 2500
|
||||
""":obj:`int`: Amount of stars a user pays, maximum amount the subscription can be set to."""
|
||||
|
||||
|
||||
class BackgroundTypeLimit(IntEnum):
|
||||
"""This enum contains limitations for :class:`telegram.BackgroundTypeFill`,
|
||||
:class:`telegram.BackgroundTypeWallpaper` and :class:`telegram.BackgroundTypePattern`.
|
||||
@@ -2724,6 +2779,11 @@ class UpdateType(StringEnum):
|
||||
|
||||
.. versionadded:: 21.1
|
||||
"""
|
||||
PURCHASED_PAID_MEDIA = "purchased_paid_media"
|
||||
""":obj:`str`: Updates with :attr:`telegram.Update.purchased_paid_media`.
|
||||
|
||||
.. versionadded:: 21.6
|
||||
"""
|
||||
|
||||
|
||||
class InvoiceLimit(IntEnum):
|
||||
@@ -2795,6 +2855,8 @@ class InvoiceLimit(IntEnum):
|
||||
:meth:`telegram.Bot.send_invoice`.
|
||||
* :paramref:`~telegram.Bot.create_invoice_link.payload` parameter of
|
||||
:meth:`telegram.Bot.create_invoice_link`.
|
||||
* :paramref:`~telegram.Bot.send_paid_media.payload` parameter of
|
||||
:meth:`telegram.Bot.send_paid_media`.
|
||||
"""
|
||||
MAX_TIP_AMOUNTS = 4
|
||||
""":obj:`int`: Maximum length of a :obj:`Sequence` passed as:
|
||||
@@ -2804,6 +2866,20 @@ class InvoiceLimit(IntEnum):
|
||||
* :paramref:`~telegram.Bot.create_invoice_link.suggested_tip_amounts` parameter of
|
||||
:meth:`telegram.Bot.create_invoice_link`.
|
||||
"""
|
||||
MIN_STAR_COUNT = 1
|
||||
""":obj:`int`: Minimum amount of starts that must be paid to buy access to a paid media
|
||||
passed as :paramref:`~telegram.Bot.send_paid_media.star_count` parameter of
|
||||
:meth:`telegram.Bot.send_paid_media`.
|
||||
|
||||
.. versionadded:: 21.6
|
||||
"""
|
||||
MAX_STAR_COUNT = 2500
|
||||
""":obj:`int`: Maximum amount of starts that must be paid to buy access to a paid media
|
||||
passed as :paramref:`~telegram.Bot.send_paid_media.star_count` parameter of
|
||||
:meth:`telegram.Bot.send_paid_media`.
|
||||
|
||||
.. versionadded:: 21.6
|
||||
"""
|
||||
|
||||
|
||||
class UserProfilePhotosLimit(IntEnum):
|
||||
@@ -3066,58 +3142,3 @@ class ReactionEmoji(StringEnum):
|
||||
""":obj:`str`: Woman Shrugging"""
|
||||
POUTING_FACE = "😡"
|
||||
""":obj:`str`: Pouting face"""
|
||||
|
||||
|
||||
class BackgroundTypeType(StringEnum):
|
||||
"""This enum contains the available types of :class:`telegram.BackgroundType`. The enum
|
||||
members of this enumeration are instances of :class:`str` and can be treated as such.
|
||||
|
||||
.. versionadded:: 21.2
|
||||
"""
|
||||
|
||||
__slots__ = ()
|
||||
|
||||
FILL = "fill"
|
||||
""":obj:`str`: A :class:`telegram.BackgroundType` with fill background."""
|
||||
WALLPAPER = "wallpaper"
|
||||
""":obj:`str`: A :class:`telegram.BackgroundType` with wallpaper background."""
|
||||
PATTERN = "pattern"
|
||||
""":obj:`str`: A :class:`telegram.BackgroundType` with pattern background."""
|
||||
CHAT_THEME = "chat_theme"
|
||||
""":obj:`str`: A :class:`telegram.BackgroundType` with chat_theme background."""
|
||||
|
||||
|
||||
class BackgroundFillType(StringEnum):
|
||||
"""This enum contains the available types of :class:`telegram.BackgroundFill`. The enum
|
||||
members of this enumeration are instances of :class:`str` and can be treated as such.
|
||||
|
||||
.. versionadded:: 21.2
|
||||
"""
|
||||
|
||||
__slots__ = ()
|
||||
|
||||
SOLID = "solid"
|
||||
""":obj:`str`: A :class:`telegram.BackgroundFill` with solid fill."""
|
||||
GRADIENT = "gradient"
|
||||
""":obj:`str`: A :class:`telegram.BackgroundFill` with gradient fill."""
|
||||
FREEFORM_GRADIENT = "freeform_gradient"
|
||||
""":obj:`str`: A :class:`telegram.BackgroundFill` with freeform_gradient fill."""
|
||||
|
||||
|
||||
class ChatSubscriptionLimit(IntEnum):
|
||||
"""This enum contains limitations for
|
||||
:paramref:`telegram.Bot.create_chat_subscription_invite_link.subscription_period` and
|
||||
:paramref:`telegram.Bot.create_chat_subscription_invite_link.subscription_price`.
|
||||
The enum members of this enumeration are instances of :class:`int` and can be treated as such.
|
||||
|
||||
.. versionadded:: 21.5
|
||||
"""
|
||||
|
||||
__slots__ = ()
|
||||
|
||||
SUBSCRIPTION_PERIOD = 2592000
|
||||
""":obj:`int`: The number of seconds the subscription will be active."""
|
||||
MIN_PRICE = 1
|
||||
""":obj:`int`: Amount of stars a user pays, minimum amount the subscription can be set to."""
|
||||
MAX_PRICE = 2500
|
||||
""":obj:`int`: Amount of stars a user pays, maximum amount the subscription can be set to."""
|
||||
|
||||
@@ -48,6 +48,7 @@ __all__ = (
|
||||
"JobQueue",
|
||||
"MessageHandler",
|
||||
"MessageReactionHandler",
|
||||
"PaidMediaPurchasedHandler",
|
||||
"PersistenceInput",
|
||||
"PicklePersistence",
|
||||
"PollAnswerHandler",
|
||||
@@ -89,6 +90,7 @@ from ._handlers.conversationhandler import ConversationHandler
|
||||
from ._handlers.inlinequeryhandler import InlineQueryHandler
|
||||
from ._handlers.messagehandler import MessageHandler
|
||||
from ._handlers.messagereactionhandler import MessageReactionHandler
|
||||
from ._handlers.paidmediapurchasedhandler import PaidMediaPurchasedHandler
|
||||
from ._handlers.pollanswerhandler import PollAnswerHandler
|
||||
from ._handlers.pollhandler import PollHandler
|
||||
from ._handlers.precheckoutqueryhandler import PreCheckoutQueryHandler
|
||||
|
||||
@@ -323,7 +323,7 @@ class Application(Generic[BT, CCT, UD, CD, BD, JQ], AsyncContextManager["Applica
|
||||
self.update_queue: asyncio.Queue[object] = update_queue
|
||||
self.context_types: ContextTypes[CCT, UD, CD, BD] = context_types
|
||||
self.updater: Optional[Updater] = updater
|
||||
self.handlers: Dict[int, List[BaseHandler[Any, CCT]]] = {}
|
||||
self.handlers: Dict[int, List[BaseHandler[Any, CCT, Any]]] = {}
|
||||
self.error_handlers: Dict[
|
||||
HandlerCallback[object, CCT, None], Union[bool, DefaultValue[bool]]
|
||||
] = {}
|
||||
@@ -1352,7 +1352,7 @@ class Application(Generic[BT, CCT, UD, CD, BD, JQ], AsyncContextManager["Applica
|
||||
# (in __create_task_callback)
|
||||
self._mark_for_persistence_update(update=update)
|
||||
|
||||
def add_handler(self, handler: BaseHandler[Any, CCT], group: int = DEFAULT_GROUP) -> None:
|
||||
def add_handler(self, handler: BaseHandler[Any, CCT, Any], group: int = DEFAULT_GROUP) -> None:
|
||||
"""Register a handler.
|
||||
|
||||
TL;DR: Order and priority counts. 0 or 1 handlers per group will be used. End handling of
|
||||
@@ -1420,8 +1420,8 @@ class Application(Generic[BT, CCT, UD, CD, BD, JQ], AsyncContextManager["Applica
|
||||
def add_handlers(
|
||||
self,
|
||||
handlers: Union[
|
||||
Union[List[BaseHandler[Any, CCT]], Tuple[BaseHandler[Any, CCT]]],
|
||||
Dict[int, Union[List[BaseHandler[Any, CCT]], Tuple[BaseHandler[Any, CCT]]]],
|
||||
Union[List[BaseHandler[Any, CCT, Any]], Tuple[BaseHandler[Any, CCT, Any]]],
|
||||
Dict[int, Union[List[BaseHandler[Any, CCT, Any]], Tuple[BaseHandler[Any, CCT, Any]]]],
|
||||
],
|
||||
group: Union[int, DefaultValue[int]] = _DEFAULT_0,
|
||||
) -> None:
|
||||
@@ -1469,7 +1469,9 @@ class Application(Generic[BT, CCT, UD, CD, BD, JQ], AsyncContextManager["Applica
|
||||
"dictionary where the keys are groups and values are sequences of handlers."
|
||||
)
|
||||
|
||||
def remove_handler(self, handler: BaseHandler[Any, CCT], group: int = DEFAULT_GROUP) -> None:
|
||||
def remove_handler(
|
||||
self, handler: BaseHandler[Any, CCT, Any], group: int = DEFAULT_GROUP
|
||||
) -> None:
|
||||
"""Remove a handler from the specified group.
|
||||
|
||||
Args:
|
||||
|
||||
@@ -29,6 +29,7 @@ from typing import (
|
||||
NoReturn,
|
||||
Optional,
|
||||
Type,
|
||||
TypeVar,
|
||||
Union,
|
||||
)
|
||||
|
||||
@@ -49,6 +50,9 @@ _STORING_DATA_WIKI = (
|
||||
"/wiki/Storing-bot%2C-user-and-chat-related-data"
|
||||
)
|
||||
|
||||
# something like poor mans "typing.Self" for py<3.11
|
||||
ST = TypeVar("ST", bound="CallbackContext[Any, Any, Any, Any]")
|
||||
|
||||
|
||||
class CallbackContext(Generic[BT, UD, CD, BD]):
|
||||
"""
|
||||
@@ -133,24 +137,24 @@ class CallbackContext(Generic[BT, UD, CD, BD]):
|
||||
)
|
||||
|
||||
def __init__(
|
||||
self: "CCT",
|
||||
application: "Application[BT, CCT, UD, CD, BD, Any]",
|
||||
self: ST,
|
||||
application: "Application[BT, ST, UD, CD, BD, Any]",
|
||||
chat_id: Optional[int] = None,
|
||||
user_id: Optional[int] = None,
|
||||
):
|
||||
self._application: Application[BT, CCT, UD, CD, BD, Any] = application
|
||||
self._application: Application[BT, ST, UD, CD, BD, Any] = application
|
||||
self._chat_id: Optional[int] = chat_id
|
||||
self._user_id: Optional[int] = user_id
|
||||
self.args: Optional[List[str]] = None
|
||||
self.matches: Optional[List[Match[str]]] = None
|
||||
self.error: Optional[Exception] = None
|
||||
self.job: Optional[Job[CCT]] = None
|
||||
self.job: Optional[Job[Any]] = None
|
||||
self.coroutine: Optional[
|
||||
Union[Generator[Optional[Future[object]], None, Any], Awaitable[Any]]
|
||||
] = None
|
||||
|
||||
@property
|
||||
def application(self) -> "Application[BT, CCT, UD, CD, BD, Any]":
|
||||
def application(self) -> "Application[BT, ST, UD, CD, BD, Any]":
|
||||
""":class:`telegram.ext.Application`: The application associated with this context."""
|
||||
return self._application
|
||||
|
||||
@@ -398,7 +402,7 @@ class CallbackContext(Generic[BT, UD, CD, BD]):
|
||||
return self._application.bot
|
||||
|
||||
@property
|
||||
def job_queue(self) -> Optional["JobQueue[CCT]"]:
|
||||
def job_queue(self) -> Optional["JobQueue[ST]"]:
|
||||
"""
|
||||
:class:`telegram.ext.JobQueue`: The :class:`JobQueue` used by the
|
||||
:class:`telegram.ext.Application`.
|
||||
|
||||
@@ -4235,6 +4235,7 @@ class ExtBot(Bot, Generic[RLARGS]):
|
||||
reply_parameters: Optional["ReplyParameters"] = None,
|
||||
reply_markup: Optional[ReplyMarkup] = None,
|
||||
business_connection_id: Optional[str] = None,
|
||||
payload: Optional[str] = None,
|
||||
*,
|
||||
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
|
||||
reply_to_message_id: Optional[int] = None,
|
||||
@@ -4265,6 +4266,7 @@ class ExtBot(Bot, Generic[RLARGS]):
|
||||
pool_timeout=pool_timeout,
|
||||
api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args),
|
||||
business_connection_id=business_connection_id,
|
||||
payload=payload,
|
||||
)
|
||||
|
||||
async def create_chat_subscription_invite_link(
|
||||
|
||||
@@ -32,14 +32,14 @@ RT = TypeVar("RT")
|
||||
UT = TypeVar("UT")
|
||||
|
||||
|
||||
class BaseHandler(Generic[UT, CCT], ABC):
|
||||
class BaseHandler(Generic[UT, CCT, RT], ABC):
|
||||
"""The base class for all update handlers. Create custom handlers by inheriting from it.
|
||||
|
||||
Warning:
|
||||
When setting :paramref:`block` to :obj:`False`, you cannot rely on adding custom
|
||||
attributes to :class:`telegram.ext.CallbackContext`. See its docs for more info.
|
||||
|
||||
This class is a :class:`~typing.Generic` class and accepts two type variables:
|
||||
This class is a :class:`~typing.Generic` class and accepts three type variables:
|
||||
|
||||
1. The type of the updates that this handler will handle. Must coincide with the type of the
|
||||
first argument of :paramref:`callback`. :meth:`check_update` must only accept
|
||||
@@ -54,6 +54,7 @@ class BaseHandler(Generic[UT, CCT], ABC):
|
||||
For this type variable, one should usually provide a :class:`~typing.TypeVar` that is
|
||||
also used for the mentioned method arguments. That way, a type checker can check whether
|
||||
this handler fits the definition of the :class:`~Application`.
|
||||
3. The return type of the :paramref:`callback` function accepted by this handler.
|
||||
|
||||
.. seealso:: :wiki:`Types of Handlers <Types-of-Handlers>`
|
||||
|
||||
@@ -89,7 +90,7 @@ class BaseHandler(Generic[UT, CCT], ABC):
|
||||
)
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
self: "BaseHandler[UT, CCT, RT]",
|
||||
callback: HandlerCallback[UT, CCT, RT],
|
||||
block: DVType[bool] = DEFAULT_TRUE,
|
||||
):
|
||||
|
||||
@@ -29,7 +29,7 @@ from telegram.ext._utils.types import CCT, HandlerCallback
|
||||
RT = TypeVar("RT")
|
||||
|
||||
|
||||
class BusinessConnectionHandler(BaseHandler[Update, CCT]):
|
||||
class BusinessConnectionHandler(BaseHandler[Update, CCT, RT]):
|
||||
"""Handler class to handle Telegram
|
||||
:attr:`Business Connections <telegram.Update.business_connection>`.
|
||||
|
||||
@@ -65,7 +65,7 @@ class BusinessConnectionHandler(BaseHandler[Update, CCT]):
|
||||
)
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
self: "BusinessConnectionHandler[CCT, RT]",
|
||||
callback: HandlerCallback[Update, CCT, RT],
|
||||
user_id: Optional[SCT[int]] = None,
|
||||
username: Optional[SCT[str]] = None,
|
||||
|
||||
@@ -29,7 +29,7 @@ from telegram.ext._utils.types import CCT, HandlerCallback
|
||||
RT = TypeVar("RT")
|
||||
|
||||
|
||||
class BusinessMessagesDeletedHandler(BaseHandler[Update, CCT]):
|
||||
class BusinessMessagesDeletedHandler(BaseHandler[Update, CCT, RT]):
|
||||
"""Handler class to handle
|
||||
:attr:`deleted Telegram Business messages <telegram.Update.deleted_business_messages>`.
|
||||
|
||||
@@ -65,7 +65,7 @@ class BusinessMessagesDeletedHandler(BaseHandler[Update, CCT]):
|
||||
)
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
self: "BusinessMessagesDeletedHandler[CCT, RT]",
|
||||
callback: HandlerCallback[Update, CCT, RT],
|
||||
chat_id: Optional[SCT[int]] = None,
|
||||
username: Optional[SCT[str]] = None,
|
||||
|
||||
@@ -33,7 +33,7 @@ if TYPE_CHECKING:
|
||||
RT = TypeVar("RT")
|
||||
|
||||
|
||||
class CallbackQueryHandler(BaseHandler[Update, CCT]):
|
||||
class CallbackQueryHandler(BaseHandler[Update, CCT, RT]):
|
||||
"""Handler class to handle Telegram
|
||||
:attr:`callback queries <telegram.Update.callback_query>`. Optionally based on a regex.
|
||||
|
||||
@@ -125,7 +125,7 @@ class CallbackQueryHandler(BaseHandler[Update, CCT]):
|
||||
__slots__ = ("game_pattern", "pattern")
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
self: "CallbackQueryHandler[CCT, RT]",
|
||||
callback: HandlerCallback[Update, CCT, RT],
|
||||
pattern: Optional[
|
||||
Union[str, Pattern[str], type, Callable[[object], Optional[bool]]]
|
||||
|
||||
@@ -23,10 +23,10 @@ from typing import Final, Optional
|
||||
from telegram import Update
|
||||
from telegram.ext._handlers.basehandler import BaseHandler
|
||||
from telegram.ext._utils._update_parsing import parse_chat_id, parse_username
|
||||
from telegram.ext._utils.types import CCT, HandlerCallback
|
||||
from telegram.ext._utils.types import CCT, RT, HandlerCallback
|
||||
|
||||
|
||||
class ChatBoostHandler(BaseHandler[Update, CCT]):
|
||||
class ChatBoostHandler(BaseHandler[Update, CCT, RT]):
|
||||
"""
|
||||
Handler class to handle Telegram updates that contain a chat boost.
|
||||
|
||||
@@ -84,8 +84,8 @@ class ChatBoostHandler(BaseHandler[Update, CCT]):
|
||||
and :attr:`telegram.Update.removed_chat_boost`."""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
callback: HandlerCallback[Update, CCT, None],
|
||||
self: "ChatBoostHandler[CCT, RT]",
|
||||
callback: HandlerCallback[Update, CCT, RT],
|
||||
chat_boost_types: int = CHAT_BOOST,
|
||||
chat_id: Optional[int] = None,
|
||||
chat_username: Optional[str] = None,
|
||||
|
||||
@@ -28,7 +28,7 @@ from telegram.ext._utils._update_parsing import parse_chat_id, parse_username
|
||||
from telegram.ext._utils.types import CCT, HandlerCallback
|
||||
|
||||
|
||||
class ChatJoinRequestHandler(BaseHandler[Update, CCT]):
|
||||
class ChatJoinRequestHandler(BaseHandler[Update, CCT, RT]):
|
||||
"""Handler class to handle Telegram updates that contain
|
||||
:attr:`telegram.Update.chat_join_request`.
|
||||
|
||||
@@ -81,7 +81,7 @@ class ChatJoinRequestHandler(BaseHandler[Update, CCT]):
|
||||
)
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
self: "ChatJoinRequestHandler[CCT, RT]",
|
||||
callback: HandlerCallback[Update, CCT, RT],
|
||||
chat_id: Optional[SCT[int]] = None,
|
||||
username: Optional[SCT[str]] = None,
|
||||
|
||||
@@ -29,7 +29,7 @@ from telegram.ext._utils.types import CCT, HandlerCallback
|
||||
RT = TypeVar("RT")
|
||||
|
||||
|
||||
class ChatMemberHandler(BaseHandler[Update, CCT]):
|
||||
class ChatMemberHandler(BaseHandler[Update, CCT, RT]):
|
||||
"""Handler class to handle Telegram updates that contain a chat member update.
|
||||
|
||||
Warning:
|
||||
@@ -87,7 +87,7 @@ class ChatMemberHandler(BaseHandler[Update, CCT]):
|
||||
and :attr:`telegram.Update.chat_member`."""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
self: "ChatMemberHandler[CCT, RT]",
|
||||
callback: HandlerCallback[Update, CCT, RT],
|
||||
chat_member_types: int = MY_CHAT_MEMBER,
|
||||
block: DVType[bool] = DEFAULT_TRUE,
|
||||
|
||||
@@ -32,7 +32,7 @@ if TYPE_CHECKING:
|
||||
from telegram.ext import Application
|
||||
|
||||
|
||||
class ChosenInlineResultHandler(BaseHandler[Update, CCT]):
|
||||
class ChosenInlineResultHandler(BaseHandler[Update, CCT, RT]):
|
||||
"""Handler class to handle Telegram updates that contain
|
||||
:attr:`telegram.Update.chosen_inline_result`.
|
||||
|
||||
@@ -76,7 +76,7 @@ class ChosenInlineResultHandler(BaseHandler[Update, CCT]):
|
||||
__slots__ = ("pattern",)
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
self: "ChosenInlineResultHandler[CCT, RT]",
|
||||
callback: HandlerCallback[Update, CCT, RT],
|
||||
block: DVType[bool] = DEFAULT_TRUE,
|
||||
pattern: Optional[Union[str, Pattern[str]]] = None,
|
||||
|
||||
@@ -33,7 +33,7 @@ if TYPE_CHECKING:
|
||||
RT = TypeVar("RT")
|
||||
|
||||
|
||||
class CommandHandler(BaseHandler[Update, CCT]):
|
||||
class CommandHandler(BaseHandler[Update, CCT, RT]):
|
||||
"""Handler class to handle Telegram commands.
|
||||
|
||||
Commands are Telegram messages that start with ``/``, optionally followed by an ``@`` and the
|
||||
@@ -118,7 +118,7 @@ class CommandHandler(BaseHandler[Update, CCT]):
|
||||
__slots__ = ("commands", "filters", "has_args")
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
self: "CommandHandler[CCT, RT]",
|
||||
command: SCT[str],
|
||||
callback: HandlerCallback[Update, CCT, RT],
|
||||
filters: Optional[filters_module.BaseFilter] = None,
|
||||
|
||||
@@ -55,7 +55,7 @@ from telegram.ext._utils.types import CCT, ConversationDict, ConversationKey
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from telegram.ext import Application, Job, JobQueue
|
||||
_CheckUpdateType = Tuple[object, ConversationKey, BaseHandler[Update, CCT], object]
|
||||
_CheckUpdateType = Tuple[object, ConversationKey, BaseHandler[Update, CCT, object], object]
|
||||
|
||||
_LOGGER = get_logger(__name__, class_name="ConversationHandler")
|
||||
|
||||
@@ -119,7 +119,7 @@ class PendingState:
|
||||
return res
|
||||
|
||||
|
||||
class ConversationHandler(BaseHandler[Update, CCT]):
|
||||
class ConversationHandler(BaseHandler[Update, CCT, object]):
|
||||
"""
|
||||
A handler to hold a conversation with a single or multiple users through Telegram updates by
|
||||
managing three collections of other handlers.
|
||||
@@ -296,10 +296,10 @@ class ConversationHandler(BaseHandler[Update, CCT]):
|
||||
|
||||
# pylint: disable=super-init-not-called
|
||||
def __init__(
|
||||
self,
|
||||
entry_points: List[BaseHandler[Update, CCT]],
|
||||
states: Dict[object, List[BaseHandler[Update, CCT]]],
|
||||
fallbacks: List[BaseHandler[Update, CCT]],
|
||||
self: "ConversationHandler[CCT]",
|
||||
entry_points: List[BaseHandler[Update, CCT, object]],
|
||||
states: Dict[object, List[BaseHandler[Update, CCT, object]]],
|
||||
fallbacks: List[BaseHandler[Update, CCT, object]],
|
||||
allow_reentry: bool = False,
|
||||
per_chat: bool = True,
|
||||
per_user: bool = True,
|
||||
@@ -324,9 +324,9 @@ class ConversationHandler(BaseHandler[Update, CCT]):
|
||||
# Store the actual setting in a protected variable instead
|
||||
self._block: DVType[bool] = block
|
||||
|
||||
self._entry_points: List[BaseHandler[Update, CCT]] = entry_points
|
||||
self._states: Dict[object, List[BaseHandler[Update, CCT]]] = states
|
||||
self._fallbacks: List[BaseHandler[Update, CCT]] = fallbacks
|
||||
self._entry_points: List[BaseHandler[Update, CCT, object]] = entry_points
|
||||
self._states: Dict[object, List[BaseHandler[Update, CCT, object]]] = states
|
||||
self._fallbacks: List[BaseHandler[Update, CCT, object]] = fallbacks
|
||||
|
||||
self._allow_reentry: bool = allow_reentry
|
||||
self._per_user: bool = per_user
|
||||
@@ -359,7 +359,7 @@ class ConversationHandler(BaseHandler[Update, CCT]):
|
||||
stacklevel=2,
|
||||
)
|
||||
|
||||
all_handlers: List[BaseHandler[Update, CCT]] = []
|
||||
all_handlers: List[BaseHandler[Update, CCT, object]] = []
|
||||
all_handlers.extend(entry_points)
|
||||
all_handlers.extend(fallbacks)
|
||||
|
||||
@@ -466,7 +466,7 @@ class ConversationHandler(BaseHandler[Update, CCT]):
|
||||
)
|
||||
|
||||
@property
|
||||
def entry_points(self) -> List[BaseHandler[Update, CCT]]:
|
||||
def entry_points(self) -> List[BaseHandler[Update, CCT, object]]:
|
||||
"""List[:class:`telegram.ext.BaseHandler`]: A list of :obj:`BaseHandler` objects that can
|
||||
trigger the start of the conversation.
|
||||
"""
|
||||
@@ -479,7 +479,7 @@ class ConversationHandler(BaseHandler[Update, CCT]):
|
||||
)
|
||||
|
||||
@property
|
||||
def states(self) -> Dict[object, List[BaseHandler[Update, CCT]]]:
|
||||
def states(self) -> Dict[object, List[BaseHandler[Update, CCT, object]]]:
|
||||
"""Dict[:obj:`object`, List[:class:`telegram.ext.BaseHandler`]]: A :obj:`dict` that
|
||||
defines the different states of conversation a user can be in and one or more
|
||||
associated :obj:`BaseHandler` objects that should be used in that state.
|
||||
@@ -491,7 +491,7 @@ class ConversationHandler(BaseHandler[Update, CCT]):
|
||||
raise AttributeError("You can not assign a new value to states after initialization.")
|
||||
|
||||
@property
|
||||
def fallbacks(self) -> List[BaseHandler[Update, CCT]]:
|
||||
def fallbacks(self) -> List[BaseHandler[Update, CCT, object]]:
|
||||
"""List[:class:`telegram.ext.BaseHandler`]: A list of handlers that might be used if
|
||||
the user is in a conversation, but every handler for their current state returned
|
||||
:obj:`False` on :meth:`check_update`.
|
||||
|
||||
@@ -32,7 +32,7 @@ if TYPE_CHECKING:
|
||||
RT = TypeVar("RT")
|
||||
|
||||
|
||||
class InlineQueryHandler(BaseHandler[Update, CCT]):
|
||||
class InlineQueryHandler(BaseHandler[Update, CCT, RT]):
|
||||
"""
|
||||
BaseHandler class to handle Telegram updates that contain a
|
||||
:attr:`telegram.Update.inline_query`.
|
||||
@@ -87,7 +87,7 @@ class InlineQueryHandler(BaseHandler[Update, CCT]):
|
||||
__slots__ = ("chat_types", "pattern")
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
self: "InlineQueryHandler[CCT, RT]",
|
||||
callback: HandlerCallback[Update, CCT, RT],
|
||||
pattern: Optional[Union[str, Pattern[str]]] = None,
|
||||
block: DVType[bool] = DEFAULT_TRUE,
|
||||
|
||||
@@ -32,7 +32,7 @@ if TYPE_CHECKING:
|
||||
RT = TypeVar("RT")
|
||||
|
||||
|
||||
class MessageHandler(BaseHandler[Update, CCT]):
|
||||
class MessageHandler(BaseHandler[Update, CCT, RT]):
|
||||
"""Handler class to handle Telegram messages. They might contain text, media or status
|
||||
updates.
|
||||
|
||||
@@ -75,7 +75,7 @@ class MessageHandler(BaseHandler[Update, CCT]):
|
||||
__slots__ = ("filters",)
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
self: "MessageHandler[CCT, RT]",
|
||||
filters: Optional[filters_module.BaseFilter],
|
||||
callback: HandlerCallback[Update, CCT, RT],
|
||||
block: DVType[bool] = DEFAULT_TRUE,
|
||||
|
||||
@@ -28,7 +28,7 @@ from telegram.ext._utils._update_parsing import parse_chat_id, parse_username
|
||||
from telegram.ext._utils.types import CCT, HandlerCallback
|
||||
|
||||
|
||||
class MessageReactionHandler(BaseHandler[Update, CCT]):
|
||||
class MessageReactionHandler(BaseHandler[Update, CCT, RT]):
|
||||
"""Handler class to handle Telegram updates that contain a message reaction.
|
||||
|
||||
Note:
|
||||
@@ -110,7 +110,7 @@ class MessageReactionHandler(BaseHandler[Update, CCT]):
|
||||
and :attr:`telegram.Update.message_reaction_count`."""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
self: "MessageReactionHandler[CCT, RT]",
|
||||
callback: HandlerCallback[Update, CCT, RT],
|
||||
chat_id: Optional[SCT[int]] = None,
|
||||
chat_username: Optional[SCT[str]] = None,
|
||||
|
||||
@@ -0,0 +1,95 @@
|
||||
#!/usr/bin/env python
|
||||
#
|
||||
# A library that provides a Python interface to the Telegram Bot API
|
||||
# Copyright (C) 2015-2024
|
||||
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Lesser Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Lesser Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser Public License
|
||||
# along with this program. If not, see [http://www.gnu.org/licenses/].
|
||||
"""This module contains the PaidMediaPurchased class."""
|
||||
|
||||
from typing import Optional
|
||||
|
||||
from telegram import Update
|
||||
from telegram._utils.defaultvalue import DEFAULT_TRUE
|
||||
from telegram._utils.types import SCT, DVType
|
||||
from telegram.ext._handlers.basehandler import BaseHandler
|
||||
from telegram.ext._utils._update_parsing import parse_chat_id, parse_username
|
||||
from telegram.ext._utils.types import CCT, RT, HandlerCallback
|
||||
|
||||
|
||||
class PaidMediaPurchasedHandler(BaseHandler[Update, CCT, RT]):
|
||||
"""Handler class to handle Telegram
|
||||
:attr:`purchased paid media <telegram.Update.purchased_paid_media>`.
|
||||
|
||||
.. versionadded:: 21.6
|
||||
|
||||
Args:
|
||||
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::
|
||||
|
||||
async def callback(update: Update, context: CallbackContext)
|
||||
user_id (:obj:`int` | Collection[:obj:`int`], optional): Filters requests to allow only
|
||||
those which are from the specified user ID(s).
|
||||
|
||||
username (:obj:`str` | Collection[:obj:`str`], optional): Filters requests to allow only
|
||||
those which are from the specified username(s).
|
||||
|
||||
block (:obj:`bool`, optional): Determines whether the return value of the callback should
|
||||
be awaited before processing the next handler in
|
||||
:meth:`telegram.ext.Application.process_update`. Defaults to :obj:`True`.
|
||||
|
||||
.. seealso:: :wiki:`Concurrency`
|
||||
Attributes:
|
||||
callback (:term:`coroutine function`): The callback function for this handler.
|
||||
block (:obj:`bool`): Determines whether the return value of the callback should be
|
||||
awaited before processing the next handler in
|
||||
:meth:`telegram.ext.Application.process_update`.
|
||||
"""
|
||||
|
||||
__slots__ = (
|
||||
"_user_ids",
|
||||
"_usernames",
|
||||
)
|
||||
|
||||
def __init__(
|
||||
self: "PaidMediaPurchasedHandler[CCT, RT]",
|
||||
callback: HandlerCallback[Update, CCT, RT],
|
||||
user_id: Optional[SCT[int]] = None,
|
||||
username: Optional[SCT[str]] = None,
|
||||
block: DVType[bool] = DEFAULT_TRUE,
|
||||
):
|
||||
super().__init__(callback, block=block)
|
||||
|
||||
self._user_ids = parse_chat_id(user_id)
|
||||
self._usernames = parse_username(username)
|
||||
|
||||
def check_update(self, update: object) -> bool:
|
||||
"""Determines whether an update should be passed to this handler's :attr:`callback`.
|
||||
|
||||
Args:
|
||||
update (:class:`telegram.Update` | :obj:`object`): Incoming update.
|
||||
|
||||
Returns:
|
||||
:obj:`bool`
|
||||
|
||||
"""
|
||||
if not isinstance(update, Update) or not update.purchased_paid_media:
|
||||
return False
|
||||
|
||||
if not self._user_ids and not self._usernames:
|
||||
return True
|
||||
if update.purchased_paid_media.from_user.id in self._user_ids:
|
||||
return True
|
||||
return update.purchased_paid_media.from_user.username in self._usernames
|
||||
@@ -21,10 +21,10 @@
|
||||
|
||||
from telegram import Update
|
||||
from telegram.ext._handlers.basehandler import BaseHandler
|
||||
from telegram.ext._utils.types import CCT
|
||||
from telegram.ext._utils.types import CCT, RT
|
||||
|
||||
|
||||
class PollAnswerHandler(BaseHandler[Update, CCT]):
|
||||
class PollAnswerHandler(BaseHandler[Update, CCT, RT]):
|
||||
"""Handler class to handle Telegram updates that contain a
|
||||
:attr:`poll answer <telegram.Update.poll_answer>`.
|
||||
|
||||
|
||||
@@ -21,10 +21,10 @@
|
||||
|
||||
from telegram import Update
|
||||
from telegram.ext._handlers.basehandler import BaseHandler
|
||||
from telegram.ext._utils.types import CCT
|
||||
from telegram.ext._utils.types import CCT, RT
|
||||
|
||||
|
||||
class PollHandler(BaseHandler[Update, CCT]):
|
||||
class PollHandler(BaseHandler[Update, CCT, RT]):
|
||||
"""Handler class to handle Telegram updates that contain a
|
||||
:attr:`poll <telegram.Update.poll>`.
|
||||
|
||||
|
||||
@@ -31,7 +31,7 @@ from telegram.ext._utils.types import CCT, HandlerCallback
|
||||
RT = TypeVar("RT")
|
||||
|
||||
|
||||
class PreCheckoutQueryHandler(BaseHandler[Update, CCT]):
|
||||
class PreCheckoutQueryHandler(BaseHandler[Update, CCT, RT]):
|
||||
"""Handler class to handle Telegram :attr:`telegram.Update.pre_checkout_query`.
|
||||
|
||||
Warning:
|
||||
@@ -73,7 +73,7 @@ class PreCheckoutQueryHandler(BaseHandler[Update, CCT]):
|
||||
__slots__ = ("pattern",)
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
self: "PreCheckoutQueryHandler[CCT, RT]",
|
||||
callback: HandlerCallback[Update, CCT, RT],
|
||||
block: DVType[bool] = DEFAULT_TRUE,
|
||||
pattern: Optional[Union[str, Pattern[str]]] = None,
|
||||
|
||||
@@ -33,7 +33,7 @@ if TYPE_CHECKING:
|
||||
RT = TypeVar("RT")
|
||||
|
||||
|
||||
class PrefixHandler(BaseHandler[Update, CCT]):
|
||||
class PrefixHandler(BaseHandler[Update, CCT, RT]):
|
||||
"""Handler class to handle custom prefix commands.
|
||||
|
||||
This is an intermediate handler between :class:`MessageHandler` and :class:`CommandHandler`.
|
||||
@@ -123,7 +123,7 @@ class PrefixHandler(BaseHandler[Update, CCT]):
|
||||
__slots__ = ("commands", "filters")
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
self: "PrefixHandler[CCT, RT]",
|
||||
prefix: SCT[str],
|
||||
command: SCT[str],
|
||||
callback: HandlerCallback[Update, CCT, RT],
|
||||
|
||||
@@ -21,10 +21,10 @@
|
||||
|
||||
from telegram import Update
|
||||
from telegram.ext._handlers.basehandler import BaseHandler
|
||||
from telegram.ext._utils.types import CCT
|
||||
from telegram.ext._utils.types import CCT, RT
|
||||
|
||||
|
||||
class ShippingQueryHandler(BaseHandler[Update, CCT]):
|
||||
class ShippingQueryHandler(BaseHandler[Update, CCT, RT]):
|
||||
"""Handler class to handle Telegram :attr:`telegram.Update.shipping_query`.
|
||||
|
||||
Warning:
|
||||
|
||||
@@ -29,7 +29,7 @@ if TYPE_CHECKING:
|
||||
from telegram.ext import Application
|
||||
|
||||
|
||||
class StringCommandHandler(BaseHandler[str, CCT]):
|
||||
class StringCommandHandler(BaseHandler[str, CCT, RT]):
|
||||
"""Handler class to handle string commands. Commands are string updates that start with
|
||||
``/``. The handler will add a :obj:`list` to the
|
||||
:class:`CallbackContext` named :attr:`CallbackContext.args`. It will contain a list of strings,
|
||||
@@ -71,7 +71,7 @@ class StringCommandHandler(BaseHandler[str, CCT]):
|
||||
__slots__ = ("command",)
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
self: "StringCommandHandler[CCT, RT]",
|
||||
command: str,
|
||||
callback: HandlerCallback[str, CCT, RT],
|
||||
block: DVType[bool] = DEFAULT_TRUE,
|
||||
|
||||
@@ -32,7 +32,7 @@ if TYPE_CHECKING:
|
||||
RT = TypeVar("RT")
|
||||
|
||||
|
||||
class StringRegexHandler(BaseHandler[str, CCT]):
|
||||
class StringRegexHandler(BaseHandler[str, CCT, RT]):
|
||||
"""Handler class to handle string updates based on a regex which checks the update content.
|
||||
|
||||
Read the documentation of the :mod:`re` module for more information. The :func:`re.match`
|
||||
@@ -74,7 +74,7 @@ class StringRegexHandler(BaseHandler[str, CCT]):
|
||||
__slots__ = ("pattern",)
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
self: "StringRegexHandler[CCT, RT]",
|
||||
pattern: Union[str, Pattern[str]],
|
||||
callback: HandlerCallback[str, CCT, RT],
|
||||
block: DVType[bool] = DEFAULT_TRUE,
|
||||
|
||||
@@ -29,7 +29,7 @@ RT = TypeVar("RT")
|
||||
UT = TypeVar("UT")
|
||||
|
||||
|
||||
class TypeHandler(BaseHandler[UT, CCT]):
|
||||
class TypeHandler(BaseHandler[UT, CCT, RT]):
|
||||
"""Handler class to handle updates of custom types.
|
||||
|
||||
Warning:
|
||||
@@ -70,7 +70,7 @@ class TypeHandler(BaseHandler[UT, CCT]):
|
||||
__slots__ = ("strict", "type")
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
self: "TypeHandler[UT, CCT, RT]",
|
||||
type: Type[UT], # pylint: disable=redefined-builtin
|
||||
callback: HandlerCallback[UT, CCT, RT],
|
||||
strict: bool = False,
|
||||
|
||||
@@ -17,7 +17,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/].
|
||||
"""This module contains methods to make POST and GET requests using the httpx library."""
|
||||
from typing import Collection, Optional, Tuple, Union
|
||||
from typing import Any, Collection, Dict, Optional, Tuple, Union
|
||||
|
||||
import httpx
|
||||
|
||||
@@ -122,6 +122,20 @@ class HTTPXRequest(BaseRequest):
|
||||
:meth:`do_request`. Defaults to ``20`` seconds.
|
||||
|
||||
.. versionadded:: 21.0
|
||||
httpx_kwargs (Dict[:obj:`str`, Any], optional): Additional keyword arguments to be passed
|
||||
to the `httpx.AsyncClient <https://www.python-httpx.org/api/#asyncclient>`_
|
||||
constructor.
|
||||
|
||||
Warning:
|
||||
This parameter is intended for advanced users that want to fine-tune the behavior
|
||||
of the underlying ``httpx`` client. The values passed here will override all the
|
||||
defaults set by ``python-telegram-bot`` and all other parameters passed to
|
||||
:class:`HTTPXRequest`. The only exception is the :paramref:`media_write_timeout`
|
||||
parameter, which is not passed to the client constructor.
|
||||
No runtime warnings will be issued about parameters that are overridden in this
|
||||
way.
|
||||
|
||||
.. versionadded:: 21.6
|
||||
|
||||
"""
|
||||
|
||||
@@ -139,6 +153,7 @@ class HTTPXRequest(BaseRequest):
|
||||
socket_options: Optional[Collection[SocketOpt]] = None,
|
||||
proxy: Optional[Union[str, httpx.Proxy, httpx.URL]] = None,
|
||||
media_write_timeout: Optional[float] = 20.0,
|
||||
httpx_kwargs: Optional[Dict[str, Any]] = None,
|
||||
):
|
||||
if proxy_url is not None and proxy is not None:
|
||||
raise ValueError("The parameters `proxy_url` and `proxy` are mutually exclusive.")
|
||||
@@ -183,6 +198,7 @@ class HTTPXRequest(BaseRequest):
|
||||
"limits": limits,
|
||||
"transport": transport,
|
||||
**http_kwargs,
|
||||
**(httpx_kwargs or {}),
|
||||
}
|
||||
|
||||
try:
|
||||
@@ -221,7 +237,7 @@ class HTTPXRequest(BaseRequest):
|
||||
return self._client.timeout.read
|
||||
|
||||
def _build_client(self) -> httpx.AsyncClient:
|
||||
return httpx.AsyncClient(**self._client_kwargs) # type: ignore[arg-type]
|
||||
return httpx.AsyncClient(**self._client_kwargs)
|
||||
|
||||
async def initialize(self) -> None:
|
||||
"""See :meth:`BaseRequest.initialize`."""
|
||||
|
||||
+1
-1
@@ -72,7 +72,7 @@ complete and correct. To run it, export an environment variable first:
|
||||
|
||||
$ export TEST_OFFICIAL=true
|
||||
|
||||
and then run ``pytest tests/test_official.py``. Note: You need py 3.10+ to run this test.
|
||||
and then run ``pytest tests/test_official/test_official.py``. Note: You need py 3.10+ to run this test.
|
||||
|
||||
We also have another marker, ``@pytest.mark.dev``, which you can add to tests that you want to run selectively.
|
||||
Use as follows:
|
||||
|
||||
@@ -51,7 +51,7 @@ async def animation(bot, chat_id):
|
||||
).animation
|
||||
|
||||
|
||||
class TestAnimationBase:
|
||||
class AnimationTestBase:
|
||||
animation_file_id = "CgADAQADngIAAuyVeEez0xRovKi9VAI"
|
||||
animation_file_unique_id = "adc3145fd2e84d95b64d68eaa22aa33e"
|
||||
width = 320
|
||||
@@ -66,7 +66,7 @@ class TestAnimationBase:
|
||||
caption = "Test *animation*"
|
||||
|
||||
|
||||
class TestAnimationWithoutRequest(TestAnimationBase):
|
||||
class TestAnimationWithoutRequest(AnimationTestBase):
|
||||
def test_slot_behaviour(self, animation):
|
||||
for attr in animation.__slots__:
|
||||
assert getattr(animation, attr, "err") != "err", f"got extra slot '{attr}'"
|
||||
@@ -84,7 +84,7 @@ class TestAnimationWithoutRequest(TestAnimationBase):
|
||||
assert animation.file_name.startswith("game.gif") == self.file_name.startswith("game.gif")
|
||||
assert isinstance(animation.thumbnail, PhotoSize)
|
||||
|
||||
def test_de_json(self, bot, animation):
|
||||
def test_de_json(self, offline_bot, animation):
|
||||
json_dict = {
|
||||
"file_id": self.animation_file_id,
|
||||
"file_unique_id": self.animation_file_unique_id,
|
||||
@@ -96,7 +96,7 @@ class TestAnimationWithoutRequest(TestAnimationBase):
|
||||
"mime_type": self.mime_type,
|
||||
"file_size": self.file_size,
|
||||
}
|
||||
animation = Animation.de_json(json_dict, bot)
|
||||
animation = Animation.de_json(json_dict, offline_bot)
|
||||
assert animation.api_kwargs == {}
|
||||
assert animation.file_id == self.animation_file_id
|
||||
assert animation.file_unique_id == self.animation_file_unique_id
|
||||
@@ -140,18 +140,22 @@ class TestAnimationWithoutRequest(TestAnimationBase):
|
||||
assert a != e
|
||||
assert hash(a) != hash(e)
|
||||
|
||||
async def test_send_animation_custom_filename(self, bot, chat_id, animation_file, monkeypatch):
|
||||
async def test_send_animation_custom_filename(
|
||||
self, offline_bot, chat_id, animation_file, monkeypatch
|
||||
):
|
||||
async def make_assertion(url, request_data: RequestData, *args, **kwargs):
|
||||
return next(iter(request_data.multipart_data.values()))[0] == "custom_filename"
|
||||
|
||||
monkeypatch.setattr(bot.request, "post", make_assertion)
|
||||
assert await bot.send_animation(chat_id, animation_file, filename="custom_filename")
|
||||
monkeypatch.setattr(offline_bot.request, "post", make_assertion)
|
||||
assert await offline_bot.send_animation(
|
||||
chat_id, animation_file, filename="custom_filename"
|
||||
)
|
||||
|
||||
@pytest.mark.parametrize("local_mode", [True, False])
|
||||
async def test_send_animation_local_files(self, monkeypatch, bot, chat_id, local_mode):
|
||||
async def test_send_animation_local_files(self, monkeypatch, offline_bot, chat_id, local_mode):
|
||||
try:
|
||||
bot._local_mode = local_mode
|
||||
# For just test that the correct paths are passed as we have no local bot API set up
|
||||
offline_bot._local_mode = local_mode
|
||||
# For just test that the correct paths are passed as we have no local Bot API set up
|
||||
test_flag = False
|
||||
file = data_file("telegram.jpg")
|
||||
expected = file.as_uri()
|
||||
@@ -167,18 +171,18 @@ class TestAnimationWithoutRequest(TestAnimationBase):
|
||||
data.get("thumbnail"), InputFile
|
||||
)
|
||||
|
||||
monkeypatch.setattr(bot, "_post", make_assertion)
|
||||
await bot.send_animation(chat_id, file, thumbnail=file)
|
||||
monkeypatch.setattr(offline_bot, "_post", make_assertion)
|
||||
await offline_bot.send_animation(chat_id, file, thumbnail=file)
|
||||
assert test_flag
|
||||
finally:
|
||||
bot._local_mode = False
|
||||
offline_bot._local_mode = False
|
||||
|
||||
async def test_send_with_animation(self, monkeypatch, bot, chat_id, animation):
|
||||
async def test_send_with_animation(self, monkeypatch, offline_bot, chat_id, animation):
|
||||
async def make_assertion(url, request_data: RequestData, *args, **kwargs):
|
||||
return request_data.json_parameters["animation"] == animation.file_id
|
||||
|
||||
monkeypatch.setattr(bot.request, "post", make_assertion)
|
||||
assert await bot.send_animation(animation=animation, chat_id=chat_id)
|
||||
monkeypatch.setattr(offline_bot.request, "post", make_assertion)
|
||||
assert await offline_bot.send_animation(animation=animation, chat_id=chat_id)
|
||||
|
||||
async def test_get_file_instance_method(self, monkeypatch, animation):
|
||||
async def make_assertion(*_, **kwargs):
|
||||
@@ -219,7 +223,7 @@ class TestAnimationWithoutRequest(TestAnimationBase):
|
||||
)
|
||||
|
||||
|
||||
class TestAnimationWithRequest(TestAnimationBase):
|
||||
class TestAnimationWithRequest(AnimationTestBase):
|
||||
async def test_send_all_args(self, bot, chat_id, animation_file, animation, thumb_file):
|
||||
message = await bot.send_animation(
|
||||
chat_id,
|
||||
|
||||
+17
-17
@@ -49,7 +49,7 @@ async def audio(bot, chat_id):
|
||||
return (await bot.send_audio(chat_id, audio=f, read_timeout=50, thumbnail=thumb)).audio
|
||||
|
||||
|
||||
class TestAudioBase:
|
||||
class AudioTestBase:
|
||||
caption = "Test *audio*"
|
||||
performer = "Leandro Toledo"
|
||||
title = "Teste"
|
||||
@@ -67,7 +67,7 @@ class TestAudioBase:
|
||||
audio_file_unique_id = "adc3145fd2e84d95b64d68eaa22aa33e"
|
||||
|
||||
|
||||
class TestAudioWithoutRequest(TestAudioBase):
|
||||
class TestAudioWithoutRequest(AudioTestBase):
|
||||
def test_slot_behaviour(self, audio):
|
||||
for attr in audio.__slots__:
|
||||
assert getattr(audio, attr, "err") != "err", f"got extra slot '{attr}'"
|
||||
@@ -91,7 +91,7 @@ class TestAudioWithoutRequest(TestAudioBase):
|
||||
assert audio.thumbnail.width == self.thumb_width
|
||||
assert audio.thumbnail.height == self.thumb_height
|
||||
|
||||
def test_de_json(self, bot, audio):
|
||||
def test_de_json(self, offline_bot, audio):
|
||||
json_dict = {
|
||||
"file_id": self.audio_file_id,
|
||||
"file_unique_id": self.audio_file_unique_id,
|
||||
@@ -103,7 +103,7 @@ class TestAudioWithoutRequest(TestAudioBase):
|
||||
"file_size": self.file_size,
|
||||
"thumbnail": audio.thumbnail.to_dict(),
|
||||
}
|
||||
json_audio = Audio.de_json(json_dict, bot)
|
||||
json_audio = Audio.de_json(json_dict, offline_bot)
|
||||
assert json_audio.api_kwargs == {}
|
||||
|
||||
assert json_audio.file_id == self.audio_file_id
|
||||
@@ -147,25 +147,25 @@ class TestAudioWithoutRequest(TestAudioBase):
|
||||
assert a != e
|
||||
assert hash(a) != hash(e)
|
||||
|
||||
async def test_send_with_audio(self, monkeypatch, bot, chat_id, audio):
|
||||
async def test_send_with_audio(self, monkeypatch, offline_bot, chat_id, audio):
|
||||
async def make_assertion(url, request_data: RequestData, *args, **kwargs):
|
||||
return request_data.json_parameters["audio"] == audio.file_id
|
||||
|
||||
monkeypatch.setattr(bot.request, "post", make_assertion)
|
||||
assert await bot.send_audio(audio=audio, chat_id=chat_id)
|
||||
monkeypatch.setattr(offline_bot.request, "post", make_assertion)
|
||||
assert await offline_bot.send_audio(audio=audio, chat_id=chat_id)
|
||||
|
||||
async def test_send_audio_custom_filename(self, bot, chat_id, audio_file, monkeypatch):
|
||||
async def test_send_audio_custom_filename(self, offline_bot, chat_id, audio_file, monkeypatch):
|
||||
async def make_assertion(url, request_data: RequestData, *args, **kwargs):
|
||||
return next(iter(request_data.multipart_data.values()))[0] == "custom_filename"
|
||||
|
||||
monkeypatch.setattr(bot.request, "post", make_assertion)
|
||||
assert await bot.send_audio(chat_id, audio_file, filename="custom_filename")
|
||||
monkeypatch.setattr(offline_bot.request, "post", make_assertion)
|
||||
assert await offline_bot.send_audio(chat_id, audio_file, filename="custom_filename")
|
||||
|
||||
@pytest.mark.parametrize("local_mode", [True, False])
|
||||
async def test_send_audio_local_files(self, monkeypatch, bot, chat_id, local_mode):
|
||||
async def test_send_audio_local_files(self, monkeypatch, offline_bot, chat_id, local_mode):
|
||||
try:
|
||||
bot._local_mode = local_mode
|
||||
# For just test that the correct paths are passed as we have no local bot API set up
|
||||
offline_bot._local_mode = local_mode
|
||||
# For just test that the correct paths are passed as we have no local Bot API set up
|
||||
test_flag = False
|
||||
file = data_file("telegram.jpg")
|
||||
expected = file.as_uri()
|
||||
@@ -179,11 +179,11 @@ class TestAudioWithoutRequest(TestAudioBase):
|
||||
data.get("thumbnail"), InputFile
|
||||
)
|
||||
|
||||
monkeypatch.setattr(bot, "_post", make_assertion)
|
||||
await bot.send_audio(chat_id, file, thumbnail=file)
|
||||
monkeypatch.setattr(offline_bot, "_post", make_assertion)
|
||||
await offline_bot.send_audio(chat_id, file, thumbnail=file)
|
||||
assert test_flag
|
||||
finally:
|
||||
bot._local_mode = False
|
||||
offline_bot._local_mode = False
|
||||
|
||||
async def test_get_file_instance_method(self, monkeypatch, audio):
|
||||
async def make_assertion(*_, **kwargs):
|
||||
@@ -222,7 +222,7 @@ class TestAudioWithoutRequest(TestAudioBase):
|
||||
await default_bot.send_audio(chat_id, audio, reply_parameters=ReplyParameters(**kwargs))
|
||||
|
||||
|
||||
class TestAudioWithRequest(TestAudioBase):
|
||||
class TestAudioWithRequest(AudioTestBase):
|
||||
async def test_send_all_args(self, bot, chat_id, audio_file, thumb_file):
|
||||
message = await bot.send_audio(
|
||||
chat_id,
|
||||
|
||||
@@ -52,7 +52,7 @@ async def chat_photo(bot, super_group_id):
|
||||
)
|
||||
|
||||
|
||||
class TestChatPhotoBase:
|
||||
class ChatPhotoTestBase:
|
||||
chatphoto_small_file_id = "smallCgADAQADngIAAuyVeEez0xRovKi9VAI"
|
||||
chatphoto_big_file_id = "bigCgADAQADngIAAuyVeEez0xRovKi9VAI"
|
||||
chatphoto_small_file_unique_id = "smalladc3145fd2e84d95b64d68eaa22aa33e"
|
||||
@@ -60,20 +60,20 @@ class TestChatPhotoBase:
|
||||
chatphoto_file_url = "https://python-telegram-bot.org/static/testfiles/telegram.jpg"
|
||||
|
||||
|
||||
class TestChatPhotoWithoutRequest(TestChatPhotoBase):
|
||||
class TestChatPhotoWithoutRequest(ChatPhotoTestBase):
|
||||
def test_slot_behaviour(self, chat_photo):
|
||||
for attr in chat_photo.__slots__:
|
||||
assert getattr(chat_photo, attr, "err") != "err", f"got extra slot '{attr}'"
|
||||
assert len(mro_slots(chat_photo)) == len(set(mro_slots(chat_photo))), "duplicate slot"
|
||||
|
||||
def test_de_json(self, bot, chat_photo):
|
||||
def test_de_json(self, offline_bot, chat_photo):
|
||||
json_dict = {
|
||||
"small_file_id": self.chatphoto_small_file_id,
|
||||
"big_file_id": self.chatphoto_big_file_id,
|
||||
"small_file_unique_id": self.chatphoto_small_file_unique_id,
|
||||
"big_file_unique_id": self.chatphoto_big_file_unique_id,
|
||||
}
|
||||
chat_photo = ChatPhoto.de_json(json_dict, bot)
|
||||
chat_photo = ChatPhoto.de_json(json_dict, offline_bot)
|
||||
assert chat_photo.api_kwargs == {}
|
||||
assert chat_photo.small_file_id == self.chatphoto_small_file_id
|
||||
assert chat_photo.big_file_id == self.chatphoto_big_file_id
|
||||
@@ -121,12 +121,14 @@ class TestChatPhotoWithoutRequest(TestChatPhotoBase):
|
||||
assert a != e
|
||||
assert hash(a) != hash(e)
|
||||
|
||||
async def test_send_with_chat_photo(self, monkeypatch, bot, super_group_id, chat_photo):
|
||||
async def test_send_with_chat_photo(
|
||||
self, monkeypatch, offline_bot, super_group_id, chat_photo
|
||||
):
|
||||
async def make_assertion(url, request_data: RequestData, *args, **kwargs):
|
||||
return request_data.parameters["photo"] == chat_photo.to_dict()
|
||||
|
||||
monkeypatch.setattr(bot.request, "post", make_assertion)
|
||||
message = await bot.set_chat_photo(photo=chat_photo, chat_id=super_group_id)
|
||||
monkeypatch.setattr(offline_bot.request, "post", make_assertion)
|
||||
message = await offline_bot.set_chat_photo(photo=chat_photo, chat_id=super_group_id)
|
||||
assert message
|
||||
|
||||
async def test_get_small_file_instance_method(self, monkeypatch, chat_photo):
|
||||
|
||||
@@ -32,42 +32,42 @@ from tests.auxil.slots import mro_slots
|
||||
@pytest.fixture(scope="module")
|
||||
def contact():
|
||||
return Contact(
|
||||
TestContactBase.phone_number,
|
||||
TestContactBase.first_name,
|
||||
TestContactBase.last_name,
|
||||
TestContactBase.user_id,
|
||||
ContactTestBase.phone_number,
|
||||
ContactTestBase.first_name,
|
||||
ContactTestBase.last_name,
|
||||
ContactTestBase.user_id,
|
||||
)
|
||||
|
||||
|
||||
class TestContactBase:
|
||||
class ContactTestBase:
|
||||
phone_number = "+11234567890"
|
||||
first_name = "Leandro"
|
||||
last_name = "Toledo"
|
||||
user_id = 23
|
||||
|
||||
|
||||
class TestContactWithoutRequest(TestContactBase):
|
||||
class TestContactWithoutRequest(ContactTestBase):
|
||||
def test_slot_behaviour(self, contact):
|
||||
for attr in contact.__slots__:
|
||||
assert getattr(contact, attr, "err") != "err", f"got extra slot '{attr}'"
|
||||
assert len(mro_slots(contact)) == len(set(mro_slots(contact))), "duplicate slot"
|
||||
|
||||
def test_de_json_required(self, bot):
|
||||
def test_de_json_required(self, offline_bot):
|
||||
json_dict = {"phone_number": self.phone_number, "first_name": self.first_name}
|
||||
contact = Contact.de_json(json_dict, bot)
|
||||
contact = Contact.de_json(json_dict, offline_bot)
|
||||
assert contact.api_kwargs == {}
|
||||
|
||||
assert contact.phone_number == self.phone_number
|
||||
assert contact.first_name == self.first_name
|
||||
|
||||
def test_de_json_all(self, bot):
|
||||
def test_de_json_all(self, offline_bot):
|
||||
json_dict = {
|
||||
"phone_number": self.phone_number,
|
||||
"first_name": self.first_name,
|
||||
"last_name": self.last_name,
|
||||
"user_id": self.user_id,
|
||||
}
|
||||
contact = Contact.de_json(json_dict, bot)
|
||||
contact = Contact.de_json(json_dict, offline_bot)
|
||||
assert contact.api_kwargs == {}
|
||||
|
||||
assert contact.phone_number == self.phone_number
|
||||
@@ -104,20 +104,20 @@ class TestContactWithoutRequest(TestContactBase):
|
||||
assert a != e
|
||||
assert hash(a) != hash(e)
|
||||
|
||||
async def test_send_contact_without_required(self, bot, chat_id):
|
||||
async def test_send_contact_without_required(self, offline_bot, chat_id):
|
||||
with pytest.raises(ValueError, match="Either contact or phone_number and first_name"):
|
||||
await bot.send_contact(chat_id=chat_id)
|
||||
await offline_bot.send_contact(chat_id=chat_id)
|
||||
|
||||
async def test_send_mutually_exclusive(self, bot, chat_id, contact):
|
||||
async def test_send_mutually_exclusive(self, offline_bot, chat_id, contact):
|
||||
with pytest.raises(ValueError, match="Not both"):
|
||||
await bot.send_contact(
|
||||
await offline_bot.send_contact(
|
||||
chat_id=chat_id,
|
||||
contact=contact,
|
||||
phone_number=contact.phone_number,
|
||||
first_name=contact.first_name,
|
||||
)
|
||||
|
||||
async def test_send_with_contact(self, monkeypatch, bot, chat_id, contact):
|
||||
async def test_send_with_contact(self, monkeypatch, offline_bot, chat_id, contact):
|
||||
async def make_assertion(url, request_data: RequestData, *args, **kwargs):
|
||||
data = request_data.json_parameters
|
||||
phone = data["phone_number"] == contact.phone_number
|
||||
@@ -125,8 +125,8 @@ class TestContactWithoutRequest(TestContactBase):
|
||||
last = data["last_name"] == contact.last_name
|
||||
return phone and first and last
|
||||
|
||||
monkeypatch.setattr(bot.request, "post", make_assertion)
|
||||
assert await bot.send_contact(contact=contact, chat_id=chat_id)
|
||||
monkeypatch.setattr(offline_bot.request, "post", make_assertion)
|
||||
assert await offline_bot.send_contact(contact=contact, chat_id=chat_id)
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
("default_bot", "custom"),
|
||||
@@ -156,7 +156,7 @@ class TestContactWithoutRequest(TestContactBase):
|
||||
)
|
||||
|
||||
|
||||
class TestContactWithRequest(TestContactBase):
|
||||
class TestContactWithRequest(ContactTestBase):
|
||||
@pytest.mark.parametrize(
|
||||
("default_bot", "custom"),
|
||||
[
|
||||
|
||||
@@ -49,7 +49,7 @@ async def document(bot, chat_id):
|
||||
return (await bot.send_document(chat_id, document=f, read_timeout=50)).document
|
||||
|
||||
|
||||
class TestDocumentBase:
|
||||
class DocumentTestBase:
|
||||
caption = "DocumentTest - *Caption*"
|
||||
document_file_url = "https://python-telegram-bot.org/static/testfiles/telegram.gif"
|
||||
file_size = 12948
|
||||
@@ -62,7 +62,7 @@ class TestDocumentBase:
|
||||
document_file_unique_id = "adc3145fd2e84d95b64d68eaa22aa33e"
|
||||
|
||||
|
||||
class TestDocumentWithoutRequest(TestDocumentBase):
|
||||
class TestDocumentWithoutRequest(DocumentTestBase):
|
||||
def test_slot_behaviour(self, document):
|
||||
for attr in document.__slots__:
|
||||
assert getattr(document, attr, "err") != "err", f"got extra slot '{attr}'"
|
||||
@@ -83,7 +83,7 @@ class TestDocumentWithoutRequest(TestDocumentBase):
|
||||
assert document.thumbnail.width == self.thumb_width
|
||||
assert document.thumbnail.height == self.thumb_height
|
||||
|
||||
def test_de_json(self, bot, document):
|
||||
def test_de_json(self, offline_bot, document):
|
||||
json_dict = {
|
||||
"file_id": self.document_file_id,
|
||||
"file_unique_id": self.document_file_unique_id,
|
||||
@@ -92,7 +92,7 @@ class TestDocumentWithoutRequest(TestDocumentBase):
|
||||
"mime_type": self.mime_type,
|
||||
"file_size": self.file_size,
|
||||
}
|
||||
test_document = Document.de_json(json_dict, bot)
|
||||
test_document = Document.de_json(json_dict, offline_bot)
|
||||
assert test_document.api_kwargs == {}
|
||||
|
||||
assert test_document.file_id == self.document_file_id
|
||||
@@ -128,13 +128,13 @@ class TestDocumentWithoutRequest(TestDocumentBase):
|
||||
assert a != e
|
||||
assert hash(a) != hash(e)
|
||||
|
||||
async def test_error_send_without_required_args(self, bot, chat_id):
|
||||
async def test_error_send_without_required_args(self, offline_bot, chat_id):
|
||||
with pytest.raises(TypeError):
|
||||
await bot.send_document(chat_id=chat_id)
|
||||
await offline_bot.send_document(chat_id=chat_id)
|
||||
|
||||
@pytest.mark.parametrize("disable_content_type_detection", [True, False, None])
|
||||
async def test_send_with_document(
|
||||
self, monkeypatch, bot, chat_id, document, disable_content_type_detection
|
||||
self, monkeypatch, offline_bot, chat_id, document, disable_content_type_detection
|
||||
):
|
||||
async def make_assertion(url, request_data: RequestData, *args, **kwargs):
|
||||
data = request_data.parameters
|
||||
@@ -143,9 +143,9 @@ class TestDocumentWithoutRequest(TestDocumentBase):
|
||||
)
|
||||
return data["document"] == document.file_id and type_detection
|
||||
|
||||
monkeypatch.setattr(bot.request, "post", make_assertion)
|
||||
monkeypatch.setattr(offline_bot.request, "post", make_assertion)
|
||||
|
||||
message = await bot.send_document(
|
||||
message = await offline_bot.send_document(
|
||||
document=document,
|
||||
chat_id=chat_id,
|
||||
disable_content_type_detection=disable_content_type_detection,
|
||||
@@ -181,10 +181,10 @@ class TestDocumentWithoutRequest(TestDocumentBase):
|
||||
)
|
||||
|
||||
@pytest.mark.parametrize("local_mode", [True, False])
|
||||
async def test_send_document_local_files(self, monkeypatch, bot, chat_id, local_mode):
|
||||
async def test_send_document_local_files(self, monkeypatch, offline_bot, chat_id, local_mode):
|
||||
try:
|
||||
bot._local_mode = local_mode
|
||||
# For just test that the correct paths are passed as we have no local bot API set up
|
||||
offline_bot._local_mode = local_mode
|
||||
# For just test that the correct paths are passed as we have no local Bot API set up
|
||||
test_flag = False
|
||||
file = data_file("telegram.jpg")
|
||||
expected = file.as_uri()
|
||||
@@ -200,11 +200,11 @@ class TestDocumentWithoutRequest(TestDocumentBase):
|
||||
data.get("thumbnail"), InputFile
|
||||
)
|
||||
|
||||
monkeypatch.setattr(bot, "_post", make_assertion)
|
||||
await bot.send_document(chat_id, file, thumbnail=file)
|
||||
monkeypatch.setattr(offline_bot, "_post", make_assertion)
|
||||
await offline_bot.send_document(chat_id, file, thumbnail=file)
|
||||
assert test_flag
|
||||
finally:
|
||||
bot._local_mode = False
|
||||
offline_bot._local_mode = False
|
||||
|
||||
async def test_get_file_instance_method(self, monkeypatch, document):
|
||||
async def make_assertion(*_, **kwargs):
|
||||
@@ -218,7 +218,7 @@ class TestDocumentWithoutRequest(TestDocumentBase):
|
||||
assert await document.get_file()
|
||||
|
||||
|
||||
class TestDocumentWithRequest(TestDocumentBase):
|
||||
class TestDocumentWithRequest(DocumentTestBase):
|
||||
async def test_error_send_empty_file(self, bot, chat_id):
|
||||
with Path(os.devnull).open("rb") as f, pytest.raises(TelegramError):
|
||||
await bot.send_document(chat_id=chat_id, document=f)
|
||||
|
||||
+24
-24
@@ -31,10 +31,10 @@ from tests.auxil.slots import mro_slots
|
||||
@pytest.fixture(scope="module")
|
||||
def file(bot):
|
||||
file = File(
|
||||
TestFileBase.file_id,
|
||||
TestFileBase.file_unique_id,
|
||||
file_path=TestFileBase.file_path,
|
||||
file_size=TestFileBase.file_size,
|
||||
FileTestBase.file_id,
|
||||
FileTestBase.file_unique_id,
|
||||
file_path=FileTestBase.file_path,
|
||||
file_size=FileTestBase.file_size,
|
||||
)
|
||||
file.set_bot(bot)
|
||||
file._unfreeze()
|
||||
@@ -51,10 +51,10 @@ def encrypted_file(bot):
|
||||
"Pt7fKPgYWKA/7a8E64Ea1X8C+Wf7Ky1tF4ANBl63vl4=",
|
||||
)
|
||||
ef = File(
|
||||
TestFileBase.file_id,
|
||||
TestFileBase.file_unique_id,
|
||||
TestFileBase.file_size,
|
||||
TestFileBase.file_path,
|
||||
FileTestBase.file_id,
|
||||
FileTestBase.file_unique_id,
|
||||
FileTestBase.file_size,
|
||||
FileTestBase.file_path,
|
||||
)
|
||||
ef.set_bot(bot)
|
||||
ef.set_credentials(fc)
|
||||
@@ -69,9 +69,9 @@ def encrypted_local_file(bot):
|
||||
"Pt7fKPgYWKA/7a8E64Ea1X8C+Wf7Ky1tF4ANBl63vl4=",
|
||||
)
|
||||
ef = File(
|
||||
TestFileBase.file_id,
|
||||
TestFileBase.file_unique_id,
|
||||
TestFileBase.file_size,
|
||||
FileTestBase.file_id,
|
||||
FileTestBase.file_unique_id,
|
||||
FileTestBase.file_size,
|
||||
file_path=str(data_file("image_encrypted.jpg")),
|
||||
)
|
||||
ef.set_bot(bot)
|
||||
@@ -82,16 +82,16 @@ def encrypted_local_file(bot):
|
||||
@pytest.fixture(scope="module")
|
||||
def local_file(bot):
|
||||
file = File(
|
||||
TestFileBase.file_id,
|
||||
TestFileBase.file_unique_id,
|
||||
FileTestBase.file_id,
|
||||
FileTestBase.file_unique_id,
|
||||
file_path=str(data_file("local_file.txt")),
|
||||
file_size=TestFileBase.file_size,
|
||||
file_size=FileTestBase.file_size,
|
||||
)
|
||||
file.set_bot(bot)
|
||||
return file
|
||||
|
||||
|
||||
class TestFileBase:
|
||||
class FileTestBase:
|
||||
file_id = "NOTVALIDDOESNOTMATTER"
|
||||
file_unique_id = "adc3145fd2e84d95b64d68eaa22aa33e"
|
||||
file_path = (
|
||||
@@ -101,20 +101,20 @@ class TestFileBase:
|
||||
file_content = "Saint-Saëns".encode() # Intentionally contains unicode chars.
|
||||
|
||||
|
||||
class TestFileWithoutRequest(TestFileBase):
|
||||
class TestFileWithoutRequest(FileTestBase):
|
||||
def test_slot_behaviour(self, file):
|
||||
for attr in file.__slots__:
|
||||
assert getattr(file, attr, "err") != "err", f"got extra slot '{attr}'"
|
||||
assert len(mro_slots(file)) == len(set(mro_slots(file))), "duplicate slot"
|
||||
|
||||
def test_de_json(self, bot):
|
||||
def test_de_json(self, offline_bot):
|
||||
json_dict = {
|
||||
"file_id": self.file_id,
|
||||
"file_unique_id": self.file_unique_id,
|
||||
"file_path": self.file_path,
|
||||
"file_size": self.file_size,
|
||||
}
|
||||
new_file = File.de_json(json_dict, bot)
|
||||
new_file = File.de_json(json_dict, offline_bot)
|
||||
assert new_file.api_kwargs == {}
|
||||
|
||||
assert new_file.file_id == self.file_id
|
||||
@@ -131,11 +131,11 @@ class TestFileWithoutRequest(TestFileBase):
|
||||
assert file_dict["file_path"] == file.file_path
|
||||
assert file_dict["file_size"] == file.file_size
|
||||
|
||||
def test_equality(self, bot):
|
||||
a = File(self.file_id, self.file_unique_id, bot)
|
||||
b = File("", self.file_unique_id, bot)
|
||||
def test_equality(self, offline_bot):
|
||||
a = File(self.file_id, self.file_unique_id, offline_bot)
|
||||
b = File("", self.file_unique_id, offline_bot)
|
||||
c = File(self.file_id, self.file_unique_id, None)
|
||||
d = File("", "", bot)
|
||||
d = File("", "", offline_bot)
|
||||
e = Voice(self.file_id, self.file_unique_id, 0)
|
||||
|
||||
assert a == b
|
||||
@@ -223,7 +223,7 @@ class TestFileWithoutRequest(TestFileBase):
|
||||
assert buf2[len(buf) :] == buf
|
||||
assert buf2[: len(buf)] == buf
|
||||
|
||||
async def test_download_encrypted(self, monkeypatch, bot, encrypted_file):
|
||||
async def test_download_encrypted(self, monkeypatch, offline_bot, encrypted_file):
|
||||
async def test(*args, **kwargs):
|
||||
return data_file("image_encrypted.jpg").read_bytes()
|
||||
|
||||
@@ -273,7 +273,7 @@ class TestFileWithoutRequest(TestFileBase):
|
||||
assert buf2[: len(buf)] == buf
|
||||
|
||||
|
||||
class TestFileWithRequest(TestFileBase):
|
||||
class TestFileWithRequest(FileTestBase):
|
||||
async def test_error_get_empty_file_id(self, bot):
|
||||
with pytest.raises(TelegramError):
|
||||
await bot.get_file(file_id="")
|
||||
|
||||
@@ -68,94 +68,94 @@ from .test_video import video, video_file # noqa: F401
|
||||
@pytest.fixture(scope="module")
|
||||
def input_media_video(class_thumb_file):
|
||||
return InputMediaVideo(
|
||||
media=TestInputMediaVideoBase.media,
|
||||
caption=TestInputMediaVideoBase.caption,
|
||||
width=TestInputMediaVideoBase.width,
|
||||
height=TestInputMediaVideoBase.height,
|
||||
duration=TestInputMediaVideoBase.duration,
|
||||
parse_mode=TestInputMediaVideoBase.parse_mode,
|
||||
caption_entities=TestInputMediaVideoBase.caption_entities,
|
||||
media=InputMediaVideoTestBase.media,
|
||||
caption=InputMediaVideoTestBase.caption,
|
||||
width=InputMediaVideoTestBase.width,
|
||||
height=InputMediaVideoTestBase.height,
|
||||
duration=InputMediaVideoTestBase.duration,
|
||||
parse_mode=InputMediaVideoTestBase.parse_mode,
|
||||
caption_entities=InputMediaVideoTestBase.caption_entities,
|
||||
thumbnail=class_thumb_file,
|
||||
supports_streaming=TestInputMediaVideoBase.supports_streaming,
|
||||
has_spoiler=TestInputMediaVideoBase.has_spoiler,
|
||||
show_caption_above_media=TestInputMediaVideoBase.show_caption_above_media,
|
||||
supports_streaming=InputMediaVideoTestBase.supports_streaming,
|
||||
has_spoiler=InputMediaVideoTestBase.has_spoiler,
|
||||
show_caption_above_media=InputMediaVideoTestBase.show_caption_above_media,
|
||||
)
|
||||
|
||||
|
||||
@pytest.fixture(scope="module")
|
||||
def input_media_photo():
|
||||
return InputMediaPhoto(
|
||||
media=TestInputMediaPhotoBase.media,
|
||||
caption=TestInputMediaPhotoBase.caption,
|
||||
parse_mode=TestInputMediaPhotoBase.parse_mode,
|
||||
caption_entities=TestInputMediaPhotoBase.caption_entities,
|
||||
has_spoiler=TestInputMediaPhotoBase.has_spoiler,
|
||||
show_caption_above_media=TestInputMediaPhotoBase.show_caption_above_media,
|
||||
media=InputMediaPhotoTestBase.media,
|
||||
caption=InputMediaPhotoTestBase.caption,
|
||||
parse_mode=InputMediaPhotoTestBase.parse_mode,
|
||||
caption_entities=InputMediaPhotoTestBase.caption_entities,
|
||||
has_spoiler=InputMediaPhotoTestBase.has_spoiler,
|
||||
show_caption_above_media=InputMediaPhotoTestBase.show_caption_above_media,
|
||||
)
|
||||
|
||||
|
||||
@pytest.fixture(scope="module")
|
||||
def input_media_animation(class_thumb_file):
|
||||
return InputMediaAnimation(
|
||||
media=TestInputMediaAnimationBase.media,
|
||||
caption=TestInputMediaAnimationBase.caption,
|
||||
parse_mode=TestInputMediaAnimationBase.parse_mode,
|
||||
caption_entities=TestInputMediaAnimationBase.caption_entities,
|
||||
width=TestInputMediaAnimationBase.width,
|
||||
height=TestInputMediaAnimationBase.height,
|
||||
media=InputMediaAnimationTestBase.media,
|
||||
caption=InputMediaAnimationTestBase.caption,
|
||||
parse_mode=InputMediaAnimationTestBase.parse_mode,
|
||||
caption_entities=InputMediaAnimationTestBase.caption_entities,
|
||||
width=InputMediaAnimationTestBase.width,
|
||||
height=InputMediaAnimationTestBase.height,
|
||||
thumbnail=class_thumb_file,
|
||||
duration=TestInputMediaAnimationBase.duration,
|
||||
has_spoiler=TestInputMediaAnimationBase.has_spoiler,
|
||||
show_caption_above_media=TestInputMediaAnimationBase.show_caption_above_media,
|
||||
duration=InputMediaAnimationTestBase.duration,
|
||||
has_spoiler=InputMediaAnimationTestBase.has_spoiler,
|
||||
show_caption_above_media=InputMediaAnimationTestBase.show_caption_above_media,
|
||||
)
|
||||
|
||||
|
||||
@pytest.fixture(scope="module")
|
||||
def input_media_audio(class_thumb_file):
|
||||
return InputMediaAudio(
|
||||
media=TestInputMediaAudioBase.media,
|
||||
caption=TestInputMediaAudioBase.caption,
|
||||
duration=TestInputMediaAudioBase.duration,
|
||||
performer=TestInputMediaAudioBase.performer,
|
||||
title=TestInputMediaAudioBase.title,
|
||||
media=InputMediaAudioTestBase.media,
|
||||
caption=InputMediaAudioTestBase.caption,
|
||||
duration=InputMediaAudioTestBase.duration,
|
||||
performer=InputMediaAudioTestBase.performer,
|
||||
title=InputMediaAudioTestBase.title,
|
||||
thumbnail=class_thumb_file,
|
||||
parse_mode=TestInputMediaAudioBase.parse_mode,
|
||||
caption_entities=TestInputMediaAudioBase.caption_entities,
|
||||
parse_mode=InputMediaAudioTestBase.parse_mode,
|
||||
caption_entities=InputMediaAudioTestBase.caption_entities,
|
||||
)
|
||||
|
||||
|
||||
@pytest.fixture(scope="module")
|
||||
def input_media_document(class_thumb_file):
|
||||
return InputMediaDocument(
|
||||
media=TestInputMediaDocumentBase.media,
|
||||
caption=TestInputMediaDocumentBase.caption,
|
||||
media=InputMediaDocumentTestBase.media,
|
||||
caption=InputMediaDocumentTestBase.caption,
|
||||
thumbnail=class_thumb_file,
|
||||
parse_mode=TestInputMediaDocumentBase.parse_mode,
|
||||
caption_entities=TestInputMediaDocumentBase.caption_entities,
|
||||
disable_content_type_detection=TestInputMediaDocumentBase.disable_content_type_detection,
|
||||
parse_mode=InputMediaDocumentTestBase.parse_mode,
|
||||
caption_entities=InputMediaDocumentTestBase.caption_entities,
|
||||
disable_content_type_detection=InputMediaDocumentTestBase.disable_content_type_detection,
|
||||
)
|
||||
|
||||
|
||||
@pytest.fixture(scope="module")
|
||||
def input_paid_media_photo():
|
||||
return InputPaidMediaPhoto(
|
||||
media=TestInputMediaPhotoBase.media,
|
||||
media=InputMediaPhotoTestBase.media,
|
||||
)
|
||||
|
||||
|
||||
@pytest.fixture(scope="module")
|
||||
def input_paid_media_video(class_thumb_file):
|
||||
return InputPaidMediaVideo(
|
||||
media=TestInputMediaVideoBase.media,
|
||||
media=InputMediaVideoTestBase.media,
|
||||
thumbnail=class_thumb_file,
|
||||
width=TestInputMediaVideoBase.width,
|
||||
height=TestInputMediaVideoBase.height,
|
||||
duration=TestInputMediaVideoBase.duration,
|
||||
supports_streaming=TestInputMediaVideoBase.supports_streaming,
|
||||
width=InputMediaVideoTestBase.width,
|
||||
height=InputMediaVideoTestBase.height,
|
||||
duration=InputMediaVideoTestBase.duration,
|
||||
supports_streaming=InputMediaVideoTestBase.supports_streaming,
|
||||
)
|
||||
|
||||
|
||||
class TestInputMediaVideoBase:
|
||||
class InputMediaVideoTestBase:
|
||||
type_ = "video"
|
||||
media = "NOTAREALFILEID"
|
||||
caption = "My Caption"
|
||||
@@ -169,7 +169,7 @@ class TestInputMediaVideoBase:
|
||||
show_caption_above_media = True
|
||||
|
||||
|
||||
class TestInputMediaVideoWithoutRequest(TestInputMediaVideoBase):
|
||||
class TestInputMediaVideoWithoutRequest(InputMediaVideoTestBase):
|
||||
def test_slot_behaviour(self, input_media_video):
|
||||
inst = input_media_video
|
||||
for attr in inst.__slots__:
|
||||
@@ -258,7 +258,7 @@ class TestInputMediaVideoWithoutRequest(TestInputMediaVideoBase):
|
||||
)
|
||||
|
||||
|
||||
class TestInputMediaPhotoBase:
|
||||
class InputMediaPhotoTestBase:
|
||||
type_ = "photo"
|
||||
media = "NOTAREALFILEID"
|
||||
caption = "My Caption"
|
||||
@@ -268,7 +268,7 @@ class TestInputMediaPhotoBase:
|
||||
show_caption_above_media = True
|
||||
|
||||
|
||||
class TestInputMediaPhotoWithoutRequest(TestInputMediaPhotoBase):
|
||||
class TestInputMediaPhotoWithoutRequest(InputMediaPhotoTestBase):
|
||||
def test_slot_behaviour(self, input_media_photo):
|
||||
inst = input_media_photo
|
||||
for attr in inst.__slots__:
|
||||
@@ -322,7 +322,7 @@ class TestInputMediaPhotoWithoutRequest(TestInputMediaPhotoBase):
|
||||
assert input_media_photo.media == data_file("telegram.mp4").as_uri()
|
||||
|
||||
|
||||
class TestInputMediaAnimationBase:
|
||||
class InputMediaAnimationTestBase:
|
||||
type_ = "animation"
|
||||
media = "NOTAREALFILEID"
|
||||
caption = "My Caption"
|
||||
@@ -335,7 +335,7 @@ class TestInputMediaAnimationBase:
|
||||
show_caption_above_media = True
|
||||
|
||||
|
||||
class TestInputMediaAnimationWithoutRequest(TestInputMediaAnimationBase):
|
||||
class TestInputMediaAnimationWithoutRequest(InputMediaAnimationTestBase):
|
||||
def test_slot_behaviour(self, input_media_animation):
|
||||
inst = input_media_animation
|
||||
for attr in inst.__slots__:
|
||||
@@ -396,7 +396,7 @@ class TestInputMediaAnimationWithoutRequest(TestInputMediaAnimationBase):
|
||||
assert input_media_animation.thumbnail == data_file("telegram.jpg").as_uri()
|
||||
|
||||
|
||||
class TestInputMediaAudioBase:
|
||||
class InputMediaAudioTestBase:
|
||||
type_ = "audio"
|
||||
media = "NOTAREALFILEID"
|
||||
caption = "My Caption"
|
||||
@@ -407,7 +407,7 @@ class TestInputMediaAudioBase:
|
||||
caption_entities = [MessageEntity(MessageEntity.BOLD, 0, 2)]
|
||||
|
||||
|
||||
class TestInputMediaAudioWithoutRequest(TestInputMediaAudioBase):
|
||||
class TestInputMediaAudioWithoutRequest(InputMediaAudioTestBase):
|
||||
def test_slot_behaviour(self, input_media_audio):
|
||||
inst = input_media_audio
|
||||
for attr in inst.__slots__:
|
||||
@@ -467,7 +467,7 @@ class TestInputMediaAudioWithoutRequest(TestInputMediaAudioBase):
|
||||
assert input_media_audio.thumbnail == data_file("telegram.jpg").as_uri()
|
||||
|
||||
|
||||
class TestInputMediaDocumentBase:
|
||||
class InputMediaDocumentTestBase:
|
||||
type_ = "document"
|
||||
media = "NOTAREALFILEID"
|
||||
caption = "My Caption"
|
||||
@@ -476,7 +476,7 @@ class TestInputMediaDocumentBase:
|
||||
disable_content_type_detection = True
|
||||
|
||||
|
||||
class TestInputMediaDocumentWithoutRequest(TestInputMediaDocumentBase):
|
||||
class TestInputMediaDocumentWithoutRequest(InputMediaDocumentTestBase):
|
||||
def test_slot_behaviour(self, input_media_document):
|
||||
inst = input_media_document
|
||||
for attr in inst.__slots__:
|
||||
@@ -535,7 +535,7 @@ class TestInputMediaDocumentWithoutRequest(TestInputMediaDocumentBase):
|
||||
assert input_media_document.thumbnail == data_file("telegram.jpg").as_uri()
|
||||
|
||||
|
||||
class TestInputPaidMediaPhotoWithoutRequest(TestInputMediaPhotoBase):
|
||||
class TestInputPaidMediaPhotoWithoutRequest(InputMediaPhotoTestBase):
|
||||
def test_slot_behaviour(self, input_paid_media_photo):
|
||||
inst = input_paid_media_photo
|
||||
for attr in inst.__slots__:
|
||||
@@ -568,7 +568,7 @@ class TestInputPaidMediaPhotoWithoutRequest(TestInputMediaPhotoBase):
|
||||
assert input_paid_media_photo.media == data_file("telegram.jpg").as_uri()
|
||||
|
||||
|
||||
class TestInputPaidMediaVideoWithoutRequest(TestInputMediaVideoBase):
|
||||
class TestInputPaidMediaVideoWithoutRequest(InputMediaVideoTestBase):
|
||||
def test_slot_behaviour(self, input_paid_media_video):
|
||||
inst = input_paid_media_video
|
||||
for attr in inst.__slots__:
|
||||
@@ -655,7 +655,7 @@ def media_group_no_caption_only_parse_mode(photo, thumb): # noqa: F811
|
||||
class TestSendMediaGroupWithoutRequest:
|
||||
async def test_send_media_group_throws_error_with_group_caption_and_individual_captions(
|
||||
self,
|
||||
bot,
|
||||
offline_bot,
|
||||
chat_id,
|
||||
media_group,
|
||||
media_group_no_caption_only_caption_entities,
|
||||
@@ -670,11 +670,11 @@ class TestSendMediaGroupWithoutRequest:
|
||||
ValueError,
|
||||
match="You can only supply either group caption or media with captions.",
|
||||
):
|
||||
await bot.send_media_group(chat_id, group, caption="foo")
|
||||
await offline_bot.send_media_group(chat_id, group, caption="foo")
|
||||
|
||||
async def test_send_media_group_custom_filename(
|
||||
self,
|
||||
bot,
|
||||
offline_bot,
|
||||
chat_id,
|
||||
photo_file, # noqa: F811
|
||||
animation_file, # noqa: F811
|
||||
@@ -690,7 +690,7 @@ class TestSendMediaGroupWithoutRequest:
|
||||
if result is True:
|
||||
raise Exception("Test was successful")
|
||||
|
||||
monkeypatch.setattr(bot.request, "post", make_assertion)
|
||||
monkeypatch.setattr(offline_bot.request, "post", make_assertion)
|
||||
|
||||
media = [
|
||||
InputMediaAnimation(animation_file, filename="custom_filename"),
|
||||
@@ -700,10 +700,10 @@ class TestSendMediaGroupWithoutRequest:
|
||||
]
|
||||
|
||||
with pytest.raises(Exception, match="Test was successful"):
|
||||
await bot.send_media_group(chat_id, media)
|
||||
await offline_bot.send_media_group(chat_id, media)
|
||||
|
||||
async def test_send_media_group_with_thumbs(
|
||||
self, bot, chat_id, video_file, photo_file, monkeypatch # noqa: F811
|
||||
self, offline_bot, chat_id, video_file, photo_file, monkeypatch # noqa: F811
|
||||
):
|
||||
async def make_assertion(method, url, request_data: RequestData, *args, **kwargs):
|
||||
nonlocal input_video
|
||||
@@ -715,13 +715,13 @@ class TestSendMediaGroupWithoutRequest:
|
||||
result = video_check and thumb_check
|
||||
raise Exception(f"Test was {'successful' if result else 'failing'}")
|
||||
|
||||
monkeypatch.setattr(bot.request, "_request_wrapper", make_assertion)
|
||||
monkeypatch.setattr(offline_bot.request, "_request_wrapper", make_assertion)
|
||||
input_video = InputMediaVideo(video_file, thumbnail=photo_file)
|
||||
with pytest.raises(Exception, match="Test was successful"):
|
||||
await bot.send_media_group(chat_id, [input_video, input_video])
|
||||
await offline_bot.send_media_group(chat_id, [input_video, input_video])
|
||||
|
||||
async def test_edit_message_media_with_thumb(
|
||||
self, bot, chat_id, video_file, photo_file, monkeypatch # noqa: F811
|
||||
self, offline_bot, chat_id, video_file, photo_file, monkeypatch # noqa: F811
|
||||
):
|
||||
async def make_assertion(
|
||||
method: str, url: str, request_data: Optional[RequestData] = None, *args, **kwargs
|
||||
@@ -734,10 +734,12 @@ class TestSendMediaGroupWithoutRequest:
|
||||
result = video_check and thumb_check
|
||||
raise Exception(f"Test was {'successful' if result else 'failing'}")
|
||||
|
||||
monkeypatch.setattr(bot.request, "_request_wrapper", make_assertion)
|
||||
monkeypatch.setattr(offline_bot.request, "_request_wrapper", make_assertion)
|
||||
input_video = InputMediaVideo(video_file, thumbnail=photo_file)
|
||||
with pytest.raises(Exception, match="Test was successful"):
|
||||
await bot.edit_message_media(chat_id=chat_id, message_id=123, media=input_video)
|
||||
await offline_bot.edit_message_media(
|
||||
chat_id=chat_id, message_id=123, media=input_video
|
||||
)
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
("default_bot", "custom"),
|
||||
|
||||
@@ -29,15 +29,15 @@ from tests.auxil.slots import mro_slots
|
||||
@pytest.fixture(scope="module")
|
||||
def input_sticker():
|
||||
return InputSticker(
|
||||
sticker=TestInputStickerBase.sticker,
|
||||
emoji_list=TestInputStickerBase.emoji_list,
|
||||
mask_position=TestInputStickerBase.mask_position,
|
||||
keywords=TestInputStickerBase.keywords,
|
||||
format=TestInputStickerBase.format,
|
||||
sticker=InputStickerTestBase.sticker,
|
||||
emoji_list=InputStickerTestBase.emoji_list,
|
||||
mask_position=InputStickerTestBase.mask_position,
|
||||
keywords=InputStickerTestBase.keywords,
|
||||
format=InputStickerTestBase.format,
|
||||
)
|
||||
|
||||
|
||||
class TestInputStickerBase:
|
||||
class InputStickerTestBase:
|
||||
sticker = "fake_file_id"
|
||||
emoji_list = ("👍", "👎")
|
||||
mask_position = MaskPosition("forehead", 0.5, 0.5, 0.5)
|
||||
@@ -45,7 +45,7 @@ class TestInputStickerBase:
|
||||
format = "static"
|
||||
|
||||
|
||||
class TestInputStickerWithoutRequest(TestInputStickerBase):
|
||||
class TestInputStickerWithoutRequest(InputStickerTestBase):
|
||||
def test_slot_behaviour(self, input_sticker):
|
||||
inst = input_sticker
|
||||
for attr in inst.__slots__:
|
||||
|
||||
@@ -31,16 +31,16 @@ from tests.auxil.slots import mro_slots
|
||||
@pytest.fixture(scope="module")
|
||||
def location():
|
||||
return Location(
|
||||
latitude=TestLocationBase.latitude,
|
||||
longitude=TestLocationBase.longitude,
|
||||
horizontal_accuracy=TestLocationBase.horizontal_accuracy,
|
||||
live_period=TestLocationBase.live_period,
|
||||
heading=TestLocationBase.live_period,
|
||||
proximity_alert_radius=TestLocationBase.proximity_alert_radius,
|
||||
latitude=LocationTestBase.latitude,
|
||||
longitude=LocationTestBase.longitude,
|
||||
horizontal_accuracy=LocationTestBase.horizontal_accuracy,
|
||||
live_period=LocationTestBase.live_period,
|
||||
heading=LocationTestBase.live_period,
|
||||
proximity_alert_radius=LocationTestBase.proximity_alert_radius,
|
||||
)
|
||||
|
||||
|
||||
class TestLocationBase:
|
||||
class LocationTestBase:
|
||||
latitude = -23.691288
|
||||
longitude = -46.788279
|
||||
horizontal_accuracy = 999
|
||||
@@ -49,13 +49,13 @@ class TestLocationBase:
|
||||
proximity_alert_radius = 50
|
||||
|
||||
|
||||
class TestLocationWithoutRequest(TestLocationBase):
|
||||
class TestLocationWithoutRequest(LocationTestBase):
|
||||
def test_slot_behaviour(self, location):
|
||||
for attr in location.__slots__:
|
||||
assert getattr(location, attr, "err") != "err", f"got extra slot '{attr}'"
|
||||
assert len(mro_slots(location)) == len(set(mro_slots(location))), "duplicate slot"
|
||||
|
||||
def test_de_json(self, bot):
|
||||
def test_de_json(self, offline_bot):
|
||||
json_dict = {
|
||||
"latitude": self.latitude,
|
||||
"longitude": self.longitude,
|
||||
@@ -64,7 +64,7 @@ class TestLocationWithoutRequest(TestLocationBase):
|
||||
"heading": self.heading,
|
||||
"proximity_alert_radius": self.proximity_alert_radius,
|
||||
}
|
||||
location = Location.de_json(json_dict, bot)
|
||||
location = Location.de_json(json_dict, offline_bot)
|
||||
assert location.api_kwargs == {}
|
||||
|
||||
assert location.latitude == self.latitude
|
||||
@@ -96,26 +96,28 @@ class TestLocationWithoutRequest(TestLocationBase):
|
||||
assert a != d
|
||||
assert hash(a) != hash(d)
|
||||
|
||||
async def test_send_location_without_required(self, bot, chat_id):
|
||||
async def test_send_location_without_required(self, offline_bot, chat_id):
|
||||
with pytest.raises(ValueError, match="Either location or latitude and longitude"):
|
||||
await bot.send_location(chat_id=chat_id)
|
||||
await offline_bot.send_location(chat_id=chat_id)
|
||||
|
||||
async def test_edit_location_without_required(self, bot):
|
||||
async def test_edit_location_without_required(self, offline_bot):
|
||||
with pytest.raises(ValueError, match="Either location or latitude and longitude"):
|
||||
await bot.edit_message_live_location(chat_id=2, message_id=3)
|
||||
await offline_bot.edit_message_live_location(chat_id=2, message_id=3)
|
||||
|
||||
async def test_send_location_with_all_args(self, bot, location):
|
||||
async def test_send_location_with_all_args(self, offline_bot, location):
|
||||
with pytest.raises(ValueError, match="Not both"):
|
||||
await bot.send_location(chat_id=1, latitude=2.5, longitude=4.6, location=location)
|
||||
await offline_bot.send_location(
|
||||
chat_id=1, latitude=2.5, longitude=4.6, location=location
|
||||
)
|
||||
|
||||
async def test_edit_location_with_all_args(self, bot, location):
|
||||
async def test_edit_location_with_all_args(self, offline_bot, location):
|
||||
with pytest.raises(ValueError, match="Not both"):
|
||||
await bot.edit_message_live_location(
|
||||
await offline_bot.edit_message_live_location(
|
||||
chat_id=1, message_id=7, latitude=2.5, longitude=4.6, location=location
|
||||
)
|
||||
|
||||
# TODO: Needs improvement with in inline sent live location.
|
||||
async def test_edit_live_inline_message(self, monkeypatch, bot, location):
|
||||
async def test_edit_live_inline_message(self, monkeypatch, offline_bot, location):
|
||||
async def make_assertion(url, request_data: RequestData, *args, **kwargs):
|
||||
data = request_data.json_parameters
|
||||
lat = data["latitude"] == str(location.latitude)
|
||||
@@ -127,8 +129,8 @@ class TestLocationWithoutRequest(TestLocationBase):
|
||||
live = data["live_period"] == "900"
|
||||
return lat and lon and id_ and ha and heading and prox_alert and live
|
||||
|
||||
monkeypatch.setattr(bot.request, "post", make_assertion)
|
||||
assert await bot.edit_message_live_location(
|
||||
monkeypatch.setattr(offline_bot.request, "post", make_assertion)
|
||||
assert await offline_bot.edit_message_live_location(
|
||||
inline_message_id=1234,
|
||||
location=location,
|
||||
horizontal_accuracy=50,
|
||||
@@ -138,30 +140,30 @@ class TestLocationWithoutRequest(TestLocationBase):
|
||||
)
|
||||
|
||||
# TODO: Needs improvement with in inline sent live location.
|
||||
async def test_stop_live_inline_message(self, monkeypatch, bot):
|
||||
async def test_stop_live_inline_message(self, monkeypatch, offline_bot):
|
||||
async def make_assertion(url, request_data: RequestData, *args, **kwargs):
|
||||
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)
|
||||
monkeypatch.setattr(offline_bot.request, "post", make_assertion)
|
||||
assert await offline_bot.stop_message_live_location(inline_message_id=1234)
|
||||
|
||||
async def test_send_with_location(self, monkeypatch, bot, chat_id, location):
|
||||
async def test_send_with_location(self, monkeypatch, offline_bot, chat_id, location):
|
||||
async def make_assertion(url, request_data: RequestData, *args, **kwargs):
|
||||
lat = request_data.json_parameters["latitude"] == str(location.latitude)
|
||||
lon = request_data.json_parameters["longitude"] == str(location.longitude)
|
||||
return lat and lon
|
||||
|
||||
monkeypatch.setattr(bot.request, "post", make_assertion)
|
||||
assert await bot.send_location(location=location, chat_id=chat_id)
|
||||
monkeypatch.setattr(offline_bot.request, "post", make_assertion)
|
||||
assert await offline_bot.send_location(location=location, chat_id=chat_id)
|
||||
|
||||
async def test_edit_live_location_with_location(self, monkeypatch, bot, location):
|
||||
async def test_edit_live_location_with_location(self, monkeypatch, offline_bot, location):
|
||||
async def make_assertion(url, request_data: RequestData, *args, **kwargs):
|
||||
lat = request_data.json_parameters["latitude"] == str(location.latitude)
|
||||
lon = request_data.json_parameters["longitude"] == str(location.longitude)
|
||||
return lat and lon
|
||||
|
||||
monkeypatch.setattr(bot.request, "post", make_assertion)
|
||||
assert await bot.edit_message_live_location(None, None, location=location)
|
||||
monkeypatch.setattr(offline_bot.request, "post", make_assertion)
|
||||
assert await offline_bot.edit_message_live_location(None, None, location=location)
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
("default_bot", "custom"),
|
||||
|
||||
+19
-19
@@ -65,7 +65,7 @@ def photo(photolist):
|
||||
return photolist[-1]
|
||||
|
||||
|
||||
class TestPhotoBase:
|
||||
class PhotoTestBase:
|
||||
width = 800
|
||||
height = 800
|
||||
caption = "<b>PhotoTest</b> - *Caption*"
|
||||
@@ -75,7 +75,7 @@ class TestPhotoBase:
|
||||
file_size = [29176, 27662]
|
||||
|
||||
|
||||
class TestPhotoWithoutRequest(TestPhotoBase):
|
||||
class TestPhotoWithoutRequest(PhotoTestBase):
|
||||
def test_slot_behaviour(self, photo):
|
||||
for attr in photo.__slots__:
|
||||
assert getattr(photo, attr, "err") != "err", f"got extra slot '{attr}'"
|
||||
@@ -105,7 +105,7 @@ class TestPhotoWithoutRequest(TestPhotoBase):
|
||||
# so far
|
||||
assert thumb.file_size in [1475, 1477]
|
||||
|
||||
def test_de_json(self, bot, photo):
|
||||
def test_de_json(self, offline_bot, photo):
|
||||
json_dict = {
|
||||
"file_id": photo.file_id,
|
||||
"file_unique_id": photo.file_unique_id,
|
||||
@@ -113,7 +113,7 @@ class TestPhotoWithoutRequest(TestPhotoBase):
|
||||
"height": self.height,
|
||||
"file_size": self.file_size,
|
||||
}
|
||||
json_photo = PhotoSize.de_json(json_dict, bot)
|
||||
json_photo = PhotoSize.de_json(json_dict, offline_bot)
|
||||
assert json_photo.api_kwargs == {}
|
||||
|
||||
assert json_photo.file_id == photo.file_id
|
||||
@@ -160,22 +160,22 @@ class TestPhotoWithoutRequest(TestPhotoBase):
|
||||
assert a != e
|
||||
assert hash(a) != hash(e)
|
||||
|
||||
async def test_error_without_required_args(self, bot, chat_id):
|
||||
async def test_error_without_required_args(self, offline_bot, chat_id):
|
||||
with pytest.raises(TypeError):
|
||||
await bot.send_photo(chat_id=chat_id)
|
||||
await offline_bot.send_photo(chat_id=chat_id)
|
||||
|
||||
async def test_send_photo_custom_filename(self, bot, chat_id, photo_file, monkeypatch):
|
||||
async def test_send_photo_custom_filename(self, offline_bot, chat_id, photo_file, monkeypatch):
|
||||
async def make_assertion(url, request_data: RequestData, *args, **kwargs):
|
||||
return next(iter(request_data.multipart_data.values()))[0] == "custom_filename"
|
||||
|
||||
monkeypatch.setattr(bot.request, "post", make_assertion)
|
||||
assert await bot.send_photo(chat_id, photo_file, filename="custom_filename")
|
||||
monkeypatch.setattr(offline_bot.request, "post", make_assertion)
|
||||
assert await offline_bot.send_photo(chat_id, photo_file, filename="custom_filename")
|
||||
|
||||
@pytest.mark.parametrize("local_mode", [True, False])
|
||||
async def test_send_photo_local_files(self, monkeypatch, bot, chat_id, local_mode):
|
||||
async def test_send_photo_local_files(self, monkeypatch, offline_bot, chat_id, local_mode):
|
||||
try:
|
||||
bot._local_mode = local_mode
|
||||
# For just test that the correct paths are passed as we have no local bot API set up
|
||||
offline_bot._local_mode = local_mode
|
||||
# For just test that the correct paths are passed as we have no local Bot API set up
|
||||
test_flag = False
|
||||
file = data_file("telegram.jpg")
|
||||
expected = file.as_uri()
|
||||
@@ -187,18 +187,18 @@ class TestPhotoWithoutRequest(TestPhotoBase):
|
||||
else:
|
||||
test_flag = isinstance(data.get("photo"), InputFile)
|
||||
|
||||
monkeypatch.setattr(bot, "_post", make_assertion)
|
||||
await bot.send_photo(chat_id, file)
|
||||
monkeypatch.setattr(offline_bot, "_post", make_assertion)
|
||||
await offline_bot.send_photo(chat_id, file)
|
||||
assert test_flag
|
||||
finally:
|
||||
bot._local_mode = False
|
||||
offline_bot._local_mode = False
|
||||
|
||||
async def test_send_with_photosize(self, monkeypatch, bot, chat_id, photo):
|
||||
async def test_send_with_photosize(self, monkeypatch, offline_bot, chat_id, photo):
|
||||
async def make_assertion(url, request_data: RequestData, *args, **kwargs):
|
||||
return request_data.json_parameters["photo"] == photo.file_id
|
||||
|
||||
monkeypatch.setattr(bot.request, "post", make_assertion)
|
||||
assert await bot.send_photo(photo=photo, chat_id=chat_id)
|
||||
monkeypatch.setattr(offline_bot.request, "post", make_assertion)
|
||||
assert await offline_bot.send_photo(photo=photo, chat_id=chat_id)
|
||||
|
||||
async def test_get_file_instance_method(self, monkeypatch, photo):
|
||||
async def make_assertion(*_, **kwargs):
|
||||
@@ -237,7 +237,7 @@ class TestPhotoWithoutRequest(TestPhotoBase):
|
||||
await default_bot.send_photo(chat_id, photo, reply_parameters=ReplyParameters(**kwargs))
|
||||
|
||||
|
||||
class TestPhotoWithRequest(TestPhotoBase):
|
||||
class TestPhotoWithRequest(PhotoTestBase):
|
||||
async def test_send_photo_all_args(self, bot, chat_id, photo_file):
|
||||
message = await bot.send_photo(
|
||||
chat_id,
|
||||
|
||||
@@ -61,7 +61,7 @@ async def sticker(bot, chat_id):
|
||||
sticker = (await bot.send_sticker(chat_id, sticker=f, read_timeout=50)).sticker
|
||||
# necessary to properly test needs_repainting
|
||||
with sticker._unfrozen():
|
||||
sticker.needs_repainting = TestStickerBase.needs_repainting
|
||||
sticker.needs_repainting = StickerTestBase.needs_repainting
|
||||
return sticker
|
||||
|
||||
|
||||
@@ -89,7 +89,7 @@ def video_sticker(bot, chat_id):
|
||||
return bot.send_sticker(chat_id, sticker=f, timeout=50).sticker
|
||||
|
||||
|
||||
class TestStickerBase:
|
||||
class StickerTestBase:
|
||||
# sticker_file_url = 'https://python-telegram-bot.org/static/testfiles/telegram.webp'
|
||||
# Serving sticker from gh since our server sends wrong content_type
|
||||
sticker_file_url = (
|
||||
@@ -116,7 +116,7 @@ class TestStickerBase:
|
||||
premium_animation = File("this_is_an_id", "this_is_an_unique_id")
|
||||
|
||||
|
||||
class TestStickerWithoutRequest(TestStickerBase):
|
||||
class TestStickerWithoutRequest(StickerTestBase):
|
||||
def test_slot_behaviour(self, sticker):
|
||||
for attr in sticker.__slots__:
|
||||
assert getattr(sticker, attr, "err") != "err", f"got extra slot '{attr}'"
|
||||
@@ -165,7 +165,7 @@ class TestStickerWithoutRequest(TestStickerBase):
|
||||
assert sticker_dict["type"] == sticker.type
|
||||
assert sticker_dict["needs_repainting"] == sticker.needs_repainting
|
||||
|
||||
def test_de_json(self, bot, sticker):
|
||||
def test_de_json(self, offline_bot, sticker):
|
||||
json_dict = {
|
||||
"file_id": self.sticker_file_id,
|
||||
"file_unique_id": self.sticker_file_unique_id,
|
||||
@@ -181,7 +181,7 @@ class TestStickerWithoutRequest(TestStickerBase):
|
||||
"custom_emoji_id": self.custom_emoji_id,
|
||||
"needs_repainting": self.needs_repainting,
|
||||
}
|
||||
json_sticker = Sticker.de_json(json_dict, bot)
|
||||
json_sticker = Sticker.de_json(json_dict, offline_bot)
|
||||
assert json_sticker.api_kwargs == {}
|
||||
|
||||
assert json_sticker.file_id == self.sticker_file_id
|
||||
@@ -284,22 +284,22 @@ class TestStickerWithoutRequest(TestStickerBase):
|
||||
assert a != e
|
||||
assert hash(a) != hash(e)
|
||||
|
||||
async def test_error_without_required_args(self, bot, chat_id):
|
||||
async def test_error_without_required_args(self, offline_bot, chat_id):
|
||||
with pytest.raises(TypeError):
|
||||
await bot.send_sticker(chat_id)
|
||||
await offline_bot.send_sticker(chat_id)
|
||||
|
||||
async def test_send_with_sticker(self, monkeypatch, bot, chat_id, sticker):
|
||||
async def test_send_with_sticker(self, monkeypatch, offline_bot, chat_id, sticker):
|
||||
async def make_assertion(url, request_data: RequestData, *args, **kwargs):
|
||||
return request_data.json_parameters["sticker"] == sticker.file_id
|
||||
|
||||
monkeypatch.setattr(bot.request, "post", make_assertion)
|
||||
assert await bot.send_sticker(sticker=sticker, chat_id=chat_id)
|
||||
monkeypatch.setattr(offline_bot.request, "post", make_assertion)
|
||||
assert await offline_bot.send_sticker(sticker=sticker, chat_id=chat_id)
|
||||
|
||||
@pytest.mark.parametrize("local_mode", [True, False])
|
||||
async def test_send_sticker_local_files(self, monkeypatch, bot, chat_id, local_mode):
|
||||
async def test_send_sticker_local_files(self, monkeypatch, offline_bot, chat_id, local_mode):
|
||||
try:
|
||||
bot._local_mode = local_mode
|
||||
# For just test that the correct paths are passed as we have no local bot API set up
|
||||
offline_bot._local_mode = local_mode
|
||||
# For just test that the correct paths are passed as we have no local Bot API set up
|
||||
test_flag = False
|
||||
file = data_file("telegram.jpg")
|
||||
expected = file.as_uri()
|
||||
@@ -311,11 +311,11 @@ class TestStickerWithoutRequest(TestStickerBase):
|
||||
else:
|
||||
test_flag = isinstance(data.get("sticker"), InputFile)
|
||||
|
||||
monkeypatch.setattr(bot, "_post", make_assertion)
|
||||
await bot.send_sticker(chat_id, file)
|
||||
monkeypatch.setattr(offline_bot, "_post", make_assertion)
|
||||
await offline_bot.send_sticker(chat_id, file)
|
||||
assert test_flag
|
||||
finally:
|
||||
bot._local_mode = False
|
||||
offline_bot._local_mode = False
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
("default_bot", "custom"),
|
||||
@@ -345,7 +345,7 @@ class TestStickerWithoutRequest(TestStickerBase):
|
||||
)
|
||||
|
||||
|
||||
class TestStickerWithRequest(TestStickerBase):
|
||||
class TestStickerWithRequest(StickerTestBase):
|
||||
async def test_send_all_args(self, bot, chat_id, sticker_file, sticker):
|
||||
message = await bot.send_sticker(
|
||||
chat_id, sticker=sticker_file, disable_notification=False, protect_content=True
|
||||
@@ -572,7 +572,7 @@ def sticker_set_thumb_file():
|
||||
yield file
|
||||
|
||||
|
||||
class TestStickerSetBase:
|
||||
class StickerSetTestBase:
|
||||
title = "Test stickers"
|
||||
stickers = [Sticker("file_id", "file_un_id", 512, 512, True, True, Sticker.REGULAR)]
|
||||
name = "NOTAREALNAME"
|
||||
@@ -580,15 +580,15 @@ class TestStickerSetBase:
|
||||
contains_masks = True
|
||||
|
||||
|
||||
class TestStickerSetWithoutRequest(TestStickerSetBase):
|
||||
class TestStickerSetWithoutRequest(StickerSetTestBase):
|
||||
def test_slot_behaviour(self):
|
||||
inst = StickerSet("this", "is", self.stickers, "not")
|
||||
for attr in inst.__slots__:
|
||||
assert getattr(inst, attr, "err") != "err", f"got extra slot '{attr}'"
|
||||
assert len(mro_slots(inst)) == len(set(mro_slots(inst))), "duplicate slot"
|
||||
|
||||
def test_de_json(self, bot, sticker):
|
||||
name = f"test_by_{bot.username}"
|
||||
def test_de_json(self, offline_bot, sticker):
|
||||
name = f"test_by_{offline_bot.username}"
|
||||
json_dict = {
|
||||
"name": name,
|
||||
"title": self.title,
|
||||
@@ -597,7 +597,7 @@ class TestStickerSetWithoutRequest(TestStickerSetBase):
|
||||
"sticker_type": self.sticker_type,
|
||||
"contains_masks": self.contains_masks,
|
||||
}
|
||||
sticker_set = StickerSet.de_json(json_dict, bot)
|
||||
sticker_set = StickerSet.de_json(json_dict, offline_bot)
|
||||
|
||||
assert sticker_set.name == name
|
||||
assert sticker_set.title == self.title
|
||||
@@ -653,11 +653,11 @@ class TestStickerSetWithoutRequest(TestStickerSetBase):
|
||||
|
||||
@pytest.mark.parametrize("local_mode", [True, False])
|
||||
async def test_upload_sticker_file_local_files(
|
||||
self, monkeypatch, bot, chat_id, local_mode, recwarn
|
||||
self, monkeypatch, offline_bot, chat_id, local_mode, recwarn
|
||||
):
|
||||
try:
|
||||
bot._local_mode = local_mode
|
||||
# For just test that the correct paths are passed as we have no local bot API set up
|
||||
offline_bot._local_mode = local_mode
|
||||
# For just test that the correct paths are passed as we have no local Bot API set up
|
||||
test_flag = False
|
||||
file = data_file("telegram.jpg")
|
||||
expected = file.as_uri()
|
||||
@@ -670,24 +670,24 @@ class TestStickerSetWithoutRequest(TestStickerSetBase):
|
||||
else isinstance(data.get("sticker"), InputFile)
|
||||
)
|
||||
|
||||
monkeypatch.setattr(bot, "_post", make_assertion)
|
||||
await bot.upload_sticker_file(
|
||||
monkeypatch.setattr(offline_bot, "_post", make_assertion)
|
||||
await offline_bot.upload_sticker_file(
|
||||
chat_id, sticker=file, sticker_format=StickerFormat.STATIC
|
||||
)
|
||||
assert test_flag
|
||||
finally:
|
||||
bot._local_mode = False
|
||||
offline_bot._local_mode = False
|
||||
|
||||
@pytest.mark.parametrize("local_mode", [True, False])
|
||||
async def test_create_new_sticker_set_local_files(
|
||||
self,
|
||||
monkeypatch,
|
||||
bot,
|
||||
offline_bot,
|
||||
chat_id,
|
||||
local_mode,
|
||||
):
|
||||
monkeypatch.setattr(bot, "_local_mode", local_mode)
|
||||
# For just test that the correct paths are passed as we have no local bot API set up
|
||||
monkeypatch.setattr(offline_bot, "_local_mode", local_mode)
|
||||
# For just test that the correct paths are passed as we have no local Bot API set up
|
||||
test_flag = False
|
||||
file = data_file("telegram.jpg")
|
||||
# always assumed to be local mode because we don't have access to local_mode setting
|
||||
@@ -698,8 +698,8 @@ class TestStickerSetWithoutRequest(TestStickerSetBase):
|
||||
nonlocal test_flag
|
||||
test_flag = data.get("stickers")[0].sticker == expected
|
||||
|
||||
monkeypatch.setattr(bot, "_post", make_assertion)
|
||||
await bot.create_new_sticker_set(
|
||||
monkeypatch.setattr(offline_bot, "_post", make_assertion)
|
||||
await offline_bot.create_new_sticker_set(
|
||||
chat_id,
|
||||
"name",
|
||||
"title",
|
||||
@@ -707,7 +707,9 @@ class TestStickerSetWithoutRequest(TestStickerSetBase):
|
||||
)
|
||||
assert test_flag
|
||||
|
||||
async def test_create_new_sticker_all_params(self, monkeypatch, bot, chat_id, mask_position):
|
||||
async def test_create_new_sticker_all_params(
|
||||
self, monkeypatch, offline_bot, chat_id, mask_position
|
||||
):
|
||||
async def make_assertion(_, data, *args, **kwargs):
|
||||
assert data["user_id"] == chat_id
|
||||
assert data["name"] == "name"
|
||||
@@ -715,8 +717,8 @@ class TestStickerSetWithoutRequest(TestStickerSetBase):
|
||||
assert data["stickers"] == ["wow.png", "wow.tgs", "wow.webp"]
|
||||
assert data["needs_repainting"] is True
|
||||
|
||||
monkeypatch.setattr(bot, "_post", make_assertion)
|
||||
await bot.create_new_sticker_set(
|
||||
monkeypatch.setattr(offline_bot, "_post", make_assertion)
|
||||
await offline_bot.create_new_sticker_set(
|
||||
chat_id,
|
||||
"name",
|
||||
"title",
|
||||
@@ -725,9 +727,11 @@ class TestStickerSetWithoutRequest(TestStickerSetBase):
|
||||
)
|
||||
|
||||
@pytest.mark.parametrize("local_mode", [True, False])
|
||||
async def test_add_sticker_to_set_local_files(self, monkeypatch, bot, chat_id, local_mode):
|
||||
monkeypatch.setattr(bot, "_local_mode", local_mode)
|
||||
# For just test that the correct paths are passed as we have no local bot API set up
|
||||
async def test_add_sticker_to_set_local_files(
|
||||
self, monkeypatch, offline_bot, chat_id, local_mode
|
||||
):
|
||||
monkeypatch.setattr(offline_bot, "_local_mode", local_mode)
|
||||
# For just test that the correct paths are passed as we have no local Bot API set up
|
||||
test_flag = False
|
||||
file = data_file("telegram.jpg")
|
||||
# always assumed to be local mode because we don't have access to local_mode setting
|
||||
@@ -738,8 +742,8 @@ class TestStickerSetWithoutRequest(TestStickerSetBase):
|
||||
nonlocal test_flag
|
||||
test_flag = data.get("sticker").sticker == expected
|
||||
|
||||
monkeypatch.setattr(bot, "_post", make_assertion)
|
||||
await bot.add_sticker_to_set(
|
||||
monkeypatch.setattr(offline_bot, "_post", make_assertion)
|
||||
await offline_bot.add_sticker_to_set(
|
||||
chat_id,
|
||||
"name",
|
||||
sticker=InputSticker(sticker=file, emoji_list=["this"], format="static"),
|
||||
@@ -748,11 +752,11 @@ class TestStickerSetWithoutRequest(TestStickerSetBase):
|
||||
|
||||
@pytest.mark.parametrize("local_mode", [True, False])
|
||||
async def test_set_sticker_set_thumbnail_local_files(
|
||||
self, monkeypatch, bot, chat_id, local_mode
|
||||
self, monkeypatch, offline_bot, chat_id, local_mode
|
||||
):
|
||||
try:
|
||||
bot._local_mode = local_mode
|
||||
# For just test that the correct paths are passed as we have no local bot API set up
|
||||
offline_bot._local_mode = local_mode
|
||||
# For just test that the correct paths are passed as we have no local Bot API set up
|
||||
test_flag = False
|
||||
file = data_file("telegram.jpg")
|
||||
expected = file.as_uri()
|
||||
@@ -764,11 +768,13 @@ class TestStickerSetWithoutRequest(TestStickerSetBase):
|
||||
else:
|
||||
test_flag = isinstance(data.get("thumbnail"), InputFile)
|
||||
|
||||
monkeypatch.setattr(bot, "_post", make_assertion)
|
||||
await bot.set_sticker_set_thumbnail("name", chat_id, thumbnail=file, format="static")
|
||||
monkeypatch.setattr(offline_bot, "_post", make_assertion)
|
||||
await offline_bot.set_sticker_set_thumbnail(
|
||||
"name", chat_id, thumbnail=file, format="static"
|
||||
)
|
||||
assert test_flag
|
||||
finally:
|
||||
bot._local_mode = False
|
||||
offline_bot._local_mode = False
|
||||
|
||||
async def test_get_file_instance_method(self, monkeypatch, sticker):
|
||||
async def make_assertion(*_, **kwargs):
|
||||
@@ -1064,35 +1070,35 @@ class TestStickerSetWithRequest:
|
||||
@pytest.fixture(scope="module")
|
||||
def mask_position():
|
||||
return MaskPosition(
|
||||
TestMaskPositionBase.point,
|
||||
TestMaskPositionBase.x_shift,
|
||||
TestMaskPositionBase.y_shift,
|
||||
TestMaskPositionBase.scale,
|
||||
MaskPositionTestBase.point,
|
||||
MaskPositionTestBase.x_shift,
|
||||
MaskPositionTestBase.y_shift,
|
||||
MaskPositionTestBase.scale,
|
||||
)
|
||||
|
||||
|
||||
class TestMaskPositionBase:
|
||||
class MaskPositionTestBase:
|
||||
point = MaskPosition.EYES
|
||||
x_shift = -1
|
||||
y_shift = 1
|
||||
scale = 2
|
||||
|
||||
|
||||
class TestMaskPositionWithoutRequest(TestMaskPositionBase):
|
||||
class TestMaskPositionWithoutRequest(MaskPositionTestBase):
|
||||
def test_slot_behaviour(self, mask_position):
|
||||
inst = mask_position
|
||||
for attr in inst.__slots__:
|
||||
assert getattr(inst, attr, "err") != "err", f"got extra slot '{attr}'"
|
||||
assert len(mro_slots(inst)) == len(set(mro_slots(inst))), "duplicate slot"
|
||||
|
||||
def test_mask_position_de_json(self, bot):
|
||||
def test_mask_position_de_json(self, offline_bot):
|
||||
json_dict = {
|
||||
"point": self.point,
|
||||
"x_shift": self.x_shift,
|
||||
"y_shift": self.y_shift,
|
||||
"scale": self.scale,
|
||||
}
|
||||
mask_position = MaskPosition.de_json(json_dict, bot)
|
||||
mask_position = MaskPosition.de_json(json_dict, offline_bot)
|
||||
assert mask_position.api_kwargs == {}
|
||||
|
||||
assert mask_position.point == self.point
|
||||
@@ -1130,7 +1136,7 @@ class TestMaskPositionWithoutRequest(TestMaskPositionBase):
|
||||
assert hash(a) != hash(e)
|
||||
|
||||
|
||||
class TestMaskPositionWithRequest(TestMaskPositionBase):
|
||||
class TestMaskPositionWithRequest(MaskPositionTestBase):
|
||||
async def test_create_new_mask_sticker_set(self, bot, chat_id, sticker_file, mask_position):
|
||||
name = f"masks_by_{bot.username}"
|
||||
try:
|
||||
|
||||
+19
-19
@@ -31,17 +31,17 @@ from tests.auxil.slots import mro_slots
|
||||
@pytest.fixture(scope="module")
|
||||
def venue():
|
||||
return Venue(
|
||||
TestVenueBase.location,
|
||||
TestVenueBase.title,
|
||||
TestVenueBase.address,
|
||||
foursquare_id=TestVenueBase.foursquare_id,
|
||||
foursquare_type=TestVenueBase.foursquare_type,
|
||||
google_place_id=TestVenueBase.google_place_id,
|
||||
google_place_type=TestVenueBase.google_place_type,
|
||||
VenueTestBase.location,
|
||||
VenueTestBase.title,
|
||||
VenueTestBase.address,
|
||||
foursquare_id=VenueTestBase.foursquare_id,
|
||||
foursquare_type=VenueTestBase.foursquare_type,
|
||||
google_place_id=VenueTestBase.google_place_id,
|
||||
google_place_type=VenueTestBase.google_place_type,
|
||||
)
|
||||
|
||||
|
||||
class TestVenueBase:
|
||||
class VenueTestBase:
|
||||
location = Location(longitude=-46.788279, latitude=-23.691288)
|
||||
title = "title"
|
||||
address = "address"
|
||||
@@ -51,13 +51,13 @@ class TestVenueBase:
|
||||
google_place_type = "google place type"
|
||||
|
||||
|
||||
class TestVenueWithoutRequest(TestVenueBase):
|
||||
class TestVenueWithoutRequest(VenueTestBase):
|
||||
def test_slot_behaviour(self, venue):
|
||||
for attr in venue.__slots__:
|
||||
assert getattr(venue, attr, "err") != "err", f"got extra slot '{attr}'"
|
||||
assert len(mro_slots(venue)) == len(set(mro_slots(venue))), "duplicate slot"
|
||||
|
||||
def test_de_json(self, bot):
|
||||
def test_de_json(self, offline_bot):
|
||||
json_dict = {
|
||||
"location": self.location.to_dict(),
|
||||
"title": self.title,
|
||||
@@ -67,7 +67,7 @@ class TestVenueWithoutRequest(TestVenueBase):
|
||||
"google_place_id": self.google_place_id,
|
||||
"google_place_type": self.google_place_type,
|
||||
}
|
||||
venue = Venue.de_json(json_dict, bot)
|
||||
venue = Venue.de_json(json_dict, offline_bot)
|
||||
assert venue.api_kwargs == {}
|
||||
|
||||
assert venue.location == self.location
|
||||
@@ -110,13 +110,13 @@ class TestVenueWithoutRequest(TestVenueBase):
|
||||
assert a != d2
|
||||
assert hash(a) != hash(d2)
|
||||
|
||||
async def test_send_venue_without_required(self, bot, chat_id):
|
||||
async def test_send_venue_without_required(self, offline_bot, chat_id):
|
||||
with pytest.raises(ValueError, match="Either venue or latitude, longitude, address and"):
|
||||
await bot.send_venue(chat_id=chat_id)
|
||||
await offline_bot.send_venue(chat_id=chat_id)
|
||||
|
||||
async def test_send_venue_mutually_exclusive(self, bot, chat_id, venue):
|
||||
async def test_send_venue_mutually_exclusive(self, offline_bot, chat_id, venue):
|
||||
with pytest.raises(ValueError, match="Not both"):
|
||||
await bot.send_venue(
|
||||
await offline_bot.send_venue(
|
||||
chat_id=chat_id,
|
||||
latitude=1,
|
||||
longitude=1,
|
||||
@@ -125,7 +125,7 @@ class TestVenueWithoutRequest(TestVenueBase):
|
||||
venue=venue,
|
||||
)
|
||||
|
||||
async def test_send_with_venue(self, monkeypatch, bot, chat_id, venue):
|
||||
async def test_send_with_venue(self, monkeypatch, offline_bot, chat_id, venue):
|
||||
async def make_assertion(url, request_data: RequestData, *args, **kwargs):
|
||||
data = request_data.json_parameters
|
||||
return (
|
||||
@@ -139,8 +139,8 @@ class TestVenueWithoutRequest(TestVenueBase):
|
||||
and data["google_place_type"] == self.google_place_type
|
||||
)
|
||||
|
||||
monkeypatch.setattr(bot.request, "post", make_assertion)
|
||||
message = await bot.send_venue(chat_id, venue=venue)
|
||||
monkeypatch.setattr(offline_bot.request, "post", make_assertion)
|
||||
message = await offline_bot.send_venue(chat_id, venue=venue)
|
||||
assert message
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
@@ -171,7 +171,7 @@ class TestVenueWithoutRequest(TestVenueBase):
|
||||
)
|
||||
|
||||
|
||||
class TestVenueWithRequest(TestVenueBase):
|
||||
class TestVenueWithRequest(VenueTestBase):
|
||||
@pytest.mark.parametrize(
|
||||
("default_bot", "custom"),
|
||||
[
|
||||
|
||||
+19
-19
@@ -49,7 +49,7 @@ async def video(bot, chat_id):
|
||||
return (await bot.send_video(chat_id, video=f, read_timeout=50)).video
|
||||
|
||||
|
||||
class TestVideoBase:
|
||||
class VideoTestBase:
|
||||
width = 360
|
||||
height = 640
|
||||
duration = 5
|
||||
@@ -66,7 +66,7 @@ class TestVideoBase:
|
||||
video_file_unique_id = "adc3145fd2e84d95b64d68eaa22aa33e"
|
||||
|
||||
|
||||
class TestVideoWithoutRequest(TestVideoBase):
|
||||
class TestVideoWithoutRequest(VideoTestBase):
|
||||
def test_slot_behaviour(self, video):
|
||||
for attr in video.__slots__:
|
||||
assert getattr(video, attr, "err") != "err", f"got extra slot '{attr}'"
|
||||
@@ -93,7 +93,7 @@ class TestVideoWithoutRequest(TestVideoBase):
|
||||
assert video.file_size == self.file_size
|
||||
assert video.mime_type == self.mime_type
|
||||
|
||||
def test_de_json(self, bot):
|
||||
def test_de_json(self, offline_bot):
|
||||
json_dict = {
|
||||
"file_id": self.video_file_id,
|
||||
"file_unique_id": self.video_file_unique_id,
|
||||
@@ -104,7 +104,7 @@ class TestVideoWithoutRequest(TestVideoBase):
|
||||
"file_size": self.file_size,
|
||||
"file_name": self.file_name,
|
||||
}
|
||||
json_video = Video.de_json(json_dict, bot)
|
||||
json_video = Video.de_json(json_dict, offline_bot)
|
||||
assert json_video.api_kwargs == {}
|
||||
|
||||
assert json_video.file_id == self.video_file_id
|
||||
@@ -149,30 +149,30 @@ class TestVideoWithoutRequest(TestVideoBase):
|
||||
assert a != e
|
||||
assert hash(a) != hash(e)
|
||||
|
||||
async def test_error_without_required_args(self, bot, chat_id):
|
||||
async def test_error_without_required_args(self, offline_bot, chat_id):
|
||||
with pytest.raises(TypeError):
|
||||
await bot.send_video(chat_id=chat_id)
|
||||
await offline_bot.send_video(chat_id=chat_id)
|
||||
|
||||
async def test_send_with_video(self, monkeypatch, bot, chat_id, video):
|
||||
async def test_send_with_video(self, monkeypatch, offline_bot, chat_id, video):
|
||||
async def make_assertion(url, request_data: RequestData, *args, **kwargs):
|
||||
return request_data.json_parameters["video"] == video.file_id
|
||||
|
||||
monkeypatch.setattr(bot.request, "post", make_assertion)
|
||||
assert await bot.send_video(chat_id, video=video)
|
||||
monkeypatch.setattr(offline_bot.request, "post", make_assertion)
|
||||
assert await offline_bot.send_video(chat_id, video=video)
|
||||
|
||||
async def test_send_video_custom_filename(self, bot, chat_id, video_file, monkeypatch):
|
||||
async def test_send_video_custom_filename(self, offline_bot, chat_id, video_file, monkeypatch):
|
||||
async def make_assertion(url, request_data: RequestData, *args, **kwargs):
|
||||
return next(iter(request_data.multipart_data.values()))[0] == "custom_filename"
|
||||
|
||||
monkeypatch.setattr(bot.request, "post", make_assertion)
|
||||
monkeypatch.setattr(offline_bot.request, "post", make_assertion)
|
||||
|
||||
assert await bot.send_video(chat_id, video_file, filename="custom_filename")
|
||||
assert await offline_bot.send_video(chat_id, video_file, filename="custom_filename")
|
||||
|
||||
@pytest.mark.parametrize("local_mode", [True, False])
|
||||
async def test_send_video_local_files(self, monkeypatch, bot, chat_id, local_mode):
|
||||
async def test_send_video_local_files(self, monkeypatch, offline_bot, chat_id, local_mode):
|
||||
try:
|
||||
bot._local_mode = local_mode
|
||||
# For just test that the correct paths are passed as we have no local bot API set up
|
||||
offline_bot._local_mode = local_mode
|
||||
# For just test that the correct paths are passed as we have no local Bot API set up
|
||||
test_flag = False
|
||||
file = data_file("telegram.jpg")
|
||||
expected = file.as_uri()
|
||||
@@ -186,11 +186,11 @@ class TestVideoWithoutRequest(TestVideoBase):
|
||||
data.get("thumbnail"), InputFile
|
||||
)
|
||||
|
||||
monkeypatch.setattr(bot, "_post", make_assertion)
|
||||
await bot.send_video(chat_id, file, thumbnail=file)
|
||||
monkeypatch.setattr(offline_bot, "_post", make_assertion)
|
||||
await offline_bot.send_video(chat_id, file, thumbnail=file)
|
||||
assert test_flag
|
||||
finally:
|
||||
bot._local_mode = False
|
||||
offline_bot._local_mode = False
|
||||
|
||||
async def test_get_file_instance_method(self, monkeypatch, video):
|
||||
async def make_assertion(*_, **kwargs):
|
||||
@@ -229,7 +229,7 @@ class TestVideoWithoutRequest(TestVideoBase):
|
||||
await default_bot.send_video(chat_id, video, reply_parameters=ReplyParameters(**kwargs))
|
||||
|
||||
|
||||
class TestVideoWithRequest(TestVideoBase):
|
||||
class TestVideoWithRequest(VideoTestBase):
|
||||
async def test_send_all_args(self, bot, chat_id, video_file, video, thumb_file):
|
||||
message = await bot.send_video(
|
||||
chat_id,
|
||||
|
||||
@@ -48,7 +48,7 @@ async def video_note(bot, chat_id):
|
||||
return (await bot.send_video_note(chat_id, video_note=f, read_timeout=50)).video_note
|
||||
|
||||
|
||||
class TestVideoNoteBase:
|
||||
class VideoNoteTestBase:
|
||||
length = 240
|
||||
duration = 3
|
||||
file_size = 132084
|
||||
@@ -60,7 +60,7 @@ class TestVideoNoteBase:
|
||||
videonote_file_unique_id = "adc3145fd2e84d95b64d68eaa22aa33e"
|
||||
|
||||
|
||||
class TestVideoNoteWithoutRequest(TestVideoNoteBase):
|
||||
class TestVideoNoteWithoutRequest(VideoNoteTestBase):
|
||||
def test_slot_behaviour(self, video_note):
|
||||
for attr in video_note.__slots__:
|
||||
assert getattr(video_note, attr, "err") != "err", f"got extra slot '{attr}'"
|
||||
@@ -85,7 +85,7 @@ class TestVideoNoteWithoutRequest(TestVideoNoteBase):
|
||||
assert video_note.duration == self.duration
|
||||
assert video_note.file_size == self.file_size
|
||||
|
||||
def test_de_json(self, bot):
|
||||
def test_de_json(self, offline_bot):
|
||||
json_dict = {
|
||||
"file_id": self.videonote_file_id,
|
||||
"file_unique_id": self.videonote_file_unique_id,
|
||||
@@ -93,7 +93,7 @@ class TestVideoNoteWithoutRequest(TestVideoNoteBase):
|
||||
"duration": self.duration,
|
||||
"file_size": self.file_size,
|
||||
}
|
||||
json_video_note = VideoNote.de_json(json_dict, bot)
|
||||
json_video_note = VideoNote.de_json(json_dict, offline_bot)
|
||||
assert json_video_note.api_kwargs == {}
|
||||
|
||||
assert json_video_note.file_id == self.videonote_file_id
|
||||
@@ -132,32 +132,36 @@ class TestVideoNoteWithoutRequest(TestVideoNoteBase):
|
||||
assert a != e
|
||||
assert hash(a) != hash(e)
|
||||
|
||||
async def test_error_without_required_args(self, bot, chat_id):
|
||||
async def test_error_without_required_args(self, offline_bot, chat_id):
|
||||
with pytest.raises(TypeError):
|
||||
await bot.send_video_note(chat_id=chat_id)
|
||||
await offline_bot.send_video_note(chat_id=chat_id)
|
||||
|
||||
async def test_send_with_video_note(self, monkeypatch, bot, chat_id, video_note):
|
||||
async def test_send_with_video_note(self, monkeypatch, offline_bot, chat_id, video_note):
|
||||
async def make_assertion(url, request_data: RequestData, *args, **kwargs):
|
||||
return request_data.json_parameters["video_note"] == video_note.file_id
|
||||
|
||||
monkeypatch.setattr(bot.request, "post", make_assertion)
|
||||
assert await bot.send_video_note(chat_id, video_note=video_note)
|
||||
monkeypatch.setattr(offline_bot.request, "post", make_assertion)
|
||||
assert await offline_bot.send_video_note(chat_id, video_note=video_note)
|
||||
|
||||
async def test_send_video_note_custom_filename(
|
||||
self, bot, chat_id, video_note_file, monkeypatch
|
||||
self, offline_bot, chat_id, video_note_file, monkeypatch
|
||||
):
|
||||
async def make_assertion(url, request_data: RequestData, *args, **kwargs):
|
||||
return next(iter(request_data.multipart_data.values()))[0] == "custom_filename"
|
||||
|
||||
monkeypatch.setattr(bot.request, "post", make_assertion)
|
||||
monkeypatch.setattr(offline_bot.request, "post", make_assertion)
|
||||
|
||||
assert await bot.send_video_note(chat_id, video_note_file, filename="custom_filename")
|
||||
assert await offline_bot.send_video_note(
|
||||
chat_id, video_note_file, filename="custom_filename"
|
||||
)
|
||||
|
||||
@pytest.mark.parametrize("local_mode", [True, False])
|
||||
async def test_send_video_note_local_files(self, monkeypatch, bot, chat_id, local_mode):
|
||||
async def test_send_video_note_local_files(
|
||||
self, monkeypatch, offline_bot, chat_id, local_mode
|
||||
):
|
||||
try:
|
||||
bot._local_mode = local_mode
|
||||
# For just test that the correct paths are passed as we have no local bot API set up
|
||||
offline_bot._local_mode = local_mode
|
||||
# For just test that the correct paths are passed as we have no local Bot API set up
|
||||
test_flag = False
|
||||
file = data_file("telegram.jpg")
|
||||
expected = file.as_uri()
|
||||
@@ -173,11 +177,11 @@ class TestVideoNoteWithoutRequest(TestVideoNoteBase):
|
||||
data.get("thumbnail"), InputFile
|
||||
)
|
||||
|
||||
monkeypatch.setattr(bot, "_post", make_assertion)
|
||||
await bot.send_video_note(chat_id, file, thumbnail=file)
|
||||
monkeypatch.setattr(offline_bot, "_post", make_assertion)
|
||||
await offline_bot.send_video_note(chat_id, file, thumbnail=file)
|
||||
assert test_flag
|
||||
finally:
|
||||
bot._local_mode = False
|
||||
offline_bot._local_mode = False
|
||||
|
||||
async def test_get_file_instance_method(self, monkeypatch, video_note):
|
||||
async def make_assertion(*_, **kwargs):
|
||||
@@ -218,7 +222,7 @@ class TestVideoNoteWithoutRequest(TestVideoNoteBase):
|
||||
)
|
||||
|
||||
|
||||
class TestVideoNoteWithRequest(TestVideoNoteBase):
|
||||
class TestVideoNoteWithRequest(VideoNoteTestBase):
|
||||
async def test_send_all_args(self, bot, chat_id, video_note_file, video_note, thumb_file):
|
||||
message = await bot.send_video_note(
|
||||
chat_id,
|
||||
|
||||
+19
-19
@@ -49,7 +49,7 @@ async def voice(bot, chat_id):
|
||||
return (await bot.send_voice(chat_id, voice=f, read_timeout=50)).voice
|
||||
|
||||
|
||||
class TestVoiceBase:
|
||||
class VoiceTestBase:
|
||||
duration = 3
|
||||
mime_type = "audio/ogg"
|
||||
file_size = 9199
|
||||
@@ -59,7 +59,7 @@ class TestVoiceBase:
|
||||
voice_file_unique_id = "adc3145fd2e84d95b64d68eaa22aa33e"
|
||||
|
||||
|
||||
class TestVoiceWithoutRequest(TestVoiceBase):
|
||||
class TestVoiceWithoutRequest(VoiceTestBase):
|
||||
def test_slot_behaviour(self, voice):
|
||||
for attr in voice.__slots__:
|
||||
assert getattr(voice, attr, "err") != "err", f"got extra slot '{attr}'"
|
||||
@@ -78,7 +78,7 @@ class TestVoiceWithoutRequest(TestVoiceBase):
|
||||
assert voice.mime_type == self.mime_type
|
||||
assert voice.file_size == self.file_size
|
||||
|
||||
def test_de_json(self, bot):
|
||||
def test_de_json(self, offline_bot):
|
||||
json_dict = {
|
||||
"file_id": self.voice_file_id,
|
||||
"file_unique_id": self.voice_file_unique_id,
|
||||
@@ -86,7 +86,7 @@ class TestVoiceWithoutRequest(TestVoiceBase):
|
||||
"mime_type": self.mime_type,
|
||||
"file_size": self.file_size,
|
||||
}
|
||||
json_voice = Voice.de_json(json_dict, bot)
|
||||
json_voice = Voice.de_json(json_dict, offline_bot)
|
||||
assert json_voice.api_kwargs == {}
|
||||
|
||||
assert json_voice.file_id == self.voice_file_id
|
||||
@@ -125,30 +125,30 @@ class TestVoiceWithoutRequest(TestVoiceBase):
|
||||
assert a != e
|
||||
assert hash(a) != hash(e)
|
||||
|
||||
async def test_error_without_required_args(self, bot, chat_id):
|
||||
async def test_error_without_required_args(self, offline_bot, chat_id):
|
||||
with pytest.raises(TypeError):
|
||||
await bot.sendVoice(chat_id)
|
||||
await offline_bot.sendVoice(chat_id)
|
||||
|
||||
async def test_send_voice_custom_filename(self, bot, chat_id, voice_file, monkeypatch):
|
||||
async def test_send_voice_custom_filename(self, offline_bot, chat_id, voice_file, monkeypatch):
|
||||
async def make_assertion(url, request_data: RequestData, *args, **kwargs):
|
||||
return next(iter(request_data.multipart_data.values()))[0] == "custom_filename"
|
||||
|
||||
monkeypatch.setattr(bot.request, "post", make_assertion)
|
||||
monkeypatch.setattr(offline_bot.request, "post", make_assertion)
|
||||
|
||||
assert await bot.send_voice(chat_id, voice_file, filename="custom_filename")
|
||||
assert await offline_bot.send_voice(chat_id, voice_file, filename="custom_filename")
|
||||
|
||||
async def test_send_with_voice(self, monkeypatch, bot, chat_id, voice):
|
||||
async def test_send_with_voice(self, monkeypatch, offline_bot, chat_id, voice):
|
||||
async def make_assertion(url, request_data: RequestData, *args, **kwargs):
|
||||
return request_data.json_parameters["voice"] == voice.file_id
|
||||
|
||||
monkeypatch.setattr(bot.request, "post", make_assertion)
|
||||
assert await bot.send_voice(chat_id, voice=voice)
|
||||
monkeypatch.setattr(offline_bot.request, "post", make_assertion)
|
||||
assert await offline_bot.send_voice(chat_id, voice=voice)
|
||||
|
||||
@pytest.mark.parametrize("local_mode", [True, False])
|
||||
async def test_send_voice_local_files(self, monkeypatch, bot, chat_id, local_mode):
|
||||
async def test_send_voice_local_files(self, monkeypatch, offline_bot, chat_id, local_mode):
|
||||
try:
|
||||
bot._local_mode = local_mode
|
||||
# For just test that the correct paths are passed as we have no local bot API set up
|
||||
offline_bot._local_mode = local_mode
|
||||
# For just test that the correct paths are passed as we have no local Bot API set up
|
||||
test_flag = False
|
||||
file = data_file("telegram.jpg")
|
||||
expected = file.as_uri()
|
||||
@@ -160,11 +160,11 @@ class TestVoiceWithoutRequest(TestVoiceBase):
|
||||
else:
|
||||
test_flag = isinstance(data.get("voice"), InputFile)
|
||||
|
||||
monkeypatch.setattr(bot, "_post", make_assertion)
|
||||
await bot.send_voice(chat_id, file)
|
||||
monkeypatch.setattr(offline_bot, "_post", make_assertion)
|
||||
await offline_bot.send_voice(chat_id, file)
|
||||
assert test_flag
|
||||
finally:
|
||||
bot._local_mode = False
|
||||
offline_bot._local_mode = False
|
||||
|
||||
async def test_get_file_instance_method(self, monkeypatch, voice):
|
||||
async def make_assertion(*_, **kwargs):
|
||||
@@ -203,7 +203,7 @@ class TestVoiceWithoutRequest(TestVoiceBase):
|
||||
await default_bot.send_voice(chat_id, voice, reply_parameters=ReplyParameters(**kwargs))
|
||||
|
||||
|
||||
class TestVoiceWithRequest(TestVoiceBase):
|
||||
class TestVoiceWithRequest(VoiceTestBase):
|
||||
async def test_send_all_args(self, bot, chat_id, voice_file, voice):
|
||||
message = await bot.send_voice(
|
||||
chat_id,
|
||||
|
||||
+12
-12
@@ -26,18 +26,18 @@ from tests.auxil.slots import mro_slots
|
||||
@pytest.fixture(scope="module")
|
||||
def game():
|
||||
game = Game(
|
||||
TestGameBase.title,
|
||||
TestGameBase.description,
|
||||
TestGameBase.photo,
|
||||
text=TestGameBase.text,
|
||||
text_entities=TestGameBase.text_entities,
|
||||
animation=TestGameBase.animation,
|
||||
GameTestBase.title,
|
||||
GameTestBase.description,
|
||||
GameTestBase.photo,
|
||||
text=GameTestBase.text,
|
||||
text_entities=GameTestBase.text_entities,
|
||||
animation=GameTestBase.animation,
|
||||
)
|
||||
game._unfreeze()
|
||||
return game
|
||||
|
||||
|
||||
class TestGameBase:
|
||||
class GameTestBase:
|
||||
title = "Python-telegram-bot Test Game"
|
||||
description = "description"
|
||||
photo = [PhotoSize("Blah", "ElseBlah", 640, 360, file_size=0)]
|
||||
@@ -49,26 +49,26 @@ class TestGameBase:
|
||||
animation = Animation("blah", "unique_id", 320, 180, 1)
|
||||
|
||||
|
||||
class TestGameWithoutRequest(TestGameBase):
|
||||
class TestGameWithoutRequest(GameTestBase):
|
||||
def test_slot_behaviour(self, game):
|
||||
for attr in game.__slots__:
|
||||
assert getattr(game, attr, "err") != "err", f"got extra slot '{attr}'"
|
||||
assert len(mro_slots(game)) == len(set(mro_slots(game))), "duplicate slot"
|
||||
|
||||
def test_de_json_required(self, bot):
|
||||
def test_de_json_required(self, offline_bot):
|
||||
json_dict = {
|
||||
"title": self.title,
|
||||
"description": self.description,
|
||||
"photo": [self.photo[0].to_dict()],
|
||||
}
|
||||
game = Game.de_json(json_dict, bot)
|
||||
game = Game.de_json(json_dict, offline_bot)
|
||||
assert game.api_kwargs == {}
|
||||
|
||||
assert game.title == self.title
|
||||
assert game.description == self.description
|
||||
assert game.photo == tuple(self.photo)
|
||||
|
||||
def test_de_json_all(self, bot):
|
||||
def test_de_json_all(self, offline_bot):
|
||||
json_dict = {
|
||||
"title": self.title,
|
||||
"description": self.description,
|
||||
@@ -77,7 +77,7 @@ class TestGameWithoutRequest(TestGameBase):
|
||||
"text_entities": [self.text_entities[0].to_dict()],
|
||||
"animation": self.animation.to_dict(),
|
||||
}
|
||||
game = Game.de_json(json_dict, bot)
|
||||
game = Game.de_json(json_dict, offline_bot)
|
||||
assert game.api_kwargs == {}
|
||||
|
||||
assert game.title == self.title
|
||||
|
||||
@@ -26,36 +26,36 @@ from tests.auxil.slots import mro_slots
|
||||
@pytest.fixture(scope="module")
|
||||
def game_highscore():
|
||||
return GameHighScore(
|
||||
TestGameHighScoreBase.position, TestGameHighScoreBase.user, TestGameHighScoreBase.score
|
||||
GameHighScoreTestBase.position, GameHighScoreTestBase.user, GameHighScoreTestBase.score
|
||||
)
|
||||
|
||||
|
||||
class TestGameHighScoreBase:
|
||||
class GameHighScoreTestBase:
|
||||
position = 12
|
||||
user = User(2, "test user", False)
|
||||
score = 42
|
||||
|
||||
|
||||
class TestGameHighScoreWithoutRequest(TestGameHighScoreBase):
|
||||
class TestGameHighScoreWithoutRequest(GameHighScoreTestBase):
|
||||
def test_slot_behaviour(self, game_highscore):
|
||||
for attr in game_highscore.__slots__:
|
||||
assert getattr(game_highscore, attr, "err") != "err", f"got extra slot '{attr}'"
|
||||
assert len(mro_slots(game_highscore)) == len(set(mro_slots(game_highscore))), "same slot"
|
||||
|
||||
def test_de_json(self, bot):
|
||||
def test_de_json(self, offline_bot):
|
||||
json_dict = {
|
||||
"position": self.position,
|
||||
"user": self.user.to_dict(),
|
||||
"score": self.score,
|
||||
}
|
||||
highscore = GameHighScore.de_json(json_dict, bot)
|
||||
highscore = GameHighScore.de_json(json_dict, offline_bot)
|
||||
assert highscore.api_kwargs == {}
|
||||
|
||||
assert highscore.position == self.position
|
||||
assert highscore.user == self.user
|
||||
assert highscore.score == self.score
|
||||
|
||||
assert GameHighScore.de_json(None, bot) is None
|
||||
assert GameHighScore.de_json(None, offline_bot) is None
|
||||
|
||||
def test_to_dict(self, game_highscore):
|
||||
game_highscore_dict = game_highscore.to_dict()
|
||||
|
||||
@@ -32,24 +32,24 @@ from tests.auxil.slots import mro_slots
|
||||
@pytest.fixture(scope="module")
|
||||
def inline_keyboard_button():
|
||||
return InlineKeyboardButton(
|
||||
TestInlineKeyboardButtonBase.text,
|
||||
url=TestInlineKeyboardButtonBase.url,
|
||||
callback_data=TestInlineKeyboardButtonBase.callback_data,
|
||||
switch_inline_query=TestInlineKeyboardButtonBase.switch_inline_query,
|
||||
InlineKeyboardButtonTestBase.text,
|
||||
url=InlineKeyboardButtonTestBase.url,
|
||||
callback_data=InlineKeyboardButtonTestBase.callback_data,
|
||||
switch_inline_query=InlineKeyboardButtonTestBase.switch_inline_query,
|
||||
switch_inline_query_current_chat=(
|
||||
TestInlineKeyboardButtonBase.switch_inline_query_current_chat
|
||||
InlineKeyboardButtonTestBase.switch_inline_query_current_chat
|
||||
),
|
||||
callback_game=TestInlineKeyboardButtonBase.callback_game,
|
||||
pay=TestInlineKeyboardButtonBase.pay,
|
||||
login_url=TestInlineKeyboardButtonBase.login_url,
|
||||
web_app=TestInlineKeyboardButtonBase.web_app,
|
||||
callback_game=InlineKeyboardButtonTestBase.callback_game,
|
||||
pay=InlineKeyboardButtonTestBase.pay,
|
||||
login_url=InlineKeyboardButtonTestBase.login_url,
|
||||
web_app=InlineKeyboardButtonTestBase.web_app,
|
||||
switch_inline_query_chosen_chat=(
|
||||
TestInlineKeyboardButtonBase.switch_inline_query_chosen_chat
|
||||
InlineKeyboardButtonTestBase.switch_inline_query_chosen_chat
|
||||
),
|
||||
)
|
||||
|
||||
|
||||
class TestInlineKeyboardButtonBase:
|
||||
class InlineKeyboardButtonTestBase:
|
||||
text = "text"
|
||||
url = "url"
|
||||
callback_data = "callback data"
|
||||
@@ -62,7 +62,7 @@ class TestInlineKeyboardButtonBase:
|
||||
switch_inline_query_chosen_chat = SwitchInlineQueryChosenChat("a_bot", True, False, True, True)
|
||||
|
||||
|
||||
class TestInlineKeyboardButtonWithoutRequest(TestInlineKeyboardButtonBase):
|
||||
class TestInlineKeyboardButtonWithoutRequest(InlineKeyboardButtonTestBase):
|
||||
def test_slot_behaviour(self, inline_keyboard_button):
|
||||
inst = inline_keyboard_button
|
||||
for attr in inst.__slots__:
|
||||
@@ -116,7 +116,7 @@ class TestInlineKeyboardButtonWithoutRequest(TestInlineKeyboardButtonBase):
|
||||
== inline_keyboard_button.switch_inline_query_chosen_chat.to_dict()
|
||||
)
|
||||
|
||||
def test_de_json(self, bot):
|
||||
def test_de_json(self, offline_bot):
|
||||
json_dict = {
|
||||
"text": self.text,
|
||||
"url": self.url,
|
||||
@@ -150,7 +150,7 @@ class TestInlineKeyboardButtonWithoutRequest(TestInlineKeyboardButtonBase):
|
||||
== self.switch_inline_query_chosen_chat
|
||||
)
|
||||
|
||||
none = InlineKeyboardButton.de_json({}, bot)
|
||||
none = InlineKeyboardButton.de_json({}, offline_bot)
|
||||
assert none is None
|
||||
|
||||
def test_equality(self):
|
||||
|
||||
@@ -31,10 +31,10 @@ from tests.auxil.slots import mro_slots
|
||||
|
||||
@pytest.fixture(scope="module")
|
||||
def inline_keyboard_markup():
|
||||
return InlineKeyboardMarkup(TestInlineKeyboardMarkupBase.inline_keyboard)
|
||||
return InlineKeyboardMarkup(InlineKeyboardMarkupTestBase.inline_keyboard)
|
||||
|
||||
|
||||
class TestInlineKeyboardMarkupBase:
|
||||
class InlineKeyboardMarkupTestBase:
|
||||
inline_keyboard = [
|
||||
[
|
||||
InlineKeyboardButton(text="button1", callback_data="data1"),
|
||||
@@ -43,7 +43,7 @@ class TestInlineKeyboardMarkupBase:
|
||||
]
|
||||
|
||||
|
||||
class TestInlineKeyboardMarkupWithoutRequest(TestInlineKeyboardMarkupBase):
|
||||
class TestInlineKeyboardMarkupWithoutRequest(InlineKeyboardMarkupTestBase):
|
||||
def test_slot_behaviour(self, inline_keyboard_markup):
|
||||
inst = inline_keyboard_markup
|
||||
for attr in inst.__slots__:
|
||||
@@ -192,7 +192,9 @@ class TestInlineKeyboardMarkupWithoutRequest(TestInlineKeyboardMarkupBase):
|
||||
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):
|
||||
async def test_expected_values_empty_switch(
|
||||
self, inline_keyboard_markup, offline_bot, monkeypatch
|
||||
):
|
||||
async def make_assertion(
|
||||
url,
|
||||
data,
|
||||
@@ -224,11 +226,11 @@ class TestInlineKeyboardMarkupWithoutRequest(TestInlineKeyboardMarkupBase):
|
||||
inline_keyboard_markup.inline_keyboard[0][1].callback_data = None
|
||||
inline_keyboard_markup.inline_keyboard[0][1].switch_inline_query_current_chat = ""
|
||||
|
||||
monkeypatch.setattr(bot, "_send_message", make_assertion)
|
||||
await bot.send_message(123, "test", reply_markup=inline_keyboard_markup)
|
||||
monkeypatch.setattr(offline_bot, "_send_message", make_assertion)
|
||||
await offline_bot.send_message(123, "test", reply_markup=inline_keyboard_markup)
|
||||
|
||||
|
||||
class TestInlineKeyborardMarkupWithRequest(TestInlineKeyboardMarkupBase):
|
||||
class TestInlineKeyborardMarkupWithRequest(InlineKeyboardMarkupTestBase):
|
||||
async def test_send_message_with_inline_keyboard_markup(
|
||||
self, bot, chat_id, inline_keyboard_markup
|
||||
):
|
||||
|
||||
@@ -31,17 +31,17 @@ from tests.auxil.slots import mro_slots
|
||||
@pytest.fixture(scope="module")
|
||||
def inline_query(bot):
|
||||
ilq = InlineQuery(
|
||||
TestInlineQueryBase.id_,
|
||||
TestInlineQueryBase.from_user,
|
||||
TestInlineQueryBase.query,
|
||||
TestInlineQueryBase.offset,
|
||||
location=TestInlineQueryBase.location,
|
||||
InlineQueryTestBase.id_,
|
||||
InlineQueryTestBase.from_user,
|
||||
InlineQueryTestBase.query,
|
||||
InlineQueryTestBase.offset,
|
||||
location=InlineQueryTestBase.location,
|
||||
)
|
||||
ilq.set_bot(bot)
|
||||
return ilq
|
||||
|
||||
|
||||
class TestInlineQueryBase:
|
||||
class InlineQueryTestBase:
|
||||
id_ = 1234
|
||||
from_user = User(1, "First name", False)
|
||||
query = "query text"
|
||||
@@ -49,13 +49,13 @@ class TestInlineQueryBase:
|
||||
location = Location(8.8, 53.1)
|
||||
|
||||
|
||||
class TestInlineQueryWithoutRequest(TestInlineQueryBase):
|
||||
class TestInlineQueryWithoutRequest(InlineQueryTestBase):
|
||||
def test_slot_behaviour(self, inline_query):
|
||||
for attr in inline_query.__slots__:
|
||||
assert getattr(inline_query, attr, "err") != "err", f"got extra slot '{attr}'"
|
||||
assert len(mro_slots(inline_query)) == len(set(mro_slots(inline_query))), "duplicate slot"
|
||||
|
||||
def test_de_json(self, bot):
|
||||
def test_de_json(self, offline_bot):
|
||||
json_dict = {
|
||||
"id": self.id_,
|
||||
"from": self.from_user.to_dict(),
|
||||
@@ -63,7 +63,7 @@ class TestInlineQueryWithoutRequest(TestInlineQueryBase):
|
||||
"offset": self.offset,
|
||||
"location": self.location.to_dict(),
|
||||
}
|
||||
inline_query_json = InlineQuery.de_json(json_dict, bot)
|
||||
inline_query_json = InlineQuery.de_json(json_dict, offline_bot)
|
||||
assert inline_query_json.api_kwargs == {}
|
||||
|
||||
assert inline_query_json.id == self.id_
|
||||
|
||||
@@ -34,20 +34,20 @@ from tests.auxil.slots import mro_slots
|
||||
@pytest.fixture(scope="module")
|
||||
def inline_query_result_article():
|
||||
return InlineQueryResultArticle(
|
||||
TestInlineQueryResultArticleBase.id_,
|
||||
TestInlineQueryResultArticleBase.title,
|
||||
input_message_content=TestInlineQueryResultArticleBase.input_message_content,
|
||||
reply_markup=TestInlineQueryResultArticleBase.reply_markup,
|
||||
url=TestInlineQueryResultArticleBase.url,
|
||||
hide_url=TestInlineQueryResultArticleBase.hide_url,
|
||||
description=TestInlineQueryResultArticleBase.description,
|
||||
thumbnail_url=TestInlineQueryResultArticleBase.thumbnail_url,
|
||||
thumbnail_height=TestInlineQueryResultArticleBase.thumbnail_height,
|
||||
thumbnail_width=TestInlineQueryResultArticleBase.thumbnail_width,
|
||||
InlineQueryResultArticleTestBase.id_,
|
||||
InlineQueryResultArticleTestBase.title,
|
||||
input_message_content=InlineQueryResultArticleTestBase.input_message_content,
|
||||
reply_markup=InlineQueryResultArticleTestBase.reply_markup,
|
||||
url=InlineQueryResultArticleTestBase.url,
|
||||
hide_url=InlineQueryResultArticleTestBase.hide_url,
|
||||
description=InlineQueryResultArticleTestBase.description,
|
||||
thumbnail_url=InlineQueryResultArticleTestBase.thumbnail_url,
|
||||
thumbnail_height=InlineQueryResultArticleTestBase.thumbnail_height,
|
||||
thumbnail_width=InlineQueryResultArticleTestBase.thumbnail_width,
|
||||
)
|
||||
|
||||
|
||||
class TestInlineQueryResultArticleBase:
|
||||
class InlineQueryResultArticleTestBase:
|
||||
id_ = "id"
|
||||
type_ = "article"
|
||||
title = "title"
|
||||
@@ -61,7 +61,7 @@ class TestInlineQueryResultArticleBase:
|
||||
thumbnail_width = 15
|
||||
|
||||
|
||||
class TestInlineQueryResultArticleWithoutRequest(TestInlineQueryResultArticleBase):
|
||||
class TestInlineQueryResultArticleWithoutRequest(InlineQueryResultArticleTestBase):
|
||||
def test_slot_behaviour(self, inline_query_result_article):
|
||||
inst = inline_query_result_article
|
||||
for attr in inst.__slots__:
|
||||
|
||||
@@ -33,20 +33,20 @@ from tests.auxil.slots import mro_slots
|
||||
@pytest.fixture(scope="module")
|
||||
def inline_query_result_audio():
|
||||
return InlineQueryResultAudio(
|
||||
TestInlineQueryResultAudioBase.id_,
|
||||
TestInlineQueryResultAudioBase.audio_url,
|
||||
TestInlineQueryResultAudioBase.title,
|
||||
performer=TestInlineQueryResultAudioBase.performer,
|
||||
audio_duration=TestInlineQueryResultAudioBase.audio_duration,
|
||||
caption=TestInlineQueryResultAudioBase.caption,
|
||||
parse_mode=TestInlineQueryResultAudioBase.parse_mode,
|
||||
caption_entities=TestInlineQueryResultAudioBase.caption_entities,
|
||||
input_message_content=TestInlineQueryResultAudioBase.input_message_content,
|
||||
reply_markup=TestInlineQueryResultAudioBase.reply_markup,
|
||||
InlineQueryResultAudioTestBase.id_,
|
||||
InlineQueryResultAudioTestBase.audio_url,
|
||||
InlineQueryResultAudioTestBase.title,
|
||||
performer=InlineQueryResultAudioTestBase.performer,
|
||||
audio_duration=InlineQueryResultAudioTestBase.audio_duration,
|
||||
caption=InlineQueryResultAudioTestBase.caption,
|
||||
parse_mode=InlineQueryResultAudioTestBase.parse_mode,
|
||||
caption_entities=InlineQueryResultAudioTestBase.caption_entities,
|
||||
input_message_content=InlineQueryResultAudioTestBase.input_message_content,
|
||||
reply_markup=InlineQueryResultAudioTestBase.reply_markup,
|
||||
)
|
||||
|
||||
|
||||
class TestInlineQueryResultAudioBase:
|
||||
class InlineQueryResultAudioTestBase:
|
||||
id_ = "id"
|
||||
type_ = "audio"
|
||||
audio_url = "audio url"
|
||||
@@ -60,7 +60,7 @@ class TestInlineQueryResultAudioBase:
|
||||
reply_markup = InlineKeyboardMarkup([[InlineKeyboardButton("reply_markup")]])
|
||||
|
||||
|
||||
class TestInlineQueryResultAudioWithoutRequest(TestInlineQueryResultAudioBase):
|
||||
class TestInlineQueryResultAudioWithoutRequest(InlineQueryResultAudioTestBase):
|
||||
def test_slot_behaviour(self, inline_query_result_audio):
|
||||
inst = inline_query_result_audio
|
||||
for attr in inst.__slots__:
|
||||
|
||||
@@ -33,17 +33,17 @@ from tests.auxil.slots import mro_slots
|
||||
@pytest.fixture(scope="module")
|
||||
def inline_query_result_cached_audio():
|
||||
return InlineQueryResultCachedAudio(
|
||||
TestInlineQueryResultCachedAudioBase.id_,
|
||||
TestInlineQueryResultCachedAudioBase.audio_file_id,
|
||||
caption=TestInlineQueryResultCachedAudioBase.caption,
|
||||
parse_mode=TestInlineQueryResultCachedAudioBase.parse_mode,
|
||||
caption_entities=TestInlineQueryResultCachedAudioBase.caption_entities,
|
||||
input_message_content=TestInlineQueryResultCachedAudioBase.input_message_content,
|
||||
reply_markup=TestInlineQueryResultCachedAudioBase.reply_markup,
|
||||
InlineQueryResultCachedAudioTestBase.id_,
|
||||
InlineQueryResultCachedAudioTestBase.audio_file_id,
|
||||
caption=InlineQueryResultCachedAudioTestBase.caption,
|
||||
parse_mode=InlineQueryResultCachedAudioTestBase.parse_mode,
|
||||
caption_entities=InlineQueryResultCachedAudioTestBase.caption_entities,
|
||||
input_message_content=InlineQueryResultCachedAudioTestBase.input_message_content,
|
||||
reply_markup=InlineQueryResultCachedAudioTestBase.reply_markup,
|
||||
)
|
||||
|
||||
|
||||
class TestInlineQueryResultCachedAudioBase:
|
||||
class InlineQueryResultCachedAudioTestBase:
|
||||
id_ = "id"
|
||||
type_ = "audio"
|
||||
audio_file_id = "audio file id"
|
||||
@@ -54,7 +54,7 @@ class TestInlineQueryResultCachedAudioBase:
|
||||
reply_markup = InlineKeyboardMarkup([[InlineKeyboardButton("reply_markup")]])
|
||||
|
||||
|
||||
class TestInlineQueryResultCachedAudioWithoutRequest(TestInlineQueryResultCachedAudioBase):
|
||||
class TestInlineQueryResultCachedAudioWithoutRequest(InlineQueryResultCachedAudioTestBase):
|
||||
def test_slot_behaviour(self, inline_query_result_cached_audio):
|
||||
inst = inline_query_result_cached_audio
|
||||
for attr in inst.__slots__:
|
||||
|
||||
@@ -33,19 +33,19 @@ from tests.auxil.slots import mro_slots
|
||||
@pytest.fixture(scope="module")
|
||||
def inline_query_result_cached_document():
|
||||
return InlineQueryResultCachedDocument(
|
||||
TestInlineQueryResultCachedDocumentBase.id_,
|
||||
TestInlineQueryResultCachedDocumentBase.title,
|
||||
TestInlineQueryResultCachedDocumentBase.document_file_id,
|
||||
caption=TestInlineQueryResultCachedDocumentBase.caption,
|
||||
parse_mode=TestInlineQueryResultCachedDocumentBase.parse_mode,
|
||||
caption_entities=TestInlineQueryResultCachedDocumentBase.caption_entities,
|
||||
description=TestInlineQueryResultCachedDocumentBase.description,
|
||||
input_message_content=TestInlineQueryResultCachedDocumentBase.input_message_content,
|
||||
reply_markup=TestInlineQueryResultCachedDocumentBase.reply_markup,
|
||||
InlineQueryResultCachedDocumentTestBase.id_,
|
||||
InlineQueryResultCachedDocumentTestBase.title,
|
||||
InlineQueryResultCachedDocumentTestBase.document_file_id,
|
||||
caption=InlineQueryResultCachedDocumentTestBase.caption,
|
||||
parse_mode=InlineQueryResultCachedDocumentTestBase.parse_mode,
|
||||
caption_entities=InlineQueryResultCachedDocumentTestBase.caption_entities,
|
||||
description=InlineQueryResultCachedDocumentTestBase.description,
|
||||
input_message_content=InlineQueryResultCachedDocumentTestBase.input_message_content,
|
||||
reply_markup=InlineQueryResultCachedDocumentTestBase.reply_markup,
|
||||
)
|
||||
|
||||
|
||||
class TestInlineQueryResultCachedDocumentBase:
|
||||
class InlineQueryResultCachedDocumentTestBase:
|
||||
id_ = "id"
|
||||
type_ = "document"
|
||||
document_file_id = "document file id"
|
||||
@@ -58,7 +58,7 @@ class TestInlineQueryResultCachedDocumentBase:
|
||||
reply_markup = InlineKeyboardMarkup([[InlineKeyboardButton("reply_markup")]])
|
||||
|
||||
|
||||
class TestInlineQueryResultCachedDocumentWithoutRequest(TestInlineQueryResultCachedDocumentBase):
|
||||
class TestInlineQueryResultCachedDocumentWithoutRequest(InlineQueryResultCachedDocumentTestBase):
|
||||
def test_slot_behaviour(self, inline_query_result_cached_document):
|
||||
inst = inline_query_result_cached_document
|
||||
for attr in inst.__slots__:
|
||||
|
||||
@@ -32,19 +32,19 @@ from tests.auxil.slots import mro_slots
|
||||
@pytest.fixture(scope="module")
|
||||
def inline_query_result_cached_gif():
|
||||
return InlineQueryResultCachedGif(
|
||||
TestInlineQueryResultCachedGifBase.id_,
|
||||
TestInlineQueryResultCachedGifBase.gif_file_id,
|
||||
title=TestInlineQueryResultCachedGifBase.title,
|
||||
caption=TestInlineQueryResultCachedGifBase.caption,
|
||||
parse_mode=TestInlineQueryResultCachedGifBase.parse_mode,
|
||||
caption_entities=TestInlineQueryResultCachedGifBase.caption_entities,
|
||||
input_message_content=TestInlineQueryResultCachedGifBase.input_message_content,
|
||||
reply_markup=TestInlineQueryResultCachedGifBase.reply_markup,
|
||||
show_caption_above_media=TestInlineQueryResultCachedGifBase.show_caption_above_media,
|
||||
InlineQueryResultCachedGifTestBase.id_,
|
||||
InlineQueryResultCachedGifTestBase.gif_file_id,
|
||||
title=InlineQueryResultCachedGifTestBase.title,
|
||||
caption=InlineQueryResultCachedGifTestBase.caption,
|
||||
parse_mode=InlineQueryResultCachedGifTestBase.parse_mode,
|
||||
caption_entities=InlineQueryResultCachedGifTestBase.caption_entities,
|
||||
input_message_content=InlineQueryResultCachedGifTestBase.input_message_content,
|
||||
reply_markup=InlineQueryResultCachedGifTestBase.reply_markup,
|
||||
show_caption_above_media=InlineQueryResultCachedGifTestBase.show_caption_above_media,
|
||||
)
|
||||
|
||||
|
||||
class TestInlineQueryResultCachedGifBase:
|
||||
class InlineQueryResultCachedGifTestBase:
|
||||
id_ = "id"
|
||||
type_ = "gif"
|
||||
gif_file_id = "gif file id"
|
||||
@@ -57,7 +57,7 @@ class TestInlineQueryResultCachedGifBase:
|
||||
show_caption_above_media = True
|
||||
|
||||
|
||||
class TestInlineQueryResultCachedGifWithoutRequest(TestInlineQueryResultCachedGifBase):
|
||||
class TestInlineQueryResultCachedGifWithoutRequest(InlineQueryResultCachedGifTestBase):
|
||||
def test_slot_behaviour(self, inline_query_result_cached_gif):
|
||||
inst = inline_query_result_cached_gif
|
||||
for attr in inst.__slots__:
|
||||
|
||||
@@ -32,19 +32,19 @@ from tests.auxil.slots import mro_slots
|
||||
@pytest.fixture(scope="module")
|
||||
def inline_query_result_cached_mpeg4_gif():
|
||||
return InlineQueryResultCachedMpeg4Gif(
|
||||
TestInlineQueryResultCachedMpeg4GifBase.id_,
|
||||
TestInlineQueryResultCachedMpeg4GifBase.mpeg4_file_id,
|
||||
title=TestInlineQueryResultCachedMpeg4GifBase.title,
|
||||
caption=TestInlineQueryResultCachedMpeg4GifBase.caption,
|
||||
parse_mode=TestInlineQueryResultCachedMpeg4GifBase.parse_mode,
|
||||
caption_entities=TestInlineQueryResultCachedMpeg4GifBase.caption_entities,
|
||||
input_message_content=TestInlineQueryResultCachedMpeg4GifBase.input_message_content,
|
||||
reply_markup=TestInlineQueryResultCachedMpeg4GifBase.reply_markup,
|
||||
show_caption_above_media=TestInlineQueryResultCachedMpeg4GifBase.show_caption_above_media,
|
||||
InlineQueryResultCachedMpeg4GifTestBase.id_,
|
||||
InlineQueryResultCachedMpeg4GifTestBase.mpeg4_file_id,
|
||||
title=InlineQueryResultCachedMpeg4GifTestBase.title,
|
||||
caption=InlineQueryResultCachedMpeg4GifTestBase.caption,
|
||||
parse_mode=InlineQueryResultCachedMpeg4GifTestBase.parse_mode,
|
||||
caption_entities=InlineQueryResultCachedMpeg4GifTestBase.caption_entities,
|
||||
input_message_content=InlineQueryResultCachedMpeg4GifTestBase.input_message_content,
|
||||
reply_markup=InlineQueryResultCachedMpeg4GifTestBase.reply_markup,
|
||||
show_caption_above_media=InlineQueryResultCachedMpeg4GifTestBase.show_caption_above_media,
|
||||
)
|
||||
|
||||
|
||||
class TestInlineQueryResultCachedMpeg4GifBase:
|
||||
class InlineQueryResultCachedMpeg4GifTestBase:
|
||||
id_ = "id"
|
||||
type_ = "mpeg4_gif"
|
||||
mpeg4_file_id = "mpeg4 file id"
|
||||
@@ -57,7 +57,7 @@ class TestInlineQueryResultCachedMpeg4GifBase:
|
||||
show_caption_above_media = True
|
||||
|
||||
|
||||
class TestInlineQueryResultCachedMpeg4GifWithoutRequest(TestInlineQueryResultCachedMpeg4GifBase):
|
||||
class TestInlineQueryResultCachedMpeg4GifWithoutRequest(InlineQueryResultCachedMpeg4GifTestBase):
|
||||
def test_slot_behaviour(self, inline_query_result_cached_mpeg4_gif):
|
||||
inst = inline_query_result_cached_mpeg4_gif
|
||||
for attr in inst.__slots__:
|
||||
|
||||
@@ -32,20 +32,20 @@ from tests.auxil.slots import mro_slots
|
||||
@pytest.fixture(scope="module")
|
||||
def inline_query_result_cached_photo():
|
||||
return InlineQueryResultCachedPhoto(
|
||||
TestInlineQueryResultCachedPhotoBase.id_,
|
||||
TestInlineQueryResultCachedPhotoBase.photo_file_id,
|
||||
title=TestInlineQueryResultCachedPhotoBase.title,
|
||||
description=TestInlineQueryResultCachedPhotoBase.description,
|
||||
caption=TestInlineQueryResultCachedPhotoBase.caption,
|
||||
parse_mode=TestInlineQueryResultCachedPhotoBase.parse_mode,
|
||||
caption_entities=TestInlineQueryResultCachedPhotoBase.caption_entities,
|
||||
input_message_content=TestInlineQueryResultCachedPhotoBase.input_message_content,
|
||||
reply_markup=TestInlineQueryResultCachedPhotoBase.reply_markup,
|
||||
show_caption_above_media=TestInlineQueryResultCachedPhotoBase.show_caption_above_media,
|
||||
InlineQueryResultCachedPhotoTestBase.id_,
|
||||
InlineQueryResultCachedPhotoTestBase.photo_file_id,
|
||||
title=InlineQueryResultCachedPhotoTestBase.title,
|
||||
description=InlineQueryResultCachedPhotoTestBase.description,
|
||||
caption=InlineQueryResultCachedPhotoTestBase.caption,
|
||||
parse_mode=InlineQueryResultCachedPhotoTestBase.parse_mode,
|
||||
caption_entities=InlineQueryResultCachedPhotoTestBase.caption_entities,
|
||||
input_message_content=InlineQueryResultCachedPhotoTestBase.input_message_content,
|
||||
reply_markup=InlineQueryResultCachedPhotoTestBase.reply_markup,
|
||||
show_caption_above_media=InlineQueryResultCachedPhotoTestBase.show_caption_above_media,
|
||||
)
|
||||
|
||||
|
||||
class TestInlineQueryResultCachedPhotoBase:
|
||||
class InlineQueryResultCachedPhotoTestBase:
|
||||
id_ = "id"
|
||||
type_ = "photo"
|
||||
photo_file_id = "photo file id"
|
||||
@@ -59,7 +59,7 @@ class TestInlineQueryResultCachedPhotoBase:
|
||||
show_caption_above_media = True
|
||||
|
||||
|
||||
class TestInlineQueryResultCachedPhotoWithoutRequest(TestInlineQueryResultCachedPhotoBase):
|
||||
class TestInlineQueryResultCachedPhotoWithoutRequest(InlineQueryResultCachedPhotoTestBase):
|
||||
def test_slot_behaviour(self, inline_query_result_cached_photo):
|
||||
inst = inline_query_result_cached_photo
|
||||
for attr in inst.__slots__:
|
||||
|
||||
@@ -31,14 +31,14 @@ from tests.auxil.slots import mro_slots
|
||||
@pytest.fixture(scope="module")
|
||||
def inline_query_result_cached_sticker():
|
||||
return InlineQueryResultCachedSticker(
|
||||
TestInlineQueryResultCachedStickerBase.id_,
|
||||
TestInlineQueryResultCachedStickerBase.sticker_file_id,
|
||||
input_message_content=TestInlineQueryResultCachedStickerBase.input_message_content,
|
||||
reply_markup=TestInlineQueryResultCachedStickerBase.reply_markup,
|
||||
InlineQueryResultCachedStickerTestBase.id_,
|
||||
InlineQueryResultCachedStickerTestBase.sticker_file_id,
|
||||
input_message_content=InlineQueryResultCachedStickerTestBase.input_message_content,
|
||||
reply_markup=InlineQueryResultCachedStickerTestBase.reply_markup,
|
||||
)
|
||||
|
||||
|
||||
class TestInlineQueryResultCachedStickerBase:
|
||||
class InlineQueryResultCachedStickerTestBase:
|
||||
id_ = "id"
|
||||
type_ = "sticker"
|
||||
sticker_file_id = "sticker file id"
|
||||
@@ -46,7 +46,7 @@ class TestInlineQueryResultCachedStickerBase:
|
||||
reply_markup = InlineKeyboardMarkup([[InlineKeyboardButton("reply_markup")]])
|
||||
|
||||
|
||||
class TestInlineQueryResultCachedStickerWithoutRequest(TestInlineQueryResultCachedStickerBase):
|
||||
class TestInlineQueryResultCachedStickerWithoutRequest(InlineQueryResultCachedStickerTestBase):
|
||||
def test_slot_behaviour(self, inline_query_result_cached_sticker):
|
||||
inst = inline_query_result_cached_sticker
|
||||
for attr in inst.__slots__:
|
||||
|
||||
@@ -32,20 +32,20 @@ from tests.auxil.slots import mro_slots
|
||||
@pytest.fixture(scope="module")
|
||||
def inline_query_result_cached_video():
|
||||
return InlineQueryResultCachedVideo(
|
||||
TestInlineQueryResultCachedVideoBase.id_,
|
||||
TestInlineQueryResultCachedVideoBase.video_file_id,
|
||||
TestInlineQueryResultCachedVideoBase.title,
|
||||
caption=TestInlineQueryResultCachedVideoBase.caption,
|
||||
parse_mode=TestInlineQueryResultCachedVideoBase.parse_mode,
|
||||
caption_entities=TestInlineQueryResultCachedVideoBase.caption_entities,
|
||||
description=TestInlineQueryResultCachedVideoBase.description,
|
||||
input_message_content=TestInlineQueryResultCachedVideoBase.input_message_content,
|
||||
reply_markup=TestInlineQueryResultCachedVideoBase.reply_markup,
|
||||
show_caption_above_media=TestInlineQueryResultCachedVideoBase.show_caption_above_media,
|
||||
InlineQueryResultCachedVideoTestBase.id_,
|
||||
InlineQueryResultCachedVideoTestBase.video_file_id,
|
||||
InlineQueryResultCachedVideoTestBase.title,
|
||||
caption=InlineQueryResultCachedVideoTestBase.caption,
|
||||
parse_mode=InlineQueryResultCachedVideoTestBase.parse_mode,
|
||||
caption_entities=InlineQueryResultCachedVideoTestBase.caption_entities,
|
||||
description=InlineQueryResultCachedVideoTestBase.description,
|
||||
input_message_content=InlineQueryResultCachedVideoTestBase.input_message_content,
|
||||
reply_markup=InlineQueryResultCachedVideoTestBase.reply_markup,
|
||||
show_caption_above_media=InlineQueryResultCachedVideoTestBase.show_caption_above_media,
|
||||
)
|
||||
|
||||
|
||||
class TestInlineQueryResultCachedVideoBase:
|
||||
class InlineQueryResultCachedVideoTestBase:
|
||||
id_ = "id"
|
||||
type_ = "video"
|
||||
video_file_id = "video file id"
|
||||
@@ -59,7 +59,7 @@ class TestInlineQueryResultCachedVideoBase:
|
||||
show_caption_above_media = True
|
||||
|
||||
|
||||
class TestInlineQueryResultCachedVideoWithoutRequest(TestInlineQueryResultCachedVideoBase):
|
||||
class TestInlineQueryResultCachedVideoWithoutRequest(InlineQueryResultCachedVideoTestBase):
|
||||
def test_slot_behaviour(self, inline_query_result_cached_video):
|
||||
inst = inline_query_result_cached_video
|
||||
for attr in inst.__slots__:
|
||||
|
||||
@@ -32,18 +32,18 @@ from tests.auxil.slots import mro_slots
|
||||
@pytest.fixture(scope="module")
|
||||
def inline_query_result_cached_voice():
|
||||
return InlineQueryResultCachedVoice(
|
||||
TestInlineQueryResultCachedVoiceBase.id_,
|
||||
TestInlineQueryResultCachedVoiceBase.voice_file_id,
|
||||
TestInlineQueryResultCachedVoiceBase.title,
|
||||
caption=TestInlineQueryResultCachedVoiceBase.caption,
|
||||
parse_mode=TestInlineQueryResultCachedVoiceBase.parse_mode,
|
||||
caption_entities=TestInlineQueryResultCachedVoiceBase.caption_entities,
|
||||
input_message_content=TestInlineQueryResultCachedVoiceBase.input_message_content,
|
||||
reply_markup=TestInlineQueryResultCachedVoiceBase.reply_markup,
|
||||
InlineQueryResultCachedVoiceTestBase.id_,
|
||||
InlineQueryResultCachedVoiceTestBase.voice_file_id,
|
||||
InlineQueryResultCachedVoiceTestBase.title,
|
||||
caption=InlineQueryResultCachedVoiceTestBase.caption,
|
||||
parse_mode=InlineQueryResultCachedVoiceTestBase.parse_mode,
|
||||
caption_entities=InlineQueryResultCachedVoiceTestBase.caption_entities,
|
||||
input_message_content=InlineQueryResultCachedVoiceTestBase.input_message_content,
|
||||
reply_markup=InlineQueryResultCachedVoiceTestBase.reply_markup,
|
||||
)
|
||||
|
||||
|
||||
class TestInlineQueryResultCachedVoiceBase:
|
||||
class InlineQueryResultCachedVoiceTestBase:
|
||||
id_ = "id"
|
||||
type_ = "voice"
|
||||
voice_file_id = "voice file id"
|
||||
@@ -55,7 +55,7 @@ class TestInlineQueryResultCachedVoiceBase:
|
||||
reply_markup = InlineKeyboardMarkup([[InlineKeyboardButton("reply_markup")]])
|
||||
|
||||
|
||||
class TestInlineQueryResultCachedVoiceWithoutRequest(TestInlineQueryResultCachedVoiceBase):
|
||||
class TestInlineQueryResultCachedVoiceWithoutRequest(InlineQueryResultCachedVoiceTestBase):
|
||||
def test_slot_behaviour(self, inline_query_result_cached_voice):
|
||||
inst = inline_query_result_cached_voice
|
||||
for attr in inst.__slots__:
|
||||
|
||||
@@ -31,19 +31,19 @@ from tests.auxil.slots import mro_slots
|
||||
@pytest.fixture(scope="module")
|
||||
def inline_query_result_contact():
|
||||
return InlineQueryResultContact(
|
||||
TestInlineQueryResultContactBase.id_,
|
||||
TestInlineQueryResultContactBase.phone_number,
|
||||
TestInlineQueryResultContactBase.first_name,
|
||||
last_name=TestInlineQueryResultContactBase.last_name,
|
||||
thumbnail_url=TestInlineQueryResultContactBase.thumbnail_url,
|
||||
thumbnail_width=TestInlineQueryResultContactBase.thumbnail_width,
|
||||
thumbnail_height=TestInlineQueryResultContactBase.thumbnail_height,
|
||||
input_message_content=TestInlineQueryResultContactBase.input_message_content,
|
||||
reply_markup=TestInlineQueryResultContactBase.reply_markup,
|
||||
InlineQueryResultContactTestBase.id_,
|
||||
InlineQueryResultContactTestBase.phone_number,
|
||||
InlineQueryResultContactTestBase.first_name,
|
||||
last_name=InlineQueryResultContactTestBase.last_name,
|
||||
thumbnail_url=InlineQueryResultContactTestBase.thumbnail_url,
|
||||
thumbnail_width=InlineQueryResultContactTestBase.thumbnail_width,
|
||||
thumbnail_height=InlineQueryResultContactTestBase.thumbnail_height,
|
||||
input_message_content=InlineQueryResultContactTestBase.input_message_content,
|
||||
reply_markup=InlineQueryResultContactTestBase.reply_markup,
|
||||
)
|
||||
|
||||
|
||||
class TestInlineQueryResultContactBase:
|
||||
class InlineQueryResultContactTestBase:
|
||||
id_ = "id"
|
||||
type_ = "contact"
|
||||
phone_number = "phone_number"
|
||||
@@ -56,7 +56,7 @@ class TestInlineQueryResultContactBase:
|
||||
reply_markup = InlineKeyboardMarkup([[InlineKeyboardButton("reply_markup")]])
|
||||
|
||||
|
||||
class TestInlineQueryResultContactWithoutRequest(TestInlineQueryResultContactBase):
|
||||
class TestInlineQueryResultContactWithoutRequest(InlineQueryResultContactTestBase):
|
||||
def test_slot_behaviour(self, inline_query_result_contact):
|
||||
inst = inline_query_result_contact
|
||||
for attr in inst.__slots__:
|
||||
|
||||
@@ -32,23 +32,23 @@ from tests.auxil.slots import mro_slots
|
||||
@pytest.fixture(scope="module")
|
||||
def inline_query_result_document():
|
||||
return InlineQueryResultDocument(
|
||||
TestInlineQueryResultDocumentBase.id_,
|
||||
TestInlineQueryResultDocumentBase.document_url,
|
||||
TestInlineQueryResultDocumentBase.title,
|
||||
TestInlineQueryResultDocumentBase.mime_type,
|
||||
caption=TestInlineQueryResultDocumentBase.caption,
|
||||
parse_mode=TestInlineQueryResultDocumentBase.parse_mode,
|
||||
caption_entities=TestInlineQueryResultDocumentBase.caption_entities,
|
||||
description=TestInlineQueryResultDocumentBase.description,
|
||||
thumbnail_url=TestInlineQueryResultDocumentBase.thumbnail_url,
|
||||
thumbnail_width=TestInlineQueryResultDocumentBase.thumbnail_width,
|
||||
thumbnail_height=TestInlineQueryResultDocumentBase.thumbnail_height,
|
||||
input_message_content=TestInlineQueryResultDocumentBase.input_message_content,
|
||||
reply_markup=TestInlineQueryResultDocumentBase.reply_markup,
|
||||
InlineQueryResultDocumentTestBase.id_,
|
||||
InlineQueryResultDocumentTestBase.document_url,
|
||||
InlineQueryResultDocumentTestBase.title,
|
||||
InlineQueryResultDocumentTestBase.mime_type,
|
||||
caption=InlineQueryResultDocumentTestBase.caption,
|
||||
parse_mode=InlineQueryResultDocumentTestBase.parse_mode,
|
||||
caption_entities=InlineQueryResultDocumentTestBase.caption_entities,
|
||||
description=InlineQueryResultDocumentTestBase.description,
|
||||
thumbnail_url=InlineQueryResultDocumentTestBase.thumbnail_url,
|
||||
thumbnail_width=InlineQueryResultDocumentTestBase.thumbnail_width,
|
||||
thumbnail_height=InlineQueryResultDocumentTestBase.thumbnail_height,
|
||||
input_message_content=InlineQueryResultDocumentTestBase.input_message_content,
|
||||
reply_markup=InlineQueryResultDocumentTestBase.reply_markup,
|
||||
)
|
||||
|
||||
|
||||
class TestInlineQueryResultDocumentBase:
|
||||
class InlineQueryResultDocumentTestBase:
|
||||
id_ = "id"
|
||||
type_ = "document"
|
||||
document_url = "document url"
|
||||
@@ -65,7 +65,7 @@ class TestInlineQueryResultDocumentBase:
|
||||
reply_markup = InlineKeyboardMarkup([[InlineKeyboardButton("reply_markup")]])
|
||||
|
||||
|
||||
class TestInlineQueryResultDocumentWithoutRequest(TestInlineQueryResultDocumentBase):
|
||||
class TestInlineQueryResultDocumentWithoutRequest(InlineQueryResultDocumentTestBase):
|
||||
def test_slot_behaviour(self, inline_query_result_document):
|
||||
inst = inline_query_result_document
|
||||
for attr in inst.__slots__:
|
||||
|
||||
@@ -30,20 +30,20 @@ from tests.auxil.slots import mro_slots
|
||||
@pytest.fixture(scope="module")
|
||||
def inline_query_result_game():
|
||||
return InlineQueryResultGame(
|
||||
TestInlineQueryResultGameBase.id_,
|
||||
TestInlineQueryResultGameBase.game_short_name,
|
||||
reply_markup=TestInlineQueryResultGameBase.reply_markup,
|
||||
InlineQueryResultGameTestBase.id_,
|
||||
InlineQueryResultGameTestBase.game_short_name,
|
||||
reply_markup=InlineQueryResultGameTestBase.reply_markup,
|
||||
)
|
||||
|
||||
|
||||
class TestInlineQueryResultGameBase:
|
||||
class InlineQueryResultGameTestBase:
|
||||
id_ = "id"
|
||||
type_ = "game"
|
||||
game_short_name = "game short name"
|
||||
reply_markup = InlineKeyboardMarkup([[InlineKeyboardButton("reply_markup")]])
|
||||
|
||||
|
||||
class TestInlineQueryResultGameWithoutRequest(TestInlineQueryResultGameBase):
|
||||
class TestInlineQueryResultGameWithoutRequest(InlineQueryResultGameTestBase):
|
||||
def test_slot_behaviour(self, inline_query_result_game):
|
||||
inst = inline_query_result_game
|
||||
for attr in inst.__slots__:
|
||||
|
||||
@@ -32,24 +32,24 @@ from tests.auxil.slots import mro_slots
|
||||
@pytest.fixture(scope="module")
|
||||
def inline_query_result_gif():
|
||||
return InlineQueryResultGif(
|
||||
TestInlineQueryResultGifBase.id_,
|
||||
TestInlineQueryResultGifBase.gif_url,
|
||||
TestInlineQueryResultGifBase.thumbnail_url,
|
||||
gif_width=TestInlineQueryResultGifBase.gif_width,
|
||||
gif_height=TestInlineQueryResultGifBase.gif_height,
|
||||
gif_duration=TestInlineQueryResultGifBase.gif_duration,
|
||||
title=TestInlineQueryResultGifBase.title,
|
||||
caption=TestInlineQueryResultGifBase.caption,
|
||||
parse_mode=TestInlineQueryResultGifBase.parse_mode,
|
||||
caption_entities=TestInlineQueryResultGifBase.caption_entities,
|
||||
input_message_content=TestInlineQueryResultGifBase.input_message_content,
|
||||
reply_markup=TestInlineQueryResultGifBase.reply_markup,
|
||||
thumbnail_mime_type=TestInlineQueryResultGifBase.thumbnail_mime_type,
|
||||
show_caption_above_media=TestInlineQueryResultGifBase.show_caption_above_media,
|
||||
InlineQueryResultGifTestBase.id_,
|
||||
InlineQueryResultGifTestBase.gif_url,
|
||||
InlineQueryResultGifTestBase.thumbnail_url,
|
||||
gif_width=InlineQueryResultGifTestBase.gif_width,
|
||||
gif_height=InlineQueryResultGifTestBase.gif_height,
|
||||
gif_duration=InlineQueryResultGifTestBase.gif_duration,
|
||||
title=InlineQueryResultGifTestBase.title,
|
||||
caption=InlineQueryResultGifTestBase.caption,
|
||||
parse_mode=InlineQueryResultGifTestBase.parse_mode,
|
||||
caption_entities=InlineQueryResultGifTestBase.caption_entities,
|
||||
input_message_content=InlineQueryResultGifTestBase.input_message_content,
|
||||
reply_markup=InlineQueryResultGifTestBase.reply_markup,
|
||||
thumbnail_mime_type=InlineQueryResultGifTestBase.thumbnail_mime_type,
|
||||
show_caption_above_media=InlineQueryResultGifTestBase.show_caption_above_media,
|
||||
)
|
||||
|
||||
|
||||
class TestInlineQueryResultGifBase:
|
||||
class InlineQueryResultGifTestBase:
|
||||
id_ = "id"
|
||||
type_ = "gif"
|
||||
gif_url = "gif url"
|
||||
@@ -67,7 +67,7 @@ class TestInlineQueryResultGifBase:
|
||||
show_caption_above_media = True
|
||||
|
||||
|
||||
class TestInlineQueryResultGifWithoutRequest(TestInlineQueryResultGifBase):
|
||||
class TestInlineQueryResultGifWithoutRequest(InlineQueryResultGifTestBase):
|
||||
def test_slot_behaviour(self, inline_query_result_gif):
|
||||
inst = inline_query_result_gif
|
||||
for attr in inst.__slots__:
|
||||
|
||||
@@ -31,23 +31,23 @@ from tests.auxil.slots import mro_slots
|
||||
@pytest.fixture(scope="module")
|
||||
def inline_query_result_location():
|
||||
return InlineQueryResultLocation(
|
||||
TestInlineQueryResultLocationBase.id_,
|
||||
TestInlineQueryResultLocationBase.latitude,
|
||||
TestInlineQueryResultLocationBase.longitude,
|
||||
TestInlineQueryResultLocationBase.title,
|
||||
live_period=TestInlineQueryResultLocationBase.live_period,
|
||||
thumbnail_url=TestInlineQueryResultLocationBase.thumbnail_url,
|
||||
thumbnail_width=TestInlineQueryResultLocationBase.thumbnail_width,
|
||||
thumbnail_height=TestInlineQueryResultLocationBase.thumbnail_height,
|
||||
input_message_content=TestInlineQueryResultLocationBase.input_message_content,
|
||||
reply_markup=TestInlineQueryResultLocationBase.reply_markup,
|
||||
horizontal_accuracy=TestInlineQueryResultLocationBase.horizontal_accuracy,
|
||||
heading=TestInlineQueryResultLocationBase.heading,
|
||||
proximity_alert_radius=TestInlineQueryResultLocationBase.proximity_alert_radius,
|
||||
InlineQueryResultLocationTestBase.id_,
|
||||
InlineQueryResultLocationTestBase.latitude,
|
||||
InlineQueryResultLocationTestBase.longitude,
|
||||
InlineQueryResultLocationTestBase.title,
|
||||
live_period=InlineQueryResultLocationTestBase.live_period,
|
||||
thumbnail_url=InlineQueryResultLocationTestBase.thumbnail_url,
|
||||
thumbnail_width=InlineQueryResultLocationTestBase.thumbnail_width,
|
||||
thumbnail_height=InlineQueryResultLocationTestBase.thumbnail_height,
|
||||
input_message_content=InlineQueryResultLocationTestBase.input_message_content,
|
||||
reply_markup=InlineQueryResultLocationTestBase.reply_markup,
|
||||
horizontal_accuracy=InlineQueryResultLocationTestBase.horizontal_accuracy,
|
||||
heading=InlineQueryResultLocationTestBase.heading,
|
||||
proximity_alert_radius=InlineQueryResultLocationTestBase.proximity_alert_radius,
|
||||
)
|
||||
|
||||
|
||||
class TestInlineQueryResultLocationBase:
|
||||
class InlineQueryResultLocationTestBase:
|
||||
id_ = "id"
|
||||
type_ = "location"
|
||||
latitude = 0.0
|
||||
@@ -64,7 +64,7 @@ class TestInlineQueryResultLocationBase:
|
||||
reply_markup = InlineKeyboardMarkup([[InlineKeyboardButton("reply_markup")]])
|
||||
|
||||
|
||||
class TestInlineQueryResultLocationWithoutRequest(TestInlineQueryResultLocationBase):
|
||||
class TestInlineQueryResultLocationWithoutRequest(InlineQueryResultLocationTestBase):
|
||||
def test_slot_behaviour(self, inline_query_result_location):
|
||||
inst = inline_query_result_location
|
||||
for attr in inst.__slots__:
|
||||
|
||||
@@ -32,24 +32,24 @@ from tests.auxil.slots import mro_slots
|
||||
@pytest.fixture(scope="module")
|
||||
def inline_query_result_mpeg4_gif():
|
||||
return InlineQueryResultMpeg4Gif(
|
||||
TestInlineQueryResultMpeg4GifBase.id_,
|
||||
TestInlineQueryResultMpeg4GifBase.mpeg4_url,
|
||||
TestInlineQueryResultMpeg4GifBase.thumbnail_url,
|
||||
mpeg4_width=TestInlineQueryResultMpeg4GifBase.mpeg4_width,
|
||||
mpeg4_height=TestInlineQueryResultMpeg4GifBase.mpeg4_height,
|
||||
mpeg4_duration=TestInlineQueryResultMpeg4GifBase.mpeg4_duration,
|
||||
title=TestInlineQueryResultMpeg4GifBase.title,
|
||||
caption=TestInlineQueryResultMpeg4GifBase.caption,
|
||||
parse_mode=TestInlineQueryResultMpeg4GifBase.parse_mode,
|
||||
caption_entities=TestInlineQueryResultMpeg4GifBase.caption_entities,
|
||||
input_message_content=TestInlineQueryResultMpeg4GifBase.input_message_content,
|
||||
reply_markup=TestInlineQueryResultMpeg4GifBase.reply_markup,
|
||||
thumbnail_mime_type=TestInlineQueryResultMpeg4GifBase.thumbnail_mime_type,
|
||||
show_caption_above_media=TestInlineQueryResultMpeg4GifBase.show_caption_above_media,
|
||||
InlineQueryResultMpeg4GifTestBase.id_,
|
||||
InlineQueryResultMpeg4GifTestBase.mpeg4_url,
|
||||
InlineQueryResultMpeg4GifTestBase.thumbnail_url,
|
||||
mpeg4_width=InlineQueryResultMpeg4GifTestBase.mpeg4_width,
|
||||
mpeg4_height=InlineQueryResultMpeg4GifTestBase.mpeg4_height,
|
||||
mpeg4_duration=InlineQueryResultMpeg4GifTestBase.mpeg4_duration,
|
||||
title=InlineQueryResultMpeg4GifTestBase.title,
|
||||
caption=InlineQueryResultMpeg4GifTestBase.caption,
|
||||
parse_mode=InlineQueryResultMpeg4GifTestBase.parse_mode,
|
||||
caption_entities=InlineQueryResultMpeg4GifTestBase.caption_entities,
|
||||
input_message_content=InlineQueryResultMpeg4GifTestBase.input_message_content,
|
||||
reply_markup=InlineQueryResultMpeg4GifTestBase.reply_markup,
|
||||
thumbnail_mime_type=InlineQueryResultMpeg4GifTestBase.thumbnail_mime_type,
|
||||
show_caption_above_media=InlineQueryResultMpeg4GifTestBase.show_caption_above_media,
|
||||
)
|
||||
|
||||
|
||||
class TestInlineQueryResultMpeg4GifBase:
|
||||
class InlineQueryResultMpeg4GifTestBase:
|
||||
id_ = "id"
|
||||
type_ = "mpeg4_gif"
|
||||
mpeg4_url = "mpeg4 url"
|
||||
@@ -67,7 +67,7 @@ class TestInlineQueryResultMpeg4GifBase:
|
||||
show_caption_above_media = True
|
||||
|
||||
|
||||
class TestInlineQueryResultMpeg4GifWithoutRequest(TestInlineQueryResultMpeg4GifBase):
|
||||
class TestInlineQueryResultMpeg4GifWithoutRequest(InlineQueryResultMpeg4GifTestBase):
|
||||
def test_slot_behaviour(self, inline_query_result_mpeg4_gif):
|
||||
inst = inline_query_result_mpeg4_gif
|
||||
for attr in inst.__slots__:
|
||||
|
||||
@@ -32,23 +32,23 @@ from tests.auxil.slots import mro_slots
|
||||
@pytest.fixture(scope="module")
|
||||
def inline_query_result_photo():
|
||||
return InlineQueryResultPhoto(
|
||||
TestInlineQueryResultPhotoBase.id_,
|
||||
TestInlineQueryResultPhotoBase.photo_url,
|
||||
TestInlineQueryResultPhotoBase.thumbnail_url,
|
||||
photo_width=TestInlineQueryResultPhotoBase.photo_width,
|
||||
photo_height=TestInlineQueryResultPhotoBase.photo_height,
|
||||
title=TestInlineQueryResultPhotoBase.title,
|
||||
description=TestInlineQueryResultPhotoBase.description,
|
||||
caption=TestInlineQueryResultPhotoBase.caption,
|
||||
parse_mode=TestInlineQueryResultPhotoBase.parse_mode,
|
||||
caption_entities=TestInlineQueryResultPhotoBase.caption_entities,
|
||||
input_message_content=TestInlineQueryResultPhotoBase.input_message_content,
|
||||
reply_markup=TestInlineQueryResultPhotoBase.reply_markup,
|
||||
show_caption_above_media=TestInlineQueryResultPhotoBase.show_caption_above_media,
|
||||
InlineQueryResultPhotoTestBase.id_,
|
||||
InlineQueryResultPhotoTestBase.photo_url,
|
||||
InlineQueryResultPhotoTestBase.thumbnail_url,
|
||||
photo_width=InlineQueryResultPhotoTestBase.photo_width,
|
||||
photo_height=InlineQueryResultPhotoTestBase.photo_height,
|
||||
title=InlineQueryResultPhotoTestBase.title,
|
||||
description=InlineQueryResultPhotoTestBase.description,
|
||||
caption=InlineQueryResultPhotoTestBase.caption,
|
||||
parse_mode=InlineQueryResultPhotoTestBase.parse_mode,
|
||||
caption_entities=InlineQueryResultPhotoTestBase.caption_entities,
|
||||
input_message_content=InlineQueryResultPhotoTestBase.input_message_content,
|
||||
reply_markup=InlineQueryResultPhotoTestBase.reply_markup,
|
||||
show_caption_above_media=InlineQueryResultPhotoTestBase.show_caption_above_media,
|
||||
)
|
||||
|
||||
|
||||
class TestInlineQueryResultPhotoBase:
|
||||
class InlineQueryResultPhotoTestBase:
|
||||
id_ = "id"
|
||||
type_ = "photo"
|
||||
photo_url = "photo url"
|
||||
@@ -66,7 +66,7 @@ class TestInlineQueryResultPhotoBase:
|
||||
show_caption_above_media = True
|
||||
|
||||
|
||||
class TestInlineQueryResultPhotoWithoutRequest(TestInlineQueryResultPhotoBase):
|
||||
class TestInlineQueryResultPhotoWithoutRequest(InlineQueryResultPhotoTestBase):
|
||||
def test_slot_behaviour(self, inline_query_result_photo):
|
||||
inst = inline_query_result_photo
|
||||
for attr in inst.__slots__:
|
||||
|
||||
@@ -31,24 +31,24 @@ from tests.auxil.slots import mro_slots
|
||||
@pytest.fixture(scope="module")
|
||||
def inline_query_result_venue():
|
||||
return InlineQueryResultVenue(
|
||||
TestInlineQueryResultVenueBase.id_,
|
||||
TestInlineQueryResultVenueBase.latitude,
|
||||
TestInlineQueryResultVenueBase.longitude,
|
||||
TestInlineQueryResultVenueBase.title,
|
||||
TestInlineQueryResultVenueBase.address,
|
||||
foursquare_id=TestInlineQueryResultVenueBase.foursquare_id,
|
||||
foursquare_type=TestInlineQueryResultVenueBase.foursquare_type,
|
||||
thumbnail_url=TestInlineQueryResultVenueBase.thumbnail_url,
|
||||
thumbnail_width=TestInlineQueryResultVenueBase.thumbnail_width,
|
||||
thumbnail_height=TestInlineQueryResultVenueBase.thumbnail_height,
|
||||
input_message_content=TestInlineQueryResultVenueBase.input_message_content,
|
||||
reply_markup=TestInlineQueryResultVenueBase.reply_markup,
|
||||
google_place_id=TestInlineQueryResultVenueBase.google_place_id,
|
||||
google_place_type=TestInlineQueryResultVenueBase.google_place_type,
|
||||
InlineQueryResultVenueTestBase.id_,
|
||||
InlineQueryResultVenueTestBase.latitude,
|
||||
InlineQueryResultVenueTestBase.longitude,
|
||||
InlineQueryResultVenueTestBase.title,
|
||||
InlineQueryResultVenueTestBase.address,
|
||||
foursquare_id=InlineQueryResultVenueTestBase.foursquare_id,
|
||||
foursquare_type=InlineQueryResultVenueTestBase.foursquare_type,
|
||||
thumbnail_url=InlineQueryResultVenueTestBase.thumbnail_url,
|
||||
thumbnail_width=InlineQueryResultVenueTestBase.thumbnail_width,
|
||||
thumbnail_height=InlineQueryResultVenueTestBase.thumbnail_height,
|
||||
input_message_content=InlineQueryResultVenueTestBase.input_message_content,
|
||||
reply_markup=InlineQueryResultVenueTestBase.reply_markup,
|
||||
google_place_id=InlineQueryResultVenueTestBase.google_place_id,
|
||||
google_place_type=InlineQueryResultVenueTestBase.google_place_type,
|
||||
)
|
||||
|
||||
|
||||
class TestInlineQueryResultVenueBase:
|
||||
class InlineQueryResultVenueTestBase:
|
||||
id_ = "id"
|
||||
type_ = "venue"
|
||||
latitude = "latitude"
|
||||
@@ -66,7 +66,7 @@ class TestInlineQueryResultVenueBase:
|
||||
reply_markup = InlineKeyboardMarkup([[InlineKeyboardButton("reply_markup")]])
|
||||
|
||||
|
||||
class TestInlineQueryResultVenueWithoutRequest(TestInlineQueryResultVenueBase):
|
||||
class TestInlineQueryResultVenueWithoutRequest(InlineQueryResultVenueTestBase):
|
||||
def test_slot_behaviour(self, inline_query_result_venue):
|
||||
inst = inline_query_result_venue
|
||||
for attr in inst.__slots__:
|
||||
|
||||
@@ -32,25 +32,25 @@ from tests.auxil.slots import mro_slots
|
||||
@pytest.fixture(scope="module")
|
||||
def inline_query_result_video():
|
||||
return InlineQueryResultVideo(
|
||||
TestInlineQueryResultVideoBase.id_,
|
||||
TestInlineQueryResultVideoBase.video_url,
|
||||
TestInlineQueryResultVideoBase.mime_type,
|
||||
TestInlineQueryResultVideoBase.thumbnail_url,
|
||||
TestInlineQueryResultVideoBase.title,
|
||||
video_width=TestInlineQueryResultVideoBase.video_width,
|
||||
video_height=TestInlineQueryResultVideoBase.video_height,
|
||||
video_duration=TestInlineQueryResultVideoBase.video_duration,
|
||||
caption=TestInlineQueryResultVideoBase.caption,
|
||||
parse_mode=TestInlineQueryResultVideoBase.parse_mode,
|
||||
caption_entities=TestInlineQueryResultVideoBase.caption_entities,
|
||||
description=TestInlineQueryResultVideoBase.description,
|
||||
input_message_content=TestInlineQueryResultVideoBase.input_message_content,
|
||||
reply_markup=TestInlineQueryResultVideoBase.reply_markup,
|
||||
show_caption_above_media=TestInlineQueryResultVideoBase.show_caption_above_media,
|
||||
InlineQueryResultVideoTestBase.id_,
|
||||
InlineQueryResultVideoTestBase.video_url,
|
||||
InlineQueryResultVideoTestBase.mime_type,
|
||||
InlineQueryResultVideoTestBase.thumbnail_url,
|
||||
InlineQueryResultVideoTestBase.title,
|
||||
video_width=InlineQueryResultVideoTestBase.video_width,
|
||||
video_height=InlineQueryResultVideoTestBase.video_height,
|
||||
video_duration=InlineQueryResultVideoTestBase.video_duration,
|
||||
caption=InlineQueryResultVideoTestBase.caption,
|
||||
parse_mode=InlineQueryResultVideoTestBase.parse_mode,
|
||||
caption_entities=InlineQueryResultVideoTestBase.caption_entities,
|
||||
description=InlineQueryResultVideoTestBase.description,
|
||||
input_message_content=InlineQueryResultVideoTestBase.input_message_content,
|
||||
reply_markup=InlineQueryResultVideoTestBase.reply_markup,
|
||||
show_caption_above_media=InlineQueryResultVideoTestBase.show_caption_above_media,
|
||||
)
|
||||
|
||||
|
||||
class TestInlineQueryResultVideoBase:
|
||||
class InlineQueryResultVideoTestBase:
|
||||
id_ = "id"
|
||||
type_ = "video"
|
||||
video_url = "video url"
|
||||
@@ -69,7 +69,7 @@ class TestInlineQueryResultVideoBase:
|
||||
show_caption_above_media = True
|
||||
|
||||
|
||||
class TestInlineQueryResultVideoWithoutRequest(TestInlineQueryResultVideoBase):
|
||||
class TestInlineQueryResultVideoWithoutRequest(InlineQueryResultVideoTestBase):
|
||||
def test_slot_behaviour(self, inline_query_result_video):
|
||||
inst = inline_query_result_video
|
||||
for attr in inst.__slots__:
|
||||
|
||||
@@ -32,19 +32,19 @@ from tests.auxil.slots import mro_slots
|
||||
@pytest.fixture(scope="module")
|
||||
def inline_query_result_voice():
|
||||
return InlineQueryResultVoice(
|
||||
id=TestInlineQueryResultVoiceBase.id_,
|
||||
voice_url=TestInlineQueryResultVoiceBase.voice_url,
|
||||
title=TestInlineQueryResultVoiceBase.title,
|
||||
voice_duration=TestInlineQueryResultVoiceBase.voice_duration,
|
||||
caption=TestInlineQueryResultVoiceBase.caption,
|
||||
parse_mode=TestInlineQueryResultVoiceBase.parse_mode,
|
||||
caption_entities=TestInlineQueryResultVoiceBase.caption_entities,
|
||||
input_message_content=TestInlineQueryResultVoiceBase.input_message_content,
|
||||
reply_markup=TestInlineQueryResultVoiceBase.reply_markup,
|
||||
id=InlineQueryResultVoiceTestBase.id_,
|
||||
voice_url=InlineQueryResultVoiceTestBase.voice_url,
|
||||
title=InlineQueryResultVoiceTestBase.title,
|
||||
voice_duration=InlineQueryResultVoiceTestBase.voice_duration,
|
||||
caption=InlineQueryResultVoiceTestBase.caption,
|
||||
parse_mode=InlineQueryResultVoiceTestBase.parse_mode,
|
||||
caption_entities=InlineQueryResultVoiceTestBase.caption_entities,
|
||||
input_message_content=InlineQueryResultVoiceTestBase.input_message_content,
|
||||
reply_markup=InlineQueryResultVoiceTestBase.reply_markup,
|
||||
)
|
||||
|
||||
|
||||
class TestInlineQueryResultVoiceBase:
|
||||
class InlineQueryResultVoiceTestBase:
|
||||
id_ = "id"
|
||||
type_ = "voice"
|
||||
voice_url = "voice url"
|
||||
@@ -57,7 +57,7 @@ class TestInlineQueryResultVoiceBase:
|
||||
reply_markup = InlineKeyboardMarkup([[InlineKeyboardButton("reply_markup")]])
|
||||
|
||||
|
||||
class TestInlineQueryResultVoiceWithoutRequest(TestInlineQueryResultVoiceBase):
|
||||
class TestInlineQueryResultVoiceWithoutRequest(InlineQueryResultVoiceTestBase):
|
||||
def test_slot_behaviour(self, inline_query_result_voice):
|
||||
inst = inline_query_result_voice
|
||||
for attr in inst.__slots__:
|
||||
|
||||
@@ -25,19 +25,19 @@ from tests.auxil.slots import mro_slots
|
||||
@pytest.fixture(scope="module")
|
||||
def input_contact_message_content():
|
||||
return InputContactMessageContent(
|
||||
TestInputContactMessageContentBase.phone_number,
|
||||
TestInputContactMessageContentBase.first_name,
|
||||
TestInputContactMessageContentBase.last_name,
|
||||
InputContactMessageContentTestBase.phone_number,
|
||||
InputContactMessageContentTestBase.first_name,
|
||||
InputContactMessageContentTestBase.last_name,
|
||||
)
|
||||
|
||||
|
||||
class TestInputContactMessageContentBase:
|
||||
class InputContactMessageContentTestBase:
|
||||
phone_number = "phone number"
|
||||
first_name = "first name"
|
||||
last_name = "last name"
|
||||
|
||||
|
||||
class TestInputContactMessageContentWithoutRequest(TestInputContactMessageContentBase):
|
||||
class TestInputContactMessageContentWithoutRequest(InputContactMessageContentTestBase):
|
||||
def test_slot_behaviour(self, input_contact_message_content):
|
||||
inst = input_contact_message_content
|
||||
for attr in inst.__slots__:
|
||||
|
||||
@@ -26,32 +26,32 @@ from tests.auxil.slots import mro_slots
|
||||
@pytest.fixture(scope="module")
|
||||
def input_invoice_message_content():
|
||||
return InputInvoiceMessageContent(
|
||||
title=TestInputInvoiceMessageContentBase.title,
|
||||
description=TestInputInvoiceMessageContentBase.description,
|
||||
payload=TestInputInvoiceMessageContentBase.payload,
|
||||
provider_token=TestInputInvoiceMessageContentBase.provider_token,
|
||||
currency=TestInputInvoiceMessageContentBase.currency,
|
||||
prices=TestInputInvoiceMessageContentBase.prices,
|
||||
max_tip_amount=TestInputInvoiceMessageContentBase.max_tip_amount,
|
||||
suggested_tip_amounts=TestInputInvoiceMessageContentBase.suggested_tip_amounts,
|
||||
provider_data=TestInputInvoiceMessageContentBase.provider_data,
|
||||
photo_url=TestInputInvoiceMessageContentBase.photo_url,
|
||||
photo_size=TestInputInvoiceMessageContentBase.photo_size,
|
||||
photo_width=TestInputInvoiceMessageContentBase.photo_width,
|
||||
photo_height=TestInputInvoiceMessageContentBase.photo_height,
|
||||
need_name=TestInputInvoiceMessageContentBase.need_name,
|
||||
need_phone_number=TestInputInvoiceMessageContentBase.need_phone_number,
|
||||
need_email=TestInputInvoiceMessageContentBase.need_email,
|
||||
need_shipping_address=TestInputInvoiceMessageContentBase.need_shipping_address,
|
||||
title=InputInvoiceMessageContentTestBase.title,
|
||||
description=InputInvoiceMessageContentTestBase.description,
|
||||
payload=InputInvoiceMessageContentTestBase.payload,
|
||||
provider_token=InputInvoiceMessageContentTestBase.provider_token,
|
||||
currency=InputInvoiceMessageContentTestBase.currency,
|
||||
prices=InputInvoiceMessageContentTestBase.prices,
|
||||
max_tip_amount=InputInvoiceMessageContentTestBase.max_tip_amount,
|
||||
suggested_tip_amounts=InputInvoiceMessageContentTestBase.suggested_tip_amounts,
|
||||
provider_data=InputInvoiceMessageContentTestBase.provider_data,
|
||||
photo_url=InputInvoiceMessageContentTestBase.photo_url,
|
||||
photo_size=InputInvoiceMessageContentTestBase.photo_size,
|
||||
photo_width=InputInvoiceMessageContentTestBase.photo_width,
|
||||
photo_height=InputInvoiceMessageContentTestBase.photo_height,
|
||||
need_name=InputInvoiceMessageContentTestBase.need_name,
|
||||
need_phone_number=InputInvoiceMessageContentTestBase.need_phone_number,
|
||||
need_email=InputInvoiceMessageContentTestBase.need_email,
|
||||
need_shipping_address=InputInvoiceMessageContentTestBase.need_shipping_address,
|
||||
send_phone_number_to_provider=(
|
||||
TestInputInvoiceMessageContentBase.send_phone_number_to_provider
|
||||
InputInvoiceMessageContentTestBase.send_phone_number_to_provider
|
||||
),
|
||||
send_email_to_provider=TestInputInvoiceMessageContentBase.send_email_to_provider,
|
||||
is_flexible=TestInputInvoiceMessageContentBase.is_flexible,
|
||||
send_email_to_provider=InputInvoiceMessageContentTestBase.send_email_to_provider,
|
||||
is_flexible=InputInvoiceMessageContentTestBase.is_flexible,
|
||||
)
|
||||
|
||||
|
||||
class TestInputInvoiceMessageContentBase:
|
||||
class InputInvoiceMessageContentTestBase:
|
||||
title = "invoice title"
|
||||
description = "invoice description"
|
||||
payload = "invoice payload"
|
||||
@@ -74,7 +74,7 @@ class TestInputInvoiceMessageContentBase:
|
||||
is_flexible = True
|
||||
|
||||
|
||||
class TestInputInvoiceMessageContentWithoutRequest(TestInputInvoiceMessageContentBase):
|
||||
class TestInputInvoiceMessageContentWithoutRequest(InputInvoiceMessageContentTestBase):
|
||||
def test_slot_behaviour(self, input_invoice_message_content):
|
||||
inst = input_invoice_message_content
|
||||
for attr in inst.__slots__:
|
||||
@@ -203,8 +203,8 @@ class TestInputInvoiceMessageContentWithoutRequest(TestInputInvoiceMessageConten
|
||||
== input_invoice_message_content.is_flexible
|
||||
)
|
||||
|
||||
def test_de_json(self, bot):
|
||||
assert InputInvoiceMessageContent.de_json({}, bot=bot) is None
|
||||
def test_de_json(self, offline_bot):
|
||||
assert InputInvoiceMessageContent.de_json({}, bot=offline_bot) is None
|
||||
|
||||
json_dict = {
|
||||
"title": self.title,
|
||||
@@ -229,7 +229,9 @@ class TestInputInvoiceMessageContentWithoutRequest(TestInputInvoiceMessageConten
|
||||
"is_flexible": self.is_flexible,
|
||||
}
|
||||
|
||||
input_invoice_message_content = InputInvoiceMessageContent.de_json(json_dict, bot=bot)
|
||||
input_invoice_message_content = InputInvoiceMessageContent.de_json(
|
||||
json_dict, bot=offline_bot
|
||||
)
|
||||
assert input_invoice_message_content.api_kwargs == {}
|
||||
|
||||
assert input_invoice_message_content.title == self.title
|
||||
|
||||
@@ -25,16 +25,16 @@ from tests.auxil.slots import mro_slots
|
||||
@pytest.fixture(scope="module")
|
||||
def input_location_message_content():
|
||||
return InputLocationMessageContent(
|
||||
TestInputLocationMessageContentBase.latitude,
|
||||
TestInputLocationMessageContentBase.longitude,
|
||||
live_period=TestInputLocationMessageContentBase.live_period,
|
||||
horizontal_accuracy=TestInputLocationMessageContentBase.horizontal_accuracy,
|
||||
heading=TestInputLocationMessageContentBase.heading,
|
||||
proximity_alert_radius=TestInputLocationMessageContentBase.proximity_alert_radius,
|
||||
InputLocationMessageContentTestBase.latitude,
|
||||
InputLocationMessageContentTestBase.longitude,
|
||||
live_period=InputLocationMessageContentTestBase.live_period,
|
||||
horizontal_accuracy=InputLocationMessageContentTestBase.horizontal_accuracy,
|
||||
heading=InputLocationMessageContentTestBase.heading,
|
||||
proximity_alert_radius=InputLocationMessageContentTestBase.proximity_alert_radius,
|
||||
)
|
||||
|
||||
|
||||
class TestInputLocationMessageContentBase:
|
||||
class InputLocationMessageContentTestBase:
|
||||
latitude = -23.691288
|
||||
longitude = -46.788279
|
||||
live_period = 80
|
||||
@@ -43,7 +43,7 @@ class TestInputLocationMessageContentBase:
|
||||
proximity_alert_radius = 999
|
||||
|
||||
|
||||
class TestInputLocationMessageContentWithoutRequest(TestInputLocationMessageContentBase):
|
||||
class TestInputLocationMessageContentWithoutRequest(InputLocationMessageContentTestBase):
|
||||
def test_slot_behaviour(self, input_location_message_content):
|
||||
inst = input_location_message_content
|
||||
for attr in inst.__slots__:
|
||||
|
||||
@@ -26,14 +26,14 @@ from tests.auxil.slots import mro_slots
|
||||
@pytest.fixture(scope="module")
|
||||
def input_text_message_content():
|
||||
return InputTextMessageContent(
|
||||
TestInputTextMessageContentBase.message_text,
|
||||
parse_mode=TestInputTextMessageContentBase.parse_mode,
|
||||
entities=TestInputTextMessageContentBase.entities,
|
||||
link_preview_options=TestInputTextMessageContentBase.link_preview_options,
|
||||
InputTextMessageContentTestBase.message_text,
|
||||
parse_mode=InputTextMessageContentTestBase.parse_mode,
|
||||
entities=InputTextMessageContentTestBase.entities,
|
||||
link_preview_options=InputTextMessageContentTestBase.link_preview_options,
|
||||
)
|
||||
|
||||
|
||||
class TestInputTextMessageContentBase:
|
||||
class InputTextMessageContentTestBase:
|
||||
message_text = "*message text*"
|
||||
parse_mode = ParseMode.MARKDOWN
|
||||
entities = [MessageEntity(MessageEntity.ITALIC, 0, 7)]
|
||||
@@ -41,7 +41,7 @@ class TestInputTextMessageContentBase:
|
||||
link_preview_options = LinkPreviewOptions(False, url="https://python-telegram-bot.org")
|
||||
|
||||
|
||||
class TestInputTextMessageContentWithoutRequest(TestInputTextMessageContentBase):
|
||||
class TestInputTextMessageContentWithoutRequest(InputTextMessageContentTestBase):
|
||||
def test_slot_behaviour(self, input_text_message_content):
|
||||
inst = input_text_message_content
|
||||
for attr in inst.__slots__:
|
||||
|
||||
@@ -25,18 +25,18 @@ from tests.auxil.slots import mro_slots
|
||||
@pytest.fixture(scope="module")
|
||||
def input_venue_message_content():
|
||||
return InputVenueMessageContent(
|
||||
TestInputVenueMessageContentBase.latitude,
|
||||
TestInputVenueMessageContentBase.longitude,
|
||||
TestInputVenueMessageContentBase.title,
|
||||
TestInputVenueMessageContentBase.address,
|
||||
foursquare_id=TestInputVenueMessageContentBase.foursquare_id,
|
||||
foursquare_type=TestInputVenueMessageContentBase.foursquare_type,
|
||||
google_place_id=TestInputVenueMessageContentBase.google_place_id,
|
||||
google_place_type=TestInputVenueMessageContentBase.google_place_type,
|
||||
InputVenueMessageContentTestBase.latitude,
|
||||
InputVenueMessageContentTestBase.longitude,
|
||||
InputVenueMessageContentTestBase.title,
|
||||
InputVenueMessageContentTestBase.address,
|
||||
foursquare_id=InputVenueMessageContentTestBase.foursquare_id,
|
||||
foursquare_type=InputVenueMessageContentTestBase.foursquare_type,
|
||||
google_place_id=InputVenueMessageContentTestBase.google_place_id,
|
||||
google_place_type=InputVenueMessageContentTestBase.google_place_type,
|
||||
)
|
||||
|
||||
|
||||
class TestInputVenueMessageContentBase:
|
||||
class InputVenueMessageContentTestBase:
|
||||
latitude = 1.0
|
||||
longitude = 2.0
|
||||
title = "title"
|
||||
@@ -47,7 +47,7 @@ class TestInputVenueMessageContentBase:
|
||||
google_place_type = "google place type"
|
||||
|
||||
|
||||
class TestInputVenueMessageContentWithoutRequest(TestInputVenueMessageContentBase):
|
||||
class TestInputVenueMessageContentWithoutRequest(InputVenueMessageContentTestBase):
|
||||
def test_slot_behaviour(self, input_venue_message_content):
|
||||
inst = input_venue_message_content
|
||||
for attr in inst.__slots__:
|
||||
|
||||
@@ -26,19 +26,19 @@ from tests.auxil.slots import mro_slots
|
||||
@pytest.fixture(scope="module")
|
||||
def encrypted_credentials():
|
||||
return EncryptedCredentials(
|
||||
TestEncryptedCredentialsBase.data,
|
||||
TestEncryptedCredentialsBase.hash,
|
||||
TestEncryptedCredentialsBase.secret,
|
||||
EncryptedCredentialsTestBase.data,
|
||||
EncryptedCredentialsTestBase.hash,
|
||||
EncryptedCredentialsTestBase.secret,
|
||||
)
|
||||
|
||||
|
||||
class TestEncryptedCredentialsBase:
|
||||
class EncryptedCredentialsTestBase:
|
||||
data = "data"
|
||||
hash = "hash"
|
||||
secret = "secret"
|
||||
|
||||
|
||||
class TestEncryptedCredentialsWithoutRequest(TestEncryptedCredentialsBase):
|
||||
class TestEncryptedCredentialsWithoutRequest(EncryptedCredentialsTestBase):
|
||||
def test_slot_behaviour(self, encrypted_credentials):
|
||||
inst = encrypted_credentials
|
||||
for attr in inst.__slots__:
|
||||
|
||||
@@ -26,19 +26,19 @@ from tests.auxil.slots import mro_slots
|
||||
@pytest.fixture(scope="module")
|
||||
def encrypted_passport_element():
|
||||
return EncryptedPassportElement(
|
||||
TestEncryptedPassportElementBase.type_,
|
||||
EncryptedPassportElementTestBase.type_,
|
||||
"this is a hash",
|
||||
data=TestEncryptedPassportElementBase.data,
|
||||
phone_number=TestEncryptedPassportElementBase.phone_number,
|
||||
email=TestEncryptedPassportElementBase.email,
|
||||
files=TestEncryptedPassportElementBase.files,
|
||||
front_side=TestEncryptedPassportElementBase.front_side,
|
||||
reverse_side=TestEncryptedPassportElementBase.reverse_side,
|
||||
selfie=TestEncryptedPassportElementBase.selfie,
|
||||
data=EncryptedPassportElementTestBase.data,
|
||||
phone_number=EncryptedPassportElementTestBase.phone_number,
|
||||
email=EncryptedPassportElementTestBase.email,
|
||||
files=EncryptedPassportElementTestBase.files,
|
||||
front_side=EncryptedPassportElementTestBase.front_side,
|
||||
reverse_side=EncryptedPassportElementTestBase.reverse_side,
|
||||
selfie=EncryptedPassportElementTestBase.selfie,
|
||||
)
|
||||
|
||||
|
||||
class TestEncryptedPassportElementBase:
|
||||
class EncryptedPassportElementTestBase:
|
||||
type_ = "type"
|
||||
hash = "this is a hash"
|
||||
data = "data"
|
||||
@@ -50,7 +50,7 @@ class TestEncryptedPassportElementBase:
|
||||
selfie = PassportFile("file_id", 50, 0, 25)
|
||||
|
||||
|
||||
class TestEncryptedPassportElementWithoutRequest(TestEncryptedPassportElementBase):
|
||||
class TestEncryptedPassportElementWithoutRequest(EncryptedPassportElementTestBase):
|
||||
def test_slot_behaviour(self, encrypted_passport_element):
|
||||
inst = encrypted_passport_element
|
||||
for attr in inst.__slots__:
|
||||
|
||||
@@ -28,7 +28,7 @@ with the TEST_WITH_OPT_DEPS environment variable set to False in addition to the
|
||||
"""
|
||||
import pytest
|
||||
|
||||
from telegram import _bot as bot
|
||||
import telegram
|
||||
from telegram._passport import credentials
|
||||
from tests.auxil.envvars import TEST_WITH_OPT_DEPS
|
||||
|
||||
@@ -39,7 +39,7 @@ from tests.auxil.envvars import TEST_WITH_OPT_DEPS
|
||||
class TestNoPassportWithoutRequest:
|
||||
def test_bot_init(self, bot_info):
|
||||
with pytest.raises(RuntimeError, match="passport"):
|
||||
bot.Bot(bot_info["token"], private_key=1, private_key_password=2)
|
||||
telegram.Bot(bot_info["token"], private_key=1, private_key_password=2)
|
||||
|
||||
def test_credentials_decrypt(self):
|
||||
with pytest.raises(RuntimeError, match="passport"):
|
||||
|
||||
@@ -220,7 +220,7 @@ def passport_data(bot):
|
||||
return PassportData.de_json(RAW_PASSPORT_DATA, bot=bot)
|
||||
|
||||
|
||||
class TestPassportBase:
|
||||
class PassportTestBase:
|
||||
driver_license_selfie_file_id = "DgADBAADEQQAAkopgFNr6oi-wISRtAI"
|
||||
driver_license_selfie_file_unique_id = "d4e390cca57b4da5a65322b304762a12"
|
||||
driver_license_front_side_file_id = "DgADBAADxwMAApnQgVPK2-ckL2eXVAI"
|
||||
@@ -243,7 +243,7 @@ class TestPassportBase:
|
||||
driver_license_selfie_credentials_secret = "tivdId6RNYNsvXYPppdzrbxOBuBOr9wXRPDcCvnXU7E="
|
||||
|
||||
|
||||
class TestPassportWithoutRequest(TestPassportBase):
|
||||
class TestPassportWithoutRequest(PassportTestBase):
|
||||
def test_slot_behaviour(self, passport_data):
|
||||
inst = passport_data
|
||||
for attr in inst.__slots__:
|
||||
@@ -390,8 +390,8 @@ class TestPassportWithoutRequest(TestPassportBase):
|
||||
assert email.type == "email"
|
||||
assert email.email == "fb3e3i47zt@dispostable.com"
|
||||
|
||||
def test_de_json_and_to_dict(self, bot):
|
||||
passport_data = PassportData.de_json(RAW_PASSPORT_DATA, bot)
|
||||
def test_de_json_and_to_dict(self, offline_bot):
|
||||
passport_data = PassportData.de_json(RAW_PASSPORT_DATA, offline_bot)
|
||||
assert passport_data.api_kwargs == {}
|
||||
assert passport_data.to_dict() == RAW_PASSPORT_DATA
|
||||
|
||||
@@ -414,14 +414,14 @@ class TestPassportWithoutRequest(TestPassportBase):
|
||||
assert a != c
|
||||
assert hash(a) != hash(c)
|
||||
|
||||
def test_bot_init_invalid_key(self, bot):
|
||||
def test_bot_init_invalid_key(self, offline_bot):
|
||||
with pytest.raises(TypeError):
|
||||
Bot(bot.token, private_key="Invalid key!")
|
||||
Bot(offline_bot.token, private_key="Invalid key!")
|
||||
|
||||
with pytest.raises(ValueError, match="Could not deserialize key data"):
|
||||
Bot(bot.token, private_key=b"Invalid key!")
|
||||
Bot(offline_bot.token, private_key=b"Invalid key!")
|
||||
|
||||
def test_all_types(self, passport_data, bot, all_passport_data):
|
||||
def test_all_types(self, passport_data, offline_bot, all_passport_data):
|
||||
credentials = passport_data.decrypted_credentials.to_dict()
|
||||
|
||||
# Copy credentials from other types to all types so we can decrypt everything
|
||||
@@ -446,46 +446,46 @@ class TestPassportWithoutRequest(TestPassportBase):
|
||||
# Replaced below
|
||||
"credentials": {"data": "data", "hash": "hash", "secret": "secret"},
|
||||
},
|
||||
bot=bot,
|
||||
bot=offline_bot,
|
||||
)
|
||||
assert new.api_kwargs == {}
|
||||
|
||||
new.credentials._decrypted_data = Credentials.de_json(credentials, bot)
|
||||
new.credentials._decrypted_data = Credentials.de_json(credentials, offline_bot)
|
||||
assert new.credentials.api_kwargs == {}
|
||||
|
||||
assert isinstance(new, PassportData)
|
||||
assert new.decrypted_data
|
||||
|
||||
async def test_passport_data_okay_with_non_crypto_bot(self, bot):
|
||||
async with make_bot(token=bot.token) as b:
|
||||
async def test_passport_data_okay_with_non_crypto_bot(self, offline_bot):
|
||||
async with make_bot(token=offline_bot.token) as b:
|
||||
assert PassportData.de_json(RAW_PASSPORT_DATA, bot=b)
|
||||
|
||||
def test_wrong_hash(self, bot):
|
||||
def test_wrong_hash(self, offline_bot):
|
||||
data = deepcopy(RAW_PASSPORT_DATA)
|
||||
data["credentials"]["hash"] = "bm90Y29ycmVjdGhhc2g=" # Not correct hash
|
||||
passport_data = PassportData.de_json(data, bot=bot)
|
||||
passport_data = PassportData.de_json(data, bot=offline_bot)
|
||||
with pytest.raises(PassportDecryptionError):
|
||||
assert passport_data.decrypted_data
|
||||
|
||||
async def test_wrong_key(self, bot):
|
||||
async def test_wrong_key(self, offline_bot):
|
||||
short_key = (
|
||||
b"-----BEGIN RSA PRIVATE"
|
||||
b" KEY-----\r\nMIIBOQIBAAJBAKU+OZ2jJm7sCA/ec4gngNZhXYPu+DZ/TAwSMl0W7vAPXAsLplBk\r\nO8l6IBHx8N0ZC4Bc65mO3b2G8YAzqndyqH8CAwEAAQJAWOx3jQFzeVXDsOaBPdAk\r\nYTncXVeIc6tlfUl9mOLyinSbRNCy1XicOiOZFgH1rRKOGIC1235QmqxFvdecySoY\r\nwQIhAOFeGgeX9CrEPuSsd9+kqUcA2avCwqdQgSdy2qggRFyJAiEAu7QHT8JQSkHU\r\nDELfzrzc24AhjyG0z1DpGZArM8COascCIDK42SboXj3Z2UXiQ0CEcMzYNiVgOisq\r\nBUd5pBi+2mPxAiAM5Z7G/Sv1HjbKrOGh29o0/sXPhtpckEuj5QMC6E0gywIgFY6S\r\nNjwrAA+cMmsgY0O2fAzEKkDc5YiFsiXaGaSS4eA=\r\n-----END"
|
||||
b" RSA PRIVATE KEY-----"
|
||||
)
|
||||
async with make_bot(token=bot.token, private_key=short_key) as b:
|
||||
async with make_bot(token=offline_bot.token, private_key=short_key) as b:
|
||||
passport_data = PassportData.de_json(RAW_PASSPORT_DATA, bot=b)
|
||||
with pytest.raises(PassportDecryptionError):
|
||||
assert passport_data.decrypted_data
|
||||
|
||||
async with make_bot(token=bot.token, private_key=short_key) as b:
|
||||
async with make_bot(token=offline_bot.token, private_key=short_key) as b:
|
||||
passport_data = PassportData.de_json(RAW_PASSPORT_DATA, bot=b)
|
||||
with pytest.raises(PassportDecryptionError):
|
||||
assert passport_data.decrypted_data
|
||||
|
||||
async def test_mocked_download_passport_file(self, passport_data, monkeypatch):
|
||||
# The files are not coming from our test bot, therefore the file id is invalid/wrong
|
||||
# when coming from this bot, so we monkeypatch the call, to make sure that Bot.get_file
|
||||
# The files are not coming from our test offline_bot, therefore the file id is invalid/wrong
|
||||
# when coming from this offline_bot, so we monkeypatch the call, to make sure that Bot.get_file
|
||||
# at least gets called
|
||||
# TODO: Actually download a passport file in a test
|
||||
selfie = passport_data.decrypted_data[1].selfie
|
||||
@@ -501,7 +501,9 @@ class TestPassportWithoutRequest(TestPassportBase):
|
||||
assert file._credentials.file_hash == self.driver_license_selfie_credentials_file_hash
|
||||
assert file._credentials.secret == self.driver_license_selfie_credentials_secret
|
||||
|
||||
async def test_mocked_set_passport_data_errors(self, monkeypatch, bot, chat_id, passport_data):
|
||||
async def test_mocked_set_passport_data_errors(
|
||||
self, monkeypatch, offline_bot, chat_id, passport_data
|
||||
):
|
||||
async def make_assertion(url, request_data: RequestData, *args, **kwargs):
|
||||
data = request_data.parameters
|
||||
return (
|
||||
@@ -514,8 +516,8 @@ class TestPassportWithoutRequest(TestPassportBase):
|
||||
== passport_data.decrypted_credentials.secure_data.driver_license.data.data_hash
|
||||
)
|
||||
|
||||
monkeypatch.setattr(bot.request, "post", make_assertion)
|
||||
message = await bot.set_passport_data_errors(
|
||||
monkeypatch.setattr(offline_bot.request, "post", make_assertion)
|
||||
message = await offline_bot.set_passport_data_errors(
|
||||
chat_id,
|
||||
[
|
||||
PassportElementErrorSelfie(
|
||||
|
||||
@@ -25,14 +25,14 @@ from tests.auxil.slots import mro_slots
|
||||
@pytest.fixture(scope="module")
|
||||
def passport_element_error_data_field():
|
||||
return PassportElementErrorDataField(
|
||||
TestPassportElementErrorDataFieldBase.type_,
|
||||
TestPassportElementErrorDataFieldBase.field_name,
|
||||
TestPassportElementErrorDataFieldBase.data_hash,
|
||||
TestPassportElementErrorDataFieldBase.message,
|
||||
PassportElementErrorDataFieldTestBase.type_,
|
||||
PassportElementErrorDataFieldTestBase.field_name,
|
||||
PassportElementErrorDataFieldTestBase.data_hash,
|
||||
PassportElementErrorDataFieldTestBase.message,
|
||||
)
|
||||
|
||||
|
||||
class TestPassportElementErrorDataFieldBase:
|
||||
class PassportElementErrorDataFieldTestBase:
|
||||
source = "data"
|
||||
type_ = "test_type"
|
||||
field_name = "test_field"
|
||||
@@ -40,7 +40,7 @@ class TestPassportElementErrorDataFieldBase:
|
||||
message = "Error message"
|
||||
|
||||
|
||||
class TestPassportElementErrorDataFieldWithoutRequest(TestPassportElementErrorDataFieldBase):
|
||||
class TestPassportElementErrorDataFieldWithoutRequest(PassportElementErrorDataFieldTestBase):
|
||||
def test_slot_behaviour(self, passport_element_error_data_field):
|
||||
inst = passport_element_error_data_field
|
||||
for attr in inst.__slots__:
|
||||
|
||||
@@ -25,20 +25,20 @@ from tests.auxil.slots import mro_slots
|
||||
@pytest.fixture(scope="module")
|
||||
def passport_element_error_file():
|
||||
return PassportElementErrorFile(
|
||||
TestPassportElementErrorFileBase.type_,
|
||||
TestPassportElementErrorFileBase.file_hash,
|
||||
TestPassportElementErrorFileBase.message,
|
||||
PassportElementErrorFileTestBase.type_,
|
||||
PassportElementErrorFileTestBase.file_hash,
|
||||
PassportElementErrorFileTestBase.message,
|
||||
)
|
||||
|
||||
|
||||
class TestPassportElementErrorFileBase:
|
||||
class PassportElementErrorFileTestBase:
|
||||
source = "file"
|
||||
type_ = "test_type"
|
||||
file_hash = "file_hash"
|
||||
message = "Error message"
|
||||
|
||||
|
||||
class TestPassportElementErrorFileWithoutRequest(TestPassportElementErrorFileBase):
|
||||
class TestPassportElementErrorFileWithoutRequest(PassportElementErrorFileTestBase):
|
||||
def test_slot_behaviour(self, passport_element_error_file):
|
||||
inst = passport_element_error_file
|
||||
for attr in inst.__slots__:
|
||||
|
||||
@@ -26,20 +26,20 @@ from tests.auxil.slots import mro_slots
|
||||
@pytest.fixture(scope="module")
|
||||
def passport_element_error_files():
|
||||
return PassportElementErrorFiles(
|
||||
TestPassportElementErrorFilesBase.type_,
|
||||
TestPassportElementErrorFilesBase.file_hashes,
|
||||
TestPassportElementErrorFilesBase.message,
|
||||
PassportElementErrorFilesTestBase.type_,
|
||||
PassportElementErrorFilesTestBase.file_hashes,
|
||||
PassportElementErrorFilesTestBase.message,
|
||||
)
|
||||
|
||||
|
||||
class TestPassportElementErrorFilesBase:
|
||||
class PassportElementErrorFilesTestBase:
|
||||
source = "files"
|
||||
type_ = "test_type"
|
||||
file_hashes = ["hash1", "hash2"]
|
||||
message = "Error message"
|
||||
|
||||
|
||||
class TestPassportElementErrorFilesWithoutRequest(TestPassportElementErrorFilesBase):
|
||||
class TestPassportElementErrorFilesWithoutRequest(PassportElementErrorFilesTestBase):
|
||||
def test_slot_behaviour(self, passport_element_error_files):
|
||||
inst = passport_element_error_files
|
||||
for attr in inst.__slots__:
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user