diff options
author | Jesús <heckyel@hyperbola.info> | 2022-06-27 01:25:17 +0800 |
---|---|---|
committer | Jesús <heckyel@hyperbola.info> | 2022-06-27 01:25:17 +0800 |
commit | 16e8548f6a720a78679e417a20a300db2036bf6c (patch) | |
tree | b1247bca3417ce882e4a4d80213f41c20113c1a4 /yt_dlp/compat | |
parent | 4bbf329feb5a820ac21269fa426c95ca14d7af25 (diff) | |
parent | e08f72e6759fb6b1102521f0bdb9457038ef7c06 (diff) | |
download | hypervideo-pre-16e8548f6a720a78679e417a20a300db2036bf6c.tar.lz hypervideo-pre-16e8548f6a720a78679e417a20a300db2036bf6c.tar.xz hypervideo-pre-16e8548f6a720a78679e417a20a300db2036bf6c.zip |
updated from upstream | 27/06/2022 at 01:25
Diffstat (limited to 'yt_dlp/compat')
-rw-r--r-- | yt_dlp/compat/__init__.py | 28 | ||||
-rw-r--r-- | yt_dlp/compat/_deprecated.py | 48 | ||||
-rw-r--r-- | yt_dlp/compat/_legacy.py | 39 | ||||
-rw-r--r-- | yt_dlp/compat/compat_utils.py | 32 | ||||
-rw-r--r-- | yt_dlp/compat/functools.py | 26 | ||||
-rw-r--r-- | yt_dlp/compat/imghdr.py | 14 |
6 files changed, 112 insertions, 75 deletions
diff --git a/yt_dlp/compat/__init__.py b/yt_dlp/compat/__init__.py index a0cd62110..9f8e8c3e5 100644 --- a/yt_dlp/compat/__init__.py +++ b/yt_dlp/compat/__init__.py @@ -1,6 +1,4 @@ -import contextlib import os -import subprocess import sys import warnings import xml.etree.ElementTree as etree @@ -9,10 +7,14 @@ from . import re from ._deprecated import * # noqa: F401, F403 from .compat_utils import passthrough_module - # XXX: Implement this the same way as other DeprecationWarnings without circular import -passthrough_module(__name__, '._legacy', callback=lambda attr: warnings.warn( - DeprecationWarning(f'{__name__}.{attr} is deprecated'), stacklevel=2)) +try: + passthrough_module(__name__, '._legacy', callback=lambda attr: warnings.warn( + DeprecationWarning(f'{__name__}.{attr} is deprecated'), stacklevel=2)) + HAS_LEGACY = True +except ModuleNotFoundError: + # Keep working even without _legacy module + HAS_LEGACY = False del passthrough_module @@ -52,7 +54,7 @@ if compat_os_name == 'nt' and sys.version_info < (3, 8): def compat_realpath(path): while os.path.islink(path): path = os.path.abspath(os.readlink(path)) - return path + return os.path.realpath(path) else: compat_realpath = os.path.realpath @@ -74,17 +76,3 @@ if compat_os_name in ('nt', 'ce'): return userhome + path[i:] else: compat_expanduser = os.path.expanduser - - -WINDOWS_VT_MODE = False if compat_os_name == 'nt' else None - - -def windows_enable_vt_mode(): # TODO: Do this the proper way https://bugs.python.org/issue30075 - if compat_os_name != 'nt': - return - global WINDOWS_VT_MODE - startupinfo = subprocess.STARTUPINFO() - startupinfo.dwFlags |= subprocess.STARTF_USESHOWWINDOW - with contextlib.suppress(Exception): - subprocess.Popen('', shell=True, startupinfo=startupinfo).wait() - WINDOWS_VT_MODE = True diff --git a/yt_dlp/compat/_deprecated.py b/yt_dlp/compat/_deprecated.py index 390f76577..342f1f80d 100644 --- a/yt_dlp/compat/_deprecated.py +++ b/yt_dlp/compat/_deprecated.py @@ -1,52 +1,16 @@ """Deprecated - New code should avoid these""" import base64 -import getpass -import html -import html.parser -import http -import http.client -import http.cookiejar -import http.cookies -import http.server -import itertools -import os -import shutil -import struct -import tokenize -import urllib +import urllib.error +import urllib.parse + +compat_str = str compat_b64decode = base64.b64decode -compat_chr = chr -compat_cookiejar = http.cookiejar -compat_cookiejar_Cookie = http.cookiejar.Cookie -compat_cookies_SimpleCookie = http.cookies.SimpleCookie -compat_get_terminal_size = shutil.get_terminal_size -compat_getenv = os.getenv -compat_getpass = getpass.getpass -compat_html_entities = html.entities -compat_html_entities_html5 = html.entities.html5 -compat_HTMLParser = html.parser.HTMLParser -compat_http_client = http.client -compat_http_server = http.server + compat_HTTPError = urllib.error.HTTPError -compat_itertools_count = itertools.count +compat_urlparse = urllib.parse compat_parse_qs = urllib.parse.parse_qs -compat_str = str -compat_struct_pack = struct.pack -compat_struct_unpack = struct.unpack -compat_tokenize_tokenize = tokenize.tokenize -compat_urllib_error = urllib.error compat_urllib_parse_unquote = urllib.parse.unquote -compat_urllib_parse_unquote_plus = urllib.parse.unquote_plus compat_urllib_parse_urlencode = urllib.parse.urlencode compat_urllib_parse_urlparse = urllib.parse.urlparse -compat_urllib_request = urllib.request -compat_urlparse = compat_urllib_parse = urllib.parse - - -def compat_setenv(key, value, env=os.environ): - env[key] = value - - -__all__ = [x for x in globals() if x.startswith('compat_')] diff --git a/yt_dlp/compat/_legacy.py b/yt_dlp/compat/_legacy.py index ce24760e5..49bb13a3c 100644 --- a/yt_dlp/compat/_legacy.py +++ b/yt_dlp/compat/_legacy.py @@ -2,18 +2,27 @@ import collections import ctypes -import http +import getpass +import html.entities +import html.parser import http.client import http.cookiejar import http.cookies import http.server +import itertools +import os import shlex +import shutil import socket import struct -import urllib +import tokenize +import urllib.error +import urllib.parse +import urllib.request import xml.etree.ElementTree as etree from subprocess import DEVNULL +from .compat_utils import passthrough_module # isort: split from .asyncio import run as compat_asyncio_run # noqa: F401 from .re import Pattern as compat_Pattern # noqa: F401 from .re import match as compat_Match # noqa: F401 @@ -21,6 +30,8 @@ from ..dependencies import Cryptodome_AES as compat_pycrypto_AES # noqa: F401 from ..dependencies import brotli as compat_brotli # noqa: F401 from ..dependencies import websockets as compat_websockets # noqa: F401 +passthrough_module(__name__, '...utils', ('WINDOWS_VT_MODE', 'windows_enable_vt_mode')) + # compat_ctypes_WINFUNCTYPE = ctypes.WINFUNCTYPE # will not work since ctypes.WINFUNCTYPE does not exist in UNIX machines @@ -28,12 +39,17 @@ def compat_ctypes_WINFUNCTYPE(*args, **kwargs): return ctypes.WINFUNCTYPE(*args, **kwargs) +def compat_setenv(key, value, env=os.environ): + env[key] = value + + compat_basestring = str compat_collections_abc = collections.abc compat_cookies = http.cookies compat_etree_Element = etree.Element compat_etree_register_namespace = etree.register_namespace compat_filter = filter +compat_getenv = os.getenv compat_input = input compat_integer_types = (int, ) compat_kwargs = lambda kwargs: kwargs @@ -49,9 +65,28 @@ compat_urllib_parse_quote_plus = urllib.parse.quote_plus compat_urllib_parse_unquote_to_bytes = urllib.parse.unquote_to_bytes compat_urllib_parse_urlunparse = urllib.parse.urlunparse compat_urllib_request_DataHandler = urllib.request.DataHandler +compat_urllib_request = urllib.request compat_urllib_response = urllib.response compat_urlretrieve = urllib.request.urlretrieve compat_xml_parse_error = etree.ParseError compat_xpath = lambda xpath: xpath compat_zip = zip workaround_optparse_bug9161 = lambda: None +compat_getpass = getpass.getpass +compat_chr = chr +compat_urllib_parse = urllib.parse +compat_itertools_count = itertools.count +compat_cookiejar = http.cookiejar +compat_cookiejar_Cookie = http.cookiejar.Cookie +compat_cookies_SimpleCookie = http.cookies.SimpleCookie +compat_get_terminal_size = shutil.get_terminal_size +compat_html_entities = html.entities +compat_html_entities_html5 = html.entities.html5 +compat_tokenize_tokenize = tokenize.tokenize +compat_HTMLParser = html.parser.HTMLParser +compat_http_client = http.client +compat_http_server = http.server +compat_struct_pack = struct.pack +compat_struct_unpack = struct.unpack +compat_urllib_error = urllib.error +compat_urllib_parse_unquote_plus = urllib.parse.unquote_plus diff --git a/yt_dlp/compat/compat_utils.py b/yt_dlp/compat/compat_utils.py index b1d58f5b9..82e176281 100644 --- a/yt_dlp/compat/compat_utils.py +++ b/yt_dlp/compat/compat_utils.py @@ -4,7 +4,6 @@ import importlib import sys import types - _NO_ATTRIBUTE = object() _Package = collections.namedtuple('Package', ('name', 'version')) @@ -31,9 +30,9 @@ def _is_package(module): return True -def passthrough_module(parent, child, *, callback=lambda _: None): +def passthrough_module(parent, child, allowed_attributes=None, *, callback=lambda _: None): parent_module = importlib.import_module(parent) - child_module = importlib.import_module(child, parent) + child_module = None # Import child module only as needed class PassthroughModule(types.ModuleType): def __getattr__(self, attr): @@ -41,19 +40,30 @@ def passthrough_module(parent, child, *, callback=lambda _: None): with contextlib.suppress(ImportError): return importlib.import_module(f'.{attr}', parent) - ret = _NO_ATTRIBUTE + ret = self.__from_child(attr) + if ret is _NO_ATTRIBUTE: + raise AttributeError(f'module {parent} has no attribute {attr}') + callback(attr) + return ret + + def __from_child(self, attr): + if allowed_attributes is None: + if attr.startswith('__') and attr.endswith('__'): + return _NO_ATTRIBUTE + elif attr not in allowed_attributes: + return _NO_ATTRIBUTE + + nonlocal child_module + child_module = child_module or importlib.import_module(child, parent) + with contextlib.suppress(AttributeError): - ret = getattr(child_module, attr) + return getattr(child_module, attr) if _is_package(child_module): with contextlib.suppress(ImportError): - ret = importlib.import_module(f'.{attr}', child) - - if ret is _NO_ATTRIBUTE: - raise AttributeError(f'module {parent} has no attribute {attr}') + return importlib.import_module(f'.{attr}', child) - callback(attr) - return ret + return _NO_ATTRIBUTE # Python 3.6 does not have module level __getattr__ # https://peps.python.org/pep-0562/ diff --git a/yt_dlp/compat/functools.py b/yt_dlp/compat/functools.py new file mode 100644 index 000000000..ec003ea90 --- /dev/null +++ b/yt_dlp/compat/functools.py @@ -0,0 +1,26 @@ +# flake8: noqa: F405 +from functools import * # noqa: F403 + +from .compat_utils import passthrough_module + +passthrough_module(__name__, 'functools') +del passthrough_module + +try: + cache # >= 3.9 +except NameError: + cache = lru_cache(maxsize=None) + +try: + cached_property # >= 3.8 +except NameError: + class cached_property: + def __init__(self, func): + update_wrapper(self, func) + self.func = func + + def __get__(self, instance, _): + if instance is None: + return self + setattr(instance, self.func.__name__, self.func(instance)) + return getattr(instance, self.func.__name__) diff --git a/yt_dlp/compat/imghdr.py b/yt_dlp/compat/imghdr.py new file mode 100644 index 000000000..734b0d876 --- /dev/null +++ b/yt_dlp/compat/imghdr.py @@ -0,0 +1,14 @@ +tests = { + 'webp': lambda h: h[0:4] == b'RIFF' and h[8:] == b'WEBP', + 'png': lambda h: h[:8] == b'\211PNG\r\n\032\n', + 'jpeg': lambda h: h[6:10] in (b'JFIF', b'Exif'), +} + + +def what(path): + """Detect format of image (Currently supports jpeg, png, webp only) + Ref: https://github.com/python/cpython/blob/3.10/Lib/imghdr.py + """ + with open(path, 'rb') as f: + head = f.read(12) + return next((type_ for type_, test in tests.items() if test(head)), None) |