aboutsummaryrefslogtreecommitdiffstats
path: root/yt_dlp/compat
diff options
context:
space:
mode:
authorJesús <heckyel@hyperbola.info>2022-06-27 01:25:17 +0800
committerJesús <heckyel@hyperbola.info>2022-06-27 01:25:17 +0800
commit16e8548f6a720a78679e417a20a300db2036bf6c (patch)
treeb1247bca3417ce882e4a4d80213f41c20113c1a4 /yt_dlp/compat
parent4bbf329feb5a820ac21269fa426c95ca14d7af25 (diff)
parente08f72e6759fb6b1102521f0bdb9457038ef7c06 (diff)
downloadhypervideo-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__.py28
-rw-r--r--yt_dlp/compat/_deprecated.py48
-rw-r--r--yt_dlp/compat/_legacy.py39
-rw-r--r--yt_dlp/compat/compat_utils.py32
-rw-r--r--yt_dlp/compat/functools.py26
-rw-r--r--yt_dlp/compat/imghdr.py14
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)