Control the read timeout from telegram servers

refs #495
refs #364
This commit is contained in:
Noam Meltzer 2017-01-06 23:48:34 +02:00
parent 68a7d9fa1b
commit 58dddfd9c3
5 changed files with 253 additions and 130 deletions

View file

@ -158,9 +158,14 @@ class Bot(TelegramObject):
return decorator
@log
def getMe(self, **kwargs):
def getMe(self, timeout=None, **kwargs):
"""A simple method for testing your bot's auth token.
Args:
timeout (Optional[int|float]): If this value is specified, use it as the read timeout
from the server (instead of the one specified during creation of the connection
pool).
Returns:
:class:`telegram.User`: A :class:`telegram.User` instance representing that bot if the
credentials are valid, `None` otherwise.
@ -171,7 +176,7 @@ class Bot(TelegramObject):
"""
url = '{0}/getMe'.format(self.base_url)
result = self._request.get(url)
result = self._request.get(url, timeout=timeout)
self.bot = User.de_json(result, self)
@ -211,8 +216,9 @@ class Bot(TelegramObject):
interface options. A JSON-serialized object for an inline
keyboard, custom reply keyboard, instructions to remove reply
keyboard or to force a reply from the user.
timeout (Optional[float]): If this value is specified, use it as
the definitive timeout (in seconds) for urlopen() operations.
timeout (Optional[int|float]): If this value is specified, use it as the read timeout
from the server (instead of the one specified during creation of the connection
pool).
**kwargs (dict): Arbitrary keyword arguments.
Returns:
@ -251,8 +257,9 @@ class Bot(TelegramObject):
message_id: Unique message identifier.
disable_notification (Optional[bool]): Sends the message silently. iOS users will not
receive a notification, Android users will receive a notification with no sound.
timeout (Optional[float]): If this value is specified, use it as
the definitive timeout (in seconds) for urlopen() operations.
timeout (Optional[int|float]): If this value is specified, use it as the read timeout
from the server (instead of the one specified during creation of the connection
pool).
**kwargs (dict): Arbitrary keyword arguments.
Returns:
@ -301,8 +308,9 @@ class Bot(TelegramObject):
reply_markup (Optional[:class:`telegram.ReplyMarkup`]): Additional interface options. A
JSON-serialized object for an inline keyboard, custom reply keyboard, instructions
to remove reply keyboard or to force a reply from the user.
timeout (Optional[float]): If this value is specified, use it as the definitive timeout
(in seconds) for urlopen() operations.
timeout (Optional[int|float]): If this value is specified, use it as the read timeout
from the server (instead of the one specified during creation of the connection
pool).
**kwargs (dict): Arbitrary keyword arguments.
Returns:
@ -362,8 +370,9 @@ class Bot(TelegramObject):
reply_markup (Optional[:class:`telegram.ReplyMarkup`]): Additional interface options. A
JSON-serialized object for an inline keyboard, custom reply keyboard, instructions
to remove reply keyboard or to force a reply from the user.
timeout (Optional[float]): If this value is specified, use it as the definitive timeout
(in seconds) for urlopen() operations.
timeout (Optional[int|float]): If this value is specified, use it as the read timeout
from the server (instead of the one specified during creation of the connection
pool).
**kwargs (dict): Arbitrary keyword arguments.
Returns:
@ -417,8 +426,9 @@ class Bot(TelegramObject):
reply_markup (Optional[:class:`telegram.ReplyMarkup`]): Additional interface options. A
JSON-serialized object for an inline keyboard, custom reply keyboard, instructions
to remove reply keyboard or to force a reply from the user.
timeout (Optional[float]): If this value is specified, use it as the definitive timeout
(in seconds) for urlopen() operations.
timeout (Optional[int|float]): If this value is specified, use it as the read timeout
from the server (instead of the one specified during creation of the connection
pool).
**kwargs (dict): Arbitrary keyword arguments.
Returns:
@ -463,8 +473,9 @@ class Bot(TelegramObject):
reply_markup (Optional[:class:`telegram.ReplyMarkup`]): Additional interface options. A
JSON-serialized object for an inline keyboard, custom reply keyboard, instructions
to remove reply keyboard or to force a reply from the user.
timeout (Optional[float]): If this value is specified, use it as the definitive timeout
(in seconds) for urlopen() operations.
timeout (Optional[int|float]): If this value is specified, use it as the read timeout
from the server (instead of the one specified during creation of the connection
pool).
**kwargs (dict): Arbitrary keyword arguments.
Returns:
@ -510,8 +521,9 @@ class Bot(TelegramObject):
reply_markup (Optional[:class:`telegram.ReplyMarkup`]): Additional interface options. A
JSON-serialized object for an inline keyboard, custom reply keyboard, instructions
to remove reply keyboard or to force a reply from the user.
timeout (Optional[float]): If this value is specified, use it as the definitive timeout
(in seconds) for urlopen() operations.
timeout (Optional[int|float]): If this value is specified, use it as the read timeout
from the server (instead of the one specified during creation of the connection
pool).
Returns:
:class:`telegram.Message`: On success, instance representing the message posted.
@ -563,8 +575,9 @@ class Bot(TelegramObject):
reply_markup (Optional[:class:`telegram.ReplyMarkup`]): Additional interface options. A
JSON-serialized object for an inline keyboard, custom reply keyboard, instructions
to remove reply keyboard or to force a reply from the user.
timeout (Optional[float]): If this value is specified, use it as the definitive timeout
(in seconds) for urlopen() operations.
timeout (Optional[int|float]): If this value is specified, use it as the read timeout
from the server (instead of the one specified during creation of the connection
pool).
**kwargs (dict): Arbitrary keyword arguments.
Returns:
@ -609,8 +622,9 @@ class Bot(TelegramObject):
reply_markup (Optional[:class:`telegram.ReplyMarkup`]): Additional interface options. A
JSON-serialized object for an inline keyboard, custom reply keyboard, instructions
to remove reply keyboard or to force a reply from the user.
timeout (Optional[float]): If this value is specified, use it as the definitive timeout
(in seconds) for urlopen() operations.
timeout (Optional[int|float]): If this value is specified, use it as the read timeout
from the server (instead of the one specified during creation of the connection
pool).
**kwargs (dict): Arbitrary keyword arguments.
Returns:
@ -658,8 +672,9 @@ class Bot(TelegramObject):
reply_markup (Optional[:class:`telegram.ReplyMarkup`]): Additional interface options. A
JSON-serialized object for an inline keyboard, custom reply keyboard, instructions
to remove reply keyboard or to force a reply from the user.
timeout (Optional[float]): If this value is specified, use it as the definitive timeout
(in seconds) for urlopen() operations.
timeout (Optional[int|float]): If this value is specified, use it as the read timeout
from the server (instead of the one specified during creation of the connection
pool).
**kwargs (dict): Arbitrary keyword arguments.
Returns:
@ -712,8 +727,9 @@ class Bot(TelegramObject):
reply_markup (Optional[:class:`telegram.ReplyMarkup`]): Additional interface options. A
JSON-serialized object for an inline keyboard, custom reply keyboard, instructions
to remove reply keyboard or to force a reply from the user.
timeout (Optional[float]): If this value is specified, use it as the definitive timeout
(in seconds) for urlopen() operations.
timeout (Optional[int|float]): If this value is specified, use it as the read timeout
from the server (instead of the one specified during creation of the connection
pool).
**kwargs (dict): Arbitrary keyword arguments.
Returns:
@ -734,7 +750,7 @@ class Bot(TelegramObject):
@log
@message
def sendGame(self, chat_id, game_short_name, **kwargs):
def sendGame(self, chat_id, game_short_name, timeout=None, **kwargs):
"""Use this method to send a game.
Args:
@ -751,8 +767,9 @@ class Bot(TelegramObject):
reply_markup (Optional[:class:`telegram.ReplyMarkup`]): Additional interface options.
A JSON-serialized object for an inline keyboard, custom reply keyboard,
instructions to remove reply keyboard or to force a reply from the user.
timeout (Optional[float]): If this value is specified, use it as
the definitive timeout (in seconds) for urlopen() operations.
timeout (Optional[int|float]): If this value is specified, use it as the read timeout
from the server (instead of the one specified during creation of the connection
pool).
Returns:
:class:`telegram.Message`: On success, the sent message is returned.
@ -769,7 +786,7 @@ class Bot(TelegramObject):
@log
@message
def sendChatAction(self, chat_id, action, **kwargs):
def sendChatAction(self, chat_id, action, timeout=None, **kwargs):
"""Use this method when you need to tell the user that something is happening on the bot's
side. The status is set for 5 seconds or less (when a message arrives from your bot,
Telegram clients clear its typing status).
@ -785,6 +802,9 @@ class Bot(TelegramObject):
- ChatAction.UPLOAD_AUDIO for audio files,
- ChatAction.UPLOAD_DOCUMENT for general files,
- ChatAction.FIND_LOCATION for location data.
timeout (Optional[int|float]): If this value is specified, use it as the read timeout
from the server (instead of the one specified during creation of the connection
pool).
**kwargs (dict): Arbitrary keyword arguments.
"""
@ -826,8 +846,9 @@ class Bot(TelegramObject):
start message with the parameter switch_pm_parameter.
switch_pm_parameter (Optional[str]): Parameter for the start message sent to the bot
when user presses the switch button.
timeout (Optional[float]): If this value is specified, use it as the definitive timeout
(in seconds) for urlopen() operations.
timeout (Optional[int|float]): If this value is specified, use it as the read timeout
from the server (instead of the one specified during creation of the connection
pool).
**kwargs (dict): Arbitrary keyword arguments.
Returns:
@ -868,8 +889,9 @@ class Bot(TelegramObject):
default, all photos are returned.
limit (Optional[int]): Limits the number of photos to be retrieved. Values between
1-100 are accepted. Defaults to 100.
timeout (Optional[float]): If this value is specified, use it as the definitive timeout
(in seconds) for urlopen() operations.
timeout (Optional[int|float]): If this value is specified, use it as the read timeout
from the server (instead of the one specified during creation of the connection
pool).
**kwargs (dict): Arbitrary keyword arguments.
Returns:
@ -900,8 +922,9 @@ class Bot(TelegramObject):
Args:
file_id: File identifier to get info about.
timeout (Optional[float]): If this value is specified, use it as the definitive timeout
(in seconds) for urlopen() operations.
timeout (Optional[int|float]): If this value is specified, use it as the read timeout
from the server (instead of the one specified during creation of the connection
pool).
**kwargs (dict): Arbitrary keyword arguments.
Returns:
@ -934,8 +957,9 @@ class Bot(TelegramObject):
chat_id: Unique identifier for the target group or username of the target supergroup
(in the format @supergroupusername).
user_id: Unique identifier of the target user.
timeout (Optional[float]): If this value is specified, use it as the definitive timeout
(in seconds) for urlopen() operations.
timeout (Optional[int|float]): If this value is specified, use it as the read timeout
from the server (instead of the one specified during creation of the connection
pool).
**kwargs (dict): Arbitrary keyword arguments.
Returns:
@ -963,8 +987,9 @@ class Bot(TelegramObject):
chat_id: Unique identifier for the target group or username of the target supergroup
(in the format @supergroupusername).
user_id: Unique identifier of the target user.
timeout (Optional[float]): If this value is specified, use it as the definitive timeout
(in seconds) for urlopen() operations.
timeout (Optional[int|float]): If this value is specified, use it as the read timeout
from the server (instead of the one specified during creation of the connection
pool).
**kwargs (dict): Arbitrary keyword arguments.
Returns:
@ -1005,8 +1030,9 @@ class Bot(TelegramObject):
cache_time (Optional[int]): The maximum amount of time in seconds that the result of
the callback query may be cached client-side. Telegram apps will support caching
starting in version 3.14. Defaults to 0.
timeout (Optional[float]): If this value is specified, use it as the definitive timeout
(in seconds) for urlopen() operations.
timeout (Optional[int|float]): If this value is specified, use it as the read timeout
from the server (instead of the one specified during creation of the connection
pool).
**kwargs (dict): Arbitrary keyword arguments.
Returns:
@ -1062,8 +1088,9 @@ class Bot(TelegramObject):
reply_markup (Optional[:class:`telegram.ReplyMarkup`]): Additional interface options. A
JSON-serialized object for an inline keyboard, custom reply keyboard, instructions
to remove reply keyboard or to force a reply from the user.
timeout (Optional[float]): If this value is specified, use it as the definitive timeout
(in seconds) for urlopen() operations.
timeout (Optional[int|float]): If this value is specified, use it as the read timeout
from the server (instead of the one specified during creation of the connection
pool).
**kwargs (dict): Arbitrary keyword arguments.
Returns:
@ -1115,8 +1142,9 @@ class Bot(TelegramObject):
caption (Optional[str]): New caption of the message.
reply_markup (Optional[:class:`telegram.InlineKeyboardMarkup`]): A JSON-serialized
object for an inline keyboard.
timeout (Optional[float]): If this value is specified, use it as the definitive timeout
(in seconds) for urlopen() operations.
timeout (Optional[int|float]): If this value is specified, use it as the read timeout
from the server (instead of the one specified during creation of the connection
pool).
**kwargs (dict): Arbitrary keyword arguments.
Returns:
@ -1169,8 +1197,9 @@ class Bot(TelegramObject):
specified. Identifier of the inline message.
reply_markup (Optional[:class:`telegram.InlineKeyboardMarkup`]): A JSON-serialized
object for an inline keyboard.
timeout (Optional[float]): If this value is specified, use it as the definitive timeout
(in seconds) for urlopen() operations.
timeout (Optional[int|float]): If this value is specified, use it as the read timeout
from the server (instead of the one specified during creation of the connection
pool).
**kwargs (dict): Arbitrary keyword arguments.
Returns:
@ -1201,7 +1230,13 @@ class Bot(TelegramObject):
return url, data
@log
def getUpdates(self, offset=None, limit=100, timeout=0, network_delay=5., **kwargs):
def getUpdates(self,
offset=None,
limit=100,
timeout=0,
network_delay=None,
read_latency=2.,
**kwargs):
"""Use this method to receive incoming updates using long polling.
Args:
@ -1213,13 +1248,25 @@ class Bot(TelegramObject):
limit (Optional[int]): Limits the number of updates to be retrieved. Values between
1-100 are accepted. Defaults to 100.
timeout (Optional[int]): Timeout in seconds for long polling. Defaults to 0, i.e. usual
short polling.
network_delay (Optional[float]): Additional timeout in seconds to allow the response
from Telegram servers. This should cover network latency around the globe, SSL
handshake and slowness of the Telegram servers (which unfortunately happens a lot
recently - 2016-05-28). Defaults to 5.
short polling. Be careful not to set this timeout too high, as the connection might
be dropped and there's no way of knowing it immediately (so most likely the failure
will be detected after the timeout had passed).
network_delay: Deprecated. Will be honoured as `read_latency` for a while but will be
removed in the future.
read_latency (Optional[float|int]): Grace time in seconds for receiving the reply from
server. Will be added to the `timeout` value and used as the read timeout from
server (Default: 2).
**kwargs (dict): Arbitrary keyword arguments.
Notes:
The main problem with long polling is that a connection will be dropped and we won't
be getting the notification in time for it. For that, we need to use long polling, but
not too long as well read latency which is short, but not too short.
Long polling improves performance, but if it's too long and the connection is dropped
on many cases we won't know the connection dropped before the long polling timeout and
the read latency time had passed. If you experience connection timeouts, you should
tune these settings.
Returns:
list[:class:`telegram.Update`]
@ -1229,6 +1276,10 @@ class Bot(TelegramObject):
"""
url = '{0}/getUpdates'.format(self.base_url)
if network_delay is not None:
warnings.warn('network_delay is deprecated, use read_latency instead')
read_latency = network_delay
data = {'timeout': timeout}
if offset:
@ -1236,9 +1287,12 @@ class Bot(TelegramObject):
if limit:
data['limit'] = limit
urlopen_timeout = timeout + network_delay
result = self._request.post(url, data, timeout=urlopen_timeout)
# Ideally we'd use an aggressive read timeout for the polling. However,
# * Short polling should return within 2 seconds.
# * Long polling poses a different problem: the connection might have been dropped while
# waiting for the server to return and there's no way of knowing the connection had been
# dropped in real time.
result = self._request.post(url, data, timeout=float(read_latency) + float(timeout))
if result:
self.logger.debug('Getting updates: %s', [u['update_id'] for u in result])
@ -1256,9 +1310,10 @@ class Bot(TelegramObject):
Args:
webhook_url: HTTPS url to send updates to. Use an empty string to remove webhook
integration
timeout (Optional[float]): If this value is specified, use it as
the definitive timeout (in seconds) for urlopen() operations.
integration.
timeout (Optional[int|float]): If this value is specified, use it as the read timeout
from the server (instead of the one specified during creation of the connection
pool).
**kwargs (dict): Arbitrary keyword arguments.
Returns:
@ -1288,8 +1343,9 @@ class Bot(TelegramObject):
Args:
chat_id: Unique identifier for the target chat or username of the target channel (in
the format @channelusername).
timeout (Optional[float]): If this value is specified, use it as the definitive timeout
(in seconds) for urlopen() operations.
timeout (Optional[int|float]): If this value is specified, use it as the read timeout
from the server (instead of the one specified during creation of the connection
pool).
**kwargs (dict): Arbitrary keyword arguments.
Returns:
@ -1315,8 +1371,9 @@ class Bot(TelegramObject):
Args:
chat_id: Unique identifier for the target chat or username of the target channel (in
the format @channelusername).
timeout (Optional[float]): If this value is specified, use it as the definitive timeout
(in seconds) for urlopen() operations.
timeout (Optional[int|float]): If this value is specified, use it as the read timeout
from the server (instead of the one specified during creation of the connection
pool).
**kwargs (dict): Arbitrary keyword arguments.
Returns:
@ -1345,8 +1402,9 @@ class Bot(TelegramObject):
Args:
chat_id: Unique identifier for the target chat or username of the target channel (in
the format @channelusername).
timeout (Optional[float]): If this value is specified, use it as the definitive timeout
(in seconds) for urlopen() operations.
timeout (Optional[int|float]): If this value is specified, use it as the read timeout
from the server (instead of the one specified during creation of the connection
pool).
**kwargs (dict): Arbitrary keyword arguments.
Returns:
@ -1371,8 +1429,9 @@ class Bot(TelegramObject):
Args:
chat_id: Unique identifier for the target chat or username of the target channel (in
the format @channelusername).
timeout (Optional[float]): If this value is specified, use it as the definitive timeout
(in seconds) for urlopen() operations.
timeout (Optional[int|float]): If this value is specified, use it as the read timeout
from the server (instead of the one specified during creation of the connection
pool).
**kwargs (dict): Arbitrary keyword arguments.
Returns:
@ -1398,8 +1457,9 @@ class Bot(TelegramObject):
chat_id: Unique identifier for the target chat or username of the target channel (in
the format @channelusername).
user_id: Unique identifier of the target user.
timeout (Optional[float]): If this value is specified, use it as the definitive timeout
(in seconds) for urlopen() operations.
timeout (Optional[int|float]): If this value is specified, use it as the read timeout
from the server (instead of the one specified during creation of the connection
pool).
**kwargs (dict): Arbitrary keyword arguments.
Returns:
@ -1417,11 +1477,16 @@ class Bot(TelegramObject):
return ChatMember.de_json(result, self)
def getWebhookInfo(self, **kwargs):
def getWebhookInfo(self, timeout=None, **kwargs):
"""Use this method to get current webhook status.
If the bot is using getUpdates, will return an object with the url field empty.
Args:
timeout (Optional[int|float]): If this value is specified, use it as the read timeout
from the server (instead of the one specified during creation of the connection
pool).
Returns:
:class: `telegram.WebhookInfo`
@ -1430,7 +1495,7 @@ class Bot(TelegramObject):
data = {}
result = self._request.post(url, data, timeout=kwargs.get('timeout'))
result = self._request.post(url, data, timeout=timeout)
return WebhookInfo.de_json(result, self)
@ -1443,6 +1508,7 @@ class Bot(TelegramObject):
edit_message=None,
force=None,
disable_edit_message=None,
timeout=None,
**kwargs):
"""Use this method to set the score of the specified user in a game.
@ -1462,10 +1528,9 @@ class Bot(TelegramObject):
automatically edited to include the current scoreboard.
edit_message (Optional[bool]): Deprecated. Has the opposite logic for
`disable_edit_message`.
Keyword Args:
timeout (Optional[float]): If this value is specified, use it as the definitive timeout
(in seconds) for urlopen() operations.
timeout (Optional[int|float]): If this value is specified, use it as the read timeout
from the server (instead of the one specified during creation of the connection
pool).
Returns:
:class:`telegram.Message` or True: The edited message, or if the
@ -1493,7 +1558,7 @@ class Bot(TelegramObject):
else:
warnings.warn('edit_message is ignored when disable_edit_message is used')
result = self._request.post(url, data, timeout=kwargs.get('timeout'))
result = self._request.post(url, data, timeout=timeout)
if result is True:
return result
else:
@ -1504,9 +1569,15 @@ class Bot(TelegramObject):
chat_id=None,
message_id=None,
inline_message_id=None,
timeout=None,
**kwargs):
"""Use this method to get data for high score tables.
Args:
timeout (Optional[int|float]): If this value is specified, use it as the read timeout
from the server (instead of the one specified during creation of the connection
pool).
Returns:
list[:class:`telegram.GameHighScore`]: Scores of the specified user and several of his
neighbors in a game.
@ -1523,7 +1594,7 @@ class Bot(TelegramObject):
if inline_message_id:
data['inline_message_id'] = inline_message_id
result = self._request.post(url, data, timeout=kwargs.get('timeout'))
result = self._request.post(url, data, timeout=timeout)
return [GameHighScore.de_json(hs, self) for hs in result]

