]> jfr.im git - yt-dlp.git/blame - yt_dlp/compat.py
Update to ytdl-commit-78ce962
[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
c589c1d3 137# Python 3.8+ does not honor %HOME% on windows, but this breaks compatibility with youtube-dl
138# See https://github.com/yt-dlp/yt-dlp/issues/792
139# https://docs.python.org/3/library/os.path.html#os.path.expanduser
140if compat_os_name in ('nt', 'ce') and 'HOME' in os.environ:
141 _userhome = os.environ['HOME']
142
143 def compat_expanduser(path):
144 if not path.startswith('~'):
145 return path
146 i = path.replace('\\', '/', 1).find('/') # ~user
147 if i < 0:
148 i = len(path)
149 userhome = os.path.join(os.path.dirname(_userhome), path[1:i]) if i > 1 else _userhome
150 return userhome + path[i:]
151else:
152 compat_expanduser = os.path.expanduser
153
154
edf65256 155try:
156 from Cryptodome.Cipher import AES as compat_pycrypto_AES
157except ImportError:
158 try:
159 from Crypto.Cipher import AES as compat_pycrypto_AES
160 except ImportError:
161 compat_pycrypto_AES = None
162
163
e3c7d495 164WINDOWS_VT_MODE = False if compat_os_name == 'nt' else None
165
166
819e0531 167def windows_enable_vt_mode(): # TODO: Do this the proper way https://bugs.python.org/issue30075
168 if compat_os_name != 'nt':
169 return
e3c7d495 170 global WINDOWS_VT_MODE
673944b0 171 startupinfo = subprocess.STARTUPINFO()
172 startupinfo.dwFlags |= subprocess.STARTF_USESHOWWINDOW
e3c7d495 173 try:
174 subprocess.Popen('', shell=True, startupinfo=startupinfo)
175 WINDOWS_VT_MODE = True
176 except Exception:
177 pass
819e0531 178
179
c634ad2a 180# Deprecated
181
182compat_basestring = str
183compat_chr = chr
d5a39898 184compat_filter = filter
c634ad2a 185compat_input = input
186compat_integer_types = (int, )
187compat_kwargs = lambda kwargs: kwargs
d5a39898 188compat_map = map
c634ad2a 189compat_numeric_types = (int, float, complex)
190compat_str = str
191compat_xpath = lambda xpath: xpath
192compat_zip = zip
193
d5a39898 194compat_collections_abc = collections.abc
c634ad2a 195compat_HTMLParser = html.parser.HTMLParser
196compat_HTTPError = urllib.error.HTTPError
197compat_Struct = struct.Struct
198compat_b64decode = base64.b64decode
199compat_cookiejar = http.cookiejar
200compat_cookiejar_Cookie = compat_cookiejar.Cookie
201compat_cookies = http.cookies
202compat_cookies_SimpleCookie = compat_cookies.SimpleCookie
203compat_etree_Element = etree.Element
204compat_etree_register_namespace = etree.register_namespace
c634ad2a 205compat_get_terminal_size = shutil.get_terminal_size
206compat_getenv = os.getenv
207compat_getpass = getpass.getpass
208compat_html_entities = html.entities
209compat_html_entities_html5 = compat_html_entities.html5
210compat_http_client = http.client
211compat_http_server = http.server
212compat_itertools_count = itertools.count
213compat_parse_qs = urllib.parse.parse_qs
214compat_shlex_split = shlex.split
215compat_socket_create_connection = socket.create_connection
216compat_struct_pack = struct.pack
217compat_struct_unpack = struct.unpack
218compat_subprocess_get_DEVNULL = lambda: DEVNULL
219compat_tokenize_tokenize = tokenize.tokenize
220compat_urllib_error = urllib.error
221compat_urllib_parse = urllib.parse
222compat_urllib_parse_quote = urllib.parse.quote
223compat_urllib_parse_quote_plus = urllib.parse.quote_plus
224compat_urllib_parse_unquote = urllib.parse.unquote
225compat_urllib_parse_unquote_plus = urllib.parse.unquote_plus
226compat_urllib_parse_unquote_to_bytes = urllib.parse.unquote_to_bytes
227compat_urllib_parse_urlencode = urllib.parse.urlencode
228compat_urllib_parse_urlparse = urllib.parse.urlparse
229compat_urllib_parse_urlunparse = urllib.parse.urlunparse
230compat_urllib_request = urllib.request
231compat_urllib_request_DataHandler = urllib.request.DataHandler
232compat_urllib_response = urllib.response
233compat_urlparse = urllib.parse
234compat_urlretrieve = urllib.request.urlretrieve
235compat_xml_parse_error = etree.ParseError
236
237
238# Set public objects
239
8c25f81b 240__all__ = [
e3c7d495 241 'WINDOWS_VT_MODE',
b081f53b 242 'compat_HTMLParseError',
8bb56eee 243 'compat_HTMLParser',
8c25f81b 244 'compat_HTTPError',
4a2f19ab
F
245 'compat_Match',
246 'compat_Pattern',
65220c3b 247 'compat_Struct',
e36d50c5 248 'compat_asyncio_run',
f206126d 249 'compat_b64decode',
0196149c 250 'compat_basestring',
8c25f81b 251 'compat_chr',
d5a39898 252 'compat_collections_abc',
8c25f81b 253 'compat_cookiejar',
6d874fee 254 'compat_cookiejar_Cookie',
799207e8 255 'compat_cookies',
f7ad7160 256 'compat_cookies_SimpleCookie',
d7cd9a9e 257 'compat_ctypes_WINFUNCTYPE',
399f7687 258 'compat_etree_Element',
36e6f62c 259 'compat_etree_fromstring',
da162c11 260 'compat_etree_register_namespace',
8c25f81b 261 'compat_expanduser',
d5a39898 262 'compat_filter',
003c69a8 263 'compat_get_terminal_size',
8c25f81b
PH
264 'compat_getenv',
265 'compat_getpass',
266 'compat_html_entities',
9631a94f 267 'compat_html_entities_html5',
8c25f81b 268 'compat_http_client',
83fda3c0 269 'compat_http_server',
e67f6880 270 'compat_input',
075a13d3 271 'compat_integer_types',
a0e060ac 272 'compat_itertools_count',
c7b0add8 273 'compat_kwargs',
d5a39898 274 'compat_map',
28572a1a 275 'compat_numeric_types',
8c25f81b 276 'compat_ord',
e9c0cdd3 277 'compat_os_name',
8c25f81b
PH
278 'compat_parse_qs',
279 'compat_print',
edf65256 280 'compat_pycrypto_AES',
bfe2b8cf 281 'compat_realpath',
fe40f9ee 282 'compat_setenv',
702ccf2d 283 'compat_shlex_quote',
51f579b6 284 'compat_shlex_split',
be4a824d 285 'compat_socket_create_connection',
987493ae 286 'compat_str',
edaa23f8
YCH
287 'compat_struct_pack',
288 'compat_struct_unpack',
8c25f81b 289 'compat_subprocess_get_DEVNULL',
67134eab 290 'compat_tokenize_tokenize',
8c25f81b
PH
291 'compat_urllib_error',
292 'compat_urllib_parse',
732044af 293 'compat_urllib_parse_quote',
294 'compat_urllib_parse_quote_plus',
8c25f81b 295 'compat_urllib_parse_unquote',
aa99aa4e 296 'compat_urllib_parse_unquote_plus',
9fefc886 297 'compat_urllib_parse_unquote_to_bytes',
15707c7e 298 'compat_urllib_parse_urlencode',
8c25f81b 299 'compat_urllib_parse_urlparse',
732044af 300 'compat_urllib_parse_urlunparse',
8c25f81b 301 'compat_urllib_request',
0a67a363
YCH
302 'compat_urllib_request_DataHandler',
303 'compat_urllib_response',
8c25f81b
PH
304 'compat_urlparse',
305 'compat_urlretrieve',
306 'compat_xml_parse_error',
57f7e3c6 307 'compat_xpath',
2384f5a6 308 'compat_zip',
819e0531 309 'windows_enable_vt_mode',
e07e9313 310 'workaround_optparse_bug9161',
8c25f81b 311]