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