View file

@ -22,6 +22,7 @@ Telegram bots intuitive."""
import logging
import os
import ssl
import warnings
from threading import Thread, Lock, current_thread, Event
from time import sleep
import subprocess
@ -61,6 +62,8 @@ class Updater(object):
bot (Optional[Bot]): A pre-initialized bot instance. If a pre-initizlied bot is used, it is
the user's responsibility to create it using a `Request` instance with a large enough
connection pool.
request_kwargs (Optional[dict]): Keyword args to control the creation of a request object
(ignored if `bot` argument is used).
Raises:
ValueError: If both `token` and `bot` are passed or none of them.
@ -68,7 +71,7 @@ class Updater(object):
"""
_request = None
def __init__(self, token=None, base_url=None, workers=4, bot=None):
def __init__(self, token=None, base_url=None, workers=4, bot=None, request_kwargs=None):
if (token is None) and (bot is None):
raise ValueError('`token` or `bot` must be passed')
if (token is not None) and (bot is not None):
@ -83,7 +86,11 @@ class Updater(object):
# * 1 for polling Updater (even if webhook is used, we can spare a connection)
# * 1 for JobQueue
# * 1 for main thread
self._request = Request(con_pool_size=workers + 4)
if request_kwargs is None:
request_kwargs = {}
if 'con_pool_size' not in request_kwargs:
request_kwargs['con_pool_size'] = workers + 4
self._request = Request(**request_kwargs)
self.bot = Bot(token, base_url, request=self._request)
self.update_queue = Queue()
self.job_queue = JobQueue(self.bot)
@ -122,9 +129,10 @@ class Updater(object):
def start_polling(self,
poll_interval=0.0,
timeout=10,
network_delay=5.,
network_delay=None,
clean=False,
bootstrap_retries=0):
bootstrap_retries=0,
read_latency=2.):
"""
Starts polling updates from Telegram.
@ -134,7 +142,8 @@ class Updater(object):
timeout (Optional[float]): Passed to Bot.getUpdates
network_delay (Optional[float]): Passed to Bot.getUpdates
network_delay: Deprecated. Will be honoured as `read_latency` for a while but will be
removed in the future.
clean (Optional[bool]): Whether to clean any pending updates on Telegram servers before
actually starting to poll. Default is False.
@ -143,13 +152,22 @@ class Updater(object):
will retry on failures on the Telegram server.
| < 0 - retry indefinitely
| 0 - no retries (default)
| 0 - no retries (default)
| > 0 - retry up to X times
read_latency (Optional[float|int]): Grace time in seconds for receiving the reply from
server. Will be added to the `timeout` value and used as the read timeout from
server (Default: 2).
Returns:
Queue: The update queue that can be filled from the main thread
"""
if network_delay is not None:
warnings.warn('network_delay is deprecated, use read_latency instead')
read_latency = network_delay
with self.__lock:
if not self.running:
self.running = True
@ -158,7 +176,7 @@ class Updater(object):
self.job_queue.start()
self._init_thread(self.dispatcher.start, "dispatcher")
self._init_thread(self._start_polling, "updater", poll_interval, timeout,
network_delay, bootstrap_retries, clean)
read_latency, bootstrap_retries, clean)
# Return the update queue so the main thread can insert updates
return self.update_queue
@ -215,7 +233,7 @@ class Updater(object):
# Return the update queue so the main thread can insert updates
return self.update_queue
def _start_polling(self, poll_interval, timeout, network_delay, bootstrap_retries, clean):
def _start_polling(self, poll_interval, timeout, read_latency, bootstrap_retries, clean):
"""
Thread target of thread 'updater'. Runs in background, pulls
updates from Telegram and inserts them in the update queue of the
@ -230,7 +248,7 @@ class Updater(object):
while self.running:
try:
updates = self.bot.getUpdates(
self.last_update_id, timeout=timeout, network_delay=network_delay)
self.last_update_id, timeout=timeout, read_latency=read_latency)
except RetryAfter as e:
self.logger.info(str(e))
cur_interval = 0.5 + e.retry_after

View file

@ -65,20 +65,24 @@ class File(TelegramObject):
return File(bot=bot, **data)
def download(self, custom_path=None, out=None):
def download(self, custom_path=None, out=None, timeout=None):
"""
Download this file. By default, the file is saved in the current working directory with its
original filename as reported by Telegram. If a ``custom_path`` is supplied, it will be
saved to that path instead. If ``out`` is defined, the file contents will be saved to that
object using the ``out.write`` method. ``custom_path`` and ``out`` are mutually exclusive.
Keyword Args:
Args:
custom_path (Optional[str]): Custom path.
out (Optional[object]): A file-like object. Must be opened in binary mode, if
applicable.
timeout (Optional[int|float]): If this value is specified, use it as the read timeout
from the server (instead of the one specified during creation of the connection
pool).
Raises:
ValueError: If both ``custom_path`` and ``out`` are passed.
"""
if custom_path is not None and out is not None:
@ -96,4 +100,4 @@ class File(TelegramObject):
else:
filename = basename(url)
self.bot.request.download(url, filename)
self.bot.request.download(url, filename, timeout=timeout)

View file

@ -17,18 +17,19 @@
# You should have received a copy of the GNU Lesser Public License
# along with this program. If not, see [http://www.gnu.org/licenses/].
"""This module contains methods to make POST and GET requests"""
import os
import socket
import logging
try:
import ujson as json
except ImportError:
import json
import os
import socket
import logging
import certifi
import urllib3
from urllib3.connection import HTTPConnection
from urllib3.util.timeout import Timeout
from telegram import (InputFile, TelegramError)
from telegram.error import (Unauthorized, NetworkError, TimedOut, BadRequest, ChatMigrated,
@ -43,23 +44,40 @@ class Request(object):
telegram servers.
Args:
con_pool_size (int): Number of connections to keep in the connection pool.
proxy_url (str): The URL to the proxy server. For example: `http://127.0.0.1:3128`.
urllib3_proxy_kwargs (dict): Arbitrary arguments passed as-is to `urllib3.ProxyManager`.
This value will be ignored if proxy_url is not set.
connect_timeout (int|float): The maximum amount of time (in seconds) to wait for a
connection attempt to a server to succeed. None will set an infinite timeout for
connection attempts. (default: 5.)
read_timeout (int|float): The maximum amount of time (in seconds) to wait between
consecutive read operations for a response from the server. None will set an infinite
timeout. This value is usually overridden by the various ``telegram.Bot`` methods.
(default: 5.)
"""
def __init__(self, con_pool_size=1, proxy_url=None, urllib3_proxy_kwargs=None):
def __init__(self,
con_pool_size=1,
proxy_url=None,
urllib3_proxy_kwargs=None,
connect_timeout=5.,
read_timeout=5.):
if urllib3_proxy_kwargs is None:
urllib3_proxy_kwargs = dict()
self._connect_timeout = connect_timeout
kwargs = dict(
maxsize=con_pool_size,
cert_reqs='CERT_REQUIRED',
ca_certs=certifi.where(),
socket_options=HTTPConnection.default_socket_options + [
(socket.SOL_SOCKET, socket.SO_KEEPALIVE, 1),
])
],
timeout=urllib3.Timeout(
connect=self._connect_timeout, read=read_timeout),)
# Set a proxy according to the following order:
# * proxy defined in proxy_url (+ urllib3_proxy_kwargs)
@ -163,33 +181,14 @@ class Request(object):
else:
raise NetworkError('{0} ({1})'.format(message, resp.status))
def get(self, url):
def get(self, url, timeout=None):
"""Request an URL.
Args:
url:
The web location we want to retrieve.
Returns:
A JSON object.
"""
result = self._request_wrapper('GET', url)
return self._parse(result)
def post(self, url, data, timeout=None):
"""Request an URL.
Args:
url:
The web location we want to retrieve.
data:
A dict of (str, unicode) key/value pairs.
timeout:
float. If this value is specified, use it as the definitive timeout (in
seconds) for urlopen() operations. [Optional]
Notes:
If neither `timeout` nor `data['timeout']` is specified. The underlying
defaults are used.
url (str): The web location we want to retrieve.
timeout (Optional[int|float]): If this value is specified, use it as the read timeout
from the server (instead of the one specified during creation of the connection
pool).
Returns:
A JSON object.
@ -198,7 +197,28 @@ class Request(object):
urlopen_kwargs = {}
if timeout is not None:
urlopen_kwargs['timeout'] = timeout
urlopen_kwargs['timeout'] = Timeout(read=timeout, connect=self._connect_timeout)
result = self._request_wrapper('GET', url, **urlopen_kwargs)
return self._parse(result)
def post(self, url, data, timeout=None):
"""Request an URL.
Args:
url (str): The web location we want to retrieve.
data (dict[str, str]): A dict of key/value pairs. Note: On py2.7 value is unicode.
timeout (Optional[int|float]): If this value is specified, use it as the read timeout
from the server (instead of the one specified during creation of the connection
pool).
Returns:
A JSON object.
"""
urlopen_kwargs = {}
if timeout is not None:
urlopen_kwargs['timeout'] = Timeout(read=timeout, connect=self._connect_timeout)
if InputFile.is_inputfile(data):
data = InputFile(data)
@ -215,24 +235,34 @@ class Request(object):
return self._parse(result)
def retrieve(self, url):
def retrieve(self, url, timeout=None):
"""Retrieve the contents of a file by its URL.
Args:
url:
The web location we want to retrieve.
"""
return self._request_wrapper('GET', url)
def download(self, url, filename):
Args:
url (str): The web location we want to retrieve.
timeout (Optional[int|float]): If this value is specified, use it as the read timeout
from the server (instead of the one specified during creation of the connection
pool).
"""
urlopen_kwargs = {}
if timeout is not None:
urlopen_kwargs['timeout'] = Timeout(read=timeout, connect=self._connect_timeout)
return self._request_wrapper('GET', url, **urlopen_kwargs)
def download(self, url, filename, timeout=None):
"""Download a file by its URL.
Args:
url:
The web location we want to retrieve.
url (str): The web location we want to retrieve.
timeout (Optional[int|float]): If this value is specified, use it as the read timeout
from the server (instead of the one specified during creation of the connection
pool).
filename:
The filename within the path to download the file.
"""
buf = self.retrieve(url)
buf = self.retrieve(url, timeout=timeout)
with open(filename, 'wb') as fobj:
fobj.write(buf)

View file

@ -809,7 +809,7 @@ class MockBot(object):
self.bootstrap_attempts += 1
raise self.bootstrap_err
def getUpdates(self, offset=None, limit=100, timeout=0, network_delay=2.):
def getUpdates(self, offset=None, limit=100, timeout=0, network_delay=None, read_latency=2.):
if self.raise_error:
raise TelegramError('Test Error 2')