mirror of
https://github.com/python-telegram-bot/python-telegram-bot.git
synced 2025-03-17 04:39:55 +01:00
Extend rich comparison of objects (#1724)
* Make most objects comparable * ID attrs for PollAnswer * fix test_game * fix test_userprofilephotos * update for API 4.7 * Warn on meaningless comparisons * Update for API 4.8 * Address review * Get started on docs, update Message._id_attrs * Change PollOption & InputLocation * Some more changes * Even more changes
This commit is contained in:
parent
2381724b7c
commit
2d4d48b89d
80 changed files with 934 additions and 21 deletions
|
@ -23,6 +23,8 @@ try:
|
|||
except ImportError:
|
||||
import json
|
||||
|
||||
import warnings
|
||||
|
||||
|
||||
class TelegramObject:
|
||||
"""Base class for most telegram objects."""
|
||||
|
@ -73,6 +75,12 @@ class TelegramObject:
|
|||
|
||||
def __eq__(self, other):
|
||||
if isinstance(other, self.__class__):
|
||||
if self._id_attrs == ():
|
||||
warnings.warn("Objects of type {} can not be meaningfully tested for "
|
||||
"equivalence.".format(self.__class__.__name__))
|
||||
if other._id_attrs == ():
|
||||
warnings.warn("Objects of type {} can not be meaningfully tested for "
|
||||
"equivalence.".format(other.__class__.__name__))
|
||||
return self._id_attrs == other._id_attrs
|
||||
return super().__eq__(other) # pylint: disable=no-member
|
||||
|
||||
|
|
|
@ -25,6 +25,9 @@ class BotCommand(TelegramObject):
|
|||
"""
|
||||
This object represents a bot command.
|
||||
|
||||
Objects of this class are comparable in terms of equality. Two objects of this class are
|
||||
considered equal, if their :attr:`command` and :attr:`description` are equal.
|
||||
|
||||
Attributes:
|
||||
command (:obj:`str`): Text of the command.
|
||||
description (:obj:`str`): Description of the command.
|
||||
|
@ -38,6 +41,8 @@ class BotCommand(TelegramObject):
|
|||
self.command = command
|
||||
self.description = description
|
||||
|
||||
self._id_attrs = (self.command, self.description)
|
||||
|
||||
@classmethod
|
||||
def de_json(cls, data, bot):
|
||||
if not data:
|
||||
|
|
|
@ -29,6 +29,9 @@ class CallbackQuery(TelegramObject):
|
|||
:attr:`message` will be present. If the button was attached to a message sent via the bot (in
|
||||
inline mode), the field :attr:`inline_message_id` will be present.
|
||||
|
||||
Objects of this class are comparable in terms of equality. Two objects of this class are
|
||||
considered equal, if their :attr:`id` is equal.
|
||||
|
||||
Note:
|
||||
* In Python `from` is a reserved word, use `from_user` instead.
|
||||
* Exactly one of the fields :attr:`data` or :attr:`game_short_name` will be present.
|
||||
|
|
|
@ -26,6 +26,9 @@ from .chatpermissions import ChatPermissions
|
|||
class Chat(TelegramObject):
|
||||
"""This object represents a chat.
|
||||
|
||||
Objects of this class are comparable in terms of equality. Two objects of this class are
|
||||
considered equal, if their :attr:`id` is equal.
|
||||
|
||||
Attributes:
|
||||
id (:obj:`int`): Unique identifier for this chat.
|
||||
type (:obj:`str`): Type of chat.
|
||||
|
|
|
@ -25,6 +25,9 @@ from telegram.utils.helpers import to_timestamp, from_timestamp
|
|||
class ChatMember(TelegramObject):
|
||||
"""This object contains information about one member of a chat.
|
||||
|
||||
Objects of this class are comparable in terms of equality. Two objects of this class are
|
||||
considered equal, if their :attr:`user` and :attr:`status` are equal.
|
||||
|
||||
Attributes:
|
||||
user (:class:`telegram.User`): Information about the user.
|
||||
status (:obj:`str`): The member's status in the chat.
|
||||
|
|
|
@ -24,6 +24,11 @@ from telegram import TelegramObject
|
|||
class ChatPermissions(TelegramObject):
|
||||
"""Describes actions that a non-administrator user is allowed to take in a chat.
|
||||
|
||||
Objects of this class are comparable in terms of equality. Two objects of this class are
|
||||
considered equal, if their :attr:`can_send_messages`, :attr:`can_send_media_messages`,
|
||||
:attr:`can_send_polls`, :attr:`can_send_other_messages`, :attr:`can_add_web_page_previews`,
|
||||
:attr:`can_change_info`, :attr:`can_invite_users` and :attr:`can_pin_message` are equal.
|
||||
|
||||
Note:
|
||||
Though not stated explicitly in the official docs, Telegram changes not only the
|
||||
permissions that are set, but also sets all the others to :obj:`False`. However, since not
|
||||
|
@ -84,6 +89,17 @@ class ChatPermissions(TelegramObject):
|
|||
self.can_invite_users = can_invite_users
|
||||
self.can_pin_messages = can_pin_messages
|
||||
|
||||
self._id_attrs = (
|
||||
self.can_send_messages,
|
||||
self.can_send_media_messages,
|
||||
self.can_send_polls,
|
||||
self.can_send_other_messages,
|
||||
self.can_add_web_page_previews,
|
||||
self.can_change_info,
|
||||
self.can_invite_users,
|
||||
self.can_pin_messages
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def de_json(cls, data, bot):
|
||||
if not data:
|
||||
|
|
|
@ -27,6 +27,9 @@ class ChosenInlineResult(TelegramObject):
|
|||
Represents a result of an inline query that was chosen by the user and sent to their chat
|
||||
partner.
|
||||
|
||||
Objects of this class are comparable in terms of equality. Two objects of this class are
|
||||
considered equal, if their :attr:`result_id` is equal.
|
||||
|
||||
Note:
|
||||
In Python `from` is a reserved word, use `from_user` instead.
|
||||
|
||||
|
|
|
@ -27,6 +27,9 @@ class Dice(TelegramObject):
|
|||
emoji. (The singular form of "dice" is "die". However, PTB mimics the Telegram API, which uses
|
||||
the term "dice".)
|
||||
|
||||
Objects of this class are comparable in terms of equality. Two objects of this class are
|
||||
considered equal, if their :attr:`value` and :attr:`emoji` are equal.
|
||||
|
||||
Note:
|
||||
If :attr:`emoji` is "🎯", a value of 6 currently represents a bullseye, while a value of 1
|
||||
indicates that the dartboard was missed. However, this behaviour is undocumented and might
|
||||
|
@ -48,6 +51,8 @@ class Dice(TelegramObject):
|
|||
self.value = value
|
||||
self.emoji = emoji
|
||||
|
||||
self._id_attrs = (self.value, self.emoji)
|
||||
|
||||
@classmethod
|
||||
def de_json(cls, data, bot):
|
||||
if not data:
|
||||
|
|
|
@ -24,6 +24,9 @@ from telegram import TelegramObject
|
|||
class Animation(TelegramObject):
|
||||
"""This object represents an animation file (GIF or H.264/MPEG-4 AVC video without sound).
|
||||
|
||||
Objects of this class are comparable in terms of equality. Two objects of this class are
|
||||
considered equal, if their :attr:`file_unique_id` is equal.
|
||||
|
||||
Attributes:
|
||||
file_id (:obj:`str`): File identifier.
|
||||
file_unique_id (:obj:`str`): Unique identifier for this file, which
|
||||
|
|
|
@ -24,6 +24,9 @@ from telegram import TelegramObject, PhotoSize
|
|||
class Audio(TelegramObject):
|
||||
"""This object represents an audio file to be treated as music by the Telegram clients.
|
||||
|
||||
Objects of this class are comparable in terms of equality. Two objects of this class are
|
||||
considered equal, if their :attr:`file_unique_id` is equal.
|
||||
|
||||
Attributes:
|
||||
file_id (:obj:`str`): Identifier for this file.
|
||||
file_unique_id (:obj:`str`): Unique identifier for this file, which
|
||||
|
|
|
@ -23,6 +23,10 @@ from telegram import TelegramObject
|
|||
class ChatPhoto(TelegramObject):
|
||||
"""This object represents a chat photo.
|
||||
|
||||
Objects of this class are comparable in terms of equality. Two objects of this class are
|
||||
considered equal, if their :attr:`small_file_unique_id` and :attr:`big_file_unique_id` are
|
||||
equal.
|
||||
|
||||
Attributes:
|
||||
small_file_id (:obj:`str`): File identifier of small (160x160) chat photo.
|
||||
This file_id can be used only for photo download and only for as long
|
||||
|
|
|
@ -24,6 +24,9 @@ from telegram import TelegramObject
|
|||
class Contact(TelegramObject):
|
||||
"""This object represents a phone contact.
|
||||
|
||||
Objects of this class are comparable in terms of equality. Two objects of this class are
|
||||
considered equal, if their :attr:`phone_number` is equal.
|
||||
|
||||
Attributes:
|
||||
phone_number (:obj:`str`): Contact's phone number.
|
||||
first_name (:obj:`str`): Contact's first name.
|
||||
|
|
|
@ -25,6 +25,9 @@ class Document(TelegramObject):
|
|||
"""This object represents a general file
|
||||
(as opposed to photos, voice messages and audio files).
|
||||
|
||||
Objects of this class are comparable in terms of equality. Two objects of this class are
|
||||
considered equal, if their :attr:`file_unique_id` is equal.
|
||||
|
||||
Attributes:
|
||||
file_id (:obj:`str`): File identifier.
|
||||
file_unique_id (:obj:`str`): Unique identifier for this file, which
|
||||
|
|
|
@ -33,6 +33,9 @@ class File(TelegramObject):
|
|||
:attr:`download`. It is guaranteed that the link will be valid for at least 1 hour. When the
|
||||
link expires, a new one can be requested by calling :meth:`telegram.Bot.get_file`.
|
||||
|
||||
Objects of this class are comparable in terms of equality. Two objects of this class are
|
||||
considered equal, if their :attr:`file_unique_id` is equal.
|
||||
|
||||
Note:
|
||||
Maximum file size to download is 20 MB.
|
||||
|
||||
|
|
|
@ -24,6 +24,9 @@ from telegram import TelegramObject
|
|||
class Location(TelegramObject):
|
||||
"""This object represents a point on the map.
|
||||
|
||||
Objects of this class are comparable in terms of equality. Two objects of this class are
|
||||
considered equal, if their :attr:`longitute` and :attr:`latitude` are equal.
|
||||
|
||||
Attributes:
|
||||
longitude (:obj:`float`): Longitude as defined by sender.
|
||||
latitude (:obj:`float`): Latitude as defined by sender.
|
||||
|
|
|
@ -24,6 +24,9 @@ from telegram import TelegramObject
|
|||
class PhotoSize(TelegramObject):
|
||||
"""This object represents one size of a photo or a file/sticker thumbnail.
|
||||
|
||||
Objects of this class are comparable in terms of equality. Two objects of this class are
|
||||
considered equal, if their :attr:`file_unique_id` is equal.
|
||||
|
||||
Attributes:
|
||||
file_id (:obj:`str`): Identifier for this file.
|
||||
file_unique_id (:obj:`str`): Unique identifier for this file, which
|
||||
|
|
|
@ -24,6 +24,9 @@ from telegram import PhotoSize, TelegramObject
|
|||
class Sticker(TelegramObject):
|
||||
"""This object represents a sticker.
|
||||
|
||||
Objects of this class are comparable in terms of equality. Two objects of this class are
|
||||
considered equal, if their :attr:`file_unique_id` is equal.
|
||||
|
||||
Attributes:
|
||||
file_id (:obj:`str`): Identifier for this file.
|
||||
file_unique_id (:obj:`str`): Unique identifier for this file, which
|
||||
|
@ -135,6 +138,9 @@ class Sticker(TelegramObject):
|
|||
class StickerSet(TelegramObject):
|
||||
"""This object represents a sticker set.
|
||||
|
||||
Objects of this class are comparable in terms of equality. Two objects of this class are
|
||||
considered equal, if their :attr:`name` is equal.
|
||||
|
||||
Attributes:
|
||||
name (:obj:`str`): Sticker set name.
|
||||
title (:obj:`str`): Sticker set title.
|
||||
|
@ -190,6 +196,10 @@ class StickerSet(TelegramObject):
|
|||
class MaskPosition(TelegramObject):
|
||||
"""This object describes the position on faces where a mask should be placed by default.
|
||||
|
||||
Objects of this class are comparable in terms of equality. Two objects of this class are
|
||||
considered equal, if their :attr:`point`, :attr:`x_shift`, :attr:`y_shift` and, :attr:`scale`
|
||||
are equal.
|
||||
|
||||
Attributes:
|
||||
point (:obj:`str`): The part of the face relative to which the mask should be placed.
|
||||
One of ``'forehead'``, ``'eyes'``, ``'mouth'``, or ``'chin'``.
|
||||
|
@ -230,6 +240,8 @@ class MaskPosition(TelegramObject):
|
|||
self.y_shift = y_shift
|
||||
self.scale = scale
|
||||
|
||||
self._id_attrs = (self.point, self.x_shift, self.y_shift, self.scale)
|
||||
|
||||
@classmethod
|
||||
def de_json(cls, data, bot):
|
||||
if data is None:
|
||||
|
|
|
@ -24,6 +24,9 @@ from telegram import TelegramObject, Location
|
|||
class Venue(TelegramObject):
|
||||
"""This object represents a venue.
|
||||
|
||||
Objects of this class are comparable in terms of equality. Two objects of this class are
|
||||
considered equal, if their :attr:`location` and :attr:`title`are equal.
|
||||
|
||||
Attributes:
|
||||
location (:class:`telegram.Location`): Venue location.
|
||||
title (:obj:`str`): Name of the venue.
|
||||
|
|
|
@ -24,6 +24,9 @@ from telegram import PhotoSize, TelegramObject
|
|||
class Video(TelegramObject):
|
||||
"""This object represents a video file.
|
||||
|
||||
Objects of this class are comparable in terms of equality. Two objects of this class are
|
||||
considered equal, if their :attr:`file_unique_id` is equal.
|
||||
|
||||
Attributes:
|
||||
file_id (:obj:`str`): Identifier for this file.
|
||||
file_unique_id (:obj:`str`): Unique identifier for this file, which
|
||||
|
|
|
@ -24,6 +24,9 @@ from telegram import PhotoSize, TelegramObject
|
|||
class VideoNote(TelegramObject):
|
||||
"""This object represents a video message (available in Telegram apps as of v.4.0).
|
||||
|
||||
Objects of this class are comparable in terms of equality. Two objects of this class are
|
||||
considered equal, if their :attr:`file_unique_id` is equal.
|
||||
|
||||
Attributes:
|
||||
file_id (:obj:`str`): Identifier for this file.
|
||||
file_unique_id (:obj:`str`): Unique identifier for this file, which
|
||||
|
|
|
@ -24,6 +24,9 @@ from telegram import TelegramObject
|
|||
class Voice(TelegramObject):
|
||||
"""This object represents a voice note.
|
||||
|
||||
Objects of this class are comparable in terms of equality. Two objects of this class are
|
||||
considered equal, if their :attr:`file_unique_id` is equal.
|
||||
|
||||
Attributes:
|
||||
file_id (:obj:`str`): Identifier for this file.
|
||||
file_unique_id (:obj:`str`): Unique identifier for this file, which
|
||||
|
|
|
@ -28,6 +28,9 @@ class ForceReply(ReplyMarkup):
|
|||
extremely useful if you want to create user-friendly step-by-step interfaces without having
|
||||
to sacrifice privacy mode.
|
||||
|
||||
Objects of this class are comparable in terms of equality. Two objects of this class are
|
||||
considered equal, if their :attr:`selective` is equal.
|
||||
|
||||
Attributes:
|
||||
force_reply (:obj:`True`): Shows reply interface to the user, as if they manually selected
|
||||
the bot's message and tapped 'Reply'.
|
||||
|
@ -50,3 +53,5 @@ class ForceReply(ReplyMarkup):
|
|||
self.force_reply = bool(force_reply)
|
||||
# Optionals
|
||||
self.selective = bool(selective)
|
||||
|
||||
self._id_attrs = (self.selective,)
|
||||
|
|
|
@ -28,6 +28,9 @@ class Game(TelegramObject):
|
|||
This object represents a game. Use `BotFather <https://t.me/BotFather>`_ to create and edit
|
||||
games, their short names will act as unique identifiers.
|
||||
|
||||
Objects of this class are comparable in terms of equality. Two objects of this class are
|
||||
considered equal, if their :attr:`title`, :attr:`description` and :attr:`photo` are equal.
|
||||
|
||||
Attributes:
|
||||
title (:obj:`str`): Title of the game.
|
||||
description (:obj:`str`): Description of the game.
|
||||
|
@ -67,13 +70,17 @@ class Game(TelegramObject):
|
|||
text_entities=None,
|
||||
animation=None,
|
||||
**kwargs):
|
||||
# Required
|
||||
self.title = title
|
||||
self.description = description
|
||||
self.photo = photo
|
||||
# Optionals
|
||||
self.text = text
|
||||
self.text_entities = text_entities or list()
|
||||
self.animation = animation
|
||||
|
||||
self._id_attrs = (self.title, self.description, self.photo)
|
||||
|
||||
@classmethod
|
||||
def de_json(cls, data, bot):
|
||||
if not data:
|
||||
|
@ -149,3 +156,6 @@ class Game(TelegramObject):
|
|||
entity: self.parse_text_entity(entity)
|
||||
for entity in self.text_entities if entity.type in types
|
||||
}
|
||||
|
||||
def __hash__(self):
|
||||
return hash((self.title, self.description, tuple(p for p in self.photo)))
|
||||
|
|
|
@ -24,6 +24,9 @@ from telegram import TelegramObject, User
|
|||
class GameHighScore(TelegramObject):
|
||||
"""This object represents one row of the high scores table for a game.
|
||||
|
||||
Objects of this class are comparable in terms of equality. Two objects of this class are
|
||||
considered equal, if their :attr:`position`, :attr:`user` and :attr:`score` are equal.
|
||||
|
||||
Attributes:
|
||||
position (:obj:`int`): Position in high score table for the game.
|
||||
user (:class:`telegram.User`): User.
|
||||
|
@ -41,6 +44,8 @@ class GameHighScore(TelegramObject):
|
|||
self.user = user
|
||||
self.score = score
|
||||
|
||||
self._id_attrs = (self.position, self.user, self.score)
|
||||
|
||||
@classmethod
|
||||
def de_json(cls, data, bot):
|
||||
if not data:
|
||||
|
|
|
@ -24,6 +24,11 @@ from telegram import TelegramObject
|
|||
class InlineKeyboardButton(TelegramObject):
|
||||
"""This object represents one button of an inline keyboard.
|
||||
|
||||
Objects of this class are comparable in terms of equality. Two objects of this class are
|
||||
considered equal, if their :attr:`text`, :attr:`url`, :attr:`login_url`, :attr:`callback_data`,
|
||||
:attr:`switch_inline_query`, :attr:`switch_inline_query_current_chat`, :attr:`callback_game`
|
||||
and :attr:`pay` are equal.
|
||||
|
||||
Note:
|
||||
You must use exactly one of the optional fields. Mind that :attr:`callback_game` is not
|
||||
working as expected. Putting a game short name in it might, but is not guaranteed to work.
|
||||
|
@ -95,6 +100,17 @@ class InlineKeyboardButton(TelegramObject):
|
|||
self.callback_game = callback_game
|
||||
self.pay = pay
|
||||
|
||||
self._id_attrs = (
|
||||
self.text,
|
||||
self.url,
|
||||
self.login_url,
|
||||
self.callback_data,
|
||||
self.switch_inline_query,
|
||||
self.switch_inline_query_current_chat,
|
||||
self.callback_game,
|
||||
self.pay,
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def de_json(cls, data, bot):
|
||||
if not data:
|
||||
|
|
|
@ -25,6 +25,9 @@ class InlineKeyboardMarkup(ReplyMarkup):
|
|||
"""
|
||||
This object represents an inline keyboard that appears right next to the message it belongs to.
|
||||
|
||||
Objects of this class are comparable in terms of equality. Two objects of this class are
|
||||
considered equal, if their the size of :attr:`inline_keyboard` and all the buttons are equal.
|
||||
|
||||
Attributes:
|
||||
inline_keyboard (List[List[:class:`telegram.InlineKeyboardButton`]]): List of button rows,
|
||||
each represented by a list of InlineKeyboardButton objects.
|
||||
|
@ -109,3 +112,19 @@ class InlineKeyboardMarkup(ReplyMarkup):
|
|||
"""
|
||||
button_grid = [[button] for button in button_column]
|
||||
return cls(button_grid, **kwargs)
|
||||
|
||||
def __eq__(self, other):
|
||||
if isinstance(other, self.__class__):
|
||||
if len(self.inline_keyboard) != len(other.inline_keyboard):
|
||||
return False
|
||||
for idx, row in enumerate(self.inline_keyboard):
|
||||
if len(row) != len(other.inline_keyboard[idx]):
|
||||
return False
|
||||
for jdx, button in enumerate(row):
|
||||
if button != other.inline_keyboard[idx][jdx]:
|
||||
return False
|
||||
return True
|
||||
return super(InlineKeyboardMarkup, self).__eq__(other) # pylint: disable=no-member
|
||||
|
||||
def __hash__(self):
|
||||
return hash(tuple(tuple(button for button in row) for row in self.inline_keyboard))
|
||||
|
|
|
@ -27,6 +27,9 @@ class InlineQuery(TelegramObject):
|
|||
This object represents an incoming inline query. When the user sends an empty query, your bot
|
||||
could return some default or trending results.
|
||||
|
||||
Objects of this class are comparable in terms of equality. Two objects of this class are
|
||||
considered equal, if their :attr:`id` is equal.
|
||||
|
||||
Note:
|
||||
* In Python `from` is a reserved word, use `from_user` instead.
|
||||
|
||||
|
|
|
@ -24,6 +24,9 @@ from telegram import TelegramObject
|
|||
class InlineQueryResult(TelegramObject):
|
||||
"""Baseclass for the InlineQueryResult* classes.
|
||||
|
||||
Objects of this class are comparable in terms of equality. Two objects of this class are
|
||||
considered equal, if their :attr:`id` is equal.
|
||||
|
||||
Attributes:
|
||||
type (:obj:`str`): Type of the result.
|
||||
id (:obj:`str`): Unique identifier for this result, 1-64 Bytes.
|
||||
|
|
|
@ -24,6 +24,9 @@ from telegram import InputMessageContent
|
|||
class InputContactMessageContent(InputMessageContent):
|
||||
"""Represents the content of a contact message to be sent as the result of an inline query.
|
||||
|
||||
Objects of this class are comparable in terms of equality. Two objects of this class are
|
||||
considered equal, if their :attr:`phone_number` is equal.
|
||||
|
||||
Attributes:
|
||||
phone_number (:obj:`str`): Contact's phone number.
|
||||
first_name (:obj:`str`): Contact's first name.
|
||||
|
@ -48,3 +51,5 @@ class InputContactMessageContent(InputMessageContent):
|
|||
# Optionals
|
||||
self.last_name = last_name
|
||||
self.vcard = vcard
|
||||
|
||||
self._id_attrs = (self.phone_number,)
|
||||
|
|
|
@ -25,11 +25,15 @@ class InputLocationMessageContent(InputMessageContent):
|
|||
"""
|
||||
Represents the content of a location message to be sent as the result of an inline query.
|
||||
|
||||
Objects of this class are comparable in terms of equality. Two objects of this class are
|
||||
considered equal, if their :attr:`latitude` and :attr:`longitude` are equal.
|
||||
|
||||
Attributes:
|
||||
latitude (:obj:`float`): Latitude of the location in degrees.
|
||||
longitude (:obj:`float`): Longitude of the location in degrees.
|
||||
live_period (:obj:`int`): Optional. Period in seconds for which the location can be
|
||||
updated, should be between 60 and 86400.
|
||||
updated.
|
||||
|
||||
Args:
|
||||
latitude (:obj:`float`): Latitude of the location in degrees.
|
||||
longitude (:obj:`float`): Longitude of the location in degrees.
|
||||
|
@ -44,3 +48,5 @@ class InputLocationMessageContent(InputMessageContent):
|
|||
self.latitude = latitude
|
||||
self.longitude = longitude
|
||||
self.live_period = live_period
|
||||
|
||||
self._id_attrs = (self.latitude, self.longitude)
|
||||
|
|
|
@ -26,6 +26,9 @@ class InputTextMessageContent(InputMessageContent):
|
|||
"""
|
||||
Represents the content of a text message to be sent as the result of an inline query.
|
||||
|
||||
Objects of this class are comparable in terms of equality. Two objects of this class are
|
||||
considered equal, if their :attr:`message_text` is equal.
|
||||
|
||||
Attributes:
|
||||
message_text (:obj:`str`): Text of the message to be sent, 1-4096 characters after entities
|
||||
parsing.
|
||||
|
@ -57,3 +60,5 @@ class InputTextMessageContent(InputMessageContent):
|
|||
# Optionals
|
||||
self.parse_mode = parse_mode
|
||||
self.disable_web_page_preview = disable_web_page_preview
|
||||
|
||||
self._id_attrs = (self.message_text,)
|
||||
|
|
|
@ -24,6 +24,10 @@ from telegram import InputMessageContent
|
|||
class InputVenueMessageContent(InputMessageContent):
|
||||
"""Represents the content of a venue message to be sent as the result of an inline query.
|
||||
|
||||
Objects of this class are comparable in terms of equality. Two objects of this class are
|
||||
considered equal, if their :attr:`latitude`, :attr:`longitude` and :attr:`title`
|
||||
are equal.
|
||||
|
||||
Attributes:
|
||||
latitude (:obj:`float`): Latitude of the location in degrees.
|
||||
longitude (:obj:`float`): Longitude of the location in degrees.
|
||||
|
@ -57,3 +61,9 @@ class InputVenueMessageContent(InputMessageContent):
|
|||
# Optionals
|
||||
self.foursquare_id = foursquare_id
|
||||
self.foursquare_type = foursquare_type
|
||||
|
||||
self._id_attrs = (
|
||||
self.latitude,
|
||||
self.longitude,
|
||||
self.title,
|
||||
)
|
||||
|
|
|
@ -26,6 +26,10 @@ class KeyboardButton(TelegramObject):
|
|||
This object represents one button of the reply keyboard. For simple text buttons String can be
|
||||
used instead of this object to specify text of the button.
|
||||
|
||||
Objects of this class are comparable in terms of equality. Two objects of this class are
|
||||
considered equal, if their :attr:`text`, :attr:`request_contact`, :attr:`request_location` and
|
||||
:attr:`request_poll` are equal.
|
||||
|
||||
Note:
|
||||
Optional fields are mutually exclusive.
|
||||
|
||||
|
@ -63,3 +67,6 @@ class KeyboardButton(TelegramObject):
|
|||
self.request_contact = request_contact
|
||||
self.request_location = request_location
|
||||
self.request_poll = request_poll
|
||||
|
||||
self._id_attrs = (self.text, self.request_contact, self.request_location,
|
||||
self.request_poll)
|
||||
|
|
|
@ -25,6 +25,9 @@ class KeyboardButtonPollType(TelegramObject):
|
|||
"""This object represents type of a poll, which is allowed to be created
|
||||
and sent when the corresponding button is pressed.
|
||||
|
||||
Objects of this class are comparable in terms of equality. Two objects of this class are
|
||||
considered equal, if their :attr:`type` is equal.
|
||||
|
||||
Attributes:
|
||||
type (:obj:`str`): Optional. If :attr:`telegram.Poll.QUIZ` is passed, the user will be
|
||||
allowed to create only polls in the quiz mode. If :attr:`telegram.Poll.REGULAR` is
|
||||
|
|
|
@ -29,6 +29,9 @@ class LoginUrl(TelegramObject):
|
|||
|
||||
Sample bot: `@discussbot <https://t.me/dicussbot>`_
|
||||
|
||||
Objects of this class are comparable in terms of equality. Two objects of this class are
|
||||
considered equal, if their :attr:`url` is equal.
|
||||
|
||||
Attributes:
|
||||
url (:obj:`str`): An HTTP URL to be opened with user authorization data.
|
||||
forward_text (:obj:`str`): Optional. New text of the button in forwarded messages.
|
||||
|
|
|
@ -33,6 +33,9 @@ _UNDEFINED = object()
|
|||
class Message(TelegramObject):
|
||||
"""This object represents a message.
|
||||
|
||||
Objects of this class are comparable in terms of equality. Two objects of this class are
|
||||
considered equal, if their :attr:`message_id` and :attr:`chat` are equal.
|
||||
|
||||
Note:
|
||||
* In Python `from` is a reserved word, use `from_user` instead.
|
||||
|
||||
|
@ -345,7 +348,7 @@ class Message(TelegramObject):
|
|||
self.bot = bot
|
||||
self.default_quote = default_quote
|
||||
|
||||
self._id_attrs = (self.message_id,)
|
||||
self._id_attrs = (self.message_id, self.chat)
|
||||
|
||||
@property
|
||||
def chat_id(self):
|
||||
|
|
|
@ -26,6 +26,9 @@ class MessageEntity(TelegramObject):
|
|||
This object represents one special entity in a text message. For example, hashtags,
|
||||
usernames, URLs, etc.
|
||||
|
||||
Objects of this class are comparable in terms of equality. Two objects of this class are
|
||||
considered equal, if their :attr:`type`, :attr:`offset` and :attr`length` are equal.
|
||||
|
||||
Attributes:
|
||||
type (:obj:`str`): Type of the entity.
|
||||
offset (:obj:`int`): Offset in UTF-16 code units to the start of the entity.
|
||||
|
|
|
@ -98,6 +98,9 @@ class EncryptedCredentials(TelegramObject):
|
|||
Telegram Passport Documentation for a complete description of the data decryption and
|
||||
authentication processes.
|
||||
|
||||
Objects of this class are comparable in terms of equality. Two objects of this class are
|
||||
considered equal, if their :attr:`data`, :attr:`hash` and :attr:`secret` are equal.
|
||||
|
||||
Attributes:
|
||||
data (:class:`telegram.Credentials` or :obj:`str`): Decrypted data with unique user's
|
||||
nonce, data hashes and secrets used for EncryptedPassportElement decryption and
|
||||
|
|
|
@ -29,6 +29,10 @@ class EncryptedPassportElement(TelegramObject):
|
|||
Contains information about documents or other Telegram Passport elements shared with the bot
|
||||
by the user. The data has been automatically decrypted by python-telegram-bot.
|
||||
|
||||
Objects of this class are comparable in terms of equality. Two objects of this class are
|
||||
considered equal, if their :attr:`type`, :attr:`data`, :attr:`phone_number`, :attr:`email`,
|
||||
:attr:`files`, :attr:`front_side`, :attr:`reverse_side` and :attr:`selfie` are equal.
|
||||
|
||||
Attributes:
|
||||
type (:obj:`str`): Element type. One of "personal_details", "passport", "driver_license",
|
||||
"identity_card", "internal_passport", "address", "utility_bill", "bank_statement",
|
||||
|
|
|
@ -24,6 +24,9 @@ from telegram import TelegramObject
|
|||
class PassportElementError(TelegramObject):
|
||||
"""Baseclass for the PassportElementError* classes.
|
||||
|
||||
Objects of this class are comparable in terms of equality. Two objects of this class are
|
||||
considered equal, if their :attr:`source` and :attr:`type` are equal.
|
||||
|
||||
Attributes:
|
||||
source (:obj:`str`): Error source.
|
||||
type (:obj:`str`): The section of the user's Telegram Passport which has the error.
|
||||
|
@ -50,6 +53,10 @@ class PassportElementErrorDataField(PassportElementError):
|
|||
Represents an issue in one of the data fields that was provided by the user. The error is
|
||||
considered resolved when the field's value changes.
|
||||
|
||||
Objects of this class are comparable in terms of equality. Two objects of this class are
|
||||
considered equal, if their :attr:`source`, :attr:`type`, :attr:`field_name`, :attr:`data_hash`
|
||||
and :attr:`message` are equal.
|
||||
|
||||
Attributes:
|
||||
type (:obj:`str`): The section of the user's Telegram Passport which has the error, one of
|
||||
"personal_details", "passport", "driver_license", "identity_card", "internal_passport",
|
||||
|
@ -88,6 +95,10 @@ class PassportElementErrorFile(PassportElementError):
|
|||
Represents an issue with a document scan. The error is considered resolved when the file with
|
||||
the document scan changes.
|
||||
|
||||
Objects of this class are comparable in terms of equality. Two objects of this class are
|
||||
considered equal, if their :attr:`source`, :attr:`type`, :attr:`file_hash`, :attr:`data_hash`
|
||||
and :attr:`message` are equal.
|
||||
|
||||
Attributes:
|
||||
type (:obj:`str`): The section of the user's Telegram Passport which has the issue, one of
|
||||
"utility_bill", "bank_statement", "rental_agreement", "passport_registration",
|
||||
|
@ -122,11 +133,15 @@ class PassportElementErrorFiles(PassportElementError):
|
|||
Represents an issue with a list of scans. The error is considered resolved when the file with
|
||||
the document scan changes.
|
||||
|
||||
Objects of this class are comparable in terms of equality. Two objects of this class are
|
||||
considered equal, if their :attr:`source`, :attr:`type`, :attr:`file_hashes`, :attr:`data_hash`
|
||||
and :attr:`message` are equal.
|
||||
|
||||
Attributes:
|
||||
type (:obj:`str`): The section of the user's Telegram Passport which has the issue, one of
|
||||
"utility_bill", "bank_statement", "rental_agreement", "passport_registration",
|
||||
"temporary_registration".
|
||||
file_hash (:obj:`str`): Base64-encoded file hash.
|
||||
file_hashes (List[:obj:`str`]): List of base64-encoded file hashes.
|
||||
message (:obj:`str`): Error message.
|
||||
|
||||
Args:
|
||||
|
@ -157,6 +172,10 @@ class PassportElementErrorFrontSide(PassportElementError):
|
|||
Represents an issue with the front side of a document. The error is considered resolved when
|
||||
the file with the front side of the document changes.
|
||||
|
||||
Objects of this class are comparable in terms of equality. Two objects of this class are
|
||||
considered equal, if their :attr:`source`, :attr:`type`, :attr:`file_hash`, :attr:`data_hash`
|
||||
and :attr:`message` are equal.
|
||||
|
||||
Attributes:
|
||||
type (:obj:`str`): The section of the user's Telegram Passport which has the issue, one of
|
||||
"passport", "driver_license", "identity_card", "internal_passport".
|
||||
|
@ -191,6 +210,10 @@ class PassportElementErrorReverseSide(PassportElementError):
|
|||
Represents an issue with the front side of a document. The error is considered resolved when
|
||||
the file with the reverse side of the document changes.
|
||||
|
||||
Objects of this class are comparable in terms of equality. Two objects of this class are
|
||||
considered equal, if their :attr:`source`, :attr:`type`, :attr:`file_hash`, :attr:`data_hash`
|
||||
and :attr:`message` are equal.
|
||||
|
||||
Attributes:
|
||||
type (:obj:`str`): The section of the user's Telegram Passport which has the issue, one of
|
||||
"passport", "driver_license", "identity_card", "internal_passport".
|
||||
|
@ -225,6 +248,10 @@ class PassportElementErrorSelfie(PassportElementError):
|
|||
Represents an issue with the selfie with a document. The error is considered resolved when
|
||||
the file with the selfie changes.
|
||||
|
||||
Objects of this class are comparable in terms of equality. Two objects of this class are
|
||||
considered equal, if their :attr:`source`, :attr:`type`, :attr:`file_hash`, :attr:`data_hash`
|
||||
and :attr:`message` are equal.
|
||||
|
||||
Attributes:
|
||||
type (:obj:`str`): The section of the user's Telegram Passport which has the issue, one of
|
||||
"passport", "driver_license", "identity_card", "internal_passport".
|
||||
|
@ -257,6 +284,10 @@ class PassportElementErrorTranslationFile(PassportElementError):
|
|||
Represents an issue with one of the files that constitute the translation of a document.
|
||||
The error is considered resolved when the file changes.
|
||||
|
||||
Objects of this class are comparable in terms of equality. Two objects of this class are
|
||||
considered equal, if their :attr:`source`, :attr:`type`, :attr:`file_hash`, :attr:`data_hash`
|
||||
and :attr:`message` are equal.
|
||||
|
||||
Attributes:
|
||||
type (:obj:`str`): Type of element of the user's Telegram Passport which has the issue,
|
||||
one of "passport", "driver_license", "identity_card", "internal_passport",
|
||||
|
@ -293,12 +324,16 @@ class PassportElementErrorTranslationFiles(PassportElementError):
|
|||
Represents an issue with the translated version of a document. The error is considered
|
||||
resolved when a file with the document translation change.
|
||||
|
||||
Objects of this class are comparable in terms of equality. Two objects of this class are
|
||||
considered equal, if their :attr:`source`, :attr:`type`, :attr:`file_hashes`, :attr:`data_hash`
|
||||
and :attr:`message` are equal.
|
||||
|
||||
Attributes:
|
||||
type (:obj:`str`): Type of element of the user's Telegram Passport which has the issue,
|
||||
one of "passport", "driver_license", "identity_card", "internal_passport",
|
||||
"utility_bill", "bank_statement", "rental_agreement", "passport_registration",
|
||||
"temporary_registration"
|
||||
file_hash (:obj:`str`): Base64-encoded file hash.
|
||||
file_hashes (List[:obj:`str`]): List of base64-encoded file hashes.
|
||||
message (:obj:`str`): Error message.
|
||||
|
||||
Args:
|
||||
|
@ -330,6 +365,10 @@ class PassportElementErrorUnspecified(PassportElementError):
|
|||
Represents an issue in an unspecified place. The error is considered resolved when new
|
||||
data is added.
|
||||
|
||||
Objects of this class are comparable in terms of equality. Two objects of this class are
|
||||
considered equal, if their :attr:`source`, :attr:`type`, :attr:`element_hash`,
|
||||
:attr:`data_hash` and :attr:`message` are equal.
|
||||
|
||||
Attributes:
|
||||
type (:obj:`str`): Type of element of the user's Telegram Passport which has the issue.
|
||||
element_hash (:obj:`str`): Base64-encoded element hash.
|
||||
|
|
|
@ -26,6 +26,9 @@ class PassportFile(TelegramObject):
|
|||
This object represents a file uploaded to Telegram Passport. Currently all Telegram Passport
|
||||
files are in JPEG format when decrypted and don't exceed 10MB.
|
||||
|
||||
Objects of this class are comparable in terms of equality. Two objects of this class are
|
||||
considered equal, if their :attr:`file_unique_id` is equal.
|
||||
|
||||
Attributes:
|
||||
file_id (:obj:`str`): Identifier for this file.
|
||||
file_unique_id (:obj:`str`): Unique identifier for this file, which
|
||||
|
|
|
@ -24,6 +24,10 @@ from telegram import TelegramObject
|
|||
class Invoice(TelegramObject):
|
||||
"""This object contains basic information about an invoice.
|
||||
|
||||
Objects of this class are comparable in terms of equality. Two objects of this class are
|
||||
considered equal, if their :attr:`title`, :attr:`description`, :attr:`start_parameter`,
|
||||
:attr:`currency` and :attr:`total_amount` are equal.
|
||||
|
||||
Attributes:
|
||||
title (:obj:`str`): Product name.
|
||||
description (:obj:`str`): Product description.
|
||||
|
@ -54,6 +58,14 @@ class Invoice(TelegramObject):
|
|||
self.currency = currency
|
||||
self.total_amount = total_amount
|
||||
|
||||
self._id_attrs = (
|
||||
self.title,
|
||||
self.description,
|
||||
self.start_parameter,
|
||||
self.currency,
|
||||
self.total_amount,
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def de_json(cls, data, bot):
|
||||
if not data:
|
||||
|
|
|
@ -24,6 +24,9 @@ from telegram import TelegramObject
|
|||
class LabeledPrice(TelegramObject):
|
||||
"""This object represents a portion of the price for goods or services.
|
||||
|
||||
Objects of this class are comparable in terms of equality. Two objects of this class are
|
||||
considered equal, if their :attr:`label` and :attr:`amount` are equal.
|
||||
|
||||
Attributes:
|
||||
label (:obj:`str`): Portion label.
|
||||
amount (:obj:`int`): Price of the product in the smallest units of the currency.
|
||||
|
@ -43,3 +46,5 @@ class LabeledPrice(TelegramObject):
|
|||
def __init__(self, label, amount, **kwargs):
|
||||
self.label = label
|
||||
self.amount = amount
|
||||
|
||||
self._id_attrs = (self.label, self.amount)
|
||||
|
|
|
@ -24,6 +24,10 @@ from telegram import TelegramObject, ShippingAddress
|
|||
class OrderInfo(TelegramObject):
|
||||
"""This object represents information about an order.
|
||||
|
||||
Objects of this class are comparable in terms of equality. Two objects of this class are
|
||||
considered equal, if their :attr:`name`, :attr:`phone_number`, :attr:`email` and
|
||||
:attr:`shipping_address` are equal.
|
||||
|
||||
Attributes:
|
||||
name (:obj:`str`): Optional. User name.
|
||||
phone_number (:obj:`str`): Optional. User's phone number.
|
||||
|
@ -45,6 +49,8 @@ class OrderInfo(TelegramObject):
|
|||
self.email = email
|
||||
self.shipping_address = shipping_address
|
||||
|
||||
self._id_attrs = (self.name, self.phone_number, self.email, self.shipping_address)
|
||||
|
||||
@classmethod
|
||||
def de_json(cls, data, bot):
|
||||
if not data:
|
||||
|
|
|
@ -24,6 +24,9 @@ from telegram import TelegramObject, User, OrderInfo
|
|||
class PreCheckoutQuery(TelegramObject):
|
||||
"""This object contains information about an incoming pre-checkout query.
|
||||
|
||||
Objects of this class are comparable in terms of equality. Two objects of this class are
|
||||
considered equal, if their :attr:`id` is equal.
|
||||
|
||||
Note:
|
||||
* In Python `from` is a reserved word, use `from_user` instead.
|
||||
|
||||
|
|
|
@ -24,6 +24,10 @@ from telegram import TelegramObject
|
|||
class ShippingAddress(TelegramObject):
|
||||
"""This object represents a Telegram ShippingAddress.
|
||||
|
||||
Objects of this class are comparable in terms of equality. Two objects of this class are
|
||||
considered equal, if their :attr:`country_code`, :attr:`state`, :attr:`city`,
|
||||
:attr:`street_line1`, :attr:`street_line2` and :attr:`post_cod` are equal.
|
||||
|
||||
Attributes:
|
||||
country_code (:obj:`str`): ISO 3166-1 alpha-2 country code.
|
||||
state (:obj:`str`): State, if applicable.
|
||||
|
|
|
@ -24,6 +24,9 @@ from telegram import TelegramObject
|
|||
class ShippingOption(TelegramObject):
|
||||
"""This object represents one shipping option.
|
||||
|
||||
Objects of this class are comparable in terms of equality. Two objects of this class are
|
||||
considered equal, if their :attr:`id` is equal.
|
||||
|
||||
Attributes:
|
||||
id (:obj:`str`): Shipping option identifier.
|
||||
title (:obj:`str`): Option title.
|
||||
|
|
|
@ -24,6 +24,9 @@ from telegram import TelegramObject, User, ShippingAddress
|
|||
class ShippingQuery(TelegramObject):
|
||||
"""This object contains information about an incoming shipping query.
|
||||
|
||||
Objects of this class are comparable in terms of equality. Two objects of this class are
|
||||
considered equal, if their :attr:`id` is equal.
|
||||
|
||||
Note:
|
||||
* In Python `from` is a reserved word, use `from_user` instead.
|
||||
|
||||
|
|
|
@ -24,6 +24,10 @@ from telegram import TelegramObject, OrderInfo
|
|||
class SuccessfulPayment(TelegramObject):
|
||||
"""This object contains basic information about a successful payment.
|
||||
|
||||
Objects of this class are comparable in terms of equality. Two objects of this class are
|
||||
considered equal, if their :attr:`telegram_payment_charge_id` and
|
||||
:attr:`provider_payment_charge_id` are equal.
|
||||
|
||||
Attributes:
|
||||
currency (:obj:`str`): Three-letter ISO 4217 currency code.
|
||||
total_amount (:obj:`int`): Total price in the smallest units of the currency.
|
||||
|
|
|
@ -29,6 +29,9 @@ class PollOption(TelegramObject):
|
|||
"""
|
||||
This object contains information about one answer option in a poll.
|
||||
|
||||
Objects of this class are comparable in terms of equality. Two objects of this class are
|
||||
considered equal, if their :attr:`text` and :attr:`voter_count` are equal.
|
||||
|
||||
Attributes:
|
||||
text (:obj:`str`): Option text, 1-100 characters.
|
||||
voter_count (:obj:`int`): Number of users that voted for this option.
|
||||
|
@ -43,6 +46,8 @@ class PollOption(TelegramObject):
|
|||
self.text = text
|
||||
self.voter_count = voter_count
|
||||
|
||||
self._id_attrs = (self.text, self.voter_count)
|
||||
|
||||
@classmethod
|
||||
def de_json(cls, data, bot):
|
||||
if not data:
|
||||
|
@ -55,6 +60,9 @@ class PollAnswer(TelegramObject):
|
|||
"""
|
||||
This object represents an answer of a user in a non-anonymous poll.
|
||||
|
||||
Objects of this class are comparable in terms of equality. Two objects of this class are
|
||||
considered equal, if their :attr:`poll_id`, :attr:`user` and :attr:`options_ids` are equal.
|
||||
|
||||
Attributes:
|
||||
poll_id (:obj:`str`): Unique poll identifier.
|
||||
user (:class:`telegram.User`): The user, who changed the answer to the poll.
|
||||
|
@ -72,6 +80,8 @@ class PollAnswer(TelegramObject):
|
|||
self.user = user
|
||||
self.option_ids = option_ids
|
||||
|
||||
self._id_attrs = (self.poll_id, self.user, tuple(self.option_ids))
|
||||
|
||||
@classmethod
|
||||
def de_json(cls, data, bot):
|
||||
if not data:
|
||||
|
@ -88,6 +98,9 @@ class Poll(TelegramObject):
|
|||
"""
|
||||
This object contains information about a poll.
|
||||
|
||||
Objects of this class are comparable in terms of equality. Two objects of this class are
|
||||
considered equal, if their :attr:`id` is equal.
|
||||
|
||||
Attributes:
|
||||
id (:obj:`str`): Unique poll identifier.
|
||||
question (:obj:`str`): Poll question, 1-255 characters.
|
||||
|
|
|
@ -19,11 +19,15 @@
|
|||
"""This module contains an object that represents a Telegram ReplyKeyboardMarkup."""
|
||||
|
||||
from telegram import ReplyMarkup
|
||||
from .keyboardbutton import KeyboardButton
|
||||
|
||||
|
||||
class ReplyKeyboardMarkup(ReplyMarkup):
|
||||
"""This object represents a custom keyboard with reply options.
|
||||
|
||||
Objects of this class are comparable in terms of equality. Two objects of this class are
|
||||
considered equal, if their the size of :attr:`keyboard` and all the buttons are equal.
|
||||
|
||||
Attributes:
|
||||
keyboard (List[List[:class:`telegram.KeyboardButton` | :obj:`str`]]): Array of button rows.
|
||||
resize_keyboard (:obj:`bool`): Optional. Requests clients to resize the keyboard.
|
||||
|
@ -66,7 +70,16 @@ class ReplyKeyboardMarkup(ReplyMarkup):
|
|||
selective=False,
|
||||
**kwargs):
|
||||
# Required
|
||||
self.keyboard = keyboard
|
||||
self.keyboard = []
|
||||
for row in keyboard:
|
||||
r = []
|
||||
for button in row:
|
||||
if hasattr(button, 'to_dict'):
|
||||
r.append(button) # telegram.KeyboardButton
|
||||
else:
|
||||
r.append(KeyboardButton(button)) # str
|
||||
self.keyboard.append(r)
|
||||
|
||||
# Optionals
|
||||
self.resize_keyboard = bool(resize_keyboard)
|
||||
self.one_time_keyboard = bool(one_time_keyboard)
|
||||
|
@ -211,3 +224,22 @@ class ReplyKeyboardMarkup(ReplyMarkup):
|
|||
one_time_keyboard=one_time_keyboard,
|
||||
selective=selective,
|
||||
**kwargs)
|
||||
|
||||
def __eq__(self, other):
|
||||
if isinstance(other, self.__class__):
|
||||
if len(self.keyboard) != len(other.keyboard):
|
||||
return False
|
||||
for idx, row in enumerate(self.keyboard):
|
||||
if len(row) != len(other.keyboard[idx]):
|
||||
return False
|
||||
for jdx, button in enumerate(row):
|
||||
if button != other.keyboard[idx][jdx]:
|
||||
return False
|
||||
return True
|
||||
return super(ReplyKeyboardMarkup, self).__eq__(other) # pylint: disable=no-member
|
||||
|
||||
def __hash__(self):
|
||||
return hash((
|
||||
tuple(tuple(button for button in row) for row in self.keyboard),
|
||||
self.resize_keyboard, self.one_time_keyboard, self.selective
|
||||
))
|
||||
|
|
|
@ -26,6 +26,9 @@ from telegram.poll import PollAnswer
|
|||
class Update(TelegramObject):
|
||||
"""This object represents an incoming update.
|
||||
|
||||
Objects of this class are comparable in terms of equality. Two objects of this class are
|
||||
considered equal, if their :attr:`update_id` is equal.
|
||||
|
||||
Note:
|
||||
At most one of the optional parameters can be present in any given update.
|
||||
|
||||
|
|
|
@ -27,6 +27,9 @@ from telegram.utils.helpers import mention_markdown as util_mention_markdown
|
|||
class User(TelegramObject):
|
||||
"""This object represents a Telegram user or bot.
|
||||
|
||||
Objects of this class are comparable in terms of equality. Two objects of this class are
|
||||
considered equal, if their :attr:`id` is equal.
|
||||
|
||||
Attributes:
|
||||
id (:obj:`int`): Unique identifier for this user or bot.
|
||||
is_bot (:obj:`bool`): :obj:`True`, if this user is a bot.
|
||||
|
|
|
@ -24,6 +24,9 @@ from telegram import PhotoSize, TelegramObject
|
|||
class UserProfilePhotos(TelegramObject):
|
||||
"""This object represent a user's profile pictures.
|
||||
|
||||
Objects of this class are comparable in terms of equality. Two objects of this class are
|
||||
considered equal, if their :attr:`total_count` and :attr:`photos` are equal.
|
||||
|
||||
Attributes:
|
||||
total_count (:obj:`int`): Total number of profile pictures.
|
||||
photos (List[List[:class:`telegram.PhotoSize`]]): Requested profile pictures.
|
||||
|
@ -40,6 +43,8 @@ class UserProfilePhotos(TelegramObject):
|
|||
self.total_count = int(total_count)
|
||||
self.photos = photos
|
||||
|
||||
self._id_attrs = (self.total_count, self.photos)
|
||||
|
||||
@classmethod
|
||||
def de_json(cls, data, bot):
|
||||
if not data:
|
||||
|
@ -59,3 +64,6 @@ class UserProfilePhotos(TelegramObject):
|
|||
data['photos'].append([x.to_dict() for x in photo])
|
||||
|
||||
return data
|
||||
|
||||
def __hash__(self):
|
||||
return hash(tuple(tuple(p for p in photo) for photo in self.photos))
|
||||
|
|
|
@ -26,6 +26,11 @@ class WebhookInfo(TelegramObject):
|
|||
|
||||
Contains information about the current status of a webhook.
|
||||
|
||||
Objects of this class are comparable in terms of equality. Two objects of this class are
|
||||
considered equal, if their :attr:`url`, :attr:`has_custom_certificate`,
|
||||
:attr:`pending_update_count`, :attr:`last_error_date`, :attr:`last_error_message`,
|
||||
:attr:`max_connections` and :attr:`allowed_updates` are equal.
|
||||
|
||||
Attributes:
|
||||
url (:obj:`str`): Webhook URL.
|
||||
has_custom_certificate (:obj:`bool`): If a custom certificate was provided for webhook.
|
||||
|
@ -71,6 +76,16 @@ class WebhookInfo(TelegramObject):
|
|||
self.max_connections = max_connections
|
||||
self.allowed_updates = allowed_updates
|
||||
|
||||
self._id_attrs = (
|
||||
self.url,
|
||||
self.has_custom_certificate,
|
||||
self.pending_update_count,
|
||||
self.last_error_date,
|
||||
self.last_error_message,
|
||||
self.max_connections,
|
||||
self.allowed_updates,
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def de_json(cls, data, bot):
|
||||
if not data:
|
||||
|
|
|
@ -19,7 +19,7 @@
|
|||
|
||||
import pytest
|
||||
|
||||
from telegram import BotCommand
|
||||
from telegram import BotCommand, Dice
|
||||
|
||||
|
||||
@pytest.fixture(scope="class")
|
||||
|
@ -46,3 +46,22 @@ class TestBotCommand:
|
|||
assert isinstance(bot_command_dict, dict)
|
||||
assert bot_command_dict['command'] == bot_command.command
|
||||
assert bot_command_dict['description'] == bot_command.description
|
||||
|
||||
def test_equality(self):
|
||||
a = BotCommand('start', 'some description')
|
||||
b = BotCommand('start', 'some description')
|
||||
c = BotCommand('start', 'some other description')
|
||||
d = BotCommand('hepl', 'some description')
|
||||
e = Dice(4, 'emoji')
|
||||
|
||||
assert a == b
|
||||
assert hash(a) == hash(b)
|
||||
|
||||
assert a != c
|
||||
assert hash(a) != hash(c)
|
||||
|
||||
assert a != d
|
||||
assert hash(a) != hash(d)
|
||||
|
||||
assert a != e
|
||||
assert hash(a) != hash(e)
|
||||
|
|
|
@ -19,7 +19,7 @@
|
|||
|
||||
import pytest
|
||||
|
||||
from telegram import ChatPermissions
|
||||
from telegram import ChatPermissions, User
|
||||
|
||||
|
||||
@pytest.fixture(scope="class")
|
||||
|
@ -77,3 +77,34 @@ class TestChatPermissions:
|
|||
assert permissions_dict['can_change_info'] == chat_permissions.can_change_info
|
||||
assert permissions_dict['can_invite_users'] == chat_permissions.can_invite_users
|
||||
assert permissions_dict['can_pin_messages'] == chat_permissions.can_pin_messages
|
||||
|
||||
def test_equality(self):
|
||||
a = ChatPermissions(
|
||||
can_send_messages=True,
|
||||
can_send_media_messages=True,
|
||||
can_send_polls=True,
|
||||
can_send_other_messages=False
|
||||
)
|
||||
b = ChatPermissions(
|
||||
can_send_polls=True,
|
||||
can_send_other_messages=False,
|
||||
can_send_messages=True,
|
||||
can_send_media_messages=True,
|
||||
)
|
||||
c = ChatPermissions(
|
||||
can_send_messages=False,
|
||||
can_send_media_messages=True,
|
||||
can_send_polls=True,
|
||||
can_send_other_messages=False
|
||||
)
|
||||
d = User(123, '', False)
|
||||
|
||||
assert a == b
|
||||
assert hash(a) == hash(b)
|
||||
assert a is not b
|
||||
|
||||
assert a != c
|
||||
assert hash(a) != hash(c)
|
||||
|
||||
assert a != d
|
||||
assert hash(a) != hash(d)
|
||||
|
|
|
@ -19,7 +19,7 @@
|
|||
|
||||
import pytest
|
||||
|
||||
from telegram import Dice
|
||||
from telegram import Dice, BotCommand
|
||||
|
||||
|
||||
@pytest.fixture(scope="class",
|
||||
|
@ -46,3 +46,22 @@ class TestDice:
|
|||
assert isinstance(dice_dict, dict)
|
||||
assert dice_dict['value'] == dice.value
|
||||
assert dice_dict['emoji'] == dice.emoji
|
||||
|
||||
def test_equality(self):
|
||||
a = Dice(3, '🎯')
|
||||
b = Dice(3, '🎯')
|
||||
c = Dice(3, '🎲')
|
||||
d = Dice(4, '🎯')
|
||||
e = BotCommand('start', 'description')
|
||||
|
||||
assert a == b
|
||||
assert hash(a) == hash(b)
|
||||
|
||||
assert a != c
|
||||
assert hash(a) != hash(c)
|
||||
|
||||
assert a != d
|
||||
assert hash(a) != hash(d)
|
||||
|
||||
assert a != e
|
||||
assert hash(a) != hash(e)
|
||||
|
|
|
@ -20,7 +20,7 @@
|
|||
import pytest
|
||||
from flaky import flaky
|
||||
|
||||
from telegram import ForceReply
|
||||
from telegram import ForceReply, ReplyKeyboardRemove
|
||||
|
||||
|
||||
@pytest.fixture(scope='class')
|
||||
|
@ -49,3 +49,18 @@ class TestForceReply:
|
|||
assert isinstance(force_reply_dict, dict)
|
||||
assert force_reply_dict['force_reply'] == force_reply.force_reply
|
||||
assert force_reply_dict['selective'] == force_reply.selective
|
||||
|
||||
def test_equality(self):
|
||||
a = ForceReply(True, False)
|
||||
b = ForceReply(False, False)
|
||||
c = ForceReply(True, True)
|
||||
d = ReplyKeyboardRemove()
|
||||
|
||||
assert a == b
|
||||
assert hash(a) == hash(b)
|
||||
|
||||
assert a != c
|
||||
assert hash(a) != hash(c)
|
||||
|
||||
assert a != d
|
||||
assert hash(a) != hash(d)
|
||||
|
|
|
@ -95,3 +95,20 @@ class TestGame:
|
|||
|
||||
assert game.parse_text_entities(MessageEntity.URL) == {entity: 'http://google.com'}
|
||||
assert game.parse_text_entities() == {entity: 'http://google.com', entity_2: 'h'}
|
||||
|
||||
def test_equality(self):
|
||||
a = Game('title', 'description', [PhotoSize('Blah', 'unique_id', 640, 360, file_size=0)])
|
||||
b = Game('title', 'description', [PhotoSize('Blah', 'unique_id', 640, 360, file_size=0)],
|
||||
text='Here is a text')
|
||||
c = Game('eltit', 'description', [PhotoSize('Blah', 'unique_id', 640, 360, file_size=0)],
|
||||
animation=Animation('blah', 'unique_id', 320, 180, 1))
|
||||
d = Animation('blah', 'unique_id', 320, 180, 1)
|
||||
|
||||
assert a == b
|
||||
assert hash(a) == hash(b)
|
||||
|
||||
assert a != c
|
||||
assert hash(a) != hash(c)
|
||||
|
||||
assert a != d
|
||||
assert hash(a) != hash(d)
|
||||
|
|
|
@ -51,3 +51,22 @@ class TestGameHighScore:
|
|||
assert game_highscore_dict['position'] == game_highscore.position
|
||||
assert game_highscore_dict['user'] == game_highscore.user.to_dict()
|
||||
assert game_highscore_dict['score'] == game_highscore.score
|
||||
|
||||
def test_equality(self):
|
||||
a = GameHighScore(1, User(2, 'test user', False), 42)
|
||||
b = GameHighScore(1, User(2, 'test user', False), 42)
|
||||
c = GameHighScore(2, User(2, 'test user', False), 42)
|
||||
d = GameHighScore(1, User(3, 'test user', False), 42)
|
||||
e = User(3, 'test user', False)
|
||||
|
||||
assert a == b
|
||||
assert hash(a) == hash(b)
|
||||
|
||||
assert a != c
|
||||
assert hash(a) != hash(c)
|
||||
|
||||
assert a != d
|
||||
assert hash(a) != hash(d)
|
||||
|
||||
assert a != e
|
||||
assert hash(a) != hash(e)
|
||||
|
|
|
@ -92,3 +92,26 @@ class TestInlineKeyboardButton:
|
|||
== self.switch_inline_query_current_chat)
|
||||
assert inline_keyboard_button.callback_game == self.callback_game
|
||||
assert inline_keyboard_button.pay == self.pay
|
||||
|
||||
def test_equality(self):
|
||||
a = InlineKeyboardButton('text', callback_data='data')
|
||||
b = InlineKeyboardButton('text', callback_data='data')
|
||||
c = InlineKeyboardButton('texts', callback_data='data')
|
||||
d = InlineKeyboardButton('text', callback_data='info')
|
||||
e = InlineKeyboardButton('text', url='http://google.com')
|
||||
f = LoginUrl("http://google.com")
|
||||
|
||||
assert a == b
|
||||
assert hash(a) == hash(b)
|
||||
|
||||
assert a != c
|
||||
assert hash(a) != hash(c)
|
||||
|
||||
assert a != d
|
||||
assert hash(a) != hash(d)
|
||||
|
||||
assert a != e
|
||||
assert hash(a) != hash(e)
|
||||
|
||||
assert a != f
|
||||
assert hash(a) != hash(f)
|
||||
|
|
|
@ -20,7 +20,7 @@
|
|||
import pytest
|
||||
from flaky import flaky
|
||||
|
||||
from telegram import InlineKeyboardButton, InlineKeyboardMarkup, ReplyMarkup
|
||||
from telegram import InlineKeyboardButton, InlineKeyboardMarkup, ReplyMarkup, ReplyKeyboardMarkup
|
||||
|
||||
|
||||
@pytest.fixture(scope='class')
|
||||
|
@ -129,3 +129,52 @@ class TestInlineKeyboardMarkup:
|
|||
|
||||
assert keyboard[0][0].text == 'start'
|
||||
assert keyboard[0][0].url == 'http://google.com'
|
||||
|
||||
def test_equality(self):
|
||||
a = InlineKeyboardMarkup.from_column([
|
||||
InlineKeyboardButton(label, callback_data='data')
|
||||
for label in ['button1', 'button2', 'button3']
|
||||
])
|
||||
b = InlineKeyboardMarkup.from_column([
|
||||
InlineKeyboardButton(label, callback_data='data')
|
||||
for label in ['button1', 'button2', 'button3']
|
||||
])
|
||||
c = InlineKeyboardMarkup.from_column([
|
||||
InlineKeyboardButton(label, callback_data='data')
|
||||
for label in ['button1', 'button2']
|
||||
])
|
||||
d = InlineKeyboardMarkup.from_column([
|
||||
InlineKeyboardButton(label, callback_data=label)
|
||||
for label in ['button1', 'button2', 'button3']
|
||||
])
|
||||
e = InlineKeyboardMarkup.from_column([
|
||||
InlineKeyboardButton(label, url=label)
|
||||
for label in ['button1', 'button2', 'button3']
|
||||
])
|
||||
f = InlineKeyboardMarkup([
|
||||
[InlineKeyboardButton(label, callback_data='data')
|
||||
for label in ['button1', 'button2']],
|
||||
[InlineKeyboardButton(label, callback_data='data')
|
||||
for label in ['button1', 'button2']],
|
||||
[InlineKeyboardButton(label, callback_data='data')
|
||||
for label in ['button1', 'button2']]
|
||||
])
|
||||
g = ReplyKeyboardMarkup.from_column(['button1', 'button2', 'button3'])
|
||||
|
||||
assert a == b
|
||||
assert hash(a) == hash(b)
|
||||
|
||||
assert a != c
|
||||
assert hash(a) != hash(c)
|
||||
|
||||
assert a != d
|
||||
assert hash(a) != hash(d)
|
||||
|
||||
assert a != e
|
||||
assert hash(a) != hash(e)
|
||||
|
||||
assert a != f
|
||||
assert hash(a) != hash(f)
|
||||
|
||||
assert a != g
|
||||
assert hash(a) != hash(g)
|
||||
|
|
|
@ -19,7 +19,7 @@
|
|||
|
||||
import pytest
|
||||
|
||||
from telegram import InputContactMessageContent
|
||||
from telegram import InputContactMessageContent, User
|
||||
|
||||
|
||||
@pytest.fixture(scope='class')
|
||||
|
@ -49,3 +49,18 @@ class TestInputContactMessageContent:
|
|||
== input_contact_message_content.first_name)
|
||||
assert (input_contact_message_content_dict['last_name']
|
||||
== input_contact_message_content.last_name)
|
||||
|
||||
def test_equality(self):
|
||||
a = InputContactMessageContent('phone', 'first', last_name='last')
|
||||
b = InputContactMessageContent('phone', 'first_name', vcard='vcard')
|
||||
c = InputContactMessageContent('phone_number', 'first', vcard='vcard')
|
||||
d = User(123, 'first', False)
|
||||
|
||||
assert a == b
|
||||
assert hash(a) == hash(b)
|
||||
|
||||
assert a != c
|
||||
assert hash(a) != hash(c)
|
||||
|
||||
assert a != d
|
||||
assert hash(a) != hash(d)
|
||||
|
|
|
@ -19,7 +19,7 @@
|
|||
|
||||
import pytest
|
||||
|
||||
from telegram import InputLocationMessageContent
|
||||
from telegram import InputLocationMessageContent, Location
|
||||
|
||||
|
||||
@pytest.fixture(scope='class')
|
||||
|
@ -49,3 +49,18 @@ class TestInputLocationMessageContent:
|
|||
== input_location_message_content.longitude)
|
||||
assert (input_location_message_content_dict['live_period']
|
||||
== input_location_message_content.live_period)
|
||||
|
||||
def test_equality(self):
|
||||
a = InputLocationMessageContent(123, 456, 70)
|
||||
b = InputLocationMessageContent(123, 456, 90)
|
||||
c = InputLocationMessageContent(123, 457, 70)
|
||||
d = Location(123, 456)
|
||||
|
||||
assert a == b
|
||||
assert hash(a) == hash(b)
|
||||
|
||||
assert a != c
|
||||
assert hash(a) != hash(c)
|
||||
|
||||
assert a != d
|
||||
assert hash(a) != hash(d)
|
||||
|
|
|
@ -50,3 +50,18 @@ class TestInputTextMessageContent:
|
|||
== input_text_message_content.parse_mode)
|
||||
assert (input_text_message_content_dict['disable_web_page_preview']
|
||||
== input_text_message_content.disable_web_page_preview)
|
||||
|
||||
def test_equality(self):
|
||||
a = InputTextMessageContent('text')
|
||||
b = InputTextMessageContent('text', parse_mode=ParseMode.HTML)
|
||||
c = InputTextMessageContent('label')
|
||||
d = ParseMode.HTML
|
||||
|
||||
assert a == b
|
||||
assert hash(a) == hash(b)
|
||||
|
||||
assert a != c
|
||||
assert hash(a) != hash(c)
|
||||
|
||||
assert a != d
|
||||
assert hash(a) != hash(d)
|
||||
|
|
|
@ -19,7 +19,7 @@
|
|||
|
||||
import pytest
|
||||
|
||||
from telegram import InputVenueMessageContent
|
||||
from telegram import InputVenueMessageContent, Location
|
||||
|
||||
|
||||
@pytest.fixture(scope='class')
|
||||
|
@ -62,3 +62,22 @@ class TestInputVenueMessageContent:
|
|||
== input_venue_message_content.foursquare_id)
|
||||
assert (input_venue_message_content_dict['foursquare_type']
|
||||
== input_venue_message_content.foursquare_type)
|
||||
|
||||
def test_equality(self):
|
||||
a = InputVenueMessageContent(123, 456, 'title', 'address')
|
||||
b = InputVenueMessageContent(123, 456, 'title', '')
|
||||
c = InputVenueMessageContent(123, 456, 'title', 'address', foursquare_id=123)
|
||||
d = InputVenueMessageContent(456, 123, 'title', 'address', foursquare_id=123)
|
||||
e = Location(123, 456)
|
||||
|
||||
assert a == b
|
||||
assert hash(a) == hash(b)
|
||||
|
||||
assert a == c
|
||||
assert hash(a) == hash(c)
|
||||
|
||||
assert a != d
|
||||
assert hash(a) != hash(d)
|
||||
|
||||
assert a != e
|
||||
assert hash(a) != hash(e)
|
||||
|
|
|
@ -120,3 +120,18 @@ class TestInvoice:
|
|||
assert bot.send_invoice(chat_id, self.title, self.description, self.payload,
|
||||
provider_token, self.start_parameter, self.currency,
|
||||
self.prices, provider_data={'test_data': 123456789})
|
||||
|
||||
def test_equality(self):
|
||||
a = Invoice('invoice', 'desc', 'start', 'EUR', 7)
|
||||
b = Invoice('invoice', 'desc', 'start', 'EUR', 7)
|
||||
c = Invoice('invoices', 'description', 'stop', 'USD', 8)
|
||||
d = LabeledPrice('label', 5)
|
||||
|
||||
assert a == b
|
||||
assert hash(a) == hash(b)
|
||||
|
||||
assert a != c
|
||||
assert hash(a) != hash(c)
|
||||
|
||||
assert a != d
|
||||
assert hash(a) != hash(d)
|
||||
|
|
|
@ -19,7 +19,7 @@
|
|||
|
||||
import pytest
|
||||
|
||||
from telegram import KeyboardButton
|
||||
from telegram import KeyboardButton, InlineKeyboardButton
|
||||
from telegram.keyboardbuttonpolltype import KeyboardButtonPollType
|
||||
|
||||
|
||||
|
@ -51,3 +51,18 @@ class TestKeyboardButton:
|
|||
assert keyboard_button_dict['request_location'] == keyboard_button.request_location
|
||||
assert keyboard_button_dict['request_contact'] == keyboard_button.request_contact
|
||||
assert keyboard_button_dict['request_poll'] == keyboard_button.request_poll.to_dict()
|
||||
|
||||
def test_equality(self):
|
||||
a = KeyboardButton('test', request_contact=True)
|
||||
b = KeyboardButton('test', request_contact=True)
|
||||
c = KeyboardButton('Test', request_location=True)
|
||||
d = InlineKeyboardButton('test', callback_data='test')
|
||||
|
||||
assert a == b
|
||||
assert hash(a) == hash(b)
|
||||
|
||||
assert a != c
|
||||
assert hash(a) != hash(c)
|
||||
|
||||
assert a != d
|
||||
assert hash(a) != hash(d)
|
||||
|
|
|
@ -19,7 +19,7 @@
|
|||
|
||||
import pytest
|
||||
|
||||
from telegram import LabeledPrice
|
||||
from telegram import LabeledPrice, Location
|
||||
|
||||
|
||||
@pytest.fixture(scope='class')
|
||||
|
@ -41,3 +41,18 @@ class TestLabeledPrice:
|
|||
assert isinstance(labeled_price_dict, dict)
|
||||
assert labeled_price_dict['label'] == labeled_price.label
|
||||
assert labeled_price_dict['amount'] == labeled_price.amount
|
||||
|
||||
def test_equality(self):
|
||||
a = LabeledPrice('label', 100)
|
||||
b = LabeledPrice('label', 100)
|
||||
c = LabeledPrice('Label', 101)
|
||||
d = Location(123, 456)
|
||||
|
||||
assert a == b
|
||||
assert hash(a) == hash(b)
|
||||
|
||||
assert a != c
|
||||
assert hash(a) != hash(c)
|
||||
|
||||
assert a != d
|
||||
assert hash(a) != hash(d)
|
||||
|
|
|
@ -888,7 +888,7 @@ class TestMessage:
|
|||
id_ = 1
|
||||
a = Message(id_, self.from_user, self.date, self.chat)
|
||||
b = Message(id_, self.from_user, self.date, self.chat)
|
||||
c = Message(id_, User(0, '', False), self.date, self.chat)
|
||||
c = Message(id_, self.from_user, self.date, Chat(123, Chat.GROUP))
|
||||
d = Message(0, self.from_user, self.date, self.chat)
|
||||
e = Update(id_)
|
||||
|
||||
|
@ -896,8 +896,8 @@ class TestMessage:
|
|||
assert hash(a) == hash(b)
|
||||
assert a is not b
|
||||
|
||||
assert a == c
|
||||
assert hash(a) == hash(c)
|
||||
assert a != c
|
||||
assert hash(a) != hash(c)
|
||||
|
||||
assert a != d
|
||||
assert hash(a) != hash(d)
|
||||
|
|
|
@ -56,3 +56,26 @@ class TestOrderInfo:
|
|||
assert order_info_dict['phone_number'] == order_info.phone_number
|
||||
assert order_info_dict['email'] == order_info.email
|
||||
assert order_info_dict['shipping_address'] == order_info.shipping_address.to_dict()
|
||||
|
||||
def test_equality(self):
|
||||
a = OrderInfo('name', 'number', 'mail',
|
||||
ShippingAddress('GB', '', 'London', '12 Grimmauld Place', '', 'WC1'))
|
||||
b = OrderInfo('name', 'number', 'mail',
|
||||
ShippingAddress('GB', '', 'London', '12 Grimmauld Place', '', 'WC1'))
|
||||
c = OrderInfo('name', 'number', 'mail',
|
||||
ShippingAddress('GB', '', 'London', '13 Grimmauld Place', '', 'WC1'))
|
||||
d = OrderInfo('name', 'number', 'e-mail',
|
||||
ShippingAddress('GB', '', 'London', '12 Grimmauld Place', '', 'WC1'))
|
||||
e = ShippingAddress('GB', '', 'London', '12 Grimmauld Place', '', 'WC1')
|
||||
|
||||
assert a == b
|
||||
assert hash(a) == hash(b)
|
||||
|
||||
assert a != c
|
||||
assert hash(a) != hash(c)
|
||||
|
||||
assert a != d
|
||||
assert hash(a) != hash(d)
|
||||
|
||||
assert a != e
|
||||
assert hash(a) != hash(e)
|
||||
|
|
|
@ -467,7 +467,7 @@ class TestBasePersistence:
|
|||
if isinstance(other, CustomClass):
|
||||
# print(self.__dict__)
|
||||
# print(other.__dict__)
|
||||
return (self.bot == other.bot
|
||||
return (self.bot is other.bot
|
||||
and self.slotted_object == other.slotted_object
|
||||
and self.list_ == other.list_
|
||||
and self.tuple_ == other.tuple_
|
||||
|
|
|
@ -51,6 +51,25 @@ class TestPollOption:
|
|||
assert poll_option_dict['text'] == poll_option.text
|
||||
assert poll_option_dict['voter_count'] == poll_option.voter_count
|
||||
|
||||
def test_equality(self):
|
||||
a = PollOption('text', 1)
|
||||
b = PollOption('text', 1)
|
||||
c = PollOption('text_1', 1)
|
||||
d = PollOption('text', 2)
|
||||
e = Poll(123, 'question', ['O1', 'O2'], 1, False, True, Poll.REGULAR, True)
|
||||
|
||||
assert a == b
|
||||
assert hash(a) == hash(b)
|
||||
|
||||
assert a != c
|
||||
assert hash(a) != hash(c)
|
||||
|
||||
assert a != d
|
||||
assert hash(a) != hash(d)
|
||||
|
||||
assert a != e
|
||||
assert hash(a) != hash(e)
|
||||
|
||||
|
||||
@pytest.fixture(scope="class")
|
||||
def poll_answer():
|
||||
|
@ -83,6 +102,25 @@ class TestPollAnswer:
|
|||
assert poll_answer_dict['user'] == poll_answer.user.to_dict()
|
||||
assert poll_answer_dict['option_ids'] == poll_answer.option_ids
|
||||
|
||||
def test_equality(self):
|
||||
a = PollAnswer(123, self.user, [2])
|
||||
b = PollAnswer(123, User(1, 'first', False), [2])
|
||||
c = PollAnswer(123, self.user, [1, 2])
|
||||
d = PollAnswer(456, self.user, [2])
|
||||
e = PollOption('Text', 1)
|
||||
|
||||
assert a == b
|
||||
assert hash(a) == hash(b)
|
||||
|
||||
assert a != c
|
||||
assert hash(a) != hash(c)
|
||||
|
||||
assert a != d
|
||||
assert hash(a) != hash(d)
|
||||
|
||||
assert a != e
|
||||
assert hash(a) != hash(e)
|
||||
|
||||
|
||||
@pytest.fixture(scope='class')
|
||||
def poll():
|
||||
|
@ -181,3 +219,18 @@ class TestPoll:
|
|||
|
||||
assert poll.parse_explanation_entities(MessageEntity.URL) == {entity: 'http://google.com'}
|
||||
assert poll.parse_explanation_entities() == {entity: 'http://google.com', entity_2: 'h'}
|
||||
|
||||
def test_equality(self):
|
||||
a = Poll(123, 'question', ['O1', 'O2'], 1, False, True, Poll.REGULAR, True)
|
||||
b = Poll(123, 'question', ['o1', 'o2'], 1, True, False, Poll.REGULAR, True)
|
||||
c = Poll(456, 'question', ['o1', 'o2'], 1, True, False, Poll.REGULAR, True)
|
||||
d = PollOption('Text', 1)
|
||||
|
||||
assert a == b
|
||||
assert hash(a) == hash(b)
|
||||
|
||||
assert a != c
|
||||
assert hash(a) != hash(c)
|
||||
|
||||
assert a != d
|
||||
assert hash(a) != hash(d)
|
||||
|
|
|
@ -20,7 +20,7 @@
|
|||
import pytest
|
||||
from flaky import flaky
|
||||
|
||||
from telegram import ReplyKeyboardMarkup, KeyboardButton
|
||||
from telegram import ReplyKeyboardMarkup, KeyboardButton, InlineKeyboardMarkup
|
||||
|
||||
|
||||
@pytest.fixture(scope='class')
|
||||
|
@ -106,3 +106,28 @@ class TestReplyKeyboardMarkup:
|
|||
assert (reply_keyboard_markup_dict['one_time_keyboard']
|
||||
== reply_keyboard_markup.one_time_keyboard)
|
||||
assert reply_keyboard_markup_dict['selective'] == reply_keyboard_markup.selective
|
||||
|
||||
def test_equality(self):
|
||||
a = ReplyKeyboardMarkup.from_column(['button1', 'button2', 'button3'])
|
||||
b = ReplyKeyboardMarkup.from_column([
|
||||
KeyboardButton(text) for text in ['button1', 'button2', 'button3']
|
||||
])
|
||||
c = ReplyKeyboardMarkup.from_column(['button1', 'button2'])
|
||||
d = ReplyKeyboardMarkup.from_column(['button1', 'button2', 'button3.1'])
|
||||
e = ReplyKeyboardMarkup([['button1', 'button1'], ['button2'], ['button3.1']])
|
||||
f = InlineKeyboardMarkup.from_column(['button1', 'button2', 'button3'])
|
||||
|
||||
assert a == b
|
||||
assert hash(a) == hash(b)
|
||||
|
||||
assert a != c
|
||||
assert hash(a) != hash(c)
|
||||
|
||||
assert a != d
|
||||
assert hash(a) != hash(d)
|
||||
|
||||
assert a != e
|
||||
assert hash(a) != hash(e)
|
||||
|
||||
assert a != f
|
||||
assert hash(a) != hash(f)
|
||||
|
|
|
@ -50,7 +50,7 @@ class TestShippingQuery:
|
|||
assert shipping_query.invoice_payload == self.invoice_payload
|
||||
assert shipping_query.from_user == self.from_user
|
||||
assert shipping_query.shipping_address == self.shipping_address
|
||||
assert shipping_query.bot == bot
|
||||
assert shipping_query.bot is bot
|
||||
|
||||
def test_to_dict(self, shipping_query):
|
||||
shipping_query_dict = shipping_query.to_dict()
|
||||
|
|
|
@ -449,3 +449,23 @@ class TestMaskPosition:
|
|||
assert mask_position_dict['x_shift'] == mask_position.x_shift
|
||||
assert mask_position_dict['y_shift'] == mask_position.y_shift
|
||||
assert mask_position_dict['scale'] == mask_position.scale
|
||||
|
||||
def test_equality(self):
|
||||
a = MaskPosition(self.point, self.x_shift, self.y_shift, self.scale)
|
||||
b = MaskPosition(self.point, self.x_shift, self.y_shift, self.scale)
|
||||
c = MaskPosition(MaskPosition.FOREHEAD, self.x_shift, self.y_shift, self.scale)
|
||||
d = MaskPosition(self.point, 0, 0, self.scale)
|
||||
e = Audio('', '', 0, None, None)
|
||||
|
||||
assert a == b
|
||||
assert hash(a) == hash(b)
|
||||
assert a is not b
|
||||
|
||||
assert a != c
|
||||
assert hash(a) != hash(c)
|
||||
|
||||
assert a != d
|
||||
assert hash(a) != hash(d)
|
||||
|
||||
assert a != e
|
||||
assert hash(a) != hash(e)
|
||||
|
|
|
@ -83,3 +83,27 @@ class TestTelegramObject:
|
|||
|
||||
subclass_instance = TelegramObjectSubclass()
|
||||
assert subclass_instance.to_dict() == {'a': 1}
|
||||
|
||||
def test_meaningless_comparison(self, recwarn):
|
||||
expected_warning = "Objects of type TGO can not be meaningfully tested for equivalence."
|
||||
|
||||
class TGO(TelegramObject):
|
||||
pass
|
||||
|
||||
a = TGO()
|
||||
b = TGO()
|
||||
assert a == b
|
||||
assert len(recwarn) == 2
|
||||
assert str(recwarn[0].message) == expected_warning
|
||||
assert str(recwarn[1].message) == expected_warning
|
||||
|
||||
def test_meaningful_comparison(self, recwarn):
|
||||
class TGO(TelegramObject):
|
||||
_id_attrs = (1,)
|
||||
|
||||
a = TGO()
|
||||
b = TGO()
|
||||
assert a == b
|
||||
assert len(recwarn) == 0
|
||||
assert b == a
|
||||
assert len(recwarn) == 0
|
||||
|
|
|
@ -48,3 +48,18 @@ class TestUserProfilePhotos:
|
|||
for ix, x in enumerate(user_profile_photos_dict['photos']):
|
||||
for iy, y in enumerate(x):
|
||||
assert y == user_profile_photos.photos[ix][iy].to_dict()
|
||||
|
||||
def test_equality(self):
|
||||
a = UserProfilePhotos(2, self.photos)
|
||||
b = UserProfilePhotos(2, self.photos)
|
||||
c = UserProfilePhotos(1, [self.photos[0]])
|
||||
d = PhotoSize('file_id1', 'unique_id', 512, 512)
|
||||
|
||||
assert a == b
|
||||
assert hash(a) == hash(b)
|
||||
|
||||
assert a != c
|
||||
assert hash(a) != hash(c)
|
||||
|
||||
assert a != d
|
||||
assert hash(a) != hash(d)
|
||||
|
|
88
tests/test_webhookinfo.py
Normal file
88
tests/test_webhookinfo.py
Normal file
|
@ -0,0 +1,88 @@
|
|||
#!/usr/bin/env python
|
||||
#
|
||||
# A library that provides a Python interface to the Telegram Bot API
|
||||
# Copyright (C) 2015-2020
|
||||
# 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/].
|
||||
|
||||
import pytest
|
||||
import time
|
||||
|
||||
from telegram import WebhookInfo, LoginUrl
|
||||
|
||||
|
||||
@pytest.fixture(scope='class')
|
||||
def webhook_info():
|
||||
return WebhookInfo(
|
||||
url=TestWebhookInfo.url,
|
||||
has_custom_certificate=TestWebhookInfo.has_custom_certificate,
|
||||
pending_update_count=TestWebhookInfo.pending_update_count,
|
||||
last_error_date=TestWebhookInfo.last_error_date,
|
||||
max_connections=TestWebhookInfo.max_connections,
|
||||
allowed_updates=TestWebhookInfo.allowed_updates,
|
||||
)
|
||||
|
||||
|
||||
class TestWebhookInfo(object):
|
||||
url = "http://www.google.com"
|
||||
has_custom_certificate = False
|
||||
pending_update_count = 5
|
||||
last_error_date = time.time()
|
||||
max_connections = 42
|
||||
allowed_updates = ['type1', 'type2']
|
||||
|
||||
def test_to_dict(self, webhook_info):
|
||||
webhook_info_dict = webhook_info.to_dict()
|
||||
|
||||
assert isinstance(webhook_info_dict, dict)
|
||||
assert webhook_info_dict['url'] == self.url
|
||||
assert webhook_info_dict['pending_update_count'] == self.pending_update_count
|
||||
assert webhook_info_dict['last_error_date'] == self.last_error_date
|
||||
assert webhook_info_dict['max_connections'] == self.max_connections
|
||||
assert webhook_info_dict['allowed_updates'] == self.allowed_updates
|
||||
|
||||
def test_equality(self):
|
||||
a = WebhookInfo(
|
||||
url=self.url,
|
||||
has_custom_certificate=self.has_custom_certificate,
|
||||
pending_update_count=self.pending_update_count,
|
||||
last_error_date=self.last_error_date,
|
||||
max_connections=self.max_connections,
|
||||
)
|
||||
b = WebhookInfo(
|
||||
url=self.url,
|
||||
has_custom_certificate=self.has_custom_certificate,
|
||||
pending_update_count=self.pending_update_count,
|
||||
last_error_date=self.last_error_date,
|
||||
max_connections=self.max_connections,
|
||||
)
|
||||
c = WebhookInfo(
|
||||
url="http://github.com",
|
||||
has_custom_certificate=True,
|
||||
pending_update_count=78,
|
||||
last_error_date=0,
|
||||
max_connections=1,
|
||||
)
|
||||
d = LoginUrl("text.com")
|
||||
|
||||
assert a == b
|
||||
assert hash(a) == hash(b)
|
||||
assert a is not b
|
||||
|
||||
assert a != c
|
||||
assert hash(a) != hash(c)
|
||||
|
||||
assert a != d
|
||||
assert hash(a) != hash(d)
|
Loading…
Add table
Reference in a new issue