]>
Commit | Line | Data |
---|---|---|
dfe5fa49 | 1 | # coding: utf-8 |
451948b2 | 2 | |
c634ad2a | 3 | import asyncio |
f206126d | 4 | import base64 |
d7cd9a9e | 5 | import ctypes |
8c25f81b | 6 | import getpass |
c634ad2a | 7 | import html |
8 | import html.parser | |
9 | import http | |
10 | import http.client | |
11 | import http.cookiejar | |
12 | import http.cookies | |
13 | import http.server | |
2384f5a6 | 14 | import itertools |
e07e9313 | 15 | import optparse |
8c25f81b | 16 | import os |
7d4111ed | 17 | import re |
51f579b6 | 18 | import shlex |
003c69a8 | 19 | import shutil |
be4a824d | 20 | import socket |
dab0daee | 21 | import struct |
673944b0 | 22 | import subprocess |
8c25f81b | 23 | import sys |
c634ad2a | 24 | import tokenize |
25 | import urllib | |
26 | import xml.etree.ElementTree as etree | |
27 | from subprocess import DEVNULL | |
72b40955 | 28 | |
72b40955 | 29 | |
c634ad2a | 30 | # HTMLParseError has been deprecated in Python 3.3 and removed in |
31 | # Python 3.5. Introducing dummy exception for Python >3.5 for compatible | |
32 | # and uniform cross-version exception handling | |
33 | class compat_HTMLParseError(Exception): | |
34 | pass | |
15707c7e | 35 | |
15707c7e | 36 | |
e6f21b3d | 37 | # compat_ctypes_WINFUNCTYPE = ctypes.WINFUNCTYPE |
38 | # will not work since ctypes.WINFUNCTYPE does not exist in UNIX machines | |
c634ad2a | 39 | def compat_ctypes_WINFUNCTYPE(*args, **kwargs): |
40 | return ctypes.WINFUNCTYPE(*args, **kwargs) | |
eb7941e3 YCH |
41 | |
42 | ||
43 | class _TreeBuilder(etree.TreeBuilder): | |
44 | def doctype(self, name, pubid, system): | |
45 | pass | |
46 | ||
582be358 | 47 | |
c634ad2a | 48 | def compat_etree_fromstring(text): |
49 | return etree.XML(text, parser=etree.XMLParser(target=_TreeBuilder())) | |
8c25f81b | 50 | |
b08e235f S |
51 | |
52 | compat_os_name = os._name if os.name == 'java' else os.name | |
53 | ||
54 | ||
55 | if compat_os_name == 'nt': | |
702ccf2d | 56 | def compat_shlex_quote(s): |
b08e235f S |
57 | return s if re.match(r'^[-_\w./]+$', s) else '"%s"' % s.replace('"', '\\"') |
58 | else: | |
c634ad2a | 59 | from shlex import quote as compat_shlex_quote |
51f579b6 S |
60 | |
61 | ||
8c25f81b | 62 | def compat_ord(c): |
5f6a1245 JW |
63 | if type(c) is int: |
64 | return c | |
65 | else: | |
66 | return ord(c) | |
8c25f81b PH |
67 | |
68 | ||
c634ad2a | 69 | def compat_setenv(key, value, env=os.environ): |
70 | env[key] = value | |
8c25f81b PH |
71 | |
72 | ||
82fea5b4 S |
73 | if compat_os_name == 'nt' and sys.version_info < (3, 8): |
74 | # os.path.realpath on Windows does not follow symbolic links | |
75 | # prior to Python 3.8 (see https://bugs.python.org/issue9949) | |
76 | def compat_realpath(path): | |
77 | while os.path.islink(path): | |
78 | path = os.path.abspath(os.readlink(path)) | |
79 | return path | |
80 | else: | |
81 | compat_realpath = os.path.realpath | |
82 | ||
83 | ||
c634ad2a | 84 | def compat_print(s): |
85 | assert isinstance(s, compat_str) | |
86 | print(s) | |
be4a824d PH |
87 | |
88 | ||
067aa17e | 89 | # Fix https://github.com/ytdl-org/youtube-dl/issues/4223 |
e07e9313 PH |
90 | # See http://bugs.python.org/issue9161 for what is broken |
91 | def workaround_optparse_bug9161(): | |
07e378fa PH |
92 | op = optparse.OptionParser() |
93 | og = optparse.OptionGroup(op, 'foo') | |
e07e9313 | 94 | try: |
07e378fa | 95 | og.add_option('-t') |
b244b5c3 | 96 | except TypeError: |
e07e9313 PH |
97 | real_add_option = optparse.OptionGroup.add_option |
98 | ||
99 | def _compat_add_option(self, *args, **kwargs): | |
100 | enc = lambda v: ( | |
101 | v.encode('ascii', 'replace') if isinstance(v, compat_str) | |
102 | else v) | |
103 | bargs = [enc(a) for a in args] | |
104 | bkwargs = dict( | |
105 | (k, enc(v)) for k, v in kwargs.items()) | |
106 | return real_add_option(self, *bargs, **bkwargs) | |
107 | optparse.OptionGroup.add_option = _compat_add_option | |
108 | ||
582be358 | 109 | |
4a2f19ab F |
110 | try: |
111 | compat_Pattern = re.Pattern | |
112 | except AttributeError: | |
113 | compat_Pattern = type(re.compile('')) | |
114 | ||
115 | ||
116 | try: | |
117 | compat_Match = re.Match | |
118 | except AttributeError: | |
119 | compat_Match = type(re.compile('').match('')) | |
120 | ||
121 | ||
e36d50c5 | 122 | try: |
c634ad2a | 123 | compat_asyncio_run = asyncio.run # >= 3.7 |
e36d50c5 | 124 | except AttributeError: |
125 | def compat_asyncio_run(coro): | |
126 | try: | |
127 | loop = asyncio.get_event_loop() | |
128 | except RuntimeError: | |
129 | loop = asyncio.new_event_loop() | |
130 | asyncio.set_event_loop(loop) | |
131 | loop.run_until_complete(coro) | |
132 | ||
133 | asyncio.run = compat_asyncio_run | |
134 | ||
135 | ||
c589c1d3 | 136 | # Python 3.8+ does not honor %HOME% on windows, but this breaks compatibility with youtube-dl |
137 | # See https://github.com/yt-dlp/yt-dlp/issues/792 | |
138 | # https://docs.python.org/3/library/os.path.html#os.path.expanduser | |
139 | if compat_os_name in ('nt', 'ce') and 'HOME' in os.environ: | |
140 | _userhome = os.environ['HOME'] | |
141 | ||
142 | def compat_expanduser(path): | |
143 | if not path.startswith('~'): | |
144 | return path | |
145 | i = path.replace('\\', '/', 1).find('/') # ~user | |
146 | if i < 0: | |
147 | i = len(path) | |
148 | userhome = os.path.join(os.path.dirname(_userhome), path[1:i]) if i > 1 else _userhome | |
149 | return userhome + path[i:] | |
150 | else: | |
151 | compat_expanduser = os.path.expanduser | |
152 | ||
153 | ||
edf65256 | 154 | try: |
155 | from Cryptodome.Cipher import AES as compat_pycrypto_AES | |
156 | except ImportError: | |
157 | try: | |
158 | from Crypto.Cipher import AES as compat_pycrypto_AES | |
159 | except ImportError: | |
160 | compat_pycrypto_AES = None | |
161 | ||
162 | ||
819e0531 | 163 | def windows_enable_vt_mode(): # TODO: Do this the proper way https://bugs.python.org/issue30075 |
164 | if compat_os_name != 'nt': | |
165 | return | |
673944b0 | 166 | startupinfo = subprocess.STARTUPINFO() |
167 | startupinfo.dwFlags |= subprocess.STARTF_USESHOWWINDOW | |
168 | subprocess.Popen('', shell=True, startupinfo=startupinfo) | |
819e0531 | 169 | |
170 | ||
c634ad2a | 171 | # Deprecated |
172 | ||
173 | compat_basestring = str | |
174 | compat_chr = chr | |
175 | compat_input = input | |
176 | compat_integer_types = (int, ) | |
177 | compat_kwargs = lambda kwargs: kwargs | |
178 | compat_numeric_types = (int, float, complex) | |
179 | compat_str = str | |
180 | compat_xpath = lambda xpath: xpath | |
181 | compat_zip = zip | |
182 | ||
183 | compat_HTMLParser = html.parser.HTMLParser | |
184 | compat_HTTPError = urllib.error.HTTPError | |
185 | compat_Struct = struct.Struct | |
186 | compat_b64decode = base64.b64decode | |
187 | compat_cookiejar = http.cookiejar | |
188 | compat_cookiejar_Cookie = compat_cookiejar.Cookie | |
189 | compat_cookies = http.cookies | |
190 | compat_cookies_SimpleCookie = compat_cookies.SimpleCookie | |
191 | compat_etree_Element = etree.Element | |
192 | compat_etree_register_namespace = etree.register_namespace | |
c634ad2a | 193 | compat_get_terminal_size = shutil.get_terminal_size |
194 | compat_getenv = os.getenv | |
195 | compat_getpass = getpass.getpass | |
196 | compat_html_entities = html.entities | |
197 | compat_html_entities_html5 = compat_html_entities.html5 | |
198 | compat_http_client = http.client | |
199 | compat_http_server = http.server | |
200 | compat_itertools_count = itertools.count | |
201 | compat_parse_qs = urllib.parse.parse_qs | |
202 | compat_shlex_split = shlex.split | |
203 | compat_socket_create_connection = socket.create_connection | |
204 | compat_struct_pack = struct.pack | |
205 | compat_struct_unpack = struct.unpack | |
206 | compat_subprocess_get_DEVNULL = lambda: DEVNULL | |
207 | compat_tokenize_tokenize = tokenize.tokenize | |
208 | compat_urllib_error = urllib.error | |
209 | compat_urllib_parse = urllib.parse | |
210 | compat_urllib_parse_quote = urllib.parse.quote | |
211 | compat_urllib_parse_quote_plus = urllib.parse.quote_plus | |
212 | compat_urllib_parse_unquote = urllib.parse.unquote | |
213 | compat_urllib_parse_unquote_plus = urllib.parse.unquote_plus | |
214 | compat_urllib_parse_unquote_to_bytes = urllib.parse.unquote_to_bytes | |
215 | compat_urllib_parse_urlencode = urllib.parse.urlencode | |
216 | compat_urllib_parse_urlparse = urllib.parse.urlparse | |
217 | compat_urllib_parse_urlunparse = urllib.parse.urlunparse | |
218 | compat_urllib_request = urllib.request | |
219 | compat_urllib_request_DataHandler = urllib.request.DataHandler | |
220 | compat_urllib_response = urllib.response | |
221 | compat_urlparse = urllib.parse | |
222 | compat_urlretrieve = urllib.request.urlretrieve | |
223 | compat_xml_parse_error = etree.ParseError | |
224 | ||
225 | ||
226 | # Set public objects | |
227 | ||
8c25f81b | 228 | __all__ = [ |
b081f53b | 229 | 'compat_HTMLParseError', |
8bb56eee | 230 | 'compat_HTMLParser', |
8c25f81b | 231 | 'compat_HTTPError', |
4a2f19ab F |
232 | 'compat_Match', |
233 | 'compat_Pattern', | |
65220c3b | 234 | 'compat_Struct', |
e36d50c5 | 235 | 'compat_asyncio_run', |
f206126d | 236 | 'compat_b64decode', |
0196149c | 237 | 'compat_basestring', |
8c25f81b PH |
238 | 'compat_chr', |
239 | 'compat_cookiejar', | |
6d874fee | 240 | 'compat_cookiejar_Cookie', |
799207e8 | 241 | 'compat_cookies', |
f7ad7160 | 242 | 'compat_cookies_SimpleCookie', |
d7cd9a9e | 243 | 'compat_ctypes_WINFUNCTYPE', |
399f7687 | 244 | 'compat_etree_Element', |
36e6f62c | 245 | 'compat_etree_fromstring', |
da162c11 | 246 | 'compat_etree_register_namespace', |
8c25f81b | 247 | 'compat_expanduser', |
003c69a8 | 248 | 'compat_get_terminal_size', |
8c25f81b PH |
249 | 'compat_getenv', |
250 | 'compat_getpass', | |
251 | 'compat_html_entities', | |
9631a94f | 252 | 'compat_html_entities_html5', |
8c25f81b | 253 | 'compat_http_client', |
83fda3c0 | 254 | 'compat_http_server', |
e67f6880 | 255 | 'compat_input', |
075a13d3 | 256 | 'compat_integer_types', |
a0e060ac | 257 | 'compat_itertools_count', |
c7b0add8 | 258 | 'compat_kwargs', |
28572a1a | 259 | 'compat_numeric_types', |
8c25f81b | 260 | 'compat_ord', |
e9c0cdd3 | 261 | 'compat_os_name', |
8c25f81b PH |
262 | 'compat_parse_qs', |
263 | 'compat_print', | |
edf65256 | 264 | 'compat_pycrypto_AES', |
bfe2b8cf | 265 | 'compat_realpath', |
fe40f9ee | 266 | 'compat_setenv', |
702ccf2d | 267 | 'compat_shlex_quote', |
51f579b6 | 268 | 'compat_shlex_split', |
be4a824d | 269 | 'compat_socket_create_connection', |
987493ae | 270 | 'compat_str', |
edaa23f8 YCH |
271 | 'compat_struct_pack', |
272 | 'compat_struct_unpack', | |
8c25f81b | 273 | 'compat_subprocess_get_DEVNULL', |
67134eab | 274 | 'compat_tokenize_tokenize', |
8c25f81b PH |
275 | 'compat_urllib_error', |
276 | 'compat_urllib_parse', | |
732044af | 277 | 'compat_urllib_parse_quote', |
278 | 'compat_urllib_parse_quote_plus', | |
8c25f81b | 279 | 'compat_urllib_parse_unquote', |
aa99aa4e | 280 | 'compat_urllib_parse_unquote_plus', |
9fefc886 | 281 | 'compat_urllib_parse_unquote_to_bytes', |
15707c7e | 282 | 'compat_urllib_parse_urlencode', |
8c25f81b | 283 | 'compat_urllib_parse_urlparse', |
732044af | 284 | 'compat_urllib_parse_urlunparse', |
8c25f81b | 285 | 'compat_urllib_request', |
0a67a363 YCH |
286 | 'compat_urllib_request_DataHandler', |
287 | 'compat_urllib_response', | |
8c25f81b PH |
288 | 'compat_urlparse', |
289 | 'compat_urlretrieve', | |
290 | 'compat_xml_parse_error', | |
57f7e3c6 | 291 | 'compat_xpath', |
2384f5a6 | 292 | 'compat_zip', |
819e0531 | 293 | 'windows_enable_vt_mode', |
e07e9313 | 294 | 'workaround_optparse_bug9161', |
8c25f81b | 295 | ] |