Merge remote-tracking branch 'origin/master'

This commit is contained in:
Jasmin Bom 2019-01-30 19:45:37 +01:00
commit ed33c4a7a9
9 changed files with 263 additions and 7 deletions

View file

@ -16,6 +16,7 @@ Contributors
The following wonderful people contributed directly or indirectly to this project:
- `Alateas <https://github.com/alateas>`_
- `Ambro17 <https://github.com/Ambro17>`_
- `Anton Tagunov <https://github.com/anton-tagunov>`_
- `Avanatiker <https://github.com/Avanatiker>`_
- `Balduro <https://github.com/Balduro>`_

View file

@ -62,7 +62,7 @@ class JobQueue(object):
raise ValueError('next_t is None')
if isinstance(next_t, datetime.datetime):
next_t = (next_t - datetime.datetime.now()).total_seconds()
next_t = (next_t - datetime.datetime.now(next_t.tzinfo)).total_seconds()
elif isinstance(next_t, datetime.time):
next_datetime = datetime.datetime.combine(datetime.date.today(), next_t)

View file

@ -48,3 +48,51 @@ class InlineKeyboardMarkup(ReplyMarkup):
data['inline_keyboard'].append([x.to_dict() for x in inline_keyboard])
return data
@classmethod
def from_button(cls, button, **kwargs):
"""Shortcut for::
InlineKeyboardMarkup([[button]], **kwargs)
Return an InlineKeyboardMarkup from a single InlineKeyboardButton
Args:
button (:class:`telegram.InlineKeyboardButton`): The button to use in the markup
**kwargs (:obj:`dict`): Arbitrary keyword arguments.
"""
return cls([[button]], **kwargs)
@classmethod
def from_row(cls, button_row, **kwargs):
"""Shortcut for::
InlineKeyboardMarkup([button_row], **kwargs)
Return an InlineKeyboardMarkup from a single row of InlineKeyboardButtons
Args:
button_row (List[:class:`telegram.InlineKeyboardButton`]): The button to use in the
markup
**kwargs (:obj:`dict`): Arbitrary keyword arguments.
"""
return cls([button_row], **kwargs)
@classmethod
def from_column(cls, button_column, **kwargs):
"""Shortcut for::
InlineKeyboardMarkup([[button] for button in button_column], **kwargs)
Return an InlineKeyboardMarkup from a single column of InlineKeyboardButtons
Args:
button_column (List[:class:`telegram.InlineKeyboardButton`]): The button to use in the
markup
**kwargs (:obj:`dict`): Arbitrary keyword arguments.
"""
button_grid = [[button] for button in button_column]
return cls(button_grid, **kwargs)

View file

