From 1d8d5a93f7187438587c3a754b53fdf30322cef0 Mon Sep 17 00:00:00 2001 From: dirkf Date: Thu, 13 Jul 2023 20:14:50 +0100 Subject: [PATCH] [test] Fixes for old Pythons --- .github/workflows/ci.yml | 4 ++-- test/helper.py | 6 ++++++ test/test_http.py | 7 ++++++- test/test_utils.py | 6 +++--- youtube_dl/jsinterp.py | 14 +++++++------- youtube_dl/utils.py | 8 ++++++-- 6 files changed, 30 insertions(+), 15 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index ce878c1b1..c3aabde47 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -301,7 +301,7 @@ jobs: if: ${{ matrix.python-version == '2.6' }} shell: bash run: | - # see pip for Jython + # Work around deprecation of support for non-SNI clients at PyPI CDN (see https://status.python.org/incidents/hzmjhqsdjqgb) $PIP -qq show unittest2 || { \ for u in "65/26/32b8464df2a97e6dd1b656ed26b2c194606c16fe163c695a992b36c11cdf/six-1.13.0-py2.py3-none-any.whl" \ "f2/94/3af39d34be01a24a6e65433d19e107099374224905f1e0cc6bbe1fd22a2f/argparse-1.4.0-py2.py3-none-any.whl" \ @@ -312,7 +312,7 @@ jobs: $PIP install ${u##*/}; \ done; } # make tests use unittest2 - for test in ./test/test_*.py; do + for test in ./test/test_*.py ./test/helper.py; do sed -r -i -e '/^import unittest$/s/test/test2 as unittest/' "$test" done #-------- nose -------- diff --git a/test/helper.py b/test/helper.py index e3314b03e..aa99001b2 100644 --- a/test/helper.py +++ b/test/helper.py @@ -9,6 +9,7 @@ import re import types import ssl import sys +import unittest import youtube_dl.extractor from youtube_dl import YoutubeDL @@ -17,6 +18,7 @@ from youtube_dl.compat import ( compat_str, ) from youtube_dl.utils import ( + IDENTITY, preferredencoding, write_string, ) @@ -298,3 +300,7 @@ def http_server_port(httpd): else: sock = httpd.socket return sock.getsockname()[1] + + +def expectedFailureIf(cond): + return unittest.expectedFailure if cond else IDENTITY diff --git a/test/test_http.py b/test/test_http.py index cd180b51f..1a6b2e878 100644 --- a/test/test_http.py +++ b/test/test_http.py @@ -8,6 +8,7 @@ import sys import unittest sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) +import contextlib import gzip import io import ssl @@ -154,7 +155,7 @@ class HTTPTestRequestHandler(compat_http_server.BaseHTTPRequestHandler): def gzip_compress(p): buf = io.BytesIO() - with gzip.GzipFile(fileobj=buf, mode='wb') as f: + with contextlib.closing(gzip.GzipFile(fileobj=buf, mode='wb')) as f: f.write(p) return buf.getvalue() @@ -306,6 +307,10 @@ class TestHTTP(unittest.TestCase): else self.https_port if scheme == 'https' else self.http_port, path) + @unittest.skipUnless( + sys.version_info >= (3, 2) + or (sys.version_info[0] == 2 and sys.version_info[1:] >= (7, 9)), + 'No support for certificate check in SSL') def test_nocheckcertificate(self): with FakeYDL({'logger': FakeLogger()}) as ydl: with self.assertRaises(compat_urllib_error.URLError): diff --git a/test/test_utils.py b/test/test_utils.py index 1fc16ed05..2ee727caf 100644 --- a/test/test_utils.py +++ b/test/test_utils.py @@ -1617,7 +1617,7 @@ Line 1 self.assertEqual(traverse_obj(_TEST_DATA, lambda x, y: x == 'urls' and isinstance(y, list)), [_TEST_DATA['urls']], msg='function as query key should perform a filter based on (key, value)') - self.assertCountEqual(traverse_obj(_TEST_DATA, lambda _, x: isinstance(x[0], str)), {'str'}, + self.assertCountEqual(traverse_obj(_TEST_DATA, lambda _, x: isinstance(x[0], str)), set(('str',)), msg='exceptions in the query function should be catched') self.assertEqual(traverse_obj(iter(range(4)), lambda _, x: x % 2 == 0), [0, 2], msg='function key should accept iterables') @@ -1643,7 +1643,7 @@ Line 1 with self.assertRaises(Exception, msg='Sets with length != 1 should raise in debug'): traverse_obj(_TEST_DATA, set()) with self.assertRaises(Exception, msg='Sets with length != 1 should raise in debug'): - traverse_obj(_TEST_DATA, {str.upper, str}) + traverse_obj(_TEST_DATA, set((str.upper, str))) # Test `slice` as a key _SLICE_DATA = [0, 1, 2, 3, 4] @@ -1779,7 +1779,7 @@ Line 1 {0: 100}, msg='type as expected_type should filter dict values') self.assertEqual(traverse_obj(_TEST_DATA, {0: 100, 1: 1.2, 2: 'None'}, expected_type=str_or_none), {0: '100', 1: '1.2'}, msg='function as expected_type should transform dict values') - self.assertEqual(traverse_obj(_TEST_DATA, ({0: 1.2}, 0, {int_or_none}), expected_type=int), + self.assertEqual(traverse_obj(_TEST_DATA, ({0: 1.2}, 0, set((int_or_none,))), expected_type=int), 1, msg='expected_type should not filter non final dict values') self.assertEqual(traverse_obj(_TEST_DATA, {0: {0: 100, 1: 'str'}}, expected_type=int), {0: {0: 100}}, msg='expected_type should transform deep dict values') diff --git a/youtube_dl/jsinterp.py b/youtube_dl/jsinterp.py index 882432b80..86d902248 100644 --- a/youtube_dl/jsinterp.py +++ b/youtube_dl/jsinterp.py @@ -280,16 +280,16 @@ class JSInterpreter(object): # make Py 2.6 conform to its lying documentation if name == 'flags': self.flags = self.__flags + return self.flags elif name == 'pattern': self.pattern = self.__pattern_txt + return self.pattern + elif hasattr(self.__self, name): + v = getattr(self.__self, name) + setattr(self, name, v) + return v elif name in ('groupindex', 'groups'): - # in case these get set after a match? - if hasattr(self.__self, name): - setattr(self, name, getattr(self.__self, name)) - else: - return 0 if name == 'groupindex' else {} - if hasattr(self, name): - return getattr(self, name) + return 0 if name == 'groupindex' else {} raise AttributeError('{0} has no attribute named {1}'.format(self, name)) @classmethod diff --git a/youtube_dl/utils.py b/youtube_dl/utils.py index ac6c81465..494f8341b 100644 --- a/youtube_dl/utils.py +++ b/youtube_dl/utils.py @@ -6198,7 +6198,8 @@ def traverse_obj(obj, *paths, **kwargs): elif isinstance(obj, compat_re_Match): result = None if isinstance(key, int) or casesense: - result = lookup_or_none(obj, key, getter=compat_re_Match.group) + # Py 2.6 doesn't have methods in the Match class/type + result = lookup_or_none(obj, key, getter=lambda _, k: obj.group(k)) elif isinstance(key, str): result = next((v for k, v in obj.groupdict().items() @@ -6246,7 +6247,10 @@ def traverse_obj(obj, *paths, **kwargs): if __debug__ and callable(key): # Verify function signature - inspect.getcallargs(key, None, None) + args = inspect.getargspec(key) + if len(args.args) != 2: + # crash differently in 2.6 ! + inspect.getcallargs(key, None, None) new_objs = [] for obj in objs: