]>
Commit | Line | Data |
---|---|---|
77f90330 | 1 | import contextlib |
2 | import os | |
3 | import subprocess | |
4 | import sys | |
5 | import types | |
6 | import xml.etree.ElementTree as etree | |
7 | ||
8 | from . import re | |
9 | from ._deprecated import * # noqa: F401, F403 | |
10 | ||
11 | ||
12 | # HTMLParseError has been deprecated in Python 3.3 and removed in | |
13 | # Python 3.5. Introducing dummy exception for Python >3.5 for compatible | |
14 | # and uniform cross-version exception handling | |
15 | class compat_HTMLParseError(Exception): | |
16 | pass | |
17 | ||
18 | ||
19 | class _TreeBuilder(etree.TreeBuilder): | |
20 | def doctype(self, name, pubid, system): | |
21 | pass | |
22 | ||
23 | ||
24 | def compat_etree_fromstring(text): | |
25 | return etree.XML(text, parser=etree.XMLParser(target=_TreeBuilder())) | |
26 | ||
27 | ||
28 | compat_os_name = os._name if os.name == 'java' else os.name | |
29 | ||
30 | ||
31 | if compat_os_name == 'nt': | |
32 | def compat_shlex_quote(s): | |
33 | return s if re.match(r'^[-_\w./]+$', s) else '"%s"' % s.replace('"', '\\"') | |
34 | else: | |
35 | from shlex import quote as compat_shlex_quote # noqa: F401 | |
36 | ||
37 | ||
38 | def compat_ord(c): | |
39 | return c if isinstance(c, int) else ord(c) | |
40 | ||
41 | ||
42 | def compat_setenv(key, value, env=os.environ): | |
43 | env[key] = value | |
44 | ||
45 | ||
46 | if compat_os_name == 'nt' and sys.version_info < (3, 8): | |
47 | # os.path.realpath on Windows does not follow symbolic links | |
48 | # prior to Python 3.8 (see https://bugs.python.org/issue9949) | |
49 | def compat_realpath(path): | |
50 | while os.path.islink(path): | |
51 | path = os.path.abspath(os.readlink(path)) | |
52 | return path | |
53 | else: | |
54 | compat_realpath = os.path.realpath | |
55 | ||
56 | ||
57 | try: | |
58 | import websockets as compat_websockets | |
59 | except ImportError: | |
60 | compat_websockets = None | |
61 | ||
62 | # Python 3.8+ does not honor %HOME% on windows, but this breaks compatibility with youtube-dl | |
63 | # See https://github.com/yt-dlp/yt-dlp/issues/792 | |
64 | # https://docs.python.org/3/library/os.path.html#os.path.expanduser | |
65 | if compat_os_name in ('nt', 'ce'): | |
66 | def compat_expanduser(path): | |
67 | HOME = os.environ.get('HOME') | |
68 | if not HOME: | |
69 | return os.path.expanduser(path) | |
70 | elif not path.startswith('~'): | |
71 | return path | |
72 | i = path.replace('\\', '/', 1).find('/') # ~user | |
73 | if i < 0: | |
74 | i = len(path) | |
75 | userhome = os.path.join(os.path.dirname(HOME), path[1:i]) if i > 1 else HOME | |
76 | return userhome + path[i:] | |
77 | else: | |
78 | compat_expanduser = os.path.expanduser | |
79 | ||
80 | ||
81 | try: | |
82 | from Cryptodome.Cipher import AES as compat_pycrypto_AES | |
83 | except ImportError: | |
84 | try: | |
85 | from Crypto.Cipher import AES as compat_pycrypto_AES | |
86 | except ImportError: | |
87 | compat_pycrypto_AES = None | |
88 | ||
89 | try: | |
90 | import brotlicffi as compat_brotli | |
91 | except ImportError: | |
92 | try: | |
93 | import brotli as compat_brotli | |
94 | except ImportError: | |
95 | compat_brotli = None | |
96 | ||
97 | WINDOWS_VT_MODE = False if compat_os_name == 'nt' else None | |
98 | ||
99 | ||
100 | def windows_enable_vt_mode(): # TODO: Do this the proper way https://bugs.python.org/issue30075 | |
101 | if compat_os_name != 'nt': | |
102 | return | |
103 | global WINDOWS_VT_MODE | |
104 | startupinfo = subprocess.STARTUPINFO() | |
105 | startupinfo.dwFlags |= subprocess.STARTF_USESHOWWINDOW | |
106 | with contextlib.suppress(Exception): | |
107 | subprocess.Popen('', shell=True, startupinfo=startupinfo).wait() | |
108 | WINDOWS_VT_MODE = True | |
109 | ||
110 | ||
111 | class _PassthroughLegacy(types.ModuleType): | |
112 | def __getattr__(self, attr): | |
113 | import importlib | |
114 | with contextlib.suppress(ImportError): | |
115 | return importlib.import_module(f'.{attr}', __name__) | |
116 | ||
117 | legacy = importlib.import_module('._legacy', __name__) | |
118 | if not hasattr(legacy, attr): | |
119 | raise AttributeError(f'module {__name__} has no attribute {attr}') | |
120 | ||
121 | # XXX: Implement this the same way as other DeprecationWarnings without circular import | |
122 | import warnings | |
123 | warnings.warn(DeprecationWarning(f'{__name__}.{attr} is deprecated'), stacklevel=2) | |
124 | return getattr(legacy, attr) | |
125 | ||
126 | ||
127 | # Python 3.6 does not have module level __getattr__ | |
128 | # https://peps.python.org/pep-0562/ | |
129 | sys.modules[__name__].__class__ = _PassthroughLegacy |