]> jfr.im git - yt-dlp.git/blame - yt_dlp/compat.py
[cleanup] Remove unused code paths (#2173)
[yt-dlp.git] / yt_dlp / compat.py
CommitLineData
dfe5fa49 1# coding: utf-8
451948b2 2
c634ad2a 3import asyncio
f206126d 4import base64
d5a39898 5import collections
d7cd9a9e 6import ctypes
8c25f81b 7import getpass
c634ad2a 8import html
9import html.parser
10import http
11import http.client
12import http.cookiejar
13import http.cookies
14import http.server
2384f5a6 15import itertools
8c25f81b 16import os
7d4111ed 17import re
51f579b6 18import shlex
003c69a8 19import shutil
be4a824d 20import socket
dab0daee 21import struct
673944b0 22import subprocess
8c25f81b 23import sys
c634ad2a 24import tokenize
25import urllib
26import xml.etree.ElementTree as etree
27from 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
33class 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 39def compat_ctypes_WINFUNCTYPE(*args, **kwargs):
40 return ctypes.WINFUNCTYPE(*args, **kwargs)
eb7941e3
YCH
41
42
43class _TreeBuilder(etree.TreeBuilder):
44 def doctype(self, name, pubid, system):
45 pass
46
582be358 47
c634ad2a 48def compat_etree_fromstring(text):
49 return etree.XML(text, parser=etree.XMLParser(target=_TreeBuilder()))
8c25f81b 50
b08e235f
S
51
52compat_os_name = os._name if os.name == 'java' else os.name
53
54
55if 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('"', '\\"')
58else:
c634ad2a 59 from shlex import quote as compat_shlex_quote
51f579b6
S
60
61
8c25f81b 62def 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 69def compat_setenv(key, value, env=os.environ):
70 env[key] = value
8c25f81b
PH
71
72
82fea5b4
S
73if 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
80else:
81 compat_realpath = os.path.realpath
82
83
c634ad2a 84def compat_print(s):
85 assert isinstance(s, compat_str)
86 print(s)
be4a824d 87
4a2f19ab
F
88try:
89 compat_Pattern = re.Pattern
90except AttributeError:
91 compat_Pattern = type(re.compile(''))
92
93
94try:
95 compat_Match = re.Match
96except AttributeError:
97 compat_Match = type(re.compile('').match(''))
98
99
e36d50c5 100try:
c634ad2a 101 compat_asyncio_run = asyncio.run # >= 3.7
e36d50c5 102except 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
da42679b
LNO
114try: # >= 3.7
115 asyncio.tasks.all_tasks
116except AttributeError:
117 asyncio.tasks.all_tasks = asyncio.tasks.Task.all_tasks
118
119try:
120 import websockets as compat_websockets
121except ImportError:
122 compat_websockets = None
123
c589c1d3 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
127if 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:]
138else:
139 compat_expanduser = os.path.expanduser
140
141
edf65256 142try:
143 from Cryptodome.Cipher import AES as compat_pycrypto_AES
144except ImportError:
145 try:
146 from Crypto.Cipher import AES as compat_pycrypto_AES
147 except ImportError:
148 compat_pycrypto_AES = None
149
4390d5ec 150try:
151 import brotlicffi as compat_brotli
152except ImportError:
153 try:
154 import brotli as compat_brotli
155 except ImportError:
156 compat_brotli = None
edf65256 157
e3c7d495 158WINDOWS_VT_MODE = False if compat_os_name == 'nt' else None
159
160
819e0531 161def windows_enable_vt_mode(): # TODO: Do this the proper way https://bugs.python.org/issue30075
162 if compat_os_name != 'nt':
163 return
e3c7d495 164 global WINDOWS_VT_MODE
673944b0 165 startupinfo = subprocess.STARTUPINFO()
166 startupinfo.dwFlags |= subprocess.STARTF_USESHOWWINDOW
e3c7d495 167 try:
168 subprocess.Popen('', shell=True, startupinfo=startupinfo)
169 WINDOWS_VT_MODE = True
170 except Exception:
171 pass
819e0531 172
173
c634ad2a 174# Deprecated
175
176compat_basestring = str
177compat_chr = chr
d5a39898 178compat_filter = filter
c634ad2a 179compat_input = input
180compat_integer_types = (int, )
181compat_kwargs = lambda kwargs: kwargs
d5a39898 182compat_map = map
c634ad2a 183compat_numeric_types = (int, float, complex)
184compat_str = str
185compat_xpath = lambda xpath: xpath
186compat_zip = zip
cfb0511d 187workaround_optparse_bug9161 = lambda: None
c634ad2a 188
d5a39898 189compat_collections_abc = collections.abc
c634ad2a 190compat_HTMLParser = html.parser.HTMLParser
191compat_HTTPError = urllib.error.HTTPError
192compat_Struct = struct.Struct
193compat_b64decode = base64.b64decode
194compat_cookiejar = http.cookiejar
195compat_cookiejar_Cookie = compat_cookiejar.Cookie
196compat_cookies = http.cookies
197compat_cookies_SimpleCookie = compat_cookies.SimpleCookie
198compat_etree_Element = etree.Element
199compat_etree_register_namespace = etree.register_namespace
c634ad2a 200compat_get_terminal_size = shutil.get_terminal_size
201compat_getenv = os.getenv
202compat_getpass = getpass.getpass
203compat_html_entities = html.entities
204compat_html_entities_html5 = compat_html_entities.html5
205compat_http_client = http.client
206compat_http_server = http.server
207compat_itertools_count = itertools.count
208compat_parse_qs = urllib.parse.parse_qs
209compat_shlex_split = shlex.split
210compat_socket_create_connection = socket.create_connection
211compat_struct_pack = struct.pack
212compat_struct_unpack = struct.unpack
213compat_subprocess_get_DEVNULL = lambda: DEVNULL
214compat_tokenize_tokenize = tokenize.tokenize
215compat_urllib_error = urllib.error
216compat_urllib_parse = urllib.parse
217compat_urllib_parse_quote = urllib.parse.quote
218compat_urllib_parse_quote_plus = urllib.parse.quote_plus
219compat_urllib_parse_unquote = urllib.parse.unquote
220compat_urllib_parse_unquote_plus = urllib.parse.unquote_plus
221compat_urllib_parse_unquote_to_bytes = urllib.parse.unquote_to_bytes
222compat_urllib_parse_urlencode = urllib.parse.urlencode
223compat_urllib_parse_urlparse = urllib.parse.urlparse
224compat_urllib_parse_urlunparse = urllib.parse.urlunparse
225compat_urllib_request = urllib.request
226compat_urllib_request_DataHandler = urllib.request.DataHandler
227compat_urllib_response = urllib.response
228compat_urlparse = urllib.parse
229compat_urlretrieve = urllib.request.urlretrieve
230compat_xml_parse_error = etree.ParseError
231
232
233# Set public objects
234
8c25f81b 235__all__ = [
e3c7d495 236 'WINDOWS_VT_MODE',
b081f53b 237 'compat_HTMLParseError',
8bb56eee 238 'compat_HTMLParser',
8c25f81b 239 'compat_HTTPError',
4a2f19ab
F
240 'compat_Match',
241 'compat_Pattern',
65220c3b 242 'compat_Struct',
e36d50c5 243 'compat_asyncio_run',
f206126d 244 'compat_b64decode',
0196149c 245 'compat_basestring',
4390d5ec 246 'compat_brotli',
8c25f81b 247 'compat_chr',
d5a39898 248 'compat_collections_abc',
8c25f81b 249 'compat_cookiejar',
6d874fee 250 'compat_cookiejar_Cookie',
799207e8 251 'compat_cookies',
f7ad7160 252 'compat_cookies_SimpleCookie',
d7cd9a9e 253 'compat_ctypes_WINFUNCTYPE',
399f7687 254 'compat_etree_Element',
36e6f62c 255 'compat_etree_fromstring',
da162c11 256 'compat_etree_register_namespace',
8c25f81b 257 'compat_expanduser',
d5a39898 258 'compat_filter',
003c69a8 259 'compat_get_terminal_size',
8c25f81b
PH
260 'compat_getenv',
261 'compat_getpass',
262 'compat_html_entities',
9631a94f 263 'compat_html_entities_html5',
8c25f81b 264 'compat_http_client',
83fda3c0 265 'compat_http_server',
e67f6880 266 'compat_input',
075a13d3 267 'compat_integer_types',
a0e060ac 268 'compat_itertools_count',
c7b0add8 269 'compat_kwargs',
d5a39898 270 'compat_map',
28572a1a 271 'compat_numeric_types',
8c25f81b 272 'compat_ord',
e9c0cdd3 273 'compat_os_name',
8c25f81b
PH
274 'compat_parse_qs',
275 'compat_print',
edf65256 276 'compat_pycrypto_AES',
bfe2b8cf 277 'compat_realpath',
fe40f9ee 278 'compat_setenv',
702ccf2d 279 'compat_shlex_quote',
51f579b6 280 'compat_shlex_split',
be4a824d 281 'compat_socket_create_connection',
987493ae 282 'compat_str',
edaa23f8
YCH
283 'compat_struct_pack',
284 'compat_struct_unpack',
8c25f81b 285 'compat_subprocess_get_DEVNULL',
67134eab 286 'compat_tokenize_tokenize',
8c25f81b
PH
287 'compat_urllib_error',
288 'compat_urllib_parse',
732044af 289 'compat_urllib_parse_quote',
290 'compat_urllib_parse_quote_plus',
8c25f81b 291 'compat_urllib_parse_unquote',
aa99aa4e 292 'compat_urllib_parse_unquote_plus',
9fefc886 293 'compat_urllib_parse_unquote_to_bytes',
15707c7e 294 'compat_urllib_parse_urlencode',
8c25f81b 295 'compat_urllib_parse_urlparse',
732044af 296 'compat_urllib_parse_urlunparse',
8c25f81b 297 'compat_urllib_request',
0a67a363
YCH
298 'compat_urllib_request_DataHandler',
299 'compat_urllib_response',
8c25f81b
PH
300 'compat_urlparse',
301 'compat_urlretrieve',
da42679b 302 'compat_websockets',
8c25f81b 303 'compat_xml_parse_error',
57f7e3c6 304 'compat_xpath',
2384f5a6 305 'compat_zip',
819e0531 306 'windows_enable_vt_mode',
e07e9313 307 'workaround_optparse_bug9161',
8c25f81b 308]