use requests instead of urllib if possible; add timeout and decorator to get and post

This commit is contained in:
pecheny 2015-09-14 19:13:22 +03:00
parent cbdeacd22d
commit d5a9c185f0
2 changed files with 94 additions and 14 deletions

View file

@ -619,7 +619,8 @@ class Bot(TelegramObject):
def getUpdates(self, def getUpdates(self,
offset=None, offset=None,
limit=100, limit=100,
timeout=0): timeout=0,
requestTimeout=None):
"""Use this method to receive incoming updates using long polling. """Use this method to receive incoming updates using long polling.
Args: Args:
@ -650,7 +651,11 @@ class Bot(TelegramObject):
if timeout: if timeout:
data['timeout'] = timeout data['timeout'] = timeout
result = request.post(url, data) kwargs = {}
if not requestTimeout is None:
kwargs['timeout'] = requestTimeout
result = request.post(url, data, **kwargs)
if result: if result:
self.logger.info( self.logger.info(

View file

@ -21,6 +21,13 @@
import json import json
REQUESTS = False
try:
import requests
REQUESTS = True
except ImportError:
pass
try: try:
from urllib.request import urlopen, Request from urllib.request import urlopen, Request
from urllib.error import HTTPError from urllib.error import HTTPError
@ -28,9 +35,53 @@ except ImportError:
from urllib2 import urlopen, Request from urllib2 import urlopen, Request
from urllib2 import HTTPError from urllib2 import HTTPError
if REQUESTS:
_universal_post = requests.post
else:
_universal_post = Request
from telegram import (InputFile, TelegramError) from telegram import (InputFile, TelegramError)
def retry(maxretries):
"""@retry(x) decorates a function to run x times
if it doesn't return correctly.
Args:
maxretries:
Max number of retries until exception is raised further.
Returns:
The decorated function.
"""
def retry_decorator(func):
def retry_wrapper(*args, **kwargs):
# logger.debug('Trying {} with arguments: {}, {}.'
# .format(func.__name__, args, kwargs))
usedtries = 0
while usedtries <= (maxretries - 1):
try:
reply = func(*args, **kwargs)
if reply:
# logger.debug(
# 'Reply: {}'.format(reply.replace('\n','\\n')))
pass
else:
# logger.debug(
# 'Reply: none')
pass
return reply
except:
if usedtries < (maxretries - 1):
# logger.debug('Exception in {}: {}'
# .format(func.__name__, args, kwargs))
usedtries += 1
else:
raise
retry_wrapper.fc = func.func_code
return retry_wrapper
return retry_decorator
def _parse(json_data): def _parse(json_data):
"""Try and parse the JSON returned from Telegram and return an empty """Try and parse the JSON returned from Telegram and return an empty
dictionary if there is any error. dictionary if there is any error.
@ -49,29 +100,45 @@ def _parse(json_data):
return data['result'] return data['result']
@retry(3)
def get(url): def get(url, timeout=None):
"""Request an URL. """Request an URL.
Args: Args:
url: url:
The web location we want to retrieve. The web location we want to retrieve.
timeout:
(optional) timeout in seconds. Raises exception
if request exceeds it.
Returns: Returns:
A JSON object. A JSON object.
""" """
result = urlopen(url).read()
kwargs = {}
if not timeout is None:
kwargs['timeout'] = timeout
if REQUESTS:
result = requests.get(url, **kwargs).content
else:
result = urlopen(url, **kwargs).read()
return _parse(result) return _parse(result)
@retry(3)
def post(url, def post(url,
data): data,
timeout=None):
"""Request an URL. """Request an URL.
Args: Args:
url: url:
The web location we want to retrieve. The web location we want to retrieve.
data: data:
A dict of (str, unicode) key/value pairs. A dict of (str, unicode) key/value pairs.
timeout:
(optional) timeout in seconds. Raises exception
if request exceeds it.
Returns: Returns:
A JSON object. A JSON object.
@ -79,15 +146,23 @@ def post(url,
try: try:
if InputFile.is_inputfile(data): if InputFile.is_inputfile(data):
data = InputFile(data) data = InputFile(data)
request = Request(url, kwargs = {
data=data.to_form(), 'data': data.to_form(),
headers=data.headers) 'headers': data.headers
}
else: else:
data = json.dumps(data) data = json.dumps(data)
request = Request(url, kwargs = {
data=data.encode(), 'data': data.encode(),
headers={'Content-Type': 'application/json'}) 'headers': {'Content-Type': 'application/json'}
}
if not timeout is None:
kwargs['timeout'] = timeout
request = _universal_post(url, **kwargs)
if REQUESTS:
request.raise_for_status()
result = request.content
else:
result = urlopen(request).read() result = urlopen(request).read()
except HTTPError as error: except HTTPError as error:
if error.getcode() == 403: if error.getcode() == 403: