diff --git a/.github/workflows/core.yml b/.github/workflows/core.yml index d0e890b30..60906044c 100644 --- a/.github/workflows/core.yml +++ b/.github/workflows/core.yml @@ -10,7 +10,7 @@ jobs: matrix: os: [ubuntu-latest] # CPython 3.9 is in quick-test - python-version: ['3.7', '3.10', 3.11-dev, pypy-3.7, pypy-3.8] + python-version: ['3.6', '3.7', '3.10', 3.11-dev, pypy-3.6, pypy-3.7, pypy-3.8] run-tests-ext: [sh] include: # atleast one of each CPython/PyPy tests must be in windows diff --git a/.github/workflows/download.yml b/.github/workflows/download.yml index cc2da62fa..874a88bfe 100644 --- a/.github/workflows/download.yml +++ b/.github/workflows/download.yml @@ -25,7 +25,7 @@ jobs: fail-fast: true matrix: os: [ubuntu-latest] - python-version: ['3.7', '3.10', 3.11-dev, pypy-3.7, pypy-3.8] + python-version: ['3.6', '3.7', '3.10', 3.11-dev, pypy-3.6, pypy-3.7, pypy-3.8] run-tests-ext: [sh] include: # atleast one of each CPython/PyPy tests must be in windows diff --git a/setup.py b/setup.py index e376a694a..d62388224 100644 --- a/setup.py +++ b/setup.py @@ -126,7 +126,7 @@ setup( url='https://github.com/yt-dlp/yt-dlp', packages=packages(), install_requires=REQUIREMENTS, - python_requires='>=3.7', + python_requires='>=3.6', project_urls={ 'Documentation': 'https://github.com/yt-dlp/yt-dlp#readme', 'Source': 'https://github.com/yt-dlp/yt-dlp', @@ -138,6 +138,7 @@ setup( 'Development Status :: 5 - Production/Stable', 'Environment :: Console', 'Programming Language :: Python', + 'Programming Language :: Python :: 3.6', 'Programming Language :: Python :: 3.7', 'Programming Language :: Python :: 3.8', 'Programming Language :: Python :: 3.9', diff --git a/test/test_compat.py b/test/test_compat.py index e3d775bc1..c6a8f4ecb 100644 --- a/test/test_compat.py +++ b/test/test_compat.py @@ -28,8 +28,7 @@ class TestCompat(unittest.TestCase): with self.assertWarns(DeprecationWarning): compat.WINDOWS_VT_MODE - # TODO: Test submodule - # compat.asyncio.events # Must not raise error + compat.asyncio.events # Must not raise error def test_compat_expanduser(self): old_home = os.environ.get('HOME') diff --git a/yt_dlp/YoutubeDL.py b/yt_dlp/YoutubeDL.py index c2b306d70..0fe40af94 100644 --- a/yt_dlp/YoutubeDL.py +++ b/yt_dlp/YoutubeDL.py @@ -591,8 +591,7 @@ class YoutubeDL: for type_, stream in self._out_files.items_ if type_ != 'console' }) - # The code is left like this to be reused for future deprecations - MIN_SUPPORTED, MIN_RECOMMENDED = (3, 7), (3, 7) + MIN_SUPPORTED, MIN_RECOMMENDED = (3, 6), (3, 7) current_version = sys.version_info[:2] if current_version < MIN_RECOMMENDED: msg = ('Support for Python version %d.%d has been deprecated. ' diff --git a/yt_dlp/__init__.py b/yt_dlp/__init__.py index 6ad2e97e8..85c63b3ae 100644 --- a/yt_dlp/__init__.py +++ b/yt_dlp/__init__.py @@ -1,4 +1,4 @@ -f'You are using an unsupported version of Python. Only Python versions 3.7 and above are supported by yt-dlp' # noqa: F541 +f'You are using an unsupported version of Python. Only Python versions 3.6 and above are supported by yt-dlp' # noqa: F541 __license__ = 'Public Domain' diff --git a/yt_dlp/compat/__init__.py b/yt_dlp/compat/__init__.py index 6d85a6a1f..25d652965 100644 --- a/yt_dlp/compat/__init__.py +++ b/yt_dlp/compat/__init__.py @@ -3,6 +3,7 @@ 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 @@ -32,7 +33,6 @@ 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 diff --git a/yt_dlp/compat/_legacy.py b/yt_dlp/compat/_legacy.py index 09259c988..e75f79bbf 100644 --- a/yt_dlp/compat/_legacy.py +++ b/yt_dlp/compat/_legacy.py @@ -22,14 +22,10 @@ import urllib.request import xml.etree.ElementTree as etree from subprocess import DEVNULL -# 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 .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 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 diff --git a/yt_dlp/compat/asyncio.py b/yt_dlp/compat/asyncio.py new file mode 100644 index 000000000..c61e5c8fd --- /dev/null +++ b/yt_dlp/compat/asyncio.py @@ -0,0 +1,23 @@ +# 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/re.py b/yt_dlp/compat/re.py new file mode 100644 index 000000000..e1d3a2645 --- /dev/null +++ b/yt_dlp/compat/re.py @@ -0,0 +1,18 @@ +# 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/downloader/websocket.py b/yt_dlp/downloader/websocket.py index 6837ff1da..727a15828 100644 --- a/yt_dlp/downloader/websocket.py +++ b/yt_dlp/downloader/websocket.py @@ -1,4 +1,3 @@ -import asyncio import contextlib import os import signal @@ -6,6 +5,7 @@ import threading from .common import FileDownloader from .external import FFmpegFD +from ..compat import asyncio from ..dependencies import websockets diff --git a/yt_dlp/extractor/common.py b/yt_dlp/extractor/common.py index a534703e5..83eae8e71 100644 --- a/yt_dlp/extractor/common.py +++ b/yt_dlp/extractor/common.py @@ -11,7 +11,6 @@ import math import netrc import os import random -import re import sys import time import types @@ -19,7 +18,7 @@ import urllib.parse import urllib.request import xml.etree.ElementTree -from ..compat import functools # isort: split +from ..compat import functools, re # isort: split from ..compat import compat_etree_fromstring, compat_expanduser, compat_os_name from ..downloader import FileDownloader from ..downloader.f4m import get_base_url, remove_encrypted_media diff --git a/yt_dlp/utils.py b/yt_dlp/utils.py index 49ee22865..cef9c808f 100644 --- a/yt_dlp/utils.py +++ b/yt_dlp/utils.py @@ -1,4 +1,3 @@ -import asyncio import atexit import base64 import binascii @@ -47,7 +46,7 @@ import urllib.request import xml.etree.ElementTree import zlib -from .compat import functools # isort: split +from .compat import asyncio, functools # isort: split from .compat import ( compat_etree_fromstring, compat_expanduser, diff --git a/yt_dlp/webvtt.py b/yt_dlp/webvtt.py index 23d67a897..a423948ae 100644 --- a/yt_dlp/webvtt.py +++ b/yt_dlp/webvtt.py @@ -9,8 +9,8 @@ in RFC 8216 ยง3.5 . """ import io -import re +from .compat import re from .utils import int_or_none, timetuple_from_msec