Compare commits

..

7 Commits

Author SHA1 Message Date
Hinrich Mahler 392d4e1a9c Bump version to v12.5.1 2020-03-30 18:25:53 +02:00
Andrej730 9cb34af65a Fix UTC as default tzinfo for Jobs (#1696)
1. Made sure that default tzinfo in JobQueue is UTC #1693.
2. Added test that checks that all methods by default set job.tzinfo as UTC.
2020-03-30 18:10:27 +02:00
Bibo-Joshi e9cb6675ca PrefixHandlers command and prefix editable (#1636)
* Rename internal list of PrefixHandler

* Make PFH.prefix and .command setable attributes

* Improve coverage
2020-03-30 17:49:50 +02:00
Bibo-Joshi 982f6707e1 Make ConversationHandler attributes immutable (#1756)
* Make ConversationHandler attributes immutable

* Add forgotten name property to test_immutable
2020-03-30 17:37:37 +02:00
Rys Artem d55d981e22 Reorder tests to make them more stable (#1835) 2020-03-30 17:06:24 +02:00
Iulian Onofrei f20953f7a9 Fix docs wording (#1855) 2020-03-30 00:32:06 +03:00
Bibo-Joshi e18220be10 Add docs for PollHandler and PollAnswerHandler (#1853) 2020-03-29 11:24:44 +02:00
14 changed files with 247 additions and 41 deletions
+20
View File
@@ -2,6 +2,26 @@
Changelog
=========
Version 12.5.1
==============
*Released 2020-03-30*
**Minor changes, doc fixes or bug fixes:**
- Add missing docs for `PollHandler` and `PollAnswerHandler` (`#1853`_)
- Fix wording in `Filters` docs (`#1855`_)
- Reorder tests to make them more stable (`#1835`_)
- Make `ConversationHandler` attributes immutable (`#1756`_)
- Make `PrefixHandler` attributes `command` and `prefix` editable (`#1636`_)
- Fix UTC as default `tzinfo` for `Job` (`#1696`_)
.. _`#1853`: https://github.com/python-telegram-bot/python-telegram-bot/pull/1853
.. _`#1855`: https://github.com/python-telegram-bot/python-telegram-bot/pull/1855
.. _`#1835`: https://github.com/python-telegram-bot/python-telegram-bot/pull/1835
.. _`#1756`: https://github.com/python-telegram-bot/python-telegram-bot/pull/1756
.. _`#1636`: https://github.com/python-telegram-bot/python-telegram-bot/pull/1636
.. _`#1696`: https://github.com/python-telegram-bot/python-telegram-bot/pull/1696
Version 12.5
============
*Released 2020-03-29*
+1 -1
View File
@@ -60,7 +60,7 @@ author = u'Leandro Toledo'
# The short X.Y version.
version = '12.5' # telegram.__version__[:3]
# The full version, including alpha/beta/rc tags.
release = '12.5' # telegram.__version__
release = '12.5.1' # telegram.__version__
# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.
@@ -0,0 +1,6 @@
telegram.ext.PollAnswerHandler
==============================
.. autoclass:: telegram.ext.PollAnswerHandler
:members:
:show-inheritance:
+6
View File
@@ -0,0 +1,6 @@
telegram.ext.PollHandler
========================
.. autoclass:: telegram.ext.PollHandler
:members:
:show-inheritance:
+2
View File
@@ -26,6 +26,8 @@ Handlers
telegram.ext.commandhandler
telegram.ext.inlinequeryhandler
telegram.ext.messagehandler
telegram.ext.pollanswerhandler
telegram.ext.pollhandler
telegram.ext.precheckoutqueryhandler
telegram.ext.prefixhandler
telegram.ext.regexhandler
+31 -6
View File
@@ -302,6 +302,10 @@ class PrefixHandler(CommandHandler):
pass_user_data=False,
pass_chat_data=False):
self._prefix = list()
self._command = list()
self._commands = list()
super(PrefixHandler, self).__init__(
'nocommand', callback, filters=filters, allow_edited=None, pass_args=pass_args,
pass_update_queue=pass_update_queue,
@@ -309,15 +313,36 @@ class PrefixHandler(CommandHandler):
pass_user_data=pass_user_data,
pass_chat_data=pass_chat_data)
self.prefix = prefix
self.command = command
self._build_commands()
@property
def prefix(self):
return self._prefix
@prefix.setter
def prefix(self, prefix):
if isinstance(prefix, string_types):
self.prefix = [prefix.lower()]
self._prefix = [prefix.lower()]
else:
self.prefix = prefix
self._prefix = prefix
self._build_commands()
@property
def command(self):
return self._command
@command.setter
def command(self, command):
if isinstance(command, string_types):
self.command = [command.lower()]
self._command = [command.lower()]
else:
self.command = command
self.command = [x.lower() + y.lower() for x in self.prefix for y in self.command]
self._command = command
self._build_commands()
def _build_commands(self):
self._commands = [x.lower() + y.lower() for x in self.prefix for y in self.command]
def check_update(self, update):
"""Determines whether an update should be passed to this handlers :attr:`callback`.
@@ -334,7 +359,7 @@ class PrefixHandler(CommandHandler):
if message.text:
text_list = message.text.split()
if text_list[0].lower() not in self.command:
if text_list[0].lower() not in self._commands:
return None
filter_result = self.filters(update)
if filter_result:
+91 -10
View File
@@ -165,23 +165,23 @@ class ConversationHandler(Handler):
persistent=False,
map_to_parent=None):
self.entry_points = entry_points
self.states = states
self.fallbacks = fallbacks
self._entry_points = entry_points
self._states = states
self._fallbacks = fallbacks
self.allow_reentry = allow_reentry
self.per_user = per_user
self.per_chat = per_chat
self.per_message = per_message
self.conversation_timeout = conversation_timeout
self.name = name
self._allow_reentry = allow_reentry
self._per_user = per_user
self._per_chat = per_chat
self._per_message = per_message
self._conversation_timeout = conversation_timeout
self._name = name
if persistent and not self.name:
raise ValueError("Conversations can't be persistent when handler is unnamed.")
self.persistent = persistent
self._persistence = None
""":obj:`telegram.ext.BasePersistance`: The persistence used to store conversations.
Set by dispatcher"""
self.map_to_parent = map_to_parent
self._map_to_parent = map_to_parent
self.timeout_jobs = dict()
self._timeout_jobs_lock = Lock()
@@ -225,6 +225,87 @@ class ConversationHandler(Handler):
"since inline queries have no chat context.")
break
@property
def entry_points(self):
return self._entry_points
@entry_points.setter
def entry_points(self, value):
raise ValueError('You can not assign a new value to entry_points after initialization.')
@property
def states(self):
return self._states
@states.setter
def states(self, value):
raise ValueError('You can not assign a new value to states after initialization.')
@property
def fallbacks(self):
return self._fallbacks
@fallbacks.setter
def fallbacks(self, value):
raise ValueError('You can not assign a new value to fallbacks after initialization.')
@property
def allow_reentry(self):
return self._allow_reentry
@allow_reentry.setter
def allow_reentry(self, value):
raise ValueError('You can not assign a new value to allow_reentry after initialization.')
@property
def per_user(self):
return self._per_user
@per_user.setter
def per_user(self, value):
raise ValueError('You can not assign a new value to per_user after initialization.')
@property
def per_chat(self):
return self._per_chat
@per_chat.setter
def per_chat(self, value):
raise ValueError('You can not assign a new value to per_chat after initialization.')
@property
def per_message(self):
return self._per_message
@per_message.setter
def per_message(self, value):
raise ValueError('You can not assign a new value to per_message after initialization.')
@property
def conversation_timeout(self):
return self._conversation_timeout
@conversation_timeout.setter
def conversation_timeout(self, value):
raise ValueError('You can not assign a new value to conversation_timeout after '
'initialization.')
@property
def name(self):
return self._name
@name.setter
def name(self, value):
raise ValueError('You can not assign a new value to name after initialization.')
@property
def map_to_parent(self):
return self._map_to_parent
@map_to_parent.setter
def map_to_parent(self, value):
raise ValueError('You can not assign a new value to map_to_parent after initialization.')
@property
def persistence(self):
return self._persistence
+2 -2
View File
@@ -50,7 +50,7 @@ class BaseFilter(object):
>>> Filters.text & (~ Filters.forwarded)
Note:
Filters use the same short circuiting logic that pythons `and`, `or` and `not`.
Filters use the same short circuiting logic as python's `and`, `or` and `not`.
This means that for example:
>>> Filters.regex(r'(a?x)') | Filters.regex(r'(b?x)')
@@ -368,7 +368,7 @@ class Filters(object):
if you need to specify flags on your pattern.
Note:
Filters use the same short circuiting logic that pythons `and`, `or` and `not`.
Filters use the same short circuiting logic as python's `and`, `or` and `not`.
This means that for example:
>>> Filters.regex(r'(a?x)') | Filters.regex(r'(b?x)')
+3 -3
View File
@@ -285,7 +285,7 @@ class JobQueue(object):
if job.enabled:
try:
current_week_day = datetime.datetime.now(job.tzinfo).date().weekday()
if any(day == current_week_day for day in job.days):
if current_week_day in job.days:
self.logger.debug('Running job %s', job.name)
job.run(self._dispatcher)
@@ -400,7 +400,7 @@ class Job(object):
days=Days.EVERY_DAY,
name=None,
job_queue=None,
tzinfo=_UTC):
tzinfo=None):
self.callback = callback
self.context = context
@@ -413,7 +413,7 @@ class Job(object):
self._days = None
self.days = days
self.tzinfo = tzinfo
self.tzinfo = tzinfo or _UTC
self._job_queue = weakref.proxy(job_queue) if job_queue is not None else None
+1 -1
View File
@@ -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.5'
__version__ = '12.5.1'
+17 -17
View File
@@ -208,18 +208,6 @@ class TestBot(object):
assert message_quiz.poll.type == Poll.QUIZ
assert message_quiz.poll.is_closed
@flaky(3, 1)
@pytest.mark.timeout(10)
def test_send_game(self, bot, chat_id):
game_short_name = 'test_game'
message = bot.send_game(chat_id, game_short_name)
assert message.game
assert message.game.description == ('A no-op test game, for python-telegram-bot '
'bot framework testing.')
assert message.game.animation.file_id != ''
assert message.game.photo[0].file_size == 851
@flaky(3, 1)
@pytest.mark.timeout(10)
def test_send_chat_action(self, bot, chat_id):
@@ -596,6 +584,18 @@ class TestBot(object):
def test_delete_chat_sticker_set(self):
pass
@flaky(3, 1)
@pytest.mark.timeout(10)
def test_send_game(self, bot, chat_id):
game_short_name = 'test_game'
message = bot.send_game(chat_id, game_short_name)
assert message.game
assert message.game.description == ('A no-op test game, for python-telegram-bot '
'bot framework testing.')
assert message.game.animation.file_id != ''
assert message.game.photo[0].file_size == 851
@flaky(3, 1)
@pytest.mark.timeout(10)
def test_set_game_score_1(self, bot, chat_id):
@@ -795,17 +795,17 @@ class TestBot(object):
assert isinstance(invite_link, string_types)
assert invite_link != ''
@flaky(3, 1)
@pytest.mark.timeout(10)
def test_delete_chat_photo(self, bot, channel_id):
assert bot.delete_chat_photo(channel_id)
@flaky(3, 1)
@pytest.mark.timeout(10)
def test_set_chat_photo(self, bot, channel_id):
with open('tests/data/telegram_test_channel.jpg', 'rb') as f:
assert bot.set_chat_photo(channel_id, f)
@flaky(3, 1)
@pytest.mark.timeout(10)
def test_delete_chat_photo(self, bot, channel_id):
assert bot.delete_chat_photo(channel_id)
@flaky(3, 1)
@pytest.mark.timeout(10)
def test_set_chat_title(self, bot, channel_id):
+23
View File
@@ -379,6 +379,29 @@ class TestPrefixHandler(BaseTest):
assert not is_match(handler, make_message_update('/test'))
assert not mock_filter.tested
def test_edit_prefix(self):
handler = self.make_default_handler()
handler.prefix = ['?', '§']
assert handler._commands == list(combinations(['?', '§'], self.COMMANDS))
handler.prefix = '+'
assert handler._commands == list(combinations(['+'], self.COMMANDS))
def test_edit_command(self):
handler = self.make_default_handler()
handler.command = 'foo'
assert handler._commands == list(combinations(self.PREFIXES, ['foo']))
def test_basic_after_editing(self, dp, prefix, command):
"""Test the basic expected response from a prefix handler"""
handler = self.make_default_handler()
dp.add_handler(handler)
text = prefix + command
assert self.response(dp, make_message_update(text))
handler.command = 'foo'
text = prefix + 'foo'
assert self.response(dp, make_message_update(text))
def test_context(self, cdp, prefix_message_update):
handler = self.make_default_handler(self.callback_context)
cdp.add_handler(handler)
+32
View File
@@ -179,6 +179,38 @@ class TestConversationHandler(object):
return self._set_state(update, self.STOPPING)
# Tests
@pytest.mark.parametrize('attr', ['entry_points', 'states', 'fallbacks', 'per_chat', 'name',
'per_user', 'allow_reentry', 'conversation_timeout', 'map_to_parent'],
indirect=False)
def test_immutable(self, attr):
ch = ConversationHandler('entry_points', {'states': ['states']}, 'fallbacks',
per_chat='per_chat',
per_user='per_user', per_message=False,
allow_reentry='allow_reentry',
conversation_timeout='conversation_timeout',
name='name', map_to_parent='map_to_parent')
value = getattr(ch, attr)
if isinstance(value, list):
assert value[0] == attr
elif isinstance(value, dict):
assert list(value.keys())[0] == attr
else:
assert getattr(ch, attr) == attr
with pytest.raises(ValueError, match='You can not assign a new value to {}'.format(attr)):
setattr(ch, attr, True)
def test_immutable_per_message(self):
ch = ConversationHandler('entry_points', {'states': ['states']}, 'fallbacks',
per_chat='per_chat',
per_user='per_user', per_message=False,
allow_reentry='allow_reentry',
conversation_timeout='conversation_timeout',
name='name', map_to_parent='map_to_parent')
assert ch.per_message is False
with pytest.raises(ValueError, match='You can not assign a new value to per_message'):
ch.per_message = True
def test_per_all_false(self):
with pytest.raises(ValueError, match="can't all be 'False'"):
ConversationHandler(self.entry_points, self.states, self.fallbacks,
+12 -1
View File
@@ -28,7 +28,7 @@ from flaky import flaky
from telegram.ext import JobQueue, Updater, Job, CallbackContext
from telegram.utils.deprecate import TelegramDeprecationWarning
from telegram.utils.helpers import _UtcOffsetTimezone
from telegram.utils.helpers import _UtcOffsetTimezone, _UTC
@pytest.fixture(scope='function')
@@ -330,3 +330,14 @@ class TestJobQueue(object):
sleep(0.03)
assert self.result == 0
def test_job_default_tzinfo(self, job_queue):
"""Test that default tzinfo is always set to UTC"""
job_1 = job_queue.run_once(self.job_run_once, 0.01)
job_2 = job_queue.run_repeating(self.job_run_once, 10)
job_3 = job_queue.run_daily(self.job_run_once, time=dtm.time(hour=15))
jobs = [job_1, job_2, job_3]
for job in jobs:
assert job.tzinfo == _UTC