X-Git-Url: https://git.rapsys.eu/youtubedl/blobdiff_plain/eed74133841b43ce901ee0dd31c7dad5a234bd48..56553d2fc728271c5fe6d6a3ecc9dfc16dacc35c:/youtube_dl/compat.py diff --git a/youtube_dl/compat.py b/youtube_dl/compat.py index 9d33a8e..f952921 100644 --- a/youtube_dl/compat.py +++ b/youtube_dl/compat.py @@ -1,55 +1,54 @@ 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 - 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: @@ -69,6 +68,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: @@ -107,16 +111,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: @@ -144,10 +168,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) @@ -155,31 +179,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): @@ -241,7 +255,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: @@ -250,7 +264,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:] @@ -264,7 +278,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) @@ -291,7 +305,9 @@ else: # Old 2.6 and 2.7 releases require kwargs to be bytes try: - (lambda x: x)(**{'x': 0}) + def _testfunc(x): + pass + _testfunc(**{'x': 0}) except TypeError: def compat_kwargs(kwargs): return dict((bytes(k), v) for k, v in kwargs.items()) @@ -299,6 +315,32 @@ 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(): @@ -319,21 +361,51 @@ def workaround_optparse_bug9161(): 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',