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,
offset=None,
limit=100,
timeout=0):
timeout=0,
requestTimeout=None):
"""Use this method to receive incoming updates using long polling.
Args:
@ -650,7 +651,11 @@ class Bot(TelegramObject):
if 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:
self.logger.info(

View file

@ -21,6 +21,13 @@
import json
REQUESTS = False
try:
import requests
REQUESTS = True
except ImportError:
pass
try:
from urllib.request import urlopen, Request
from urllib.error import HTTPError
@ -28,9 +35,53 @@ except ImportError:
from urllib2 import urlopen, Request
from urllib2 import HTTPError
if REQUESTS:
_universal_post = requests.post
else:
_universal_post = Request
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):
"""Try and parse the JSON returned from Telegram and return an empty
dictionary if there is any error.
@ -49,29 +100,45 @@ def _parse(json_data):
return data['result']
def get(url):
@retry(3)
def get(url, timeout=None):
"""Request an URL.
Args:
url:
The web location we want to retrieve.
timeout:
(optional) timeout in seconds. Raises exception
if request exceeds it.
Returns:
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)
@retry(3)
def post(url,
data):
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:
(optional) timeout in seconds. Raises exception
if request exceeds it.
Returns:
A JSON object.
@ -79,16 +146,24 @@ def post(url,
try:
if InputFile.is_inputfile(data):
data = InputFile(data)
request = Request(url,
data=data.to_form(),
headers=data.headers)
kwargs = {
'data': data.to_form(),
'headers': data.headers
}
else:
data = json.dumps(data)
request = Request(url,
data=data.encode(),
headers={'Content-Type': 'application/json'})
result = urlopen(request).read()
kwargs = {
'data': data.encode(),
'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()
except HTTPError as error:
if error.getcode() == 403:
raise TelegramError('Unauthorized')