25 import xml
.etree
.ElementTree
as etree
26 from subprocess
import DEVNULL
29 # HTMLParseError has been deprecated in Python 3.3 and removed in
30 # Python 3.5. Introducing dummy exception for Python >3.5 for compatible
31 # and uniform cross-version exception handling
32 class compat_HTMLParseError(Exception):
36 # compat_ctypes_WINFUNCTYPE = ctypes.WINFUNCTYPE
37 # will not work since ctypes.WINFUNCTYPE does not exist in UNIX machines
38 def compat_ctypes_WINFUNCTYPE(*args
, **kwargs
):
39 return ctypes
.WINFUNCTYPE(*args
, **kwargs
)
42 class _TreeBuilder(etree
.TreeBuilder
):
43 def doctype(self
, name
, pubid
, system
):
47 def compat_etree_fromstring(text
):
48 return etree
.XML(text
, parser
=etree
.XMLParser(target
=_TreeBuilder()))
51 compat_os_name
= os
._name
if os
.name
== 'java' else os
.name
54 if compat_os_name
== 'nt':
55 def compat_shlex_quote(s
):
56 return s
if re
.match(r
'^[-_\w./]+$', s
) else '"%s"' % s
.replace('"', '\\"')
58 from shlex
import quote
as compat_shlex_quote
# noqa: F401
62 return c
if isinstance(c
, int) else ord(c
)
65 def compat_setenv(key
, value
, env
=os
.environ
):
69 if compat_os_name
== 'nt' and sys
.version_info
< (3, 8):
70 # os.path.realpath on Windows does not follow symbolic links
71 # prior to Python 3.8 (see https://bugs.python.org/issue9949)
72 def compat_realpath(path
):
73 while os
.path
.islink(path
):
74 path
= os
.path
.abspath(os
.readlink(path
))
77 compat_realpath
= os
.path
.realpath
81 compat_Pattern
= re
.Pattern
82 except AttributeError:
83 compat_Pattern
= type(re
.compile(''))
87 compat_Match
= re
.Match
88 except AttributeError:
89 compat_Match
= type(re
.compile('').match(''))
93 compat_asyncio_run
= asyncio
.run
# >= 3.7
94 except AttributeError:
95 def compat_asyncio_run(coro
):
97 loop
= asyncio
.get_event_loop()
99 loop
= asyncio
.new_event_loop()
100 asyncio
.set_event_loop(loop
)
101 loop
.run_until_complete(coro
)
103 asyncio
.run
= compat_asyncio_run
107 asyncio
.tasks
.all_tasks
108 except AttributeError:
109 asyncio
.tasks
.all_tasks
= asyncio
.tasks
.Task
.all_tasks
112 import websockets
as compat_websockets
114 compat_websockets
= None
116 # Python 3.8+ does not honor %HOME% on windows, but this breaks compatibility with youtube-dl
117 # See https://github.com/yt-dlp/yt-dlp/issues/792
118 # https://docs.python.org/3/library/os.path.html#os.path.expanduser
119 if compat_os_name
in ('nt', 'ce'):
120 def compat_expanduser(path
):
121 HOME
= os
.environ
.get('HOME')
123 return os
.path
.expanduser(path
)
124 elif not path
.startswith('~'):
126 i
= path
.replace('\\', '/', 1).find('/') # ~user
129 userhome
= os
.path
.join(os
.path
.dirname(HOME
), path
[1:i
]) if i
> 1 else HOME
130 return userhome
+ path
[i
:]
132 compat_expanduser
= os
.path
.expanduser
136 from Cryptodome
.Cipher
import AES
as compat_pycrypto_AES
139 from Crypto
.Cipher
import AES
as compat_pycrypto_AES
141 compat_pycrypto_AES
= None
144 import brotlicffi
as compat_brotli
147 import brotli
as compat_brotli
151 WINDOWS_VT_MODE
= False if compat_os_name
== 'nt' else None
154 def windows_enable_vt_mode(): # TODO: Do this the proper way https://bugs.python.org/issue30075
155 if compat_os_name
!= 'nt':
157 global WINDOWS_VT_MODE
158 startupinfo
= subprocess
.STARTUPINFO()
159 startupinfo
.dwFlags |
= subprocess
.STARTF_USESHOWWINDOW
160 with contextlib
.suppress(Exception):
161 subprocess
.Popen('', shell
=True, startupinfo
=startupinfo
).wait()
162 WINDOWS_VT_MODE
= True
167 compat_b64decode
= base64
.b64decode
169 compat_cookiejar
= http
.cookiejar
170 compat_cookiejar_Cookie
= http
.cookiejar
.Cookie
171 compat_cookies_SimpleCookie
= http
.cookies
.SimpleCookie
172 compat_get_terminal_size
= shutil
.get_terminal_size
173 compat_getenv
= os
.getenv
174 compat_getpass
= getpass
.getpass
175 compat_html_entities
= html
.entities
176 compat_html_entities_html5
= html
.entities
.html5
177 compat_HTMLParser
= html
.parser
.HTMLParser
178 compat_http_client
= http
.client
179 compat_http_server
= http
.server
180 compat_HTTPError
= urllib
.error
.HTTPError
181 compat_itertools_count
= itertools
.count
182 compat_parse_qs
= urllib
.parse
.parse_qs
184 compat_struct_pack
= struct
.pack
185 compat_struct_unpack
= struct
.unpack
186 compat_tokenize_tokenize
= tokenize
.tokenize
187 compat_urllib_error
= urllib
.error
188 compat_urllib_parse_unquote
= urllib
.parse
.unquote
189 compat_urllib_parse_unquote_plus
= urllib
.parse
.unquote_plus
190 compat_urllib_parse_urlencode
= urllib
.parse
.urlencode
191 compat_urllib_parse_urlparse
= urllib
.parse
.urlparse
192 compat_urllib_request
= urllib
.request
193 compat_urlparse
= compat_urllib_parse
= urllib
.parse
196 # To be removed - Do not use
198 compat_basestring
= str
199 compat_collections_abc
= collections
.abc
200 compat_cookies
= http
.cookies
201 compat_etree_Element
= etree
.Element
202 compat_etree_register_namespace
= etree
.register_namespace
203 compat_filter
= filter
205 compat_integer_types
= (int, )
206 compat_kwargs
= lambda kwargs
: kwargs
208 compat_numeric_types
= (int, float, complex)
210 compat_shlex_split
= shlex
.split
211 compat_socket_create_connection
= socket
.create_connection
212 compat_Struct
= struct
.Struct
213 compat_subprocess_get_DEVNULL
= lambda: DEVNULL
214 compat_urllib_parse_quote
= urllib
.parse
.quote
215 compat_urllib_parse_quote_plus
= urllib
.parse
.quote_plus
216 compat_urllib_parse_unquote_to_bytes
= urllib
.parse
.unquote_to_bytes
217 compat_urllib_parse_urlunparse
= urllib
.parse
.urlunparse
218 compat_urllib_request_DataHandler
= urllib
.request
.DataHandler
219 compat_urllib_response
= urllib
.response
220 compat_urlretrieve
= urllib
.request
.urlretrieve
221 compat_xml_parse_error
= etree
.ParseError
222 compat_xpath
= lambda xpath
: xpath
224 workaround_optparse_bug9161
= lambda: None
231 'compat_HTMLParseError',
237 'compat_asyncio_run',
242 'compat_collections_abc',
244 'compat_cookiejar_Cookie',
246 'compat_cookies_SimpleCookie',
247 'compat_ctypes_WINFUNCTYPE',
248 'compat_etree_Element',
249 'compat_etree_fromstring',
250 'compat_etree_register_namespace',
253 'compat_get_terminal_size',
256 'compat_html_entities',
257 'compat_html_entities_html5',
258 'compat_http_client',
259 'compat_http_server',
261 'compat_integer_types',
262 'compat_itertools_count',
265 'compat_numeric_types',
270 'compat_pycrypto_AES',
273 'compat_shlex_quote',
274 'compat_shlex_split',
275 'compat_socket_create_connection',
277 'compat_struct_pack',
278 'compat_struct_unpack',
279 'compat_subprocess_get_DEVNULL',
280 'compat_tokenize_tokenize',
281 'compat_urllib_error',
282 'compat_urllib_parse',
283 'compat_urllib_parse_quote',
284 'compat_urllib_parse_quote_plus',
285 'compat_urllib_parse_unquote',
286 'compat_urllib_parse_unquote_plus',
287 'compat_urllib_parse_unquote_to_bytes',
288 'compat_urllib_parse_urlencode',
289 'compat_urllib_parse_urlparse',
290 'compat_urllib_parse_urlunparse',
291 'compat_urllib_request',
292 'compat_urllib_request_DataHandler',
293 'compat_urllib_response',
295 'compat_urlretrieve',
297 'compat_xml_parse_error',
300 'windows_enable_vt_mode',
301 'workaround_optparse_bug9161',