diff options
Diffstat (limited to 'yt_dlp/compat')
-rw-r--r-- | yt_dlp/compat/__init__.py | 20 | ||||
-rw-r--r-- | yt_dlp/compat/_legacy.py | 51 | ||||
-rw-r--r-- | yt_dlp/compat/asyncio.py | 23 | ||||
-rw-r--r-- | yt_dlp/compat/imghdr.py | 12 | ||||
-rw-r--r-- | yt_dlp/compat/re.py | 18 | ||||
-rw-r--r-- | yt_dlp/compat/shutil.py | 30 |
6 files changed, 75 insertions, 79 deletions
diff --git a/yt_dlp/compat/__init__.py b/yt_dlp/compat/__init__.py index 9f8e8c3e5..5d3db4b4c 100644 --- a/yt_dlp/compat/__init__.py +++ b/yt_dlp/compat/__init__.py @@ -3,25 +3,18 @@ import sys import warnings import xml.etree.ElementTree as etree -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 -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 +passthrough_module(__name__, '._legacy', callback=lambda attr: warnings.warn( + DeprecationWarning(f'{__name__}.{attr} is deprecated'), stacklevel=3)) # HTMLParseError has been deprecated in Python 3.3 and removed in # Python 3.5. Introducing dummy exception for Python >3.5 for compatible # and uniform cross-version exception handling -class compat_HTMLParseError(Exception): +class compat_HTMLParseError(ValueError): pass @@ -39,6 +32,7 @@ compat_os_name = os._name if os.name == 'java' else os.name if compat_os_name == 'nt': def compat_shlex_quote(s): + import re return s if re.match(r'^[-_\w./]+$', s) else '"%s"' % s.replace('"', '\\"') else: from shlex import quote as compat_shlex_quote # noqa: F401 @@ -76,3 +70,9 @@ if compat_os_name in ('nt', 'ce'): return userhome + path[i:] else: compat_expanduser = os.path.expanduser + + +# NB: Add modules that are imported dynamically here so that PyInstaller can find them +# See https://github.com/pyinstaller/pyinstaller-hooks-contrib/issues/438 +if False: + from . import _legacy # noqa: F401 diff --git a/yt_dlp/compat/_legacy.py b/yt_dlp/compat/_legacy.py index 49bb13a3c..d19333d31 100644 --- a/yt_dlp/compat/_legacy.py +++ b/yt_dlp/compat/_legacy.py @@ -22,10 +22,14 @@ 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 +# isort: split +import asyncio # noqa: F401 +import re # noqa: F401 +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 + +from .compat_utils import passthrough_module 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 @@ -44,14 +48,27 @@ def compat_setenv(key, value, env=os.environ): compat_basestring = str +compat_casefold = str.casefold +compat_chr = chr compat_collections_abc = collections.abc +compat_cookiejar = http.cookiejar +compat_cookiejar_Cookie = http.cookiejar.Cookie compat_cookies = http.cookies +compat_cookies_SimpleCookie = http.cookies.SimpleCookie compat_etree_Element = etree.Element compat_etree_register_namespace = etree.register_namespace compat_filter = filter +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_input = input compat_integer_types = (int, ) +compat_itertools_count = itertools.count compat_kwargs = lambda kwargs: kwargs compat_map = map compat_numeric_types = (int, float, complex) @@ -59,34 +76,22 @@ compat_print = print compat_shlex_split = shlex.split compat_socket_create_connection = socket.create_connection compat_Struct = struct.Struct +compat_struct_pack = struct.pack +compat_struct_unpack = struct.unpack compat_subprocess_get_DEVNULL = lambda: DEVNULL +compat_tokenize_tokenize = tokenize.tokenize +compat_urllib_error = urllib.error +compat_urllib_parse = urllib.parse compat_urllib_parse_quote = urllib.parse.quote compat_urllib_parse_quote_plus = urllib.parse.quote_plus +compat_urllib_parse_unquote_plus = urllib.parse.unquote_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_request_DataHandler = urllib.request.DataHandler 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/asyncio.py b/yt_dlp/compat/asyncio.py deleted file mode 100644 index c61e5c8fd..000000000 --- a/yt_dlp/compat/asyncio.py +++ /dev/null @@ -1,23 +0,0 @@ -# flake8: noqa: F405 -from asyncio import * # noqa: F403 - -from .compat_utils import passthrough_module - -passthrough_module(__name__, 'asyncio') -del passthrough_module - -try: - run # >= 3.7 -except NameError: - def run(coro): - try: - loop = get_event_loop() - except RuntimeError: - loop = new_event_loop() - set_event_loop(loop) - loop.run_until_complete(coro) - -try: - all_tasks # >= 3.7 -except NameError: - all_tasks = Task.all_tasks diff --git a/yt_dlp/compat/imghdr.py b/yt_dlp/compat/imghdr.py index 734b0d876..5d64ab07b 100644 --- a/yt_dlp/compat/imghdr.py +++ b/yt_dlp/compat/imghdr.py @@ -2,13 +2,15 @@ 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'), + 'gif': lambda h: h[:6] in (b'GIF87a', b'GIF89a'), } -def what(path): - """Detect format of image (Currently supports jpeg, png, webp only) +def what(file=None, h=None): + """Detect format of image (Currently supports jpeg, png, webp, gif 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) + if h is None: + with open(file, 'rb') as f: + h = f.read(12) + return next((type_ for type_, test in tests.items() if test(h)), None) diff --git a/yt_dlp/compat/re.py b/yt_dlp/compat/re.py deleted file mode 100644 index e1d3a2645..000000000 --- a/yt_dlp/compat/re.py +++ /dev/null @@ -1,18 +0,0 @@ -# flake8: noqa: F405 -from re import * # F403 - -from .compat_utils import passthrough_module - -passthrough_module(__name__, 're') -del passthrough_module - -try: - Pattern # >= 3.7 -except NameError: - Pattern = type(compile('')) - - -try: - Match # >= 3.7 -except NameError: - Match = type(compile('').match('')) diff --git a/yt_dlp/compat/shutil.py b/yt_dlp/compat/shutil.py new file mode 100644 index 000000000..23239d5ce --- /dev/null +++ b/yt_dlp/compat/shutil.py @@ -0,0 +1,30 @@ +# flake8: noqa: F405 +from shutil import * # noqa: F403 + +from .compat_utils import passthrough_module + +passthrough_module(__name__, 'shutil') +del passthrough_module + + +import sys + +if sys.platform.startswith('freebsd'): + import errno + import os + import shutil + + # Workaround for PermissionError when using restricted ACL mode on FreeBSD + def copy2(src, dst, *args, **kwargs): + if os.path.isdir(dst): + dst = os.path.join(dst, os.path.basename(src)) + shutil.copyfile(src, dst, *args, **kwargs) + try: + shutil.copystat(src, dst, *args, **kwargs) + except PermissionError as e: + if e.errno != getattr(errno, 'EPERM', None): + raise + return dst + + def move(*args, copy_function=copy2, **kwargs): + return shutil.move(*args, copy_function=copy_function, **kwargs) |