You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

60 lines
1.9 KiB

import json
import socket
import urllib.request
import urllib.parse
from collections import defaultdict
from urllib.error import HTTPError
LAUNCHPAD_URL = 'https://api.launchpad.net/1.0/'
class Rest:
"""Wrap common REST APIs with some retry logic."""
def query_rest_api(self, obj, query):
"""Do a REST request
Request <obj>?<query>.
Returns string received from web service.
Raises HTTPError, ValueError, or ConnectionError based on different
transient failures connecting.
"""
for retry in range(5):
url = '%s?%s' % (obj, urllib.parse.urlencode(query))
try:
with urllib.request.urlopen(url, timeout=30) as req:
code = req.getcode()
if 200 <= code < 300:
return req.read().decode('UTF-8')
raise ConnectionError('Failed to reach launchpad, HTTP %s'
% code)
except socket.timeout as e:
self.log("Timeout downloading '%s', will retry %d more times."
% (url, 5 - retry - 1))
exc = e
except HTTPError as e:
if e.code != 503:
raise
self.log("Caught error 503 downloading '%s', will retry %d more times."
% (url, 5 - retry - 1))
exc = e
else:
raise exc
def query_lp_rest_api(self, obj, query):
"""Do a Launchpad REST request
Request <LAUNCHPAD_URL><obj>?<query>.
Returns dict of parsed json result from launchpad.
Raises HTTPError, ValueError, or ConnectionError based on different
transient failures connecting to launchpad.
"""
if not obj.startswith(LAUNCHPAD_URL):
obj = LAUNCHPAD_URL + obj
return json.loads(self.query_rest_api(obj, query))