X-Git-Url: http://git.bitcoin.ninja/index.cgi?a=blobdiff_plain;f=youtube_dl%2Fcompat.py;h=973bcd32074107f70c1b781e95b97ef34501b88f;hb=70a1165b32acf253905109e9b4f245295d67af1f;hp=3e35e2b84625cf55f41ee7a572417b54bca14478;hpb=baa708036c64e2dce419b5f0648ee6b84ce2132e;p=youtube-dl diff --git a/youtube_dl/compat.py b/youtube_dl/compat.py index 3e35e2b84..973bcd320 100644 --- a/youtube_dl/compat.py +++ b/youtube_dl/compat.py @@ -1,52 +1,59 @@ +from __future__ import unicode_literals + +import collections import getpass +import optparse import os +import re +import shutil +import socket import subprocess import sys try: import urllib.request as compat_urllib_request -except ImportError: # Python 2 +except ImportError: # Python 2 import urllib2 as compat_urllib_request try: import urllib.error as compat_urllib_error -except ImportError: # Python 2 +except ImportError: # Python 2 import urllib2 as compat_urllib_error try: import urllib.parse as compat_urllib_parse -except ImportError: # Python 2 +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 +except ImportError: # Python 2 from urlparse import urlparse as compat_urllib_parse_urlparse try: import urllib.parse as compat_urlparse -except ImportError: # Python 2 +except ImportError: # Python 2 import urlparse as compat_urlparse try: import http.cookiejar as compat_cookiejar -except ImportError: # Python 2 +except ImportError: # Python 2 import cookielib as compat_cookiejar try: import html.entities as compat_html_entities -except ImportError: # Python 2 +except ImportError: # Python 2 import htmlentitydefs as compat_html_entities try: import html.parser as compat_html_parser -except ImportError: # Python 2 +except ImportError: # Python 2 import HTMLParser as compat_html_parser try: import http.client as compat_http_client -except ImportError: # Python 2 +except ImportError: # Python 2 import httplib as compat_http_client try: @@ -66,6 +73,11 @@ try: except ImportError: compat_subprocess_get_DEVNULL = lambda: open(os.path.devnull, 'w') +try: + import http.server as compat_http_server +except ImportError: + import BaseHTTPServer as compat_http_server + try: from urllib.parse import unquote as compat_urllib_parse_unquote except ImportError: @@ -104,16 +116,36 @@ except ImportError: string += pct_sequence.decode(encoding, errors) return string +try: + compat_str = unicode # Python 2 +except NameError: + compat_str = str + +try: + compat_basestring = basestring # Python 2 +except NameError: + compat_basestring = 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 urllib.parse import parse_qs as compat_parse_qs -except ImportError: # Python 2 +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 + encoding='utf-8', errors='replace'): + qs, _coerce_result = qs, compat_str pairs = [s2 for s1 in qs.split('&') for s2 in s1.split(';')] r = [] for name_value in pairs: @@ -141,10 +173,10 @@ except ImportError: # Python 2 return r def compat_parse_qs(qs, keep_blank_values=False, strict_parsing=False, - encoding='utf-8', errors='replace'): + encoding='utf-8', errors='replace'): parsed_result = {} pairs = _parse_qsl(qs, keep_blank_values, strict_parsing, - encoding=encoding, errors=errors) + encoding=encoding, errors=errors) for name, value in pairs: if name in parsed_result: parsed_result[name].append(value) @@ -152,31 +184,21 @@ except ImportError: # Python 2 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("'", "'\"'\"'") + "'" + if re.match(r'^[-_\w./]+$', s): + return s + else: + return "'" + s.replace("'", "'\"'\"'") + "'" def compat_ord(c): - if type(c) is int: return c - else: return ord(c) + if type(c) is int: + return c + else: + return ord(c) if sys.version_info >= (3, 0): @@ -238,7 +260,7 @@ else: userhome = compat_getenv('HOME') elif 'USERPROFILE' in os.environ: userhome = compat_getenv('USERPROFILE') - elif not 'HOMEPATH' in os.environ: + elif 'HOMEPATH' not in os.environ: return path else: try: @@ -247,7 +269,7 @@ else: drive = '' userhome = os.path.join(drive, compat_getenv('HOMEPATH')) - if i != 1: #~user + if i != 1: # ~user userhome = os.path.join(os.path.dirname(userhome), path[1:i]) return userhome + path[i:] @@ -261,7 +283,7 @@ if sys.version_info < (3, 0): print(s.encode(preferredencoding(), 'xmlcharrefreplace')) else: def compat_print(s): - assert type(s) == type(u'') + assert isinstance(s, compat_str) print(s) @@ -286,20 +308,110 @@ if sys.version_info < (3, 0) and sys.platform == 'win32': else: compat_getpass = getpass.getpass +# Old 2.6 and 2.7 releases require kwargs to be bytes +try: + def _testfunc(x): + pass + _testfunc(**{'x': 0}) +except TypeError: + def compat_kwargs(kwargs): + return dict((bytes(k), v) for k, v in kwargs.items()) +else: + compat_kwargs = lambda kwargs: kwargs + + +if sys.version_info < (2, 7): + def compat_socket_create_connection(address, timeout, source_address=None): + host, port = address + err = None + for res in socket.getaddrinfo(host, port, 0, socket.SOCK_STREAM): + af, socktype, proto, canonname, sa = res + sock = None + try: + sock = socket.socket(af, socktype, proto) + sock.settimeout(timeout) + if source_address: + sock.bind(source_address) + sock.connect(sa) + return sock + except socket.error as _: + err = _ + if sock is not None: + sock.close() + if err is not None: + raise err + else: + raise socket.error("getaddrinfo returns an empty list") +else: + compat_socket_create_connection = socket.create_connection + + +# Fix https://github.com/rg3/youtube-dl/issues/4223 +# See http://bugs.python.org/issue9161 for what is broken +def workaround_optparse_bug9161(): + op = optparse.OptionParser() + og = optparse.OptionGroup(op, 'foo') + try: + og.add_option('-t') + except TypeError: + real_add_option = optparse.OptionGroup.add_option + + def _compat_add_option(self, *args, **kwargs): + enc = lambda v: ( + v.encode('ascii', 'replace') if isinstance(v, compat_str) + else v) + bargs = [enc(a) for a in args] + bkwargs = dict( + (k, enc(v)) for k, v in kwargs.items()) + return real_add_option(self, *bargs, **bkwargs) + optparse.OptionGroup.add_option = _compat_add_option + +if hasattr(shutil, 'get_terminal_size'): # Python >= 3.3 + compat_get_terminal_size = shutil.get_terminal_size +else: + _terminal_size = collections.namedtuple('terminal_size', ['columns', 'lines']) + + def compat_get_terminal_size(): + columns = compat_getenv('COLUMNS', None) + if columns: + columns = int(columns) + else: + columns = None + lines = compat_getenv('LINES', None) + if lines: + lines = int(lines) + else: + lines = None + + try: + sp = subprocess.Popen( + ['stty', 'size'], + stdout=subprocess.PIPE, stderr=subprocess.PIPE) + out, err = sp.communicate() + lines, columns = map(int, out.split()) + except Exception: + pass + return _terminal_size(columns, lines) + __all__ = [ 'compat_HTTPError', + 'compat_basestring', 'compat_chr', 'compat_cookiejar', 'compat_expanduser', + 'compat_get_terminal_size', 'compat_getenv', 'compat_getpass', 'compat_html_entities', 'compat_html_parser', 'compat_http_client', + 'compat_http_server', + 'compat_kwargs', 'compat_ord', 'compat_parse_qs', 'compat_print', + 'compat_socket_create_connection', 'compat_str', 'compat_subprocess_get_DEVNULL', 'compat_urllib_error', @@ -312,4 +424,5 @@ __all__ = [ 'compat_xml_parse_error', 'shlex_quote', 'subprocess_check_output', + 'workaround_optparse_bug9161', ]