@ -85,3 +85,125 @@ class ReplyKeyboardMarkup(ReplyMarkup):
r.append(button) # str
data['keyboard'].append(r)
return data
@classmethod
def from_button(cls,
button,
resize_keyboard=False,
one_time_keyboard=False,
selective=False,
**kwargs):
"""Shortcut for::
ReplyKeyboardMarkup([[button]], **kwargs)
Return an ReplyKeyboardMarkup from a single KeyboardButton
Args:
button (:class:`telegram.KeyboardButton` | :obj:`str`): The button to use in the markup
resize_keyboard (:obj:`bool`, optional): Requests clients to resize the keyboard vertically
for optimal fit (e.g., make the keyboard smaller if there are just two rows of
buttons). Defaults to false, in which case the custom keyboard is always of the same
height as the app's standard keyboard. Defaults to ``False``
one_time_keyboard (:obj:`bool`, optional): Requests clients to hide the keyboard as soon as
it's been used. The keyboard will still be available, but clients will automatically
display the usual letter-keyboard in the chat - the user can press a special button in
the input field to see the custom keyboard again. Defaults to ``False``.
selective (:obj:`bool`, optional): Use this parameter if you want to show the keyboard to
specific users only. Targets:
1) users that are @mentioned in the text of the Message object
2) if the bot's message is a reply (has reply_to_message_id), sender of the original
message.
Defaults to ``False``.
**kwargs (:obj:`dict`): Arbitrary keyword arguments.
"""
return cls([[button]],
resize_keyboard=resize_keyboard,
one_time_keyboard=one_time_keyboard,
selective=selective,
**kwargs)
@classmethod
def from_row(cls,
button_row,
resize_keyboard=False,
one_time_keyboard=False,
selective=False,
**kwargs):
"""Shortcut for::
ReplyKeyboardMarkup([button_row], **kwargs)
Return an ReplyKeyboardMarkup from a single row of KeyboardButtons
Args:
button_row (List[:class:`telegram.KeyboardButton` | :obj:`str`]): The button to use in the
markup
resize_keyboard (:obj:`bool`, optional): Requests clients to resize the keyboard vertically
for optimal fit (e.g., make the keyboard smaller if there are just two rows of
buttons). Defaults to false, in which case the custom keyboard is always of the same
height as the app's standard keyboard. Defaults to ``False``
one_time_keyboard (:obj:`bool`, optional): Requests clients to hide the keyboard as soon as
it's been used. The keyboard will still be available, but clients will automatically
display the usual letter-keyboard in the chat - the user can press a special button in
the input field to see the custom keyboard again. Defaults to ``False``.
selective (:obj:`bool`, optional): Use this parameter if you want to show the keyboard to
specific users only. Targets:
1) users that are @mentioned in the text of the Message object
2) if the bot's message is a reply (has reply_to_message_id), sender of the original
message.
Defaults to ``False``.
**kwargs (:obj:`dict`): Arbitrary keyword arguments.
"""
return cls([button_row],
resize_keyboard=resize_keyboard,
one_time_keyboard=one_time_keyboard,
selective=selective,
**kwargs)
@classmethod
def from_column(cls,
button_column,
resize_keyboard=False,
one_time_keyboard=False,
selective=False,
**kwargs):
"""Shortcut for::
ReplyKeyboardMarkup([[button] for button in button_column], **kwargs)
Return an ReplyKeyboardMarkup from a single column of KeyboardButtons
Args:
button_column (List[:class:`telegram.KeyboardButton` | :obj:`str`]): The button to use in the
markup
resize_keyboard (:obj:`bool`, optional): Requests clients to resize the keyboard vertically
for optimal fit (e.g., make the keyboard smaller if there are just two rows of
buttons). Defaults to false, in which case the custom keyboard is always of the same
height as the app's standard keyboard. Defaults to ``False``
one_time_keyboard (:obj:`bool`, optional): Requests clients to hide the keyboard as soon as
it's been used. The keyboard will still be available, but clients will automatically
display the usual letter-keyboard in the chat - the user can press a special button in
the input field to see the custom keyboard again. Defaults to ``False``.
selective (:obj:`bool`, optional): Use this parameter if you want to show the keyboard to
specific users only. Targets:
1) users that are @mentioned in the text of the Message object
2) if the bot's message is a reply (has reply_to_message_id), sender of the original
message.
Defaults to ``False``.
**kwargs (:obj:`dict`): Arbitrary keyword arguments.
"""
button_grid = [[button] for button in button_column]
return cls(button_grid,
resize_keyboard=resize_keyboard,
one_time_keyboard=one_time_keyboard,
selective=selective,
**kwargs)

View file

@ -323,7 +323,8 @@ class Request(object):
else:
result = self._request_wrapper('POST', url,
body=json.dumps(data).encode('utf-8'),
headers={'Content-Type': 'application/json'})
headers={'Content-Type': 'application/json'},
**urlopen_kwargs)
return self._parse(result)

View file

@ -618,16 +618,27 @@ class TestBot(object):
# test_sticker module.
def test_timeout_propagation(self, monkeypatch, bot, chat_id):
from telegram.vendor.ptb_urllib3.urllib3.util.timeout import Timeout
class OkException(Exception):
pass
timeout = 500
TIMEOUT = 500
def post(*args, **kwargs):
if kwargs.get('timeout') == 500:
def request_wrapper(*args, **kwargs):
obj = kwargs.get('timeout')
if isinstance(obj, Timeout) and obj._read == TIMEOUT:
raise OkException
monkeypatch.setattr('telegram.utils.request.Request.post', post)
return b'{"ok": true, "result": []}'
monkeypatch.setattr('telegram.utils.request.Request._request_wrapper', request_wrapper)
# Test file uploading
with pytest.raises(OkException):
bot.send_photo(chat_id, open('tests/data/telegram.jpg', 'rb'), timeout=timeout)
bot.send_photo(chat_id, open('tests/data/telegram.jpg', 'rb'), timeout=TIMEOUT)
# Test JSON submition
with pytest.raises(OkException):
bot.get_chat_administrators(chat_id, timeout=TIMEOUT)

