Bladeren bron

[compat] Clean-up
* make workaround_optparse_bug9161 private
* add comments
* avoid leaving test objects behind

dirkf 5 maanden geleden
bovenliggende
commit
cecaa18b80
2 gewijzigde bestanden met toevoegingen van 129 en 47 verwijderingen
  1. 2 2
      youtube_dl/__init__.py
  2. 127 45
      youtube_dl/compat.py

+ 2 - 2
youtube_dl/__init__.py

@@ -18,7 +18,7 @@ from .compat import (
     compat_getpass,
     compat_getpass,
     compat_register_utf8,
     compat_register_utf8,
     compat_shlex_split,
     compat_shlex_split,
-    workaround_optparse_bug9161,
+    _workaround_optparse_bug9161,
 )
 )
 from .utils import (
 from .utils import (
     _UnsafeExtensionError,
     _UnsafeExtensionError,
@@ -50,7 +50,7 @@ def _real_main(argv=None):
     # Compatibility fix for Windows
     # Compatibility fix for Windows
     compat_register_utf8()
     compat_register_utf8()
 
 
-    workaround_optparse_bug9161()
+    _workaround_optparse_bug9161()
 
 
     setproctitle('youtube-dl')
     setproctitle('youtube-dl')
 
 

+ 127 - 45
youtube_dl/compat.py

@@ -16,7 +16,6 @@ import os
 import platform
 import platform
 import re
 import re
 import shlex
 import shlex
-import shutil
 import socket
 import socket
 import struct
 import struct
 import subprocess
 import subprocess
@@ -24,11 +23,15 @@ import sys
 import types
 import types
 import xml.etree.ElementTree
 import xml.etree.ElementTree
 
 
+_IDENTITY = lambda x: x
+
 # naming convention
 # naming convention
 # 'compat_' + Python3_name.replace('.', '_')
 # 'compat_' + Python3_name.replace('.', '_')
 # other aliases exist for convenience and/or legacy
 # other aliases exist for convenience and/or legacy
+# wrap disposable test values in type() to reclaim storage
 
 
-# deal with critical unicode/str things first
+# deal with critical unicode/str things first:
+# compat_str, compat_basestring, compat_chr
 try:
 try:
     # Python 2
     # Python 2
     compat_str, compat_basestring, compat_chr = (
     compat_str, compat_basestring, compat_chr = (
@@ -39,18 +42,23 @@ except NameError:
         str, (str, bytes), chr
         str, (str, bytes), chr
     )
     )
 
 
-# casefold
+
+# compat_casefold
 try:
 try:
     compat_str.casefold
     compat_str.casefold
     compat_casefold = lambda s: s.casefold()
     compat_casefold = lambda s: s.casefold()
 except AttributeError:
 except AttributeError:
     from .casefold import _casefold as compat_casefold
     from .casefold import _casefold as compat_casefold
 
 
+
+# compat_collections_abc
 try:
 try:
     import collections.abc as compat_collections_abc
     import collections.abc as compat_collections_abc
 except ImportError:
 except ImportError:
     import collections as compat_collections_abc
     import collections as compat_collections_abc
 
 
+
+# compat_urllib_request
 try:
 try:
     import urllib.request as compat_urllib_request
     import urllib.request as compat_urllib_request
 except ImportError:  # Python 2
 except ImportError:  # Python 2
@@ -79,11 +87,15 @@ except TypeError:
     _add_init_method_arg(compat_urllib_request.Request)
     _add_init_method_arg(compat_urllib_request.Request)
     del _add_init_method_arg
     del _add_init_method_arg
 
 
+
+# compat_urllib_error
 try:
 try:
     import urllib.error as compat_urllib_error
     import urllib.error as compat_urllib_error
 except ImportError:  # Python 2
 except ImportError:  # Python 2
     import urllib2 as compat_urllib_error
     import urllib2 as compat_urllib_error
 
 
+
+# compat_urllib_parse
 try:
 try:
     import urllib.parse as compat_urllib_parse
     import urllib.parse as compat_urllib_parse
 except ImportError:  # Python 2
 except ImportError:  # Python 2
@@ -98,17 +110,23 @@ except ImportError:  # Python 2
 compat_urlparse = compat_urllib_parse
 compat_urlparse = compat_urllib_parse
 compat_urllib_parse_urlparse = compat_urllib_parse.urlparse
 compat_urllib_parse_urlparse = compat_urllib_parse.urlparse
 
 
+
+# compat_urllib_response
 try:
 try:
     import urllib.response as compat_urllib_response
     import urllib.response as compat_urllib_response
 except ImportError:  # Python 2
 except ImportError:  # Python 2
     import urllib as compat_urllib_response
     import urllib as compat_urllib_response
 
 
+
+# compat_urllib_response.addinfourl
 try:
 try:
     compat_urllib_response.addinfourl.status
     compat_urllib_response.addinfourl.status
 except AttributeError:
 except AttributeError:
     # .getcode() is deprecated in Py 3.
     # .getcode() is deprecated in Py 3.
     compat_urllib_response.addinfourl.status = property(lambda self: self.getcode())
     compat_urllib_response.addinfourl.status = property(lambda self: self.getcode())
 
 
+
+# compat_http_cookiejar
 try:
 try:
     import http.cookiejar as compat_cookiejar
     import http.cookiejar as compat_cookiejar
 except ImportError:  # Python 2
 except ImportError:  # Python 2
@@ -127,12 +145,16 @@ else:
     compat_cookiejar_Cookie = compat_cookiejar.Cookie
     compat_cookiejar_Cookie = compat_cookiejar.Cookie
 compat_http_cookiejar_Cookie = compat_cookiejar_Cookie
 compat_http_cookiejar_Cookie = compat_cookiejar_Cookie
 
 
+
+# compat_http_cookies
 try:
 try:
     import http.cookies as compat_cookies
     import http.cookies as compat_cookies
 except ImportError:  # Python 2
 except ImportError:  # Python 2
     import Cookie as compat_cookies
     import Cookie as compat_cookies
 compat_http_cookies = compat_cookies
 compat_http_cookies = compat_cookies
 
 
+
+# compat_http_cookies_SimpleCookie
 if sys.version_info[0] == 2 or sys.version_info < (3, 3):
 if sys.version_info[0] == 2 or sys.version_info < (3, 3):
     class compat_cookies_SimpleCookie(compat_cookies.SimpleCookie):
     class compat_cookies_SimpleCookie(compat_cookies.SimpleCookie):
         def load(self, rawdata):
         def load(self, rawdata):
@@ -155,11 +177,15 @@ else:
     compat_cookies_SimpleCookie = compat_cookies.SimpleCookie
     compat_cookies_SimpleCookie = compat_cookies.SimpleCookie
 compat_http_cookies_SimpleCookie = compat_cookies_SimpleCookie
 compat_http_cookies_SimpleCookie = compat_cookies_SimpleCookie
 
 
+
+# compat_html_entities, probably useless now
 try:
 try:
     import html.entities as compat_html_entities
     import html.entities as compat_html_entities
 except ImportError:  # Python 2
 except ImportError:  # Python 2
     import htmlentitydefs as compat_html_entities
     import htmlentitydefs as compat_html_entities
 
 
+
+# compat_html_entities_html5
 try:  # Python >= 3.3
 try:  # Python >= 3.3
     compat_html_entities_html5 = compat_html_entities.html5
     compat_html_entities_html5 = compat_html_entities.html5
 except AttributeError:
 except AttributeError:
@@ -2408,18 +2434,24 @@ except AttributeError:
     # Py < 3.1
     # Py < 3.1
     compat_http_client.HTTPResponse.getcode = lambda self: self.status
     compat_http_client.HTTPResponse.getcode = lambda self: self.status
 
 
+
+# compat_urllib_HTTPError
 try:
 try:
     from urllib.error import HTTPError as compat_HTTPError
     from urllib.error import HTTPError as compat_HTTPError
 except ImportError:  # Python 2
 except ImportError:  # Python 2
     from urllib2 import HTTPError as compat_HTTPError
     from urllib2 import HTTPError as compat_HTTPError
 compat_urllib_HTTPError = compat_HTTPError
 compat_urllib_HTTPError = compat_HTTPError
 
 
+
+# compat_urllib_request_urlretrieve
 try:
 try:
     from urllib.request import urlretrieve as compat_urlretrieve
     from urllib.request import urlretrieve as compat_urlretrieve
 except ImportError:  # Python 2
 except ImportError:  # Python 2
     from urllib import urlretrieve as compat_urlretrieve
     from urllib import urlretrieve as compat_urlretrieve
 compat_urllib_request_urlretrieve = compat_urlretrieve
 compat_urllib_request_urlretrieve = compat_urlretrieve
 
 
+
+# compat_html_parser_HTMLParser, compat_html_parser_HTMLParseError
 try:
 try:
     from HTMLParser import (
     from HTMLParser import (
         HTMLParser as compat_HTMLParser,
         HTMLParser as compat_HTMLParser,
@@ -2432,22 +2464,33 @@ except ImportError:  # Python 3
         # HTMLParseError was deprecated in Python 3.3 and removed in
         # HTMLParseError was deprecated in Python 3.3 and removed in
         # Python 3.5. Introducing dummy exception for Python >3.5 for compatible
         # Python 3.5. Introducing dummy exception for Python >3.5 for compatible
         # and uniform cross-version exception handling
         # and uniform cross-version exception handling
+
         class compat_HTMLParseError(Exception):
         class compat_HTMLParseError(Exception):
             pass
             pass
+
 compat_html_parser_HTMLParser = compat_HTMLParser
 compat_html_parser_HTMLParser = compat_HTMLParser
 compat_html_parser_HTMLParseError = compat_HTMLParseError
 compat_html_parser_HTMLParseError = compat_HTMLParseError
 
 
+
+# compat_subprocess_get_DEVNULL
 try:
 try:
     _DEVNULL = subprocess.DEVNULL
     _DEVNULL = subprocess.DEVNULL
     compat_subprocess_get_DEVNULL = lambda: _DEVNULL
     compat_subprocess_get_DEVNULL = lambda: _DEVNULL
 except AttributeError:
 except AttributeError:
     compat_subprocess_get_DEVNULL = lambda: open(os.path.devnull, 'w')
     compat_subprocess_get_DEVNULL = lambda: open(os.path.devnull, 'w')
 
 
+
+# compat_http_server
 try:
 try:
     import http.server as compat_http_server
     import http.server as compat_http_server
 except ImportError:
 except ImportError:
     import BaseHTTPServer as compat_http_server
     import BaseHTTPServer as compat_http_server
 
 
+
+# compat_urllib_parse_unquote_to_bytes,
+# compat_urllib_parse_unquote, compat_urllib_parse_unquote_plus,
+# compat_urllib_parse_urlencode,
+# compat_urllib_parse_parse_qs
 try:
 try:
     from urllib.parse import unquote_to_bytes as compat_urllib_parse_unquote_to_bytes
     from urllib.parse import unquote_to_bytes as compat_urllib_parse_unquote_to_bytes
     from urllib.parse import unquote as compat_urllib_parse_unquote
     from urllib.parse import unquote as compat_urllib_parse_unquote
@@ -2598,6 +2641,8 @@ except ImportError:  # Python 2
 
 
 compat_urllib_parse_parse_qs = compat_parse_qs
 compat_urllib_parse_parse_qs = compat_parse_qs
 
 
+
+# compat_urllib_request_DataHandler
 try:
 try:
     from urllib.request import DataHandler as compat_urllib_request_DataHandler
     from urllib.request import DataHandler as compat_urllib_request_DataHandler
 except ImportError:  # Python < 3.4
 except ImportError:  # Python < 3.4
@@ -2632,16 +2677,20 @@ except ImportError:  # Python < 3.4
 
 
             return compat_urllib_response.addinfourl(io.BytesIO(data), headers, url)
             return compat_urllib_response.addinfourl(io.BytesIO(data), headers, url)
 
 
+
+# compat_xml_etree_ElementTree_ParseError
 try:
 try:
     from xml.etree.ElementTree import ParseError as compat_xml_parse_error
     from xml.etree.ElementTree import ParseError as compat_xml_parse_error
 except ImportError:  # Python 2.6
 except ImportError:  # Python 2.6
     from xml.parsers.expat import ExpatError as compat_xml_parse_error
     from xml.parsers.expat import ExpatError as compat_xml_parse_error
 compat_xml_etree_ElementTree_ParseError = compat_xml_parse_error
 compat_xml_etree_ElementTree_ParseError = compat_xml_parse_error
 
 
-etree = xml.etree.ElementTree
+
+# compat_xml_etree_ElementTree_Element
+_etree = xml.etree.ElementTree
 
 
 
 
-class _TreeBuilder(etree.TreeBuilder):
+class _TreeBuilder(_etree.TreeBuilder):
     def doctype(self, name, pubid, system):
     def doctype(self, name, pubid, system):
         pass
         pass
 
 
@@ -2650,7 +2699,7 @@ try:
     # xml.etree.ElementTree.Element is a method in Python <=2.6 and
     # xml.etree.ElementTree.Element is a method in Python <=2.6 and
     # the following will crash with:
     # the following will crash with:
     #  TypeError: isinstance() arg 2 must be a class, type, or tuple of classes and types
     #  TypeError: isinstance() arg 2 must be a class, type, or tuple of classes and types
-    isinstance(None, etree.Element)
+    isinstance(None, _etree.Element)
     from xml.etree.ElementTree import Element as compat_etree_Element
     from xml.etree.ElementTree import Element as compat_etree_Element
 except TypeError:  # Python <=2.6
 except TypeError:  # Python <=2.6
     from xml.etree.ElementTree import _ElementInterface as compat_etree_Element
     from xml.etree.ElementTree import _ElementInterface as compat_etree_Element
@@ -2658,12 +2707,12 @@ compat_xml_etree_ElementTree_Element = compat_etree_Element
 
 
 if sys.version_info[0] >= 3:
 if sys.version_info[0] >= 3:
     def compat_etree_fromstring(text):
     def compat_etree_fromstring(text):
-        return etree.XML(text, parser=etree.XMLParser(target=_TreeBuilder()))
+        return _etree.XML(text, parser=_etree.XMLParser(target=_TreeBuilder()))
 else:
 else:
     # python 2.x tries to encode unicode strings with ascii (see the
     # python 2.x tries to encode unicode strings with ascii (see the
     # XMLParser._fixtext method)
     # XMLParser._fixtext method)
     try:
     try:
-        _etree_iter = etree.Element.iter
+        _etree_iter = _etree.Element.iter
     except AttributeError:  # Python <=2.6
     except AttributeError:  # Python <=2.6
         def _etree_iter(root):
         def _etree_iter(root):
             for el in root.findall('*'):
             for el in root.findall('*'):
@@ -2675,27 +2724,29 @@ else:
     # 2.7 source
     # 2.7 source
     def _XML(text, parser=None):
     def _XML(text, parser=None):
         if not parser:
         if not parser:
-            parser = etree.XMLParser(target=_TreeBuilder())
+            parser = _etree.XMLParser(target=_TreeBuilder())
         parser.feed(text)
         parser.feed(text)
         return parser.close()
         return parser.close()
 
 
     def _element_factory(*args, **kwargs):
     def _element_factory(*args, **kwargs):
-        el = etree.Element(*args, **kwargs)
+        el = _etree.Element(*args, **kwargs)
         for k, v in el.items():
         for k, v in el.items():
             if isinstance(v, bytes):
             if isinstance(v, bytes):
                 el.set(k, v.decode('utf-8'))
                 el.set(k, v.decode('utf-8'))
         return el
         return el
 
 
     def compat_etree_fromstring(text):
     def compat_etree_fromstring(text):
-        doc = _XML(text, parser=etree.XMLParser(target=_TreeBuilder(element_factory=_element_factory)))
+        doc = _XML(text, parser=_etree.XMLParser(target=_TreeBuilder(element_factory=_element_factory)))
         for el in _etree_iter(doc):
         for el in _etree_iter(doc):
             if el.text is not None and isinstance(el.text, bytes):
             if el.text is not None and isinstance(el.text, bytes):
                 el.text = el.text.decode('utf-8')
                 el.text = el.text.decode('utf-8')
         return doc
         return doc
 
 
-if hasattr(etree, 'register_namespace'):
-    compat_etree_register_namespace = etree.register_namespace
-else:
+
+# compat_xml_etree_register_namespace
+try:
+    compat_etree_register_namespace = _etree.register_namespace
+except AttributeError:
     def compat_etree_register_namespace(prefix, uri):
     def compat_etree_register_namespace(prefix, uri):
         """Register a namespace prefix.
         """Register a namespace prefix.
         The registry is global, and any existing mapping for either the
         The registry is global, and any existing mapping for either the
@@ -2704,14 +2755,16 @@ else:
         attributes in this namespace will be serialized with prefix if possible.
         attributes in this namespace will be serialized with prefix if possible.
         ValueError is raised if prefix is reserved or is invalid.
         ValueError is raised if prefix is reserved or is invalid.
         """
         """
-        if re.match(r"ns\d+$", prefix):
-            raise ValueError("Prefix format reserved for internal use")
-        for k, v in list(etree._namespace_map.items()):
+        if re.match(r'ns\d+$', prefix):
+            raise ValueError('Prefix format reserved for internal use')
+        for k, v in list(_etree._namespace_map.items()):
             if k == uri or v == prefix:
             if k == uri or v == prefix:
-                del etree._namespace_map[k]
-        etree._namespace_map[uri] = prefix
+                del _etree._namespace_map[k]
+        _etree._namespace_map[uri] = prefix
 compat_xml_etree_register_namespace = compat_etree_register_namespace
 compat_xml_etree_register_namespace = compat_etree_register_namespace
 
 
+
+# compat_xpath, compat_etree_iterfind
 if sys.version_info < (2, 7):
 if sys.version_info < (2, 7):
     # Here comes the crazy part: In 2.6, if the xpath is a unicode,
     # Here comes the crazy part: In 2.6, if the xpath is a unicode,
     # .//node does not match if a node is a direct child of . !
     # .//node does not match if a node is a direct child of . !
@@ -2898,7 +2951,6 @@ if sys.version_info < (2, 7):
         def __init__(self, root):
         def __init__(self, root):
             self.root = root
             self.root = root
 
 
-    ##
     # Generate all matching objects.
     # Generate all matching objects.
 
 
     def compat_etree_iterfind(elem, path, namespaces=None):
     def compat_etree_iterfind(elem, path, namespaces=None):
@@ -2933,13 +2985,15 @@ if sys.version_info < (2, 7):
 
 
 
 
 else:
 else:
-    compat_xpath = lambda xpath: xpath
     compat_etree_iterfind = lambda element, match: element.iterfind(match)
     compat_etree_iterfind = lambda element, match: element.iterfind(match)
+    compat_xpath = _IDENTITY
 
 
 
 
+# compat_os_name
 compat_os_name = os._name if os.name == 'java' else os.name
 compat_os_name = os._name if os.name == 'java' else os.name
 
 
 
 
+# compat_shlex_quote
 if compat_os_name == 'nt':
 if compat_os_name == 'nt':
     def compat_shlex_quote(s):
     def compat_shlex_quote(s):
         return s if re.match(r'^[-_\w./]+$', s) else '"%s"' % s.replace('"', '\\"')
         return s if re.match(r'^[-_\w./]+$', s) else '"%s"' % s.replace('"', '\\"')
@@ -2954,6 +3008,7 @@ else:
                 return "'" + s.replace("'", "'\"'\"'") + "'"
                 return "'" + s.replace("'", "'\"'\"'") + "'"
 
 
 
 
+# compat_shlex.split
 try:
 try:
     args = shlex.split('中文')
     args = shlex.split('中文')
     assert (isinstance(args, list)
     assert (isinstance(args, list)
@@ -2969,6 +3024,7 @@ except (AssertionError, UnicodeEncodeError):
         return list(map(lambda s: s.decode('utf-8'), shlex.split(s, comments, posix)))
         return list(map(lambda s: s.decode('utf-8'), shlex.split(s, comments, posix)))
 
 
 
 
+# compat_ord
 def compat_ord(c):
 def compat_ord(c):
     if isinstance(c, int):
     if isinstance(c, int):
         return c
         return c
@@ -2976,6 +3032,7 @@ def compat_ord(c):
         return ord(c)
         return ord(c)
 
 
 
 
+# compat_getenv, compat_os_path_expanduser, compat_setenv
 if sys.version_info >= (3, 0):
 if sys.version_info >= (3, 0):
     compat_getenv = os.getenv
     compat_getenv = os.getenv
     compat_expanduser = os.path.expanduser
     compat_expanduser = os.path.expanduser
@@ -3063,6 +3120,7 @@ else:
 compat_os_path_expanduser = compat_expanduser
 compat_os_path_expanduser = compat_expanduser
 
 
 
 
+# compat_os_path_realpath
 if compat_os_name == 'nt' and sys.version_info < (3, 8):
 if compat_os_name == 'nt' and sys.version_info < (3, 8):
     # os.path.realpath on Windows does not follow symbolic links
     # os.path.realpath on Windows does not follow symbolic links
     # prior to Python 3.8 (see https://bugs.python.org/issue9949)
     # prior to Python 3.8 (see https://bugs.python.org/issue9949)
@@ -3076,6 +3134,7 @@ else:
 compat_os_path_realpath = compat_realpath
 compat_os_path_realpath = compat_realpath
 
 
 
 
+# compat_print
 if sys.version_info < (3, 0):
 if sys.version_info < (3, 0):
     def compat_print(s):
     def compat_print(s):
         from .utils import preferredencoding
         from .utils import preferredencoding
@@ -3086,6 +3145,7 @@ else:
         print(s)
         print(s)
 
 
 
 
+# compat_getpass_getpass
 if sys.version_info < (3, 0) and sys.platform == 'win32':
 if sys.version_info < (3, 0) and sys.platform == 'win32':
     def compat_getpass(prompt, *args, **kwargs):
     def compat_getpass(prompt, *args, **kwargs):
         if isinstance(prompt, compat_str):
         if isinstance(prompt, compat_str):
@@ -3098,22 +3158,22 @@ else:
 compat_getpass_getpass = compat_getpass
 compat_getpass_getpass = compat_getpass
 
 
 
 
+# compat_input
 try:
 try:
     compat_input = raw_input
     compat_input = raw_input
 except NameError:  # Python 3
 except NameError:  # Python 3
     compat_input = input
     compat_input = input
 
 
 
 
+# compat_kwargs
 # Python < 2.6.5 require kwargs to be bytes
 # Python < 2.6.5 require kwargs to be bytes
 try:
 try:
-    def _testfunc(x):
-        pass
-    _testfunc(**{'x': 0})
+    (lambda x: x)(**{'x': 0})
 except TypeError:
 except TypeError:
     def compat_kwargs(kwargs):
     def compat_kwargs(kwargs):
         return dict((bytes(k), v) for k, v in kwargs.items())
         return dict((bytes(k), v) for k, v in kwargs.items())
 else:
 else:
-    compat_kwargs = lambda kwargs: kwargs
+    compat_kwargs = _IDENTITY
 
 
 
 
 # compat_numeric_types
 # compat_numeric_types
@@ -3132,6 +3192,8 @@ except NameError:  # Python 3
 # compat_int
 # compat_int
 compat_int = compat_integer_types[-1]
 compat_int = compat_integer_types[-1]
 
 
+
+# compat_socket_create_connection
 if sys.version_info < (2, 7):
 if sys.version_info < (2, 7):
     def compat_socket_create_connection(address, timeout, source_address=None):
     def compat_socket_create_connection(address, timeout, source_address=None):
         host, port = address
         host, port = address
@@ -3158,6 +3220,7 @@ else:
     compat_socket_create_connection = socket.create_connection
     compat_socket_create_connection = socket.create_connection
 
 
 
 
+# compat_contextlib_suppress
 try:
 try:
     from contextlib import suppress as compat_contextlib_suppress
     from contextlib import suppress as compat_contextlib_suppress
 except ImportError:
 except ImportError:
@@ -3200,12 +3263,12 @@ except AttributeError:
                         # repeated .close() is OK, but just in case
                         # repeated .close() is OK, but just in case
                         with compat_contextlib_suppress(EnvironmentError):
                         with compat_contextlib_suppress(EnvironmentError):
                             f.close()
                             f.close()
-                popen.wait()
+            popen.wait()
 
 
 
 
 # Fix https://github.com/ytdl-org/youtube-dl/issues/4223
 # Fix https://github.com/ytdl-org/youtube-dl/issues/4223
 # See http://bugs.python.org/issue9161 for what is broken
 # See http://bugs.python.org/issue9161 for what is broken
-def workaround_optparse_bug9161():
+def _workaround_optparse_bug9161():
     op = optparse.OptionParser()
     op = optparse.OptionParser()
     og = optparse.OptionGroup(op, 'foo')
     og = optparse.OptionGroup(op, 'foo')
     try:
     try:
@@ -3224,9 +3287,10 @@ def workaround_optparse_bug9161():
         optparse.OptionGroup.add_option = _compat_add_option
         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:
+# compat_shutil_get_terminal_size
+try:
+    from shutil import get_terminal_size as compat_get_terminal_size  # Python >= 3.3
+except ImportError:
     _terminal_size = collections.namedtuple('terminal_size', ['columns', 'lines'])
     _terminal_size = collections.namedtuple('terminal_size', ['columns', 'lines'])
 
 
     def compat_get_terminal_size(fallback=(80, 24)):
     def compat_get_terminal_size(fallback=(80, 24)):
@@ -3256,27 +3320,33 @@ else:
                 columns = _columns
                 columns = _columns
             if lines is None or lines <= 0:
             if lines is None or lines <= 0:
                 lines = _lines
                 lines = _lines
+
         return _terminal_size(columns, lines)
         return _terminal_size(columns, lines)
 
 
+compat_shutil_get_terminal_size = compat_get_terminal_size
+
 
 
+# compat_itertools_count
 try:
 try:
-    itertools.count(start=0, step=1)
+    type(itertools.count(start=0, step=1))
     compat_itertools_count = itertools.count
     compat_itertools_count = itertools.count
-except TypeError:  # Python 2.6
+except TypeError:  # Python 2.6 lacks step
     def compat_itertools_count(start=0, step=1):
     def compat_itertools_count(start=0, step=1):
         while True:
         while True:
             yield start
             yield start
             start += step
             start += step
 
 
 
 
+# compat_tokenize_tokenize
 if sys.version_info >= (3, 0):
 if sys.version_info >= (3, 0):
     from tokenize import tokenize as compat_tokenize_tokenize
     from tokenize import tokenize as compat_tokenize_tokenize
 else:
 else:
     from tokenize import generate_tokens as compat_tokenize_tokenize
     from tokenize import generate_tokens as compat_tokenize_tokenize
 
 
 
 
+# compat_struct_pack, compat_struct_unpack, compat_Struct
 try:
 try:
-    struct.pack('!I', 0)
+    type(struct.pack('!I', 0))
 except TypeError:
 except TypeError:
     # In Python 2.6 and 2.7.x < 2.7.7, struct requires a bytes argument
     # In Python 2.6 and 2.7.x < 2.7.7, struct requires a bytes argument
     # See https://bugs.python.org/issue19099
     # See https://bugs.python.org/issue19099
@@ -3308,8 +3378,10 @@ else:
         compat_Struct = struct.Struct
         compat_Struct = struct.Struct
 
 
 
 
-# compat_map/filter() returning an iterator, supposedly the
-# same versioning as for zip below
+# builtins returning an iterator
+
+# compat_map, compat_filter
+# supposedly the same versioning as for zip below
 try:
 try:
     from future_builtins import map as compat_map
     from future_builtins import map as compat_map
 except ImportError:
 except ImportError:
@@ -3326,6 +3398,7 @@ except ImportError:
     except ImportError:
     except ImportError:
         compat_filter = filter
         compat_filter = filter
 
 
+# compat_zip
 try:
 try:
     from future_builtins import zip as compat_zip
     from future_builtins import zip as compat_zip
 except ImportError:  # not 2.6+ or is 3.x
 except ImportError:  # not 2.6+ or is 3.x
@@ -3335,6 +3408,7 @@ except ImportError:  # not 2.6+ or is 3.x
         compat_zip = zip
         compat_zip = zip
 
 
 
 
+# compat_itertools_zip_longest
 # method renamed between Py2/3
 # method renamed between Py2/3
 try:
 try:
     from itertools import zip_longest as compat_itertools_zip_longest
     from itertools import zip_longest as compat_itertools_zip_longest
@@ -3342,7 +3416,8 @@ except ImportError:
     from itertools import izip_longest as compat_itertools_zip_longest
     from itertools import izip_longest as compat_itertools_zip_longest
 
 
 
 
-# new class in collections
+# compat_collections_chain_map
+# collections.ChainMap: new class
 try:
 try:
     from collections import ChainMap as compat_collections_chain_map
     from collections import ChainMap as compat_collections_chain_map
     # Py3.3's ChainMap is deficient
     # Py3.3's ChainMap is deficient
@@ -3405,12 +3480,14 @@ except ImportError:
             return compat_collections_chain_map(*(self.maps[1:]))
             return compat_collections_chain_map(*(self.maps[1:]))
 
 
 
 
+# compat_re_Pattern, compat_re_Match
 # Pythons disagree on the type of a pattern (RegexObject, _sre.SRE_Pattern, Pattern, ...?)
 # Pythons disagree on the type of a pattern (RegexObject, _sre.SRE_Pattern, Pattern, ...?)
 compat_re_Pattern = type(re.compile(''))
 compat_re_Pattern = type(re.compile(''))
 # and on the type of a match
 # and on the type of a match
 compat_re_Match = type(re.match('a', 'a'))
 compat_re_Match = type(re.match('a', 'a'))
 
 
 
 
+# compat_base64_b64decode
 if sys.version_info < (3, 3):
 if sys.version_info < (3, 3):
     def compat_b64decode(s, *args, **kwargs):
     def compat_b64decode(s, *args, **kwargs):
         if isinstance(s, compat_str):
         if isinstance(s, compat_str):
@@ -3422,6 +3499,7 @@ else:
 compat_base64_b64decode = compat_b64decode
 compat_base64_b64decode = compat_b64decode
 
 
 
 
+# compat_ctypes_WINFUNCTYPE
 if platform.python_implementation() == 'PyPy' and sys.pypy_version_info < (5, 4, 0):
 if platform.python_implementation() == 'PyPy' and sys.pypy_version_info < (5, 4, 0):
     # PyPy2 prior to version 5.4.0 expects byte strings as Windows function
     # PyPy2 prior to version 5.4.0 expects byte strings as Windows function
     # names, see the original PyPy issue [1] and the youtube-dl one [2].
     # names, see the original PyPy issue [1] and the youtube-dl one [2].
@@ -3440,6 +3518,7 @@ else:
         return ctypes.WINFUNCTYPE(*args, **kwargs)
         return ctypes.WINFUNCTYPE(*args, **kwargs)
 
 
 
 
+# compat_open
 if sys.version_info < (3, 0):
 if sys.version_info < (3, 0):
     # open(file, mode='r', buffering=- 1, encoding=None, errors=None, newline=None, closefd=True) not: opener=None
     # open(file, mode='r', buffering=- 1, encoding=None, errors=None, newline=None, closefd=True) not: opener=None
     def compat_open(file_, *args, **kwargs):
     def compat_open(file_, *args, **kwargs):
@@ -3467,12 +3546,15 @@ except AttributeError:
     def compat_datetime_timedelta_total_seconds(td):
     def compat_datetime_timedelta_total_seconds(td):
         return (td.microseconds + (td.seconds + td.days * 24 * 3600) * 10**6) / 10**6
         return (td.microseconds + (td.seconds + td.days * 24 * 3600) * 10**6) / 10**6
 
 
+
 # optional decompression packages
 # optional decompression packages
+# compat_brotli
 # PyPi brotli package implements 'br' Content-Encoding
 # PyPi brotli package implements 'br' Content-Encoding
 try:
 try:
     import brotli as compat_brotli
     import brotli as compat_brotli
 except ImportError:
 except ImportError:
     compat_brotli = None
     compat_brotli = None
+# compat_ncompress
 # PyPi ncompress package implements 'compress' Content-Encoding
 # PyPi ncompress package implements 'compress' Content-Encoding
 try:
 try:
     import ncompress as compat_ncompress
     import ncompress as compat_ncompress
@@ -3495,6 +3577,7 @@ legacy = [
     'compat_getpass',
     'compat_getpass',
     'compat_parse_qs',
     'compat_parse_qs',
     'compat_realpath',
     'compat_realpath',
+    'compat_shlex_split',
     'compat_urllib_parse_parse_qs',
     'compat_urllib_parse_parse_qs',
     'compat_urllib_parse_unquote',
     'compat_urllib_parse_unquote',
     'compat_urllib_parse_unquote_plus',
     'compat_urllib_parse_unquote_plus',
@@ -3508,8 +3591,6 @@ legacy = [
 
 
 
 
 __all__ = [
 __all__ = [
-    'compat_html_parser_HTMLParseError',
-    'compat_html_parser_HTMLParser',
     'compat_Struct',
     'compat_Struct',
     'compat_base64_b64decode',
     'compat_base64_b64decode',
     'compat_basestring',
     'compat_basestring',
@@ -3518,13 +3599,9 @@ __all__ = [
     'compat_chr',
     'compat_chr',
     'compat_collections_abc',
     'compat_collections_abc',
     'compat_collections_chain_map',
     'compat_collections_chain_map',
-    'compat_datetime_timedelta_total_seconds',
-    'compat_http_cookiejar',
-    'compat_http_cookiejar_Cookie',
-    'compat_http_cookies',
-    'compat_http_cookies_SimpleCookie',
     'compat_contextlib_suppress',
     'compat_contextlib_suppress',
     'compat_ctypes_WINFUNCTYPE',
     'compat_ctypes_WINFUNCTYPE',
+    'compat_datetime_timedelta_total_seconds',
     'compat_etree_fromstring',
     'compat_etree_fromstring',
     'compat_etree_iterfind',
     'compat_etree_iterfind',
     'compat_filter',
     'compat_filter',
@@ -3533,6 +3610,12 @@ __all__ = [
     'compat_getpass_getpass',
     'compat_getpass_getpass',
     'compat_html_entities',
     'compat_html_entities',
     'compat_html_entities_html5',
     'compat_html_entities_html5',
+    'compat_html_parser_HTMLParseError',
+    'compat_html_parser_HTMLParser',
+    'compat_http_cookiejar',
+    'compat_http_cookiejar_Cookie',
+    'compat_http_cookies',
+    'compat_http_cookies_SimpleCookie',
     'compat_http_client',
     'compat_http_client',
     'compat_http_server',
     'compat_http_server',
     'compat_input',
     'compat_input',
@@ -3555,7 +3638,7 @@ __all__ = [
     'compat_register_utf8',
     'compat_register_utf8',
     'compat_setenv',
     'compat_setenv',
     'compat_shlex_quote',
     'compat_shlex_quote',
-    'compat_shlex_split',
+    'compat_shutil_get_terminal_size',
     'compat_socket_create_connection',
     'compat_socket_create_connection',
     'compat_str',
     'compat_str',
     'compat_struct_pack',
     'compat_struct_pack',
@@ -3575,5 +3658,4 @@ __all__ = [
     'compat_xml_etree_register_namespace',
     'compat_xml_etree_register_namespace',
     'compat_xpath',
     'compat_xpath',
     'compat_zip',
     'compat_zip',
-    'workaround_optparse_bug9161',
 ]
 ]