mirror of
https://github.com/python-telegram-bot/python-telegram-bot.git
synced 2026-06-27 03:34:37 +00:00
Compare commits
5 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 72ecc696cb | |||
| a447760411 | |||
| 6da529c46b | |||
| bd1b2fb6c1 | |||
| f9a8cd924c |
+20
@@ -2,6 +2,26 @@
|
||||
Changelog
|
||||
=========
|
||||
|
||||
Version 12.4.2
|
||||
==============
|
||||
*Released 2020-02-10*
|
||||
|
||||
**Bug Fixes**
|
||||
|
||||
- Pass correct parse_mode to InlineResults if bot.defaults is None (`#1763`_)
|
||||
- Make sure PP can read files that dont have bot_data (`#1760`_)
|
||||
|
||||
.. _`#1763`: https://github.com/python-telegram-bot/python-telegram-bot/pull/1763
|
||||
.. _`#1760`: https://github.com/python-telegram-bot/python-telegram-bot/pull/1760
|
||||
|
||||
Version 12.4.1
|
||||
==============
|
||||
*Released 2020-02-08*
|
||||
|
||||
This is a quick release for `#1744`_ which was accidently left out of v12.4.0 though mentioned in the
|
||||
release notes.
|
||||
|
||||
|
||||
Version 12.4.0
|
||||
==============
|
||||
*Released 2020-02-08*
|
||||
|
||||
+1
-1
@@ -60,7 +60,7 @@ author = u'Leandro Toledo'
|
||||
# The short X.Y version.
|
||||
version = '12.4' # telegram.__version__[:3]
|
||||
# The full version, including alpha/beta/rc tags.
|
||||
release = '12.4.0' # telegram.__version__
|
||||
release = '12.4.2' # telegram.__version__
|
||||
|
||||
# The language for content autogenerated by Sphinx. Refer to documentation
|
||||
# for a list of supported languages.
|
||||
|
||||
+4
-1
@@ -1512,7 +1512,10 @@ class Bot(TelegramObject):
|
||||
|
||||
for res in results:
|
||||
if res._has_parse_mode and res.parse_mode == DEFAULT_NONE:
|
||||
res.parse_mode = self.defaults.parse_mode
|
||||
if self.defaults:
|
||||
res.parse_mode = self.defaults.parse_mode
|
||||
else:
|
||||
res.parse_mode = None
|
||||
if res._has_input_message_content and res.input_message_content:
|
||||
if (res.input_message_content._has_parse_mode
|
||||
and res.input_message_content.parse_mode == DEFAULT_NONE):
|
||||
|
||||
+35
-11
@@ -22,7 +22,7 @@ import re
|
||||
|
||||
from future.utils import string_types
|
||||
|
||||
from telegram import Chat, Update
|
||||
from telegram import Chat, Update, MessageEntity
|
||||
|
||||
__all__ = ['Filters', 'BaseFilter', 'InvertedFilter', 'MergedFilter']
|
||||
|
||||
@@ -249,10 +249,7 @@ class Filters(object):
|
||||
|
||||
def __call__(self, update):
|
||||
if isinstance(update, Update):
|
||||
if self.update_filter:
|
||||
return self.filter(update)
|
||||
else:
|
||||
return self.filter(update.effective_message)
|
||||
return self.filter(update.effective_message)
|
||||
else:
|
||||
return self._TextIterable(update)
|
||||
|
||||
@@ -296,10 +293,7 @@ class Filters(object):
|
||||
|
||||
def __call__(self, update):
|
||||
if isinstance(update, Update):
|
||||
if self.update_filter:
|
||||
return self.filter(update)
|
||||
else:
|
||||
return self.filter(update.effective_message)
|
||||
return self.filter(update.effective_message)
|
||||
else:
|
||||
return self._CaptionIterable(update)
|
||||
|
||||
@@ -321,11 +315,41 @@ class Filters(object):
|
||||
class _Command(BaseFilter):
|
||||
name = 'Filters.command'
|
||||
|
||||
class _CommandOnlyStart(BaseFilter):
|
||||
|
||||
def __init__(self, only_start):
|
||||
self.only_start = only_start
|
||||
self.name = 'Filters.command({})'.format(only_start)
|
||||
|
||||
def filter(self, message):
|
||||
return (message.entities
|
||||
and any([e.type == MessageEntity.BOT_COMMAND for e in message.entities]))
|
||||
|
||||
def __call__(self, update):
|
||||
if isinstance(update, Update):
|
||||
return self.filter(update.effective_message)
|
||||
else:
|
||||
return self._CommandOnlyStart(update)
|
||||
|
||||
def filter(self, message):
|
||||
return bool(message.text and message.text.startswith('/'))
|
||||
return (message.entities and message.entities[0].type == MessageEntity.BOT_COMMAND
|
||||
and message.entities[0].offset == 0)
|
||||
|
||||
command = _Command()
|
||||
"""Messages starting with ``/``."""
|
||||
"""
|
||||
Messages with a :attr:`telegram.MessageEntity.BOT_COMMAND`. By default only allows
|
||||
messages `starting` with a bot command. Pass ``False`` to also allow messages that contain a
|
||||
bot command `anywhere` in the text.
|
||||
|
||||
Examples::
|
||||
|
||||
MessageHandler(Filters.command, command_at_start_callback)
|
||||
MessageHandler(Filters.command(False), command_anywhere_callback)
|
||||
|
||||
Args:
|
||||
update (:obj:`bool`, optional): Whether to only allow messages that `start` with a bot
|
||||
command. Defaults to ``True``.
|
||||
"""
|
||||
|
||||
class regex(BaseFilter):
|
||||
"""
|
||||
|
||||
@@ -84,7 +84,8 @@ class PicklePersistence(BasePersistence):
|
||||
all = pickle.load(f)
|
||||
self.user_data = defaultdict(dict, all['user_data'])
|
||||
self.chat_data = defaultdict(dict, all['chat_data'])
|
||||
self.bot_data = all['bot_data']
|
||||
# For backwards compatibility with files not containing bot data
|
||||
self.bot_data = all.get('bot_data', {})
|
||||
self.conversations = all['conversations']
|
||||
except IOError:
|
||||
self.conversations = {}
|
||||
|
||||
+1
-1
@@ -17,4 +17,4 @@
|
||||
# You should have received a copy of the GNU Lesser Public License
|
||||
# along with this program. If not, see [http://www.gnu.org/licenses/].
|
||||
|
||||
__version__ = '12.4.0'
|
||||
__version__ = '12.4.2'
|
||||
|
||||
+63
-1
@@ -28,7 +28,8 @@ from future.utils import string_types
|
||||
|
||||
from telegram import (Bot, Update, ChatAction, TelegramError, User, InlineKeyboardMarkup,
|
||||
InlineKeyboardButton, InlineQueryResultArticle, InputTextMessageContent,
|
||||
ShippingOption, LabeledPrice, ChatPermissions, Poll)
|
||||
ShippingOption, LabeledPrice, ChatPermissions, Poll,
|
||||
InlineQueryResultDocument)
|
||||
from telegram.error import BadRequest, InvalidToken, NetworkError, RetryAfter
|
||||
from telegram.utils.helpers import from_timestamp, escape_markdown
|
||||
|
||||
@@ -237,6 +238,67 @@ class TestBot(object):
|
||||
switch_pm_text='switch pm',
|
||||
switch_pm_parameter='start_pm')
|
||||
|
||||
def test_answer_inline_query_no_default_parse_mode(self, monkeypatch, bot):
|
||||
def test(_, url, data, *args, **kwargs):
|
||||
return data == {'cache_time': 300,
|
||||
'results': [{'title': 'test_result', 'id': '123', 'type': 'document',
|
||||
'document_url': 'https://raw.githubusercontent.com/'
|
||||
'python-telegram-bot/logos/master/logo/png/'
|
||||
'ptb-logo_240.png', 'mime_type': 'image/png',
|
||||
'caption': 'ptb_logo'}],
|
||||
'next_offset': '42', 'switch_pm_parameter': 'start_pm',
|
||||
'inline_query_id': 1234, 'is_personal': True,
|
||||
'switch_pm_text': 'switch pm'}
|
||||
|
||||
monkeypatch.setattr('telegram.utils.request.Request.post', test)
|
||||
results = [InlineQueryResultDocument(
|
||||
id='123',
|
||||
document_url='https://raw.githubusercontent.com/python-telegram-bot/logos/master/'
|
||||
'logo/png/ptb-logo_240.png',
|
||||
title='test_result',
|
||||
mime_type='image/png',
|
||||
caption='ptb_logo',
|
||||
)]
|
||||
|
||||
assert bot.answer_inline_query(1234,
|
||||
results=results,
|
||||
cache_time=300,
|
||||
is_personal=True,
|
||||
next_offset='42',
|
||||
switch_pm_text='switch pm',
|
||||
switch_pm_parameter='start_pm')
|
||||
|
||||
@pytest.mark.parametrize('default_bot', [{'parse_mode': 'Markdown'}], indirect=True)
|
||||
def test_answer_inline_query_default_parse_mode(self, monkeypatch, default_bot):
|
||||
def test(_, url, data, *args, **kwargs):
|
||||
return data == {'cache_time': 300,
|
||||
'results': [{'title': 'test_result', 'id': '123', 'type': 'document',
|
||||
'document_url': 'https://raw.githubusercontent.com/'
|
||||
'python-telegram-bot/logos/master/logo/png/'
|
||||
'ptb-logo_240.png', 'mime_type': 'image/png',
|
||||
'caption': 'ptb_logo', 'parse_mode': 'Markdown'}],
|
||||
'next_offset': '42', 'switch_pm_parameter': 'start_pm',
|
||||
'inline_query_id': 1234, 'is_personal': True,
|
||||
'switch_pm_text': 'switch pm'}
|
||||
|
||||
monkeypatch.setattr('telegram.utils.request.Request.post', test)
|
||||
results = [InlineQueryResultDocument(
|
||||
id='123',
|
||||
document_url='https://raw.githubusercontent.com/python-telegram-bot/logos/master/'
|
||||
'logo/png/ptb-logo_240.png',
|
||||
title='test_result',
|
||||
mime_type='image/png',
|
||||
caption='ptb_logo',
|
||||
)]
|
||||
|
||||
assert default_bot.answer_inline_query(1234,
|
||||
results=results,
|
||||
cache_time=300,
|
||||
is_personal=True,
|
||||
next_offset='42',
|
||||
switch_pm_text='switch pm',
|
||||
switch_pm_parameter='start_pm')
|
||||
|
||||
@flaky(3, 1)
|
||||
@pytest.mark.timeout(10)
|
||||
def test_get_user_profile_photos(self, bot, chat_id):
|
||||
|
||||
+28
-1
@@ -63,12 +63,23 @@ class TestFilters(object):
|
||||
assert Filters.caption({'test', 'test1'})(update)
|
||||
assert not Filters.caption(['test1', 'test2'])(update)
|
||||
|
||||
def test_filters_command(self, update):
|
||||
def test_filters_command_default(self, update):
|
||||
update.message.text = 'test'
|
||||
assert not Filters.command(update)
|
||||
update.message.text = '/test'
|
||||
assert not Filters.command(update)
|
||||
# Only accept commands at the beginning
|
||||
update.message.entities = [MessageEntity(MessageEntity.BOT_COMMAND, 3, 5)]
|
||||
assert not Filters.command(update)
|
||||
update.message.entities = [MessageEntity(MessageEntity.BOT_COMMAND, 0, 5)]
|
||||
assert Filters.command(update)
|
||||
|
||||
def test_filters_command_anywhere(self, update):
|
||||
update.message.text = 'test /cmd'
|
||||
assert not (Filters.command(False))(update)
|
||||
update.message.entities = [MessageEntity(MessageEntity.BOT_COMMAND, 5, 4)]
|
||||
assert (Filters.command(False))(update)
|
||||
|
||||
def test_filters_regex(self, update):
|
||||
SRE_TYPE = type(re.match("", ""))
|
||||
update.message.text = '/start deep-linked param'
|
||||
@@ -120,6 +131,7 @@ class TestFilters(object):
|
||||
def test_filters_merged_with_regex(self, update):
|
||||
SRE_TYPE = type(re.match("", ""))
|
||||
update.message.text = '/start deep-linked param'
|
||||
update.message.entities = [MessageEntity(MessageEntity.BOT_COMMAND, 0, 6)]
|
||||
result = (Filters.command & Filters.regex(r'linked param'))(update)
|
||||
assert result
|
||||
assert isinstance(result, dict)
|
||||
@@ -216,6 +228,7 @@ class TestFilters(object):
|
||||
result = filter(update)
|
||||
assert not result
|
||||
update.message.text = '/start'
|
||||
update.message.entities = [MessageEntity(MessageEntity.BOT_COMMAND, 0, 6)]
|
||||
result = filter(update)
|
||||
assert result
|
||||
assert isinstance(result, bool)
|
||||
@@ -230,6 +243,7 @@ class TestFilters(object):
|
||||
|
||||
def test_regex_inverted(self, update):
|
||||
update.message.text = '/start deep-linked param'
|
||||
update.message.entities = [MessageEntity(MessageEntity.BOT_COMMAND, 0, 5)]
|
||||
filter = ~Filters.regex(r'deep-linked param')
|
||||
result = filter(update)
|
||||
assert not result
|
||||
@@ -243,6 +257,7 @@ class TestFilters(object):
|
||||
result = filter(update)
|
||||
assert not result
|
||||
update.message.text = '/start'
|
||||
update.message.entities = [MessageEntity(MessageEntity.BOT_COMMAND, 0, 6)]
|
||||
result = filter(update)
|
||||
assert result
|
||||
update.message.text = '/linked'
|
||||
@@ -251,15 +266,18 @@ class TestFilters(object):
|
||||
|
||||
filter = (~Filters.regex('linked') | Filters.command)
|
||||
update.message.text = "it's linked"
|
||||
update.message.entities = []
|
||||
result = filter(update)
|
||||
assert not result
|
||||
update.message.text = '/start linked'
|
||||
update.message.entities = [MessageEntity(MessageEntity.BOT_COMMAND, 0, 6)]
|
||||
result = filter(update)
|
||||
assert result
|
||||
update.message.text = '/start'
|
||||
result = filter(update)
|
||||
assert result
|
||||
update.message.text = 'nothig'
|
||||
update.message.entities = []
|
||||
result = filter(update)
|
||||
assert result
|
||||
|
||||
@@ -664,14 +682,17 @@ class TestFilters(object):
|
||||
|
||||
def test_inverted_filters(self, update):
|
||||
update.message.text = '/test'
|
||||
update.message.entities = [MessageEntity(MessageEntity.BOT_COMMAND, 0, 5)]
|
||||
assert Filters.command(update)
|
||||
assert not (~Filters.command)(update)
|
||||
update.message.text = 'test'
|
||||
update.message.entities = []
|
||||
assert not Filters.command(update)
|
||||
assert (~Filters.command)(update)
|
||||
|
||||
def test_inverted_and_filters(self, update):
|
||||
update.message.text = '/test'
|
||||
update.message.entities = [MessageEntity(MessageEntity.BOT_COMMAND, 0, 5)]
|
||||
update.message.forward_date = 1
|
||||
assert (Filters.forwarded & Filters.command)(update)
|
||||
assert not (~Filters.forwarded & Filters.command)(update)
|
||||
@@ -683,6 +704,7 @@ class TestFilters(object):
|
||||
assert not (Filters.forwarded & ~Filters.command)(update)
|
||||
assert (~(Filters.forwarded & Filters.command))(update)
|
||||
update.message.text = 'test'
|
||||
update.message.entities = []
|
||||
assert not (Filters.forwarded & Filters.command)(update)
|
||||
assert not (~Filters.forwarded & Filters.command)(update)
|
||||
assert not (Filters.forwarded & ~Filters.command)(update)
|
||||
@@ -746,6 +768,7 @@ class TestFilters(object):
|
||||
|
||||
def test_merged_short_circuit_and(self, update):
|
||||
update.message.text = '/test'
|
||||
update.message.entities = [MessageEntity(MessageEntity.BOT_COMMAND, 0, 5)]
|
||||
|
||||
class TestException(Exception):
|
||||
pass
|
||||
@@ -760,6 +783,7 @@ class TestFilters(object):
|
||||
(Filters.command & raising_filter)(update)
|
||||
|
||||
update.message.text = 'test'
|
||||
update.message.entities = []
|
||||
(Filters.command & raising_filter)(update)
|
||||
|
||||
def test_merged_short_circuit_or(self, update):
|
||||
@@ -778,10 +802,12 @@ class TestFilters(object):
|
||||
(Filters.command | raising_filter)(update)
|
||||
|
||||
update.message.text = '/test'
|
||||
update.message.entities = [MessageEntity(MessageEntity.BOT_COMMAND, 0, 5)]
|
||||
(Filters.command | raising_filter)(update)
|
||||
|
||||
def test_merged_data_merging_and(self, update):
|
||||
update.message.text = '/test'
|
||||
update.message.entities = [MessageEntity(MessageEntity.BOT_COMMAND, 0, 5)]
|
||||
|
||||
class DataFilter(BaseFilter):
|
||||
data_filter = True
|
||||
@@ -799,6 +825,7 @@ class TestFilters(object):
|
||||
assert result['test'] == ['blah1', 'blah2']
|
||||
|
||||
update.message.text = 'test'
|
||||
update.message.entities = []
|
||||
result = (Filters.command & DataFilter('blah'))(update)
|
||||
assert not result
|
||||
|
||||
|
||||
@@ -335,6 +335,23 @@ def good_pickle_files(user_data, chat_data, bot_data, conversations):
|
||||
os.remove(name)
|
||||
|
||||
|
||||
@pytest.fixture(scope='function')
|
||||
def pickle_files_wo_bot_data(user_data, chat_data, conversations):
|
||||
all = {'user_data': user_data, 'chat_data': chat_data, 'conversations': conversations}
|
||||
with open('pickletest_user_data', 'wb') as f:
|
||||
pickle.dump(user_data, f)
|
||||
with open('pickletest_chat_data', 'wb') as f:
|
||||
pickle.dump(chat_data, f)
|
||||
with open('pickletest_conversations', 'wb') as f:
|
||||
pickle.dump(conversations, f)
|
||||
with open('pickletest', 'wb') as f:
|
||||
pickle.dump(all, f)
|
||||
yield True
|
||||
for name in ['pickletest_user_data', 'pickletest_chat_data',
|
||||
'pickletest_conversations', 'pickletest']:
|
||||
os.remove(name)
|
||||
|
||||
|
||||
@pytest.fixture(scope='function')
|
||||
def update(bot):
|
||||
user = User(id=321, first_name='test_user', is_bot=False)
|
||||
@@ -447,6 +464,54 @@ class TestPickelPersistence(object):
|
||||
with pytest.raises(KeyError):
|
||||
conversation2[(123, 123)]
|
||||
|
||||
def test_with_multi_file_wo_bot_data(self, pickle_persistence, pickle_files_wo_bot_data):
|
||||
user_data = pickle_persistence.get_user_data()
|
||||
assert isinstance(user_data, defaultdict)
|
||||
assert user_data[12345]['test1'] == 'test2'
|
||||
assert user_data[67890][3] == 'test4'
|
||||
assert user_data[54321] == {}
|
||||
|
||||
chat_data = pickle_persistence.get_chat_data()
|
||||
assert isinstance(chat_data, defaultdict)
|
||||
assert chat_data[-12345]['test1'] == 'test2'
|
||||
assert chat_data[-67890][3] == 'test4'
|
||||
assert chat_data[-54321] == {}
|
||||
|
||||
bot_data = pickle_persistence.get_bot_data()
|
||||
assert isinstance(bot_data, dict)
|
||||
assert not bot_data.keys()
|
||||
|
||||
conversation1 = pickle_persistence.get_conversations('name1')
|
||||
assert isinstance(conversation1, dict)
|
||||
assert conversation1[(123, 123)] == 3
|
||||
assert conversation1[(456, 654)] == 4
|
||||
with pytest.raises(KeyError):
|
||||
conversation1[(890, 890)]
|
||||
conversation2 = pickle_persistence.get_conversations('name2')
|
||||
assert isinstance(conversation1, dict)
|
||||
assert conversation2[(123, 321)] == 1
|
||||
assert conversation2[(890, 890)] == 2
|
||||
with pytest.raises(KeyError):
|
||||
conversation2[(123, 123)]
|
||||
|
||||
def test_with_single_file_wo_bot_data(self, pickle_persistence, pickle_files_wo_bot_data):
|
||||
pickle_persistence.single_file = True
|
||||
user_data = pickle_persistence.get_user_data()
|
||||
assert isinstance(user_data, defaultdict)
|
||||
assert user_data[12345]['test1'] == 'test2'
|
||||
assert user_data[67890][3] == 'test4'
|
||||
assert user_data[54321] == {}
|
||||
|
||||
chat_data = pickle_persistence.get_chat_data()
|
||||
assert isinstance(chat_data, defaultdict)
|
||||
assert chat_data[-12345]['test1'] == 'test2'
|
||||
assert chat_data[-67890][3] == 'test4'
|
||||
assert chat_data[-54321] == {}
|
||||
|
||||
bot_data = pickle_persistence.get_bot_data()
|
||||
assert isinstance(bot_data, dict)
|
||||
assert not bot_data.keys()
|
||||
|
||||
def test_updating_multi_file(self, pickle_persistence, good_pickle_files):
|
||||
user_data = pickle_persistence.get_user_data()
|
||||
user_data[54321]['test9'] = 'test 10'
|
||||
@@ -659,7 +724,7 @@ class TestPickelPersistence(object):
|
||||
if not context.chat_data == {}:
|
||||
pytest.fail()
|
||||
if not context.bot_data == bot_data:
|
||||
pytest.failt()
|
||||
pytest.fail()
|
||||
context.user_data['test1'] = 'test2'
|
||||
context.chat_data['test3'] = 'test4'
|
||||
context.bot_data['test1'] = 'test0'
|
||||
|
||||
Reference in New Issue
Block a user