View file

@ -44,6 +44,27 @@ class TestInlineKeyboardMarkup(object):
assert message.text == 'Testing InlineKeyboardMarkup'
def test_from_button(self):
inline_keyboard_markup = InlineKeyboardMarkup.from_button(
InlineKeyboardButton(text='button1', callback_data='data1')).inline_keyboard
assert len(inline_keyboard_markup) == 1
assert len(inline_keyboard_markup[0]) == 1
def test_from_row(self):
inline_keyboard_markup = InlineKeyboardMarkup.from_row([
InlineKeyboardButton(text='button1', callback_data='data1'),
InlineKeyboardButton(text='button1', callback_data='data1')]).inline_keyboard
assert len(inline_keyboard_markup) == 1
assert len(inline_keyboard_markup[0]) == 2
def test_from_column(self):
inline_keyboard_markup = InlineKeyboardMarkup.from_column([
InlineKeyboardButton(text='button1', callback_data='data1'),
InlineKeyboardButton(text='button1', callback_data='data1')]).inline_keyboard
assert len(inline_keyboard_markup) == 2
assert len(inline_keyboard_markup[0]) == 1
assert len(inline_keyboard_markup[1]) == 1
def test_expected_values(self, inline_keyboard_markup):
assert inline_keyboard_markup.inline_keyboard == self.inline_keyboard

View file

@ -184,6 +184,24 @@ class TestJobQueue(object):
sleep(0.06)
assert pytest.approx(self.job_time) == expected_time
def test_datetime_with_timezone_job_run_once(self, job_queue):
# Test that run_once jobs work with timezone aware datetimes.
offset = datetime.timedelta(hours=-3)
when = datetime.datetime.now(datetime.timezone(offset))
job_queue.run_once(self.job_run_once, when)
sleep(0.01)
assert self.result == 1
def test_datetime_with_timezone_job_run_repeating(self, job_queue):
# Test that run_repeating jobs work with timezone aware datetimes.
offset = datetime.timedelta(hours=5)
now_with_offset = datetime.datetime.now(datetime.timezone(offset))
job_queue.run_repeating(self.job_run_once, interval=0.01, first=now_with_offset)
sleep(0.015)
assert self.result == 2
def test_time_unit_dt_time_today(self, job_queue):
# Testing running at a specific time today
delta = 0.05

View file

@ -51,6 +51,40 @@ class TestReplyKeyboardMarkup(object):
assert message.text == 'text 2'
def test_from_button(self):
reply_keyboard_markup = ReplyKeyboardMarkup.from_button(
KeyboardButton(text='button1')).keyboard
assert len(reply_keyboard_markup) == 1
assert len(reply_keyboard_markup[0]) == 1
reply_keyboard_markup = ReplyKeyboardMarkup.from_button('button1').keyboard
assert len(reply_keyboard_markup) == 1
assert len(reply_keyboard_markup[0]) == 1
def test_from_row(self):
reply_keyboard_markup = ReplyKeyboardMarkup.from_row([
KeyboardButton(text='button1'),
KeyboardButton(text='button2')]).keyboard
assert len(reply_keyboard_markup) == 1
assert len(reply_keyboard_markup[0]) == 2
reply_keyboard_markup = ReplyKeyboardMarkup.from_row(['button1', 'button2']).keyboard
assert len(reply_keyboard_markup) == 1
assert len(reply_keyboard_markup[0]) == 2
def test_from_column(self):
reply_keyboard_markup = ReplyKeyboardMarkup.from_column([
KeyboardButton(text='button1'),
KeyboardButton(text='button2')]).keyboard
assert len(reply_keyboard_markup) == 2
assert len(reply_keyboard_markup[0]) == 1
assert len(reply_keyboard_markup[1]) == 1
reply_keyboard_markup = ReplyKeyboardMarkup.from_column(['button1', 'button2']).keyboard
assert len(reply_keyboard_markup) == 2
assert len(reply_keyboard_markup[0]) == 1
assert len(reply_keyboard_markup[1]) == 1
def test_expected_values(self, reply_keyboard_markup):
assert isinstance(reply_keyboard_markup.keyboard, list)
assert isinstance(reply_keyboard_markup.keyboard[0][0], KeyboardButton)