|
@@ -29,254 +29,19 @@ import traceback
|
|
|
import xml.etree.ElementTree
|
|
|
import zlib
|
|
|
|
|
|
-try:
|
|
|
- import urllib.request as compat_urllib_request
|
|
|
-except ImportError: # Python 2
|
|
|
- import urllib2 as compat_urllib_request
|
|
|
-
|
|
|
-try:
|
|
|
- import urllib.error as compat_urllib_error
|
|
|
-except ImportError: # Python 2
|
|
|
- import urllib2 as compat_urllib_error
|
|
|
-
|
|
|
-try:
|
|
|
- import urllib.parse as compat_urllib_parse
|
|
|
-except ImportError: # Python 2
|
|
|
- import urllib as compat_urllib_parse
|
|
|
-
|
|
|
-try:
|
|
|
- from urllib.parse import urlparse as compat_urllib_parse_urlparse
|
|
|
-except ImportError: # Python 2
|
|
|
- from urlparse import urlparse as compat_urllib_parse_urlparse
|
|
|
-
|
|
|
-try:
|
|
|
- import urllib.parse as compat_urlparse
|
|
|
-except ImportError: # Python 2
|
|
|
- import urlparse as compat_urlparse
|
|
|
-
|
|
|
-try:
|
|
|
- import http.cookiejar as compat_cookiejar
|
|
|
-except ImportError: # Python 2
|
|
|
- import cookielib as compat_cookiejar
|
|
|
-
|
|
|
-try:
|
|
|
- import html.entities as compat_html_entities
|
|
|
-except ImportError: # Python 2
|
|
|
- import htmlentitydefs as compat_html_entities
|
|
|
-
|
|
|
-try:
|
|
|
- import html.parser as compat_html_parser
|
|
|
-except ImportError: # Python 2
|
|
|
- import HTMLParser as compat_html_parser
|
|
|
-
|
|
|
-try:
|
|
|
- import http.client as compat_http_client
|
|
|
-except ImportError: # Python 2
|
|
|
- import httplib as compat_http_client
|
|
|
-
|
|
|
-try:
|
|
|
- from urllib.error import HTTPError as compat_HTTPError
|
|
|
-except ImportError: # Python 2
|
|
|
- from urllib2 import HTTPError as compat_HTTPError
|
|
|
-
|
|
|
-try:
|
|
|
- from urllib.request import urlretrieve as compat_urlretrieve
|
|
|
-except ImportError: # Python 2
|
|
|
- from urllib import urlretrieve as compat_urlretrieve
|
|
|
-
|
|
|
-
|
|
|
-try:
|
|
|
- from subprocess import DEVNULL
|
|
|
- compat_subprocess_get_DEVNULL = lambda: DEVNULL
|
|
|
-except ImportError:
|
|
|
- compat_subprocess_get_DEVNULL = lambda: open(os.path.devnull, 'w')
|
|
|
-
|
|
|
-try:
|
|
|
- from urllib.parse import unquote as compat_urllib_parse_unquote
|
|
|
-except ImportError:
|
|
|
- def compat_urllib_parse_unquote(string, encoding='utf-8', errors='replace'):
|
|
|
- if string == '':
|
|
|
- return string
|
|
|
- res = string.split('%')
|
|
|
- if len(res) == 1:
|
|
|
- return string
|
|
|
- if encoding is None:
|
|
|
- encoding = 'utf-8'
|
|
|
- if errors is None:
|
|
|
- errors = 'replace'
|
|
|
- # pct_sequence: contiguous sequence of percent-encoded bytes, decoded
|
|
|
- pct_sequence = b''
|
|
|
- string = res[0]
|
|
|
- for item in res[1:]:
|
|
|
- try:
|
|
|
- if not item:
|
|
|
- raise ValueError
|
|
|
- pct_sequence += item[:2].decode('hex')
|
|
|
- rest = item[2:]
|
|
|
- if not rest:
|
|
|
- # This segment was just a single percent-encoded character.
|
|
|
- # May be part of a sequence of code units, so delay decoding.
|
|
|
- # (Stored in pct_sequence).
|
|
|
- continue
|
|
|
- except ValueError:
|
|
|
- rest = '%' + item
|
|
|
- # Encountered non-percent-encoded characters. Flush the current
|
|
|
- # pct_sequence.
|
|
|
- string += pct_sequence.decode(encoding, errors) + rest
|
|
|
- pct_sequence = b''
|
|
|
- if pct_sequence:
|
|
|
- # Flush the final pct_sequence
|
|
|
- string += pct_sequence.decode(encoding, errors)
|
|
|
- return string
|
|
|
-
|
|
|
-
|
|
|
-try:
|
|
|
- from urllib.parse import parse_qs as compat_parse_qs
|
|
|
-except ImportError: # Python 2
|
|
|
- # HACK: The following is the correct parse_qs implementation from cpython 3's stdlib.
|
|
|
- # Python 2's version is apparently totally broken
|
|
|
-
|
|
|
- def _parse_qsl(qs, keep_blank_values=False, strict_parsing=False,
|
|
|
- encoding='utf-8', errors='replace'):
|
|
|
- qs, _coerce_result = qs, unicode
|
|
|
- pairs = [s2 for s1 in qs.split('&') for s2 in s1.split(';')]
|
|
|
- r = []
|
|
|
- for name_value in pairs:
|
|
|
- if not name_value and not strict_parsing:
|
|
|
- continue
|
|
|
- nv = name_value.split('=', 1)
|
|
|
- if len(nv) != 2:
|
|
|
- if strict_parsing:
|
|
|
- raise ValueError("bad query field: %r" % (name_value,))
|
|
|
- # Handle case of a control-name with no equal sign
|
|
|
- if keep_blank_values:
|
|
|
- nv.append('')
|
|
|
- else:
|
|
|
- continue
|
|
|
- if len(nv[1]) or keep_blank_values:
|
|
|
- name = nv[0].replace('+', ' ')
|
|
|
- name = compat_urllib_parse_unquote(
|
|
|
- name, encoding=encoding, errors=errors)
|
|
|
- name = _coerce_result(name)
|
|
|
- value = nv[1].replace('+', ' ')
|
|
|
- value = compat_urllib_parse_unquote(
|
|
|
- value, encoding=encoding, errors=errors)
|
|
|
- value = _coerce_result(value)
|
|
|
- r.append((name, value))
|
|
|
- return r
|
|
|
-
|
|
|
- def compat_parse_qs(qs, keep_blank_values=False, strict_parsing=False,
|
|
|
- encoding='utf-8', errors='replace'):
|
|
|
- parsed_result = {}
|
|
|
- pairs = _parse_qsl(qs, keep_blank_values, strict_parsing,
|
|
|
- encoding=encoding, errors=errors)
|
|
|
- for name, value in pairs:
|
|
|
- if name in parsed_result:
|
|
|
- parsed_result[name].append(value)
|
|
|
- else:
|
|
|
- parsed_result[name] = [value]
|
|
|
- return parsed_result
|
|
|
-
|
|
|
-try:
|
|
|
- compat_str = unicode # Python 2
|
|
|
-except NameError:
|
|
|
- compat_str = str
|
|
|
-
|
|
|
-try:
|
|
|
- compat_chr = unichr # Python 2
|
|
|
-except NameError:
|
|
|
- compat_chr = chr
|
|
|
-
|
|
|
-try:
|
|
|
- from xml.etree.ElementTree import ParseError as compat_xml_parse_error
|
|
|
-except ImportError: # Python 2.6
|
|
|
- from xml.parsers.expat import ExpatError as compat_xml_parse_error
|
|
|
-
|
|
|
-try:
|
|
|
- from shlex import quote as shlex_quote
|
|
|
-except ImportError: # Python < 3.3
|
|
|
- def shlex_quote(s):
|
|
|
- return "'" + s.replace("'", "'\"'\"'") + "'"
|
|
|
-
|
|
|
-
|
|
|
-def compat_ord(c):
|
|
|
- if type(c) is int: return c
|
|
|
- else: return ord(c)
|
|
|
-
|
|
|
-
|
|
|
-if sys.version_info >= (3, 0):
|
|
|
- compat_getenv = os.getenv
|
|
|
- compat_expanduser = os.path.expanduser
|
|
|
-else:
|
|
|
- # Environment variables should be decoded with filesystem encoding.
|
|
|
- # Otherwise it will fail if any non-ASCII characters present (see #3854 #3217 #2918)
|
|
|
-
|
|
|
- def compat_getenv(key, default=None):
|
|
|
- env = os.getenv(key, default)
|
|
|
- if env:
|
|
|
- env = env.decode(get_filesystem_encoding())
|
|
|
- return env
|
|
|
-
|
|
|
- # HACK: The default implementations of os.path.expanduser from cpython do not decode
|
|
|
- # environment variables with filesystem encoding. We will work around this by
|
|
|
- # providing adjusted implementations.
|
|
|
- # The following are os.path.expanduser implementations from cpython 2.7.8 stdlib
|
|
|
- # for different platforms with correct environment variables decoding.
|
|
|
-
|
|
|
- if os.name == 'posix':
|
|
|
- def compat_expanduser(path):
|
|
|
- """Expand ~ and ~user constructions. If user or $HOME is unknown,
|
|
|
- do nothing."""
|
|
|
- if not path.startswith('~'):
|
|
|
- return path
|
|
|
- i = path.find('/', 1)
|
|
|
- if i < 0:
|
|
|
- i = len(path)
|
|
|
- if i == 1:
|
|
|
- if 'HOME' not in os.environ:
|
|
|
- import pwd
|
|
|
- userhome = pwd.getpwuid(os.getuid()).pw_dir
|
|
|
- else:
|
|
|
- userhome = compat_getenv('HOME')
|
|
|
- else:
|
|
|
- import pwd
|
|
|
- try:
|
|
|
- pwent = pwd.getpwnam(path[1:i])
|
|
|
- except KeyError:
|
|
|
- return path
|
|
|
- userhome = pwent.pw_dir
|
|
|
- userhome = userhome.rstrip('/')
|
|
|
- return (userhome + path[i:]) or '/'
|
|
|
- elif os.name == 'nt' or os.name == 'ce':
|
|
|
- def compat_expanduser(path):
|
|
|
- """Expand ~ and ~user constructs.
|
|
|
-
|
|
|
- If user or $HOME is unknown, do nothing."""
|
|
|
- if path[:1] != '~':
|
|
|
- return path
|
|
|
- i, n = 1, len(path)
|
|
|
- while i < n and path[i] not in '/\\':
|
|
|
- i = i + 1
|
|
|
-
|
|
|
- if 'HOME' in os.environ:
|
|
|
- userhome = compat_getenv('HOME')
|
|
|
- elif 'USERPROFILE' in os.environ:
|
|
|
- userhome = compat_getenv('USERPROFILE')
|
|
|
- elif not 'HOMEPATH' in os.environ:
|
|
|
- return path
|
|
|
- else:
|
|
|
- try:
|
|
|
- drive = compat_getenv('HOMEDRIVE')
|
|
|
- except KeyError:
|
|
|
- drive = ''
|
|
|
- userhome = os.path.join(drive, compat_getenv('HOMEPATH'))
|
|
|
-
|
|
|
- if i != 1: #~user
|
|
|
- userhome = os.path.join(os.path.dirname(userhome), path[1:i])
|
|
|
-
|
|
|
- return userhome + path[i:]
|
|
|
- else:
|
|
|
- compat_expanduser = os.path.expanduser
|
|
|
+from .compat import (
|
|
|
+ compat_chr,
|
|
|
+ compat_getenv,
|
|
|
+ compat_html_entities,
|
|
|
+ compat_html_parser,
|
|
|
+ compat_parse_qs,
|
|
|
+ compat_str,
|
|
|
+ compat_urllib_error,
|
|
|
+ compat_urllib_parse,
|
|
|
+ compat_urllib_parse_urlparse,
|
|
|
+ compat_urllib_request,
|
|
|
+ compat_urlparse,
|
|
|
+)
|
|
|
|
|
|
|
|
|
# This is not clearly defined otherwise
|
|
@@ -304,14 +69,6 @@ def preferredencoding():
|
|
|
|
|
|
return pref
|
|
|
|
|
|
-if sys.version_info < (3,0):
|
|
|
- def compat_print(s):
|
|
|
- print(s.encode(preferredencoding(), 'xmlcharrefreplace'))
|
|
|
-else:
|
|
|
- def compat_print(s):
|
|
|
- assert type(s) == type(u'')
|
|
|
- print(s)
|
|
|
-
|
|
|
|
|
|
def write_json_file(obj, fn):
|
|
|
""" Encode obj as JSON and write it to fn, atomically """
|
|
@@ -1655,15 +1412,6 @@ def parse_xml(s):
|
|
|
return tree
|
|
|
|
|
|
|
|
|
-if sys.version_info < (3, 0) and sys.platform == 'win32':
|
|
|
- def compat_getpass(prompt, *args, **kwargs):
|
|
|
- if isinstance(prompt, compat_str):
|
|
|
- prompt = prompt.encode(preferredencoding())
|
|
|
- return getpass.getpass(prompt, *args, **kwargs)
|
|
|
-else:
|
|
|
- compat_getpass = getpass.getpass
|
|
|
-
|
|
|
-
|
|
|
US_RATINGS = {
|
|
|
'G': 0,
|
|
|
'PG': 10,
|
|
@@ -1721,18 +1469,6 @@ def qualities(quality_ids):
|
|
|
|
|
|
DEFAULT_OUTTMPL = '%(title)s-%(id)s.%(ext)s'
|
|
|
|
|
|
-try:
|
|
|
- subprocess_check_output = subprocess.check_output
|
|
|
-except AttributeError:
|
|
|
- def subprocess_check_output(*args, **kwargs):
|
|
|
- assert 'input' not in kwargs
|
|
|
- p = subprocess.Popen(*args, stdout=subprocess.PIPE, **kwargs)
|
|
|
- output, _ = p.communicate()
|
|
|
- ret = p.poll()
|
|
|
- if ret:
|
|
|
- raise subprocess.CalledProcessError(ret, p.args, output=output)
|
|
|
- return output
|
|
|
-
|
|
|
|
|
|
def limit_length(s, length):
|
|
|
""" Add ellipses to overly long strings """
|