]> jfr.im git - yt-dlp.git/blob - yt_dlp/compat.py
[cleanup] Remove unused code paths (#2173)
[yt-dlp.git] / yt_dlp / compat.py
1 # coding: utf-8
2
3 import asyncio
4 import base64
5 import collections
6 import ctypes
7 import getpass
8 import html
9 import html.parser
10 import http
11 import http.client
12 import http.cookiejar
13 import http.cookies
14 import http.server
15 import itertools
16 import os
17 import re
18 import shlex
19 import shutil
20 import socket
21 import struct
22 import subprocess
23 import sys
24 import tokenize
25 import urllib
26 import xml.etree.ElementTree as etree
27 from subprocess import DEVNULL
28
29
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
35
36
37 # compat_ctypes_WINFUNCTYPE = ctypes.WINFUNCTYPE
38 # will not work since ctypes.WINFUNCTYPE does not exist in UNIX machines
39 def compat_ctypes_WINFUNCTYPE(*args, **kwargs):
40 return ctypes.WINFUNCTYPE(*args, **kwargs)
41
42
43 class _TreeBuilder(etree.TreeBuilder):
44 def doctype(self, name, pubid, system):
45 pass
46
47
48 def compat_etree_fromstring(text):
49 return etree.XML(text, parser=etree.XMLParser(target=_TreeBuilder()))
50
51
52 compat_os_name = os._name if os.name == 'java' else os.name
53
54
55 if compat_os_name == 'nt':
56 def compat_shlex_quote(s):
57 return s if re.match(r'^[-_\w./]+$', s) else '"%s"' % s.replace('"', '\\"')
58 else:
59 from shlex import quote as compat_shlex_quote
60
61
62 def compat_ord(c):
63 if type(c) is int:
64 return c
65 else:
66 return ord(c)
67
68
69 def compat_setenv(key, value, env=os.environ):
70 env[key] = value
71
72
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
84 def compat_print(s):
85 assert isinstance(s, compat_str)
86 print(s)
87
88 try:
89 compat_Pattern = re.Pattern
90 except AttributeError:
91 compat_Pattern = type(re.compile(''))
92
93
94 try:
95 compat_Match = re.Match
96 except AttributeError:
97 compat_Match = type(re.compile('').match(''))
98
99
100 try:
101 compat_asyncio_run = asyncio.run # >= 3.7
102 except AttributeError:
103 def compat_asyncio_run(coro):
104 try:
105 loop = asyncio.get_event_loop()
106 except RuntimeError:
107 loop = asyncio.new_event_loop()
108 asyncio.set_event_loop(loop)
109 loop.run_until_complete(coro)
110
111 asyncio.run = compat_asyncio_run
112
113
114 try: # >= 3.7
115 asyncio.tasks.all_tasks
116 except AttributeError:
117 asyncio.tasks.all_tasks = asyncio.tasks.Task.all_tasks
118
119 try:
120 import websockets as compat_websockets
121 except ImportError:
122 compat_websockets = None
123
124 # Python 3.8+ does not honor %HOME% on windows, but this breaks compatibility with youtube-dl
125 # See https://github.com/yt-dlp/yt-dlp/issues/792
126 # https://docs.python.org/3/library/os.path.html#os.path.expanduser
127 if compat_os_name in ('nt', 'ce') and 'HOME' in os.environ:
128 _userhome = os.environ['HOME']
129
130 def compat_expanduser(path):
131 if not path.startswith('~'):
132 return path
133 i = path.replace('\\', '/', 1).find('/') # ~user
134 if i < 0:
135 i = len(path)
136 userhome = os.path.join(os.path.dirname(_userhome), path[1:i]) if i > 1 else _userhome
137 return userhome + path[i:]
138 else:
139 compat_expanduser = os.path.expanduser
140
141
142 try:
143 from Cryptodome.Cipher import AES as compat_pycrypto_AES
144 except ImportError:
145 try:
146 from Crypto.Cipher import AES as compat_pycrypto_AES
147 except ImportError:
148 compat_pycrypto_AES = None
149
150 try:
151 import brotlicffi as compat_brotli
152 except ImportError:
153 try:
154 import brotli as compat_brotli
155 except ImportError:
156 compat_brotli = None
157
158 WINDOWS_VT_MODE = False if compat_os_name == 'nt' else None
159
160
161 def windows_enable_vt_mode(): # TODO: Do this the proper way https://bugs.python.org/issue30075
162 if compat_os_name != 'nt':
163 return
164 global WINDOWS_VT_MODE
165 startupinfo = subprocess.STARTUPINFO()
166 startupinfo.dwFlags |= subprocess.STARTF_USESHOWWINDOW
167 try:
168 subprocess.Popen('', shell=True, startupinfo=startupinfo)
169 WINDOWS_VT_MODE = True
170 except Exception:
171 pass
172
173
174 # Deprecated
175
176 compat_basestring = str
177 compat_chr = chr
178 compat_filter = filter
179 compat_input = input
180 compat_integer_types = (int, )
181 compat_kwargs = lambda kwargs: kwargs
182 compat_map = map
183 compat_numeric_types = (int, float, complex)
184 compat_str = str
185 compat_xpath = lambda xpath: xpath
186 compat_zip = zip
187 workaround_optparse_bug9161 = lambda: None
188
189 compat_collections_abc = collections.abc
190 compat_HTMLParser = html.parser.HTMLParser
191 compat_HTTPError = urllib.error.HTTPError
192 compat_Struct = struct.Struct
193 compat_b64decode = base64.b64decode
194 compat_cookiejar = http.cookiejar
195 compat_cookiejar_Cookie = compat_cookiejar.Cookie
196 compat_cookies = http.cookies
197 compat_cookies_SimpleCookie = compat_cookies.SimpleCookie
198 compat_etree_Element = etree.Element
199 compat_etree_register_namespace = etree.register_namespace
200 compat_get_terminal_size = shutil.get_terminal_size
201 compat_getenv = os.getenv
202 compat_getpass = getpass.getpass
203 compat_html_entities = html.entities
204 compat_html_entities_html5 = compat_html_entities.html5
205 compat_http_client = http.client
206 compat_http_server = http.server
207 compat_itertools_count = itertools.count
208 compat_parse_qs = urllib.parse.parse_qs
209 compat_shlex_split = shlex.split
210 compat_socket_create_connection = socket.create_connection
211 compat_struct_pack = struct.pack
212 compat_struct_unpack = struct.unpack
213 compat_subprocess_get_DEVNULL = lambda: DEVNULL
214 compat_tokenize_tokenize = tokenize.tokenize
215 compat_urllib_error = urllib.error
216 compat_urllib_parse = urllib.parse
217 compat_urllib_parse_quote = urllib.parse.quote
218 compat_urllib_parse_quote_plus = urllib.parse.quote_plus
219 compat_urllib_parse_unquote = urllib.parse.unquote
220 compat_urllib_parse_unquote_plus = urllib.parse.unquote_plus
221 compat_urllib_parse_unquote_to_bytes = urllib.parse.unquote_to_bytes
222 compat_urllib_parse_urlencode = urllib.parse.urlencode
223 compat_urllib_parse_urlparse = urllib.parse.urlparse
224 compat_urllib_parse_urlunparse = urllib.parse.urlunparse
225 compat_urllib_request = urllib.request
226 compat_urllib_request_DataHandler = urllib.request.DataHandler
227 compat_urllib_response = urllib.response
228 compat_urlparse = urllib.parse
229 compat_urlretrieve = urllib.request.urlretrieve
230 compat_xml_parse_error = etree.ParseError
231
232
233 # Set public objects
234
235 __all__ = [
236 'WINDOWS_VT_MODE',
237 'compat_HTMLParseError',
238 'compat_HTMLParser',
239 'compat_HTTPError',
240 'compat_Match',
241 'compat_Pattern',
242 'compat_Struct',
243 'compat_asyncio_run',
244 'compat_b64decode',
245 'compat_basestring',
246 'compat_brotli',
247 'compat_chr',
248 'compat_collections_abc',
249 'compat_cookiejar',
250 'compat_cookiejar_Cookie',
251 'compat_cookies',
252 'compat_cookies_SimpleCookie',
253 'compat_ctypes_WINFUNCTYPE',
254 'compat_etree_Element',
255 'compat_etree_fromstring',
256 'compat_etree_register_namespace',
257 'compat_expanduser',
258 'compat_filter',
259 'compat_get_terminal_size',
260 'compat_getenv',
261 'compat_getpass',
262 'compat_html_entities',
263 'compat_html_entities_html5',
264 'compat_http_client',
265 'compat_http_server',
266 'compat_input',
267 'compat_integer_types',
268 'compat_itertools_count',
269 'compat_kwargs',
270 'compat_map',
271 'compat_numeric_types',
272 'compat_ord',
273 'compat_os_name',
274 'compat_parse_qs',
275 'compat_print',
276 'compat_pycrypto_AES',
277 'compat_realpath',
278 'compat_setenv',
279 'compat_shlex_quote',
280 'compat_shlex_split',
281 'compat_socket_create_connection',
282 'compat_str',
283 'compat_struct_pack',
284 'compat_struct_unpack',
285 'compat_subprocess_get_DEVNULL',
286 'compat_tokenize_tokenize',
287 'compat_urllib_error',
288 'compat_urllib_parse',
289 'compat_urllib_parse_quote',
290 'compat_urllib_parse_quote_plus',
291 'compat_urllib_parse_unquote',
292 'compat_urllib_parse_unquote_plus',
293 'compat_urllib_parse_unquote_to_bytes',
294 'compat_urllib_parse_urlencode',
295 'compat_urllib_parse_urlparse',
296 'compat_urllib_parse_urlunparse',
297 'compat_urllib_request',
298 'compat_urllib_request_DataHandler',
299 'compat_urllib_response',
300 'compat_urlparse',
301 'compat_urlretrieve',
302 'compat_websockets',
303 'compat_xml_parse_error',
304 'compat_xpath',
305 'compat_zip',
306 'windows_enable_vt_mode',
307 'workaround_optparse_bug9161',
308 ]