From 50305066fa068b78e92e94b9ca3e22cc7d5e8d01 Mon Sep 17 00:00:00 2001 From: Hinrich Mahler Date: Thu, 23 Jan 2020 20:47:57 +0100 Subject: [PATCH 01/12] Make most objects comparable --- telegram/chatpermissions.py | 11 +++ telegram/forcereply.py | 2 + telegram/games/game.py | 7 ++ telegram/games/gamehighscore.py | 2 + telegram/inline/inlinekeyboardbutton.py | 11 +++ telegram/inline/inlinekeyboardmarkup.py | 16 ++++ telegram/inline/inputcontactmessagecontent.py | 2 + .../inline/inputlocationmessagecontent.py | 2 + telegram/inline/inputtextmessagecontent.py | 2 + telegram/inline/inputvenuemessagecontent.py | 7 ++ telegram/keyboardbutton.py | 2 + telegram/payment/invoice.py | 8 ++ telegram/payment/labeledprice.py | 2 + telegram/payment/orderinfo.py | 2 + telegram/poll.py | 2 + telegram/replykeyboardmarkup.py | 31 ++++++- telegram/userprofilephotos.py | 5 ++ telegram/webhookinfo.py | 10 +++ tests/test_chatpermissions.py | 33 ++++++- tests/test_forcereply.py | 17 +++- tests/test_game.py | 17 ++++ tests/test_gamehighscore.py | 19 ++++ tests/test_inlinekeyboardbutton.py | 23 +++++ tests/test_inlinekeyboardmarkup.py | 40 ++++++++- tests/test_inputcontactmessagecontent.py | 17 +++- tests/test_inputlocationmessagecontent.py | 17 +++- tests/test_inputtextmessagecontent.py | 15 ++++ tests/test_inputvenuemessagecontent.py | 17 +++- tests/test_invoice.py | 15 ++++ tests/test_keyboardbutton.py | 17 +++- tests/test_labeledprice.py | 17 +++- tests/test_orderinfo.py | 23 +++++ tests/test_poll.py | 30 +++++++ tests/test_replykeyboardmarkup.py | 23 ++++- tests/test_userprofilephotos.py | 15 ++++ tests/test_webhookinfo.py | 88 +++++++++++++++++++ 36 files changed, 557 insertions(+), 10 deletions(-) create mode 100644 tests/test_webhookinfo.py diff --git a/telegram/chatpermissions.py b/telegram/chatpermissions.py index 70b787b0954..71a7c666102 100644 --- a/telegram/chatpermissions.py +++ b/telegram/chatpermissions.py @@ -79,6 +79,17 @@ def __init__(self, can_send_messages=None, can_send_media_messages=None, can_sen 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: diff --git a/telegram/forcereply.py b/telegram/forcereply.py index fa89f314fa8..568889bd909 100644 --- a/telegram/forcereply.py +++ b/telegram/forcereply.py @@ -49,3 +49,5 @@ def __init__(self, force_reply=True, selective=False, **kwargs): self.force_reply = bool(force_reply) # Optionals self.selective = bool(selective) + + self._id_attrs = (self.force_reply, self.selective) diff --git a/telegram/games/game.py b/telegram/games/game.py index 089ac8dfeff..4218423944b 100644 --- a/telegram/games/game.py +++ b/telegram/games/game.py @@ -65,13 +65,17 @@ def __init__(self, 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: @@ -147,3 +151,6 @@ def parse_text_entities(self, types=None): 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))) diff --git a/telegram/games/gamehighscore.py b/telegram/games/gamehighscore.py index aea2939786d..16a5d057b55 100644 --- a/telegram/games/gamehighscore.py +++ b/telegram/games/gamehighscore.py @@ -41,6 +41,8 @@ def __init__(self, position, user, score): 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: diff --git a/telegram/inline/inlinekeyboardbutton.py b/telegram/inline/inlinekeyboardbutton.py index 57212af3665..b4b1e34e55f 100644 --- a/telegram/inline/inlinekeyboardbutton.py +++ b/telegram/inline/inlinekeyboardbutton.py @@ -94,6 +94,17 @@ def __init__(self, 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: diff --git a/telegram/inline/inlinekeyboardmarkup.py b/telegram/inline/inlinekeyboardmarkup.py index 064231b78bf..3516a54f60c 100644 --- a/telegram/inline/inlinekeyboardmarkup.py +++ b/telegram/inline/inlinekeyboardmarkup.py @@ -109,3 +109,19 @@ def from_column(cls, button_column, **kwargs): """ 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)) diff --git a/telegram/inline/inputcontactmessagecontent.py b/telegram/inline/inputcontactmessagecontent.py index c655b0fd33e..da4995fb7cd 100644 --- a/telegram/inline/inputcontactmessagecontent.py +++ b/telegram/inline/inputcontactmessagecontent.py @@ -48,3 +48,5 @@ def __init__(self, phone_number, first_name, last_name=None, vcard=None, **kwarg # Optionals self.last_name = last_name self.vcard = vcard + + self._id_attrs = (self.phone_number, self.first_name) diff --git a/telegram/inline/inputlocationmessagecontent.py b/telegram/inline/inputlocationmessagecontent.py index 16010ecd575..61b2fb27d70 100644 --- a/telegram/inline/inputlocationmessagecontent.py +++ b/telegram/inline/inputlocationmessagecontent.py @@ -43,3 +43,5 @@ def __init__(self, latitude, longitude, live_period=None, **kwargs): self.latitude = latitude self.longitude = longitude self.live_period = live_period + + self._id_attrs = (self.latitude, self.longitude, self.live_period) diff --git a/telegram/inline/inputtextmessagecontent.py b/telegram/inline/inputtextmessagecontent.py index 3e08d6b978b..85ae4dcc457 100644 --- a/telegram/inline/inputtextmessagecontent.py +++ b/telegram/inline/inputtextmessagecontent.py @@ -49,3 +49,5 @@ def __init__(self, message_text, parse_mode=None, disable_web_page_preview=None, # Optionals self.parse_mode = parse_mode self.disable_web_page_preview = disable_web_page_preview + + self._id_attrs = (self.message_text,) diff --git a/telegram/inline/inputvenuemessagecontent.py b/telegram/inline/inputvenuemessagecontent.py index d0f1fdc5b7a..70dd10303af 100644 --- a/telegram/inline/inputvenuemessagecontent.py +++ b/telegram/inline/inputvenuemessagecontent.py @@ -57,3 +57,10 @@ def __init__(self, latitude, longitude, title, address, foursquare_id=None, # Optionals self.foursquare_id = foursquare_id self.foursquare_type = foursquare_type + + self._id_attrs = ( + self.latitude, + self.longitude, + self.title, + self.address + ) diff --git a/telegram/keyboardbutton.py b/telegram/keyboardbutton.py index a8ed639ac81..59f361b300f 100644 --- a/telegram/keyboardbutton.py +++ b/telegram/keyboardbutton.py @@ -54,3 +54,5 @@ def __init__(self, text, request_contact=None, request_location=None, **kwargs): # Optionals self.request_contact = request_contact self.request_location = request_location + + self._id_attrs = (self.text, self.request_contact, self.request_location) diff --git a/telegram/payment/invoice.py b/telegram/payment/invoice.py index cefc35a7bf9..a951f8de0f5 100644 --- a/telegram/payment/invoice.py +++ b/telegram/payment/invoice.py @@ -50,6 +50,14 @@ def __init__(self, title, description, start_parameter, currency, total_amount, 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: diff --git a/telegram/payment/labeledprice.py b/telegram/payment/labeledprice.py index 5ee3c27a7cc..8ef6214055d 100644 --- a/telegram/payment/labeledprice.py +++ b/telegram/payment/labeledprice.py @@ -41,3 +41,5 @@ class LabeledPrice(TelegramObject): def __init__(self, label, amount, **kwargs): self.label = label self.amount = amount + + self._id_attrs = (self.label, self.amount) diff --git a/telegram/payment/orderinfo.py b/telegram/payment/orderinfo.py index 21f8657f297..2005d6df620 100644 --- a/telegram/payment/orderinfo.py +++ b/telegram/payment/orderinfo.py @@ -45,6 +45,8 @@ def __init__(self, name=None, phone_number=None, email=None, shipping_address=No 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: diff --git a/telegram/poll.py b/telegram/poll.py index 0c22d1bb2fb..52569e30c88 100644 --- a/telegram/poll.py +++ b/telegram/poll.py @@ -40,6 +40,8 @@ def __init__(self, text, voter_count, **kwargs): self.text = text self.voter_count = voter_count + self._id_attrs = (self.text,) + @classmethod def de_json(cls, data, bot): if not data: diff --git a/telegram/replykeyboardmarkup.py b/telegram/replykeyboardmarkup.py index c633a1e9cd8..03cf8212b5f 100644 --- a/telegram/replykeyboardmarkup.py +++ b/telegram/replykeyboardmarkup.py @@ -19,6 +19,7 @@ """This module contains an object that represents a Telegram ReplyKeyboardMarkup.""" from telegram import ReplyMarkup +from .keyboardbutton import KeyboardButton class ReplyKeyboardMarkup(ReplyMarkup): @@ -66,7 +67,16 @@ def __init__(self, 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) @@ -213,3 +223,22 @@ def from_column(cls, 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 + )) diff --git a/telegram/userprofilephotos.py b/telegram/userprofilephotos.py index ec94a0ac128..a6f756c1170 100644 --- a/telegram/userprofilephotos.py +++ b/telegram/userprofilephotos.py @@ -40,6 +40,8 @@ def __init__(self, total_count, photos, **kwargs): 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 +61,6 @@ def to_dict(self): 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)) diff --git a/telegram/webhookinfo.py b/telegram/webhookinfo.py index 57b962914ab..dc58d858af8 100644 --- a/telegram/webhookinfo.py +++ b/telegram/webhookinfo.py @@ -71,6 +71,16 @@ def __init__(self, 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: diff --git a/tests/test_chatpermissions.py b/tests/test_chatpermissions.py index 129a5252b26..119cbd1eae5 100644 --- a/tests/test_chatpermissions.py +++ b/tests/test_chatpermissions.py @@ -19,7 +19,7 @@ import pytest -from telegram import ChatPermissions +from telegram import ChatPermissions, User @pytest.fixture(scope="class") @@ -77,3 +77,34 @@ def test_to_dict(self, chat_permissions): 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) diff --git a/tests/test_forcereply.py b/tests/test_forcereply.py index 81fdd7bf2dc..595f53128ac 100644 --- a/tests/test_forcereply.py +++ b/tests/test_forcereply.py @@ -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 @@ def test_to_dict(self, force_reply): 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(True, 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) diff --git a/tests/test_game.py b/tests/test_game.py index 6f293a24e63..4b54aad11b0 100644 --- a/tests/test_game.py +++ b/tests/test_game.py @@ -95,3 +95,20 @@ def test_parse_entities(self, game): 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', 640, 360, file_size=0)]) + b = Game('title', 'description', [PhotoSize('Blah', 640, 360, file_size=0)], + text='Here is a text') + c = Game('eltit', 'description', [PhotoSize('Blah', 640, 360, file_size=0)], + animation=Animation('blah', 320, 180, 1)) + d = Animation('blah', 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) diff --git a/tests/test_gamehighscore.py b/tests/test_gamehighscore.py index ecb35674b96..be7b9fcfa28 100644 --- a/tests/test_gamehighscore.py +++ b/tests/test_gamehighscore.py @@ -51,3 +51,22 @@ def test_to_dict(self, game_highscore): 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) diff --git a/tests/test_inlinekeyboardbutton.py b/tests/test_inlinekeyboardbutton.py index 98faf17340e..bff5ff59b74 100644 --- a/tests/test_inlinekeyboardbutton.py +++ b/tests/test_inlinekeyboardbutton.py @@ -92,3 +92,26 @@ def test_de_json(self, bot): == 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) diff --git a/tests/test_inlinekeyboardmarkup.py b/tests/test_inlinekeyboardmarkup.py index 8666ff185f1..15ba29f4dbc 100644 --- a/tests/test_inlinekeyboardmarkup.py +++ b/tests/test_inlinekeyboardmarkup.py @@ -20,7 +20,7 @@ import pytest from flaky import flaky -from telegram import InlineKeyboardButton, InlineKeyboardMarkup +from telegram import InlineKeyboardButton, InlineKeyboardMarkup, ReplyKeyboardMarkup @pytest.fixture(scope='class') @@ -109,3 +109,41 @@ def test_de_json(self): 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 = 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) diff --git a/tests/test_inputcontactmessagecontent.py b/tests/test_inputcontactmessagecontent.py index dfe5cd59348..909ff197da2 100644 --- a/tests/test_inputcontactmessagecontent.py +++ b/tests/test_inputcontactmessagecontent.py @@ -19,7 +19,7 @@ import pytest -from telegram import InputContactMessageContent +from telegram import InputContactMessageContent, User @pytest.fixture(scope='class') @@ -49,3 +49,18 @@ def test_to_dict(self, input_contact_message_content): == 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', 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) diff --git a/tests/test_inputlocationmessagecontent.py b/tests/test_inputlocationmessagecontent.py index f9b551752ea..ef1cd250f99 100644 --- a/tests/test_inputlocationmessagecontent.py +++ b/tests/test_inputlocationmessagecontent.py @@ -19,7 +19,7 @@ import pytest -from telegram import InputLocationMessageContent +from telegram import InputLocationMessageContent, Location @pytest.fixture(scope='class') @@ -49,3 +49,18 @@ def test_to_dict(self, input_location_message_content): == 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, 70) + c = InputLocationMessageContent(123, 456, 80) + 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) diff --git a/tests/test_inputtextmessagecontent.py b/tests/test_inputtextmessagecontent.py index 477ea1967d8..9a69355b1e4 100644 --- a/tests/test_inputtextmessagecontent.py +++ b/tests/test_inputtextmessagecontent.py @@ -50,3 +50,18 @@ def test_to_dict(self, input_text_message_content): == 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) diff --git a/tests/test_inputvenuemessagecontent.py b/tests/test_inputvenuemessagecontent.py index 34f45696407..878f110d8a0 100644 --- a/tests/test_inputvenuemessagecontent.py +++ b/tests/test_inputvenuemessagecontent.py @@ -19,7 +19,7 @@ import pytest -from telegram import InputVenueMessageContent +from telegram import InputVenueMessageContent, Location @pytest.fixture(scope='class') @@ -62,3 +62,18 @@ def test_to_dict(self, input_venue_message_content): == 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', 'address', foursquare_id=123) + c = InputVenueMessageContent(456, 123, 'title', 'address', foursquare_id=123) + 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) diff --git a/tests/test_invoice.py b/tests/test_invoice.py index 5722e852c0b..0cffdcf5779 100644 --- a/tests/test_invoice.py +++ b/tests/test_invoice.py @@ -120,3 +120,18 @@ def test(_, url, data, **kwargs): 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) diff --git a/tests/test_keyboardbutton.py b/tests/test_keyboardbutton.py index 69eeaf80287..75be14b3900 100644 --- a/tests/test_keyboardbutton.py +++ b/tests/test_keyboardbutton.py @@ -19,7 +19,7 @@ import pytest -from telegram import KeyboardButton +from telegram import KeyboardButton, InlineKeyboardButton @pytest.fixture(scope='class') @@ -46,3 +46,18 @@ def test_to_dict(self, keyboard_button): assert keyboard_button_dict['text'] == keyboard_button.text assert keyboard_button_dict['request_location'] == keyboard_button.request_location assert keyboard_button_dict['request_contact'] == keyboard_button.request_contact + + 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) diff --git a/tests/test_labeledprice.py b/tests/test_labeledprice.py index cb742d6e45d..ffd9c2baafc 100644 --- a/tests/test_labeledprice.py +++ b/tests/test_labeledprice.py @@ -19,7 +19,7 @@ import pytest -from telegram import LabeledPrice +from telegram import LabeledPrice, Location @pytest.fixture(scope='class') @@ -41,3 +41,18 @@ def test_to_dict(self, labeled_price): 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) diff --git a/tests/test_orderinfo.py b/tests/test_orderinfo.py index 609812ec3c5..4a79557114b 100644 --- a/tests/test_orderinfo.py +++ b/tests/test_orderinfo.py @@ -56,3 +56,26 @@ def test_to_dict(self, order_info): 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) diff --git a/tests/test_poll.py b/tests/test_poll.py index bbadf22520f..7319baa4312 100644 --- a/tests/test_poll.py +++ b/tests/test_poll.py @@ -49,6 +49,21 @@ def test_to_dict(self, poll_option): 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', 2) + c = PollOption('text_1', 1) + d = Poll(123, 'question', ['O1', 'O2'], 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) + @pytest.fixture(scope='class') def poll(): @@ -90,3 +105,18 @@ def test_to_dict(self, poll): assert poll_dict['question'] == poll.question assert poll_dict['options'] == [o.to_dict() for o in poll.options] assert poll_dict['is_closed'] == poll.is_closed + + def test_equality(self): + a = Poll(123, 'question', ['o1', 'o2'], False) + b = Poll(123, 'question?', ['o1.1', 'o2.2'], True) + c = Poll(456, 'question?', ['o1.1', 'o2.2'], 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) diff --git a/tests/test_replykeyboardmarkup.py b/tests/test_replykeyboardmarkup.py index 91f997f7f4a..0aaca70831c 100644 --- a/tests/test_replykeyboardmarkup.py +++ b/tests/test_replykeyboardmarkup.py @@ -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,24 @@ def test_to_dict(self, reply_keyboard_markup): 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 = 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) diff --git a/tests/test_userprofilephotos.py b/tests/test_userprofilephotos.py index ee96c58abf0..4e58342dbc2 100644 --- a/tests/test_userprofilephotos.py +++ b/tests/test_userprofilephotos.py @@ -48,3 +48,18 @@ def test_to_dict(self): 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', 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) diff --git a/tests/test_webhookinfo.py b/tests/test_webhookinfo.py new file mode 100644 index 00000000000..6d27277353f --- /dev/null +++ b/tests/test_webhookinfo.py @@ -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 +# +# 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) From 5ac6253ccda9c6caf7908fcf59364c1d8d56901a Mon Sep 17 00:00:00 2001 From: Hinrich Mahler Date: Sun, 29 Mar 2020 12:23:02 +0200 Subject: [PATCH 02/12] ID attrs for PollAnswer --- telegram/poll.py | 2 ++ tests/test_poll.py | 19 +++++++++++++++++++ 2 files changed, 21 insertions(+) diff --git a/telegram/poll.py b/telegram/poll.py index e8f443d9a5f..a9203f52464 100644 --- a/telegram/poll.py +++ b/telegram/poll.py @@ -71,6 +71,8 @@ def __init__(self, poll_id, user, option_ids, **kwargs): 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: diff --git a/tests/test_poll.py b/tests/test_poll.py index 712d5a84eed..ab0f4b228ac 100644 --- a/tests/test_poll.py +++ b/tests/test_poll.py @@ -96,6 +96,25 @@ def test_to_dict(self, poll_answer): 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(): From dcb9699133bdb3e7c4a5a86f8b74d535b838d1c8 Mon Sep 17 00:00:00 2001 From: Hinrich Mahler Date: Sun, 29 Mar 2020 13:03:13 +0200 Subject: [PATCH 03/12] fix test_game --- tests/test_game.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/tests/test_game.py b/tests/test_game.py index a30f9497395..356094e7d06 100644 --- a/tests/test_game.py +++ b/tests/test_game.py @@ -97,12 +97,12 @@ def test_parse_entities(self, game): assert game.parse_text_entities() == {entity: 'http://google.com', entity_2: 'h'} def test_equality(self): - a = Game('title', 'description', [PhotoSize('Blah', 640, 360, file_size=0)]) - b = Game('title', 'description', [PhotoSize('Blah', 640, 360, file_size=0)], + 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', 640, 360, file_size=0)], - animation=Animation('blah', 320, 180, 1)) - d = Animation('blah', 320, 180, 1) + 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) From a86136b2979beec33c2957c372aec5b6a0a86253 Mon Sep 17 00:00:00 2001 From: Hinrich Mahler Date: Sun, 29 Mar 2020 13:37:15 +0200 Subject: [PATCH 04/12] fix test_userprofilephotos --- tests/test_userprofilephotos.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_userprofilephotos.py b/tests/test_userprofilephotos.py index e6f1db98919..ecb2bfa491d 100644 --- a/tests/test_userprofilephotos.py +++ b/tests/test_userprofilephotos.py @@ -53,7 +53,7 @@ def test_equality(self): a = UserProfilePhotos(2, self.photos) b = UserProfilePhotos(2, self.photos) c = UserProfilePhotos(1, [self.photos[0]]) - d = PhotoSize('file_id1', 512, 512) + d = PhotoSize('file_id1', 'unique_id', 512, 512) assert a == b assert hash(a) == hash(b) From 89c612fd5468cdc5567a7ee823a221722b39cd9f Mon Sep 17 00:00:00 2001 From: Hinrich Mahler Date: Wed, 15 Apr 2020 09:38:00 +0200 Subject: [PATCH 05/12] update for API 4.7 --- telegram/botcommand.py | 2 ++ telegram/dice.py | 2 ++ tests/test_botcommand.py | 21 ++++++++++++++++++++- tests/test_dice.py | 17 ++++++++++++++++- tests/test_inlinekeyboardmarkup.py | 13 ++++++++++++- tests/test_replykeyboardmarkup.py | 6 +++++- 6 files changed, 57 insertions(+), 4 deletions(-) diff --git a/telegram/botcommand.py b/telegram/botcommand.py index 293a5035ca1..189b6761b2a 100644 --- a/telegram/botcommand.py +++ b/telegram/botcommand.py @@ -38,6 +38,8 @@ def __init__(self, command, description, **kwargs): self.command = command self.description = description + self._id_attrs = (self.command, self.description) + @classmethod def de_json(cls, data, bot): if not data: diff --git a/telegram/dice.py b/telegram/dice.py index b90aeb36320..c934716e463 100644 --- a/telegram/dice.py +++ b/telegram/dice.py @@ -35,6 +35,8 @@ class Dice(TelegramObject): def __init__(self, value, **kwargs): self.value = value + self._id_attrs = (self.value,) + @classmethod def de_json(cls, data, bot): if not data: diff --git a/tests/test_botcommand.py b/tests/test_botcommand.py index 9b339276dc2..912834d727a 100644 --- a/tests/test_botcommand.py +++ b/tests/test_botcommand.py @@ -19,7 +19,7 @@ import pytest -from telegram import BotCommand +from telegram import BotCommand, Dice @pytest.fixture(scope="class") @@ -46,3 +46,22 @@ def test_to_dict(self, bot_command): 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) + + 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) diff --git a/tests/test_dice.py b/tests/test_dice.py index 89805f45fb5..4fceb4a2bee 100644 --- a/tests/test_dice.py +++ b/tests/test_dice.py @@ -19,7 +19,7 @@ import pytest -from telegram import Dice +from telegram import Dice, BotCommand @pytest.fixture(scope="class") @@ -42,3 +42,18 @@ def test_to_dict(self, dice): assert isinstance(dice_dict, dict) assert dice_dict['value'] == dice.value + + def test_equality(self): + a = Dice(3) + b = Dice(3) + c = Dice(4) + d = 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) diff --git a/tests/test_inlinekeyboardmarkup.py b/tests/test_inlinekeyboardmarkup.py index 4f7d935735b..1501c6cd815 100644 --- a/tests/test_inlinekeyboardmarkup.py +++ b/tests/test_inlinekeyboardmarkup.py @@ -151,7 +151,15 @@ def test_equality(self): InlineKeyboardButton(label, url=label) for label in ['button1', 'button2', 'button3'] ]) - f = ReplyKeyboardMarkup.from_column(['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) @@ -167,3 +175,6 @@ def test_equality(self): assert a != f assert hash(a) != hash(f) + + assert a != g + assert hash(a) != hash(g) diff --git a/tests/test_replykeyboardmarkup.py b/tests/test_replykeyboardmarkup.py index d6146043cbf..569e757c53f 100644 --- a/tests/test_replykeyboardmarkup.py +++ b/tests/test_replykeyboardmarkup.py @@ -114,7 +114,8 @@ def test_equality(self): ]) c = ReplyKeyboardMarkup.from_column(['button1', 'button2']) d = ReplyKeyboardMarkup.from_column(['button1', 'button2', 'button3.1']) - e = InlineKeyboardMarkup.from_column(['button1', 'button2', 'button3']) + e = ReplyKeyboardMarkup([['button1', 'button1'], ['button2'], ['button3.1']]) + f = InlineKeyboardMarkup.from_column(['button1', 'button2', 'button3']) assert a == b assert hash(a) == hash(b) @@ -127,3 +128,6 @@ def test_equality(self): assert a != e assert hash(a) != hash(e) + + assert a != f + assert hash(a) != hash(f) From 2de5abc383f99aa242a62f38ccc76eba92196311 Mon Sep 17 00:00:00 2001 From: Hinrich Mahler Date: Sat, 25 Apr 2020 20:46:36 +0200 Subject: [PATCH 06/12] Warn on meaningless comparisons --- telegram/base.py | 4 ++++ tests/test_telegramobject.py | 21 +++++++++++++++++++++ 2 files changed, 25 insertions(+) diff --git a/telegram/base.py b/telegram/base.py index 4564b5b12d6..c710a1901fc 100644 --- a/telegram/base.py +++ b/telegram/base.py @@ -23,6 +23,7 @@ except ImportError: import json +import warnings from abc import ABCMeta @@ -81,6 +82,9 @@ def to_dict(self): 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__)) return self._id_attrs == other._id_attrs return super(TelegramObject, self).__eq__(other) # pylint: disable=no-member diff --git a/tests/test_telegramobject.py b/tests/test_telegramobject.py index 66f52dbfb88..be2ee7693f2 100644 --- a/tests/test_telegramobject.py +++ b/tests/test_telegramobject.py @@ -74,3 +74,24 @@ def test_to_json_ujson(self, monkeypatch): monkeypatch.setattr('telegram.TelegramObject.to_dict', lambda _: d) telegram_object.to_json() + + def test_meaningless_comparison(self, recwarn): + class TGO(TelegramObject): + pass + + a = TGO() + b = TGO() + assert a == b + assert len(recwarn) == 1 + assert str(recwarn[0].message) == ( + "Objects of type TGO can not be meaningfully tested for equivalence." + ) + + def test_meaningful_comparison(self, recwarn): + class TGO(TelegramObject): + _id_attrs = (1,) + + a = TGO() + b = TGO() + assert a == b + assert len(recwarn) == 0 From 0f9a5f9208d11e0f6cf3c86abbf844e5c01eb8e4 Mon Sep 17 00:00:00 2001 From: Hinrich Mahler Date: Sat, 23 May 2020 16:44:18 +0200 Subject: [PATCH 07/12] Update for API 4.8 --- telegram/dice.py | 2 +- tests/test_botcommand.py | 2 +- tests/test_dice.py | 12 ++++++++---- tests/test_shippingquery.py | 2 +- 4 files changed, 11 insertions(+), 7 deletions(-) diff --git a/telegram/dice.py b/telegram/dice.py index 916c465d8cc..b5f7d05e030 100644 --- a/telegram/dice.py +++ b/telegram/dice.py @@ -44,7 +44,7 @@ def __init__(self, value, emoji, **kwargs): self.value = value self.emoji = emoji - self._id_attrs = (self.value,) + self._id_attrs = (self.value, self.emoji) @classmethod def de_json(cls, data, bot): diff --git a/tests/test_botcommand.py b/tests/test_botcommand.py index 912834d727a..8cb3cbbba64 100644 --- a/tests/test_botcommand.py +++ b/tests/test_botcommand.py @@ -52,7 +52,7 @@ def test_equality(self): b = BotCommand('start', 'some description') c = BotCommand('start', 'some other description') d = BotCommand('hepl', 'some description') - e = Dice(4) + e = Dice(4, 'emoji') assert a == b assert hash(a) == hash(b) diff --git a/tests/test_dice.py b/tests/test_dice.py index 8b7c263e980..565c3562ae3 100644 --- a/tests/test_dice.py +++ b/tests/test_dice.py @@ -48,10 +48,11 @@ def test_to_dict(self, dice): assert dice_dict['emoji'] == dice.emoji def test_equality(self): - a = Dice(3) - b = Dice(3) - c = Dice(4) - d = BotCommand('start', 'description') + a = Dice(3, '🎯') + b = Dice(3, '🎯') + c = Dice(3, '🎲') + d = Dice(4, '🎯') + e = BotCommand('start', 'description') assert a == b assert hash(a) == hash(b) @@ -61,3 +62,6 @@ def test_equality(self): assert a != d assert hash(a) != hash(d) + + assert a != e + assert hash(a) != hash(e) diff --git a/tests/test_shippingquery.py b/tests/test_shippingquery.py index 88ef057a11a..78f3070ec99 100644 --- a/tests/test_shippingquery.py +++ b/tests/test_shippingquery.py @@ -50,7 +50,7 @@ def test_de_json(self, bot): 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() From 28c11316ac98890556d2f77af1f2f4062b264f58 Mon Sep 17 00:00:00 2001 From: Hinrich Mahler Date: Wed, 27 May 2020 22:02:11 +0200 Subject: [PATCH 08/12] Address review --- telegram/base.py | 3 +++ tests/test_telegramobject.py | 11 +++++++---- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/telegram/base.py b/telegram/base.py index 1fb0ba61d8e..109c9648f86 100644 --- a/telegram/base.py +++ b/telegram/base.py @@ -83,6 +83,9 @@ def __eq__(self, other): 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(TelegramObject, self).__eq__(other) # pylint: disable=no-member diff --git a/tests/test_telegramobject.py b/tests/test_telegramobject.py index be2ee7693f2..5bc51232c0d 100644 --- a/tests/test_telegramobject.py +++ b/tests/test_telegramobject.py @@ -76,16 +76,17 @@ def test_to_json_ujson(self, monkeypatch): telegram_object.to_json() 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) == 1 - assert str(recwarn[0].message) == ( - "Objects of type TGO can not be meaningfully tested for equivalence." - ) + 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): @@ -95,3 +96,5 @@ class TGO(TelegramObject): b = TGO() assert a == b assert len(recwarn) == 0 + assert b == a + assert len(recwarn) == 0 From 176ee9850125e0922abc49e42705dfcb252848bd Mon Sep 17 00:00:00 2001 From: Hinrich Mahler Date: Thu, 28 May 2020 20:15:47 +0200 Subject: [PATCH 09/12] Get started on docs, update Message._id_attrs --- telegram/botcommand.py | 3 ++ telegram/callbackquery.py | 3 ++ telegram/chat.py | 3 ++ telegram/chatmember.py | 3 ++ telegram/chatpermissions.py | 5 +++ telegram/choseninlineresult.py | 3 ++ telegram/dice.py | 3 ++ telegram/files/animation.py | 3 ++ telegram/files/audio.py | 3 ++ telegram/files/chatphoto.py | 4 ++ telegram/files/contact.py | 3 ++ telegram/files/document.py | 3 ++ telegram/files/file.py | 3 ++ telegram/files/location.py | 3 ++ telegram/files/photosize.py | 3 ++ telegram/files/sticker.py | 12 ++++++ telegram/files/venue.py | 3 ++ telegram/files/video.py | 3 ++ telegram/files/videonote.py | 3 ++ telegram/files/voice.py | 3 ++ telegram/forcereply.py | 3 ++ telegram/games/game.py | 3 ++ telegram/games/gamehighscore.py | 3 ++ telegram/inline/inlinekeyboardbutton.py | 5 +++ telegram/inline/inlinekeyboardmarkup.py | 3 ++ telegram/inline/inlinequery.py | 3 ++ telegram/inline/inlinequeryresult.py | 3 ++ telegram/inline/inputcontactmessagecontent.py | 3 ++ .../inline/inputlocationmessagecontent.py | 6 +++ telegram/inline/inputtextmessagecontent.py | 3 ++ telegram/inline/inputvenuemessagecontent.py | 4 ++ telegram/keyboardbutton.py | 4 ++ telegram/keyboardbuttonpolltype.py | 3 ++ telegram/loginurl.py | 4 ++ telegram/message.py | 5 ++- telegram/messageentity.py | 3 ++ telegram/passport/credentials.py | 3 ++ telegram/passport/encryptedpassportelement.py | 4 ++ telegram/passport/passportelementerrors.py | 43 ++++++++++++++++++- telegram/passport/passportfile.py | 3 ++ telegram/payment/invoice.py | 4 ++ telegram/payment/labeledprice.py | 3 ++ telegram/payment/orderinfo.py | 4 ++ telegram/payment/precheckoutquery.py | 3 ++ telegram/payment/shippingaddress.py | 4 ++ telegram/payment/shippingoption.py | 3 ++ telegram/payment/shippingquery.py | 3 ++ telegram/payment/successfulpayment.py | 4 ++ telegram/poll.py | 9 ++++ telegram/replykeyboardmarkup.py | 3 ++ telegram/update.py | 3 ++ telegram/user.py | 3 ++ telegram/userprofilephotos.py | 3 ++ telegram/webhookinfo.py | 5 +++ tests/test_message.py | 6 +-- tests/test_sticker.py | 20 +++++++++ 56 files changed, 257 insertions(+), 6 deletions(-) diff --git a/telegram/botcommand.py b/telegram/botcommand.py index 189b6761b2a..560826f8cae 100644 --- a/telegram/botcommand.py +++ b/telegram/botcommand.py @@ -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. diff --git a/telegram/callbackquery.py b/telegram/callbackquery.py index 2e3483155ff..2fb0212d3dd 100644 --- a/telegram/callbackquery.py +++ b/telegram/callbackquery.py @@ -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. diff --git a/telegram/chat.py b/telegram/chat.py index 09392896fa3..f95521f86ae 100644 --- a/telegram/chat.py +++ b/telegram/chat.py @@ -26,6 +26,9 @@ 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. diff --git a/telegram/chatmember.py b/telegram/chatmember.py index 5dea1169e4f..114c6d89a4e 100644 --- a/telegram/chatmember.py +++ b/telegram/chatmember.py @@ -25,6 +25,9 @@ class ChatMember(TelegramObject): """This object contains information about one member of the 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. diff --git a/telegram/chatpermissions.py b/telegram/chatpermissions.py index 1531f7e286d..3b50133bf9d 100644 --- a/telegram/chatpermissions.py +++ b/telegram/chatpermissions.py @@ -24,6 +24,11 @@ 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 offical docs, Telegram changes not only the permissions that are set, but also sets all the others to :obj:`False`. However, since not documented, diff --git a/telegram/choseninlineresult.py b/telegram/choseninlineresult.py index 27a8ee0d2ba..768787b2e3b 100644 --- a/telegram/choseninlineresult.py +++ b/telegram/choseninlineresult.py @@ -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. diff --git a/telegram/dice.py b/telegram/dice.py index b5f7d05e030..0659237ad3b 100644 --- a/telegram/dice.py +++ b/telegram/dice.py @@ -27,6 +27,9 @@ class Dice(TelegramObject): (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 diff --git a/telegram/files/animation.py b/telegram/files/animation.py index 4aa69afa5b3..c5c1a2d54c1 100644 --- a/telegram/files/animation.py +++ b/telegram/files/animation.py @@ -24,6 +24,9 @@ class Animation(TelegramObject): """This object represents an animation file to be displayed in the message containing a game. + 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 diff --git a/telegram/files/audio.py b/telegram/files/audio.py index 65a0deee7fa..94853cec2d0 100644 --- a/telegram/files/audio.py +++ b/telegram/files/audio.py @@ -24,6 +24,9 @@ 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`): Unique identifier for this file. file_unique_id (:obj:`str`): Unique identifier for this file, which diff --git a/telegram/files/chatphoto.py b/telegram/files/chatphoto.py index c258c8ced3c..843a3b09196 100644 --- a/telegram/files/chatphoto.py +++ b/telegram/files/chatphoto.py @@ -23,6 +23,10 @@ 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 diff --git a/telegram/files/contact.py b/telegram/files/contact.py index 482b3de2015..5cb6db3f4eb 100644 --- a/telegram/files/contact.py +++ b/telegram/files/contact.py @@ -24,6 +24,9 @@ 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. diff --git a/telegram/files/document.py b/telegram/files/document.py index 89cfe7ef79e..d596882c5a8 100644 --- a/telegram/files/document.py +++ b/telegram/files/document.py @@ -24,6 +24,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`): Unique file identifier. file_unique_id (:obj:`str`): Unique identifier for this file, which diff --git a/telegram/files/file.py b/telegram/files/file.py index 34a5fa80388..e27ef4e2f41 100644 --- a/telegram/files/file.py +++ b/telegram/files/file.py @@ -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 getFile. + 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 diff --git a/telegram/files/location.py b/telegram/files/location.py index b4ca9098c0a..ad719db249a 100644 --- a/telegram/files/location.py +++ b/telegram/files/location.py @@ -24,6 +24,9 @@ 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. diff --git a/telegram/files/photosize.py b/telegram/files/photosize.py index 93032194305..29f1f78873b 100644 --- a/telegram/files/photosize.py +++ b/telegram/files/photosize.py @@ -24,6 +24,9 @@ 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`): Unique identifier for this file. file_unique_id (:obj:`str`): Unique identifier for this file, which diff --git a/telegram/files/sticker.py b/telegram/files/sticker.py index c8d6518bfec..27e277ab2f8 100644 --- a/telegram/files/sticker.py +++ b/telegram/files/sticker.py @@ -24,6 +24,9 @@ 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`): Unique identifier for this file. file_unique_id (:obj:`str`): Unique identifier for this file, which @@ -132,6 +135,9 @@ def get_file(self, timeout=None, **kwargs): 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. @@ -187,6 +193,10 @@ def to_dict(self): 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`, :attr:`scale` and + :attr:`latitude` are equal. + Attributes: point (:obj:`str`): The part of the face relative to which the mask should be placed. x_shift (:obj:`float`): Shift by X-axis measured in widths of the mask scaled to the face @@ -225,6 +235,8 @@ def __init__(self, point, x_shift, y_shift, scale, **kwargs): 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: diff --git a/telegram/files/venue.py b/telegram/files/venue.py index 5ae92e222b0..0808bc89c2a 100644 --- a/telegram/files/venue.py +++ b/telegram/files/venue.py @@ -24,6 +24,9 @@ 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. diff --git a/telegram/files/video.py b/telegram/files/video.py index a0a57d8e9ac..c9d14089dbc 100644 --- a/telegram/files/video.py +++ b/telegram/files/video.py @@ -24,6 +24,9 @@ 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`): Unique identifier for this file. file_unique_id (:obj:`str`): Unique identifier for this file, which diff --git a/telegram/files/videonote.py b/telegram/files/videonote.py index 529cc42b8c9..1f04540b4a6 100644 --- a/telegram/files/videonote.py +++ b/telegram/files/videonote.py @@ -24,6 +24,9 @@ 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`): Unique identifier for this file. file_unique_id (:obj:`str`): Unique identifier for this file, which diff --git a/telegram/files/voice.py b/telegram/files/voice.py index 47892ec4f19..12f3c5e0e75 100644 --- a/telegram/files/voice.py +++ b/telegram/files/voice.py @@ -24,6 +24,9 @@ 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`): Unique identifier for this file. file_unique_id (:obj:`str`): Unique identifier for this file, which diff --git a/telegram/forcereply.py b/telegram/forcereply.py index 17196f971ed..cc451125adc 100644 --- a/telegram/forcereply.py +++ b/telegram/forcereply.py @@ -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:`force_reply` and :attr:`selective` are equal. + Attributes: force_reply (:obj:`True`): Shows reply interface to the user. selective (:obj:`bool`): Optional. Force reply from specific users only. diff --git a/telegram/games/game.py b/telegram/games/game.py index 872068655c0..e340541a0b1 100644 --- a/telegram/games/game.py +++ b/telegram/games/game.py @@ -28,6 +28,9 @@ class Game(TelegramObject): This object represents a game. Use 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. diff --git a/telegram/games/gamehighscore.py b/telegram/games/gamehighscore.py index c2fa6b39e81..cf6bce8353f 100644 --- a/telegram/games/gamehighscore.py +++ b/telegram/games/gamehighscore.py @@ -24,6 +24,9 @@ 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. diff --git a/telegram/inline/inlinekeyboardbutton.py b/telegram/inline/inlinekeyboardbutton.py index 495c9ad9294..0268e426a1b 100644 --- a/telegram/inline/inlinekeyboardbutton.py +++ b/telegram/inline/inlinekeyboardbutton.py @@ -24,6 +24,11 @@ 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. diff --git a/telegram/inline/inlinekeyboardmarkup.py b/telegram/inline/inlinekeyboardmarkup.py index 3579907986f..ab7526fa3c4 100644 --- a/telegram/inline/inlinekeyboardmarkup.py +++ b/telegram/inline/inlinekeyboardmarkup.py @@ -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`]]): Array of button rows, each represented by an Array of InlineKeyboardButton objects. diff --git a/telegram/inline/inlinequery.py b/telegram/inline/inlinequery.py index a52a18c9251..e7dc838f718 100644 --- a/telegram/inline/inlinequery.py +++ b/telegram/inline/inlinequery.py @@ -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. diff --git a/telegram/inline/inlinequeryresult.py b/telegram/inline/inlinequeryresult.py index 6073dd8af93..36483850fe4 100644 --- a/telegram/inline/inlinequeryresult.py +++ b/telegram/inline/inlinequeryresult.py @@ -24,6 +24,9 @@ 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. diff --git a/telegram/inline/inputcontactmessagecontent.py b/telegram/inline/inputcontactmessagecontent.py index 4a41cc986e5..f7b054b7293 100644 --- a/telegram/inline/inputcontactmessagecontent.py +++ b/telegram/inline/inputcontactmessagecontent.py @@ -24,6 +24,9 @@ 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` and :attr:`first_name` are equal. + Attributes: phone_number (:obj:`str`): Contact's phone number. first_name (:obj:`str`): Contact's first name. diff --git a/telegram/inline/inputlocationmessagecontent.py b/telegram/inline/inputlocationmessagecontent.py index 450ddb0701b..5f56eeec3ac 100644 --- a/telegram/inline/inputlocationmessagecontent.py +++ b/telegram/inline/inputlocationmessagecontent.py @@ -25,9 +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`, :attr:`longitude` and :attr:`live_period` 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. Args: latitude (:obj:`float`): Latitude of the location in degrees. diff --git a/telegram/inline/inputtextmessagecontent.py b/telegram/inline/inputtextmessagecontent.py index 47ab2bfcf6e..96fa9a4cc56 100644 --- a/telegram/inline/inputtextmessagecontent.py +++ b/telegram/inline/inputtextmessagecontent.py @@ -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. diff --git a/telegram/inline/inputvenuemessagecontent.py b/telegram/inline/inputvenuemessagecontent.py index 29d79db31e1..0b587c8133d 100644 --- a/telegram/inline/inputvenuemessagecontent.py +++ b/telegram/inline/inputvenuemessagecontent.py @@ -24,6 +24,10 @@ 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`, :attr:`title` and + :attr:`address` are equal. + Attributes: latitude (:obj:`float`): Latitude of the location in degrees. longitude (:obj:`float`): Longitude of the location in degrees. diff --git a/telegram/keyboardbutton.py b/telegram/keyboardbutton.py index 0f0a7f58073..1dd0a5ac155 100644 --- a/telegram/keyboardbutton.py +++ b/telegram/keyboardbutton.py @@ -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. diff --git a/telegram/keyboardbuttonpolltype.py b/telegram/keyboardbuttonpolltype.py index 39c2bb48708..46e2089cd4f 100644 --- a/telegram/keyboardbuttonpolltype.py +++ b/telegram/keyboardbuttonpolltype.py @@ -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 diff --git a/telegram/loginurl.py b/telegram/loginurl.py index 81a44abe430..7961df2a2da 100644 --- a/telegram/loginurl.py +++ b/telegram/loginurl.py @@ -29,6 +29,10 @@ class LoginUrl(TelegramObject): Sample bot: `@discussbot `_ + 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. + 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. diff --git a/telegram/message.py b/telegram/message.py index 9868158a682..1b18cfc95b3 100644 --- a/telegram/message.py +++ b/telegram/message.py @@ -33,6 +33,9 @@ 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. @@ -339,7 +342,7 @@ def __init__(self, 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): diff --git a/telegram/messageentity.py b/telegram/messageentity.py index 308f5801fe7..70c13d41d13 100644 --- a/telegram/messageentity.py +++ b/telegram/messageentity.py @@ -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. diff --git a/telegram/passport/credentials.py b/telegram/passport/credentials.py index 110f091c489..8105a99d57c 100644 --- a/telegram/passport/credentials.py +++ b/telegram/passport/credentials.py @@ -96,6 +96,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 diff --git a/telegram/passport/encryptedpassportelement.py b/telegram/passport/encryptedpassportelement.py index 1959e52449a..c996a757999 100644 --- a/telegram/passport/encryptedpassportelement.py +++ b/telegram/passport/encryptedpassportelement.py @@ -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", diff --git a/telegram/passport/passportelementerrors.py b/telegram/passport/passportelementerrors.py index d03d6cdc16a..d752e5aa9e5 100644 --- a/telegram/passport/passportelementerrors.py +++ b/telegram/passport/passportelementerrors.py @@ -24,6 +24,9 @@ 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", @@ -294,12 +325,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: @@ -332,6 +367,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. diff --git a/telegram/passport/passportfile.py b/telegram/passport/passportfile.py index bdf6fc441b5..264705b9d5c 100644 --- a/telegram/passport/passportfile.py +++ b/telegram/passport/passportfile.py @@ -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`): Unique identifier for this file. file_unique_id (:obj:`str`): Unique identifier for this file, which diff --git a/telegram/payment/invoice.py b/telegram/payment/invoice.py index f1a55c28d20..930962898f2 100644 --- a/telegram/payment/invoice.py +++ b/telegram/payment/invoice.py @@ -24,6 +24,10 @@ 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. diff --git a/telegram/payment/labeledprice.py b/telegram/payment/labeledprice.py index a8f5a437c45..34bdb68093a 100644 --- a/telegram/payment/labeledprice.py +++ b/telegram/payment/labeledprice.py @@ -24,6 +24,9 @@ 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. diff --git a/telegram/payment/orderinfo.py b/telegram/payment/orderinfo.py index 95da5db2e2b..29cd38f0a55 100644 --- a/telegram/payment/orderinfo.py +++ b/telegram/payment/orderinfo.py @@ -24,6 +24,10 @@ 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:`shpping_address` are equal. + Attributes: name (:obj:`str`): Optional. User name. phone_number (:obj:`str`): Optional. User's phone number. diff --git a/telegram/payment/precheckoutquery.py b/telegram/payment/precheckoutquery.py index a8f6e8d497a..434ce2c48c8 100644 --- a/telegram/payment/precheckoutquery.py +++ b/telegram/payment/precheckoutquery.py @@ -24,6 +24,9 @@ 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. diff --git a/telegram/payment/shippingaddress.py b/telegram/payment/shippingaddress.py index c380a10b313..a51b4d1cc47 100644 --- a/telegram/payment/shippingaddress.py +++ b/telegram/payment/shippingaddress.py @@ -24,6 +24,10 @@ 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. diff --git a/telegram/payment/shippingoption.py b/telegram/payment/shippingoption.py index 522fb10760c..8822f2e9e23 100644 --- a/telegram/payment/shippingoption.py +++ b/telegram/payment/shippingoption.py @@ -24,6 +24,9 @@ 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. diff --git a/telegram/payment/shippingquery.py b/telegram/payment/shippingquery.py index 549e35f5b99..fb1e363f0bd 100644 --- a/telegram/payment/shippingquery.py +++ b/telegram/payment/shippingquery.py @@ -24,6 +24,9 @@ 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. diff --git a/telegram/payment/successfulpayment.py b/telegram/payment/successfulpayment.py index 870c5b8b9c3..240cf26cbb5 100644 --- a/telegram/payment/successfulpayment.py +++ b/telegram/payment/successfulpayment.py @@ -24,6 +24,10 @@ 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. diff --git a/telegram/poll.py b/telegram/poll.py index a1c0e61ff01..ce250187df7 100644 --- a/telegram/poll.py +++ b/telegram/poll.py @@ -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` is equal. + Attributes: text (:obj:`str`): Option text, 1-100 characters. voter_count (:obj:`int`): Number of users that voted for this option. @@ -57,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. @@ -92,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. diff --git a/telegram/replykeyboardmarkup.py b/telegram/replykeyboardmarkup.py index 2c767b05df0..bb38b2ea590 100644 --- a/telegram/replykeyboardmarkup.py +++ b/telegram/replykeyboardmarkup.py @@ -25,6 +25,9 @@ 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. diff --git a/telegram/update.py b/telegram/update.py index 499eeba9fa0..3f1b08baed3 100644 --- a/telegram/update.py +++ b/telegram/update.py @@ -26,6 +26,9 @@ 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. diff --git a/telegram/user.py b/telegram/user.py index 084fd65a0cf..c9f3e02aab0 100644 --- a/telegram/user.py +++ b/telegram/user.py @@ -27,6 +27,9 @@ 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`): True, if this user is a bot diff --git a/telegram/userprofilephotos.py b/telegram/userprofilephotos.py index daf069f8b90..4c7c95f5b67 100644 --- a/telegram/userprofilephotos.py +++ b/telegram/userprofilephotos.py @@ -24,6 +24,9 @@ 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. diff --git a/telegram/webhookinfo.py b/telegram/webhookinfo.py index 08f658f436e..391329f959a 100644 --- a/telegram/webhookinfo.py +++ b/telegram/webhookinfo.py @@ -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. diff --git a/tests/test_message.py b/tests/test_message.py index ef270431fbd..1f875de0db3 100644 --- a/tests/test_message.py +++ b/tests/test_message.py @@ -818,7 +818,7 @@ def test_equality(self): 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_) @@ -826,8 +826,8 @@ def test_equality(self): 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) diff --git a/tests/test_sticker.py b/tests/test_sticker.py index a4f199c973b..e077cf2cdb6 100644 --- a/tests/test_sticker.py +++ b/tests/test_sticker.py @@ -453,3 +453,23 @@ def test_mask_position_to_dict(self, mask_position): 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) From b18827dddfb5ce582363dadf81191b2e8e6392ef Mon Sep 17 00:00:00 2001 From: Hinrich Mahler Date: Thu, 28 May 2020 20:43:12 +0200 Subject: [PATCH 10/12] Change PollOption & InputLocation --- telegram/inline/inputlocationmessagecontent.py | 5 ++--- telegram/poll.py | 4 ++-- tests/test_inputlocationmessagecontent.py | 4 ++-- tests/test_poll.py | 8 ++++++-- 4 files changed, 12 insertions(+), 9 deletions(-) diff --git a/telegram/inline/inputlocationmessagecontent.py b/telegram/inline/inputlocationmessagecontent.py index 5f56eeec3ac..891c8cdc29a 100644 --- a/telegram/inline/inputlocationmessagecontent.py +++ b/telegram/inline/inputlocationmessagecontent.py @@ -26,8 +26,7 @@ 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`, :attr:`longitude` and :attr:`live_period` are - equal. + considered equal, if their :attr:`latitude` and :attr:`longitude` are equal. Attributes: latitude (:obj:`float`): Latitude of the location in degrees. @@ -50,4 +49,4 @@ def __init__(self, latitude, longitude, live_period=None, **kwargs): self.longitude = longitude self.live_period = live_period - self._id_attrs = (self.latitude, self.longitude, self.live_period) + self._id_attrs = (self.latitude, self.longitude) diff --git a/telegram/poll.py b/telegram/poll.py index ce250187df7..aec356346a1 100644 --- a/telegram/poll.py +++ b/telegram/poll.py @@ -30,7 +30,7 @@ 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` is equal. + considered equal, if their :attr:`text` and :attr:`voter_count` are equal. Attributes: text (:obj:`str`): Option text, 1-100 characters. @@ -46,7 +46,7 @@ def __init__(self, text, voter_count, **kwargs): self.text = text self.voter_count = voter_count - self._id_attrs = (self.text,) + self._id_attrs = (self.text, self.voter_count) @classmethod def de_json(cls, data, bot): diff --git a/tests/test_inputlocationmessagecontent.py b/tests/test_inputlocationmessagecontent.py index 1edd29e4169..f8e4e2731c2 100644 --- a/tests/test_inputlocationmessagecontent.py +++ b/tests/test_inputlocationmessagecontent.py @@ -52,8 +52,8 @@ def test_to_dict(self, input_location_message_content): def test_equality(self): a = InputLocationMessageContent(123, 456, 70) - b = InputLocationMessageContent(123, 456, 70) - c = InputLocationMessageContent(123, 456, 80) + b = InputLocationMessageContent(123, 456, 90) + c = InputLocationMessageContent(123, 457, 70) d = Location(123, 456) assert a == b diff --git a/tests/test_poll.py b/tests/test_poll.py index 216c17810ef..5063ccee98c 100644 --- a/tests/test_poll.py +++ b/tests/test_poll.py @@ -53,9 +53,10 @@ def test_to_dict(self, poll_option): def test_equality(self): a = PollOption('text', 1) - b = PollOption('text', 2) + b = PollOption('text', 1) c = PollOption('text_1', 1) - d = Poll(123, 'question', ['O1', 'O2'], 1, False, True, Poll.REGULAR, True) + d = PollOption('text', 2) + e = Poll(123, 'question', ['O1', 'O2'], 1, False, True, Poll.REGULAR, True) assert a == b assert hash(a) == hash(b) @@ -66,6 +67,9 @@ def test_equality(self): assert a != d assert hash(a) != hash(d) + assert a != e + assert hash(a) != hash(e) + @pytest.fixture(scope="class") def poll_answer(): From 2904ae3f8e12635dc6c5eb52a97a58e2442aafa1 Mon Sep 17 00:00:00 2001 From: Hinrich Mahler Date: Tue, 14 Jul 2020 20:06:29 +0200 Subject: [PATCH 11/12] Some more changes --- telegram/files/venue.py | 4 ++-- telegram/forcereply.py | 4 ++-- telegram/inline/inputcontactmessagecontent.py | 4 ++-- telegram/payment/orderinfo.py | 2 +- tests/test_forcereply.py | 2 +- tests/test_inputcontactmessagecontent.py | 2 +- tests/test_persistence.py | 2 +- tests/test_venue.py | 4 ++-- 8 files changed, 12 insertions(+), 12 deletions(-) diff --git a/telegram/files/venue.py b/telegram/files/venue.py index 142a0e9bfd8..cccd17b2890 100644 --- a/telegram/files/venue.py +++ b/telegram/files/venue.py @@ -25,7 +25,7 @@ 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. + considered equal, if their :attr:`location`, :attr:`title` and :attr:`address` are equal. Attributes: location (:class:`telegram.Location`): Venue location. @@ -56,7 +56,7 @@ def __init__(self, location, title, address, foursquare_id=None, foursquare_type self.foursquare_id = foursquare_id self.foursquare_type = foursquare_type - self._id_attrs = (self.location, self.title) + self._id_attrs = (self.location, self.title, self.address) @classmethod def de_json(cls, data, bot): diff --git a/telegram/forcereply.py b/telegram/forcereply.py index cc451125adc..a2b200f6934 100644 --- a/telegram/forcereply.py +++ b/telegram/forcereply.py @@ -29,7 +29,7 @@ class ForceReply(ReplyMarkup): 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:`force_reply` and :attr:`selective` are equal. + considered equal, if their :attr:`selective` is equal. Attributes: force_reply (:obj:`True`): Shows reply interface to the user. @@ -53,4 +53,4 @@ def __init__(self, force_reply=True, selective=False, **kwargs): # Optionals self.selective = bool(selective) - self._id_attrs = (self.force_reply, self.selective) + self._id_attrs = (self.selective,) diff --git a/telegram/inline/inputcontactmessagecontent.py b/telegram/inline/inputcontactmessagecontent.py index f7b054b7293..efcd1e3ad31 100644 --- a/telegram/inline/inputcontactmessagecontent.py +++ b/telegram/inline/inputcontactmessagecontent.py @@ -25,7 +25,7 @@ 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` and :attr:`first_name` are equal. + considered equal, if their :attr:`phone_number` is equal. Attributes: phone_number (:obj:`str`): Contact's phone number. @@ -52,4 +52,4 @@ def __init__(self, phone_number, first_name, last_name=None, vcard=None, **kwarg self.last_name = last_name self.vcard = vcard - self._id_attrs = (self.phone_number, self.first_name) + self._id_attrs = (self.phone_number,) diff --git a/telegram/payment/orderinfo.py b/telegram/payment/orderinfo.py index fcbaeb926af..bd5d6611079 100644 --- a/telegram/payment/orderinfo.py +++ b/telegram/payment/orderinfo.py @@ -26,7 +26,7 @@ class OrderInfo(TelegramObject): 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:`shpping_address` are equal. + :attr:`shipping_address` are equal. Attributes: name (:obj:`str`): Optional. User name. diff --git a/tests/test_forcereply.py b/tests/test_forcereply.py index 05e00d7e907..946cd692c08 100644 --- a/tests/test_forcereply.py +++ b/tests/test_forcereply.py @@ -52,7 +52,7 @@ def test_to_dict(self, force_reply): def test_equality(self): a = ForceReply(True, False) - b = ForceReply(True, False) + b = ForceReply(False, False) c = ForceReply(True, True) d = ReplyKeyboardRemove() diff --git a/tests/test_inputcontactmessagecontent.py b/tests/test_inputcontactmessagecontent.py index ea9baa44427..7478b4f107e 100644 --- a/tests/test_inputcontactmessagecontent.py +++ b/tests/test_inputcontactmessagecontent.py @@ -52,7 +52,7 @@ def test_to_dict(self, input_contact_message_content): def test_equality(self): a = InputContactMessageContent('phone', 'first', last_name='last') - b = InputContactMessageContent('phone', 'first', vcard='vcard') + b = InputContactMessageContent('phone', 'first_name', vcard='vcard') c = InputContactMessageContent('phone_number', 'first', vcard='vcard') d = User(123, 'first', False) diff --git a/tests/test_persistence.py b/tests/test_persistence.py index fec89d06afd..93e7163e2ec 100644 --- a/tests/test_persistence.py +++ b/tests/test_persistence.py @@ -367,7 +367,7 @@ def __eq__(self, other): 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_ diff --git a/tests/test_venue.py b/tests/test_venue.py index 965d4f354c1..c90006a8b6d 100644 --- a/tests/test_venue.py +++ b/tests/test_venue.py @@ -92,8 +92,8 @@ def test_equality(self): 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) From 81cbf673e66bb1b2440d4aa7f555d467cf4ab419 Mon Sep 17 00:00:00 2001 From: Hinrich Mahler Date: Tue, 14 Jul 2020 21:14:11 +0200 Subject: [PATCH 12/12] Even more changes --- telegram/files/sticker.py | 4 ++-- telegram/files/venue.py | 4 ++-- telegram/inline/inputvenuemessagecontent.py | 5 ++--- telegram/loginurl.py | 3 +-- tests/test_inputvenuemessagecontent.py | 14 +++++++++----- tests/test_venue.py | 4 ++-- 6 files changed, 18 insertions(+), 16 deletions(-) diff --git a/telegram/files/sticker.py b/telegram/files/sticker.py index d9541101064..f2e63e6e287 100644 --- a/telegram/files/sticker.py +++ b/telegram/files/sticker.py @@ -195,8 +195,8 @@ 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`, :attr:`scale` and - :attr:`latitude` are equal. + 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. diff --git a/telegram/files/venue.py b/telegram/files/venue.py index cccd17b2890..a54d7978553 100644 --- a/telegram/files/venue.py +++ b/telegram/files/venue.py @@ -25,7 +25,7 @@ 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`, :attr:`title` and :attr:`address` are equal. + considered equal, if their :attr:`location` and :attr:`title`are equal. Attributes: location (:class:`telegram.Location`): Venue location. @@ -56,7 +56,7 @@ def __init__(self, location, title, address, foursquare_id=None, foursquare_type self.foursquare_id = foursquare_id self.foursquare_type = foursquare_type - self._id_attrs = (self.location, self.title, self.address) + self._id_attrs = (self.location, self.title) @classmethod def de_json(cls, data, bot): diff --git a/telegram/inline/inputvenuemessagecontent.py b/telegram/inline/inputvenuemessagecontent.py index 0b587c8133d..bcd67dd1ec9 100644 --- a/telegram/inline/inputvenuemessagecontent.py +++ b/telegram/inline/inputvenuemessagecontent.py @@ -25,8 +25,8 @@ 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`, :attr:`title` and - :attr:`address` are equal. + considered equal, if their :attr:`latitude`, :attr:`longitude` and :attr:`title` + are equal. Attributes: latitude (:obj:`float`): Latitude of the location in degrees. @@ -66,5 +66,4 @@ def __init__(self, latitude, longitude, title, address, foursquare_id=None, self.latitude, self.longitude, self.title, - self.address ) diff --git a/telegram/loginurl.py b/telegram/loginurl.py index 7961df2a2da..4177e40e70f 100644 --- a/telegram/loginurl.py +++ b/telegram/loginurl.py @@ -30,8 +30,7 @@ class LoginUrl(TelegramObject): Sample bot: `@discussbot `_ 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. + considered equal, if their :attr:`url` is equal. Attributes: url (:obj:`str`): An HTTP URL to be opened with user authorization data. diff --git a/tests/test_inputvenuemessagecontent.py b/tests/test_inputvenuemessagecontent.py index 201636019c7..c6e377ea778 100644 --- a/tests/test_inputvenuemessagecontent.py +++ b/tests/test_inputvenuemessagecontent.py @@ -65,15 +65,19 @@ def test_to_dict(self, input_venue_message_content): def test_equality(self): a = InputVenueMessageContent(123, 456, 'title', 'address') - b = InputVenueMessageContent(123, 456, 'title', 'address', foursquare_id=123) - c = InputVenueMessageContent(456, 123, 'title', 'address', foursquare_id=123) - d = Location(123, 456) + 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 == c + assert hash(a) == hash(c) assert a != d assert hash(a) != hash(d) + + assert a != e + assert hash(a) != hash(e) diff --git a/tests/test_venue.py b/tests/test_venue.py index c90006a8b6d..965d4f354c1 100644 --- a/tests/test_venue.py +++ b/tests/test_venue.py @@ -92,8 +92,8 @@ def test_equality(self): 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)