aboutsummaryrefslogtreecommitdiffstats
path: root/yt_dlp/compat
diff options
context:
space:
mode:
Diffstat (limited to 'yt_dlp/compat')
-rw-r--r--yt_dlp/compat/__init__.py20
-rw-r--r--yt_dlp/compat/_legacy.py51
-rw-r--r--yt_dlp/compat/asyncio.py23
-rw-r--r--yt_dlp/compat/imghdr.py12
-rw-r--r--yt_dlp/compat/re.py18
-rw-r--r--yt_dlp/compat/shutil.py30
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)