112 lines
3.1 KiB
Python
112 lines
3.1 KiB
Python
from contextlib import closing
|
|
import logging
|
|
import sys
|
|
|
|
if sys.version_info >= (3, 0):
|
|
_is_py3 = True
|
|
from urllib.request import build_opener, ContentTooShortError
|
|
else:
|
|
_is_py3 = False
|
|
from urllib2 import build_opener
|
|
from urllib import FancyURLopener
|
|
|
|
|
|
logger = logging.getLogger('glad.opener')
|
|
|
|
|
|
def build_urllib_opener(user_agent, *args, **kwargs):
|
|
if _is_py3:
|
|
return None
|
|
|
|
class UrllibURLOpener(FancyURLopener):
|
|
version = user_agent
|
|
return UrllibURLOpener(*args, **kwargs)
|
|
|
|
|
|
def _urlretrieve_with_opener(opener, url, filename, data=None):
|
|
if not _is_py3:
|
|
raise SyntaxError('Only call this in Python 3 code.')
|
|
|
|
# borrowed from the original implementation at urllib.request.urlretrieve.
|
|
with closing(opener.open(url, data=data)) as src:
|
|
headers = src.info()
|
|
|
|
with open(filename, 'wb') as dest:
|
|
result = filename, headers
|
|
bs = 1024*8
|
|
size = -1
|
|
read = 0
|
|
blocknum = 0
|
|
if "content-length" in headers:
|
|
size = int(headers["Content-Length"])
|
|
|
|
while True:
|
|
block = src.read(bs)
|
|
if not block:
|
|
break
|
|
read += len(block)
|
|
dest.write(block)
|
|
blocknum += 1
|
|
|
|
if size >= 0 and read < size:
|
|
raise ContentTooShortError(
|
|
'retrieval incomplete: got only %i out of %i bytes'
|
|
% (read, size), result)
|
|
|
|
return result
|
|
|
|
|
|
class URLOpener(object):
|
|
"""
|
|
Class to download/find Khronos related files, like
|
|
the official specs and khrplatform.h.
|
|
|
|
Can also be used to download files, exists mainly because of
|
|
Python 2 and Python 3 incompatibilities.
|
|
"""
|
|
def __init__(self, user_agent='Mozilla/5.0'):
|
|
# the urllib2/urllib.request opener
|
|
self.opener = build_opener()
|
|
self.opener.addheaders = [('User-agent', user_agent)]
|
|
|
|
# the urllib opener (Python 2 only)
|
|
self.opener2 = build_urllib_opener(user_agent)
|
|
|
|
def urlopen(self, url, data=None, *args, **kwargs):
|
|
"""
|
|
Same as urllib2.urlopen or urllib.request.urlopen,
|
|
the only difference is that it links to the internal opener.
|
|
"""
|
|
logger.info('opening: \'%s\'', url)
|
|
|
|
if data is None:
|
|
return self.opener.open(url)
|
|
|
|
return self.opener.open(url, data)
|
|
|
|
def urlretrieve(self, url, filename, data=None):
|
|
"""
|
|
Similar to urllib.urlretrieve or urllib.request.urlretrieve
|
|
only that *filname* is required.
|
|
|
|
:param url: URL to download.
|
|
:param filename: Filename to save the content to.
|
|
:param data: Valid URL-encoded data.
|
|
:return: Tuple containing path and headers.
|
|
"""
|
|
logger.info('saving: \'%s\' to \'%s\'', url, filename)
|
|
|
|
if _is_py3:
|
|
return _urlretrieve_with_opener(self.opener, url, filename, data=data)
|
|
|
|
return self.opener2.retrieve(url, filename, data=data)
|
|
|
|
# just a singleton helper:
|
|
_default = None
|
|
|
|
@classmethod
|
|
def default(cls):
|
|
if cls._default is None:
|
|
cls._default = cls()
|
|
|
|
return cls._default
|