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