summaryrefslogtreecommitdiffstats
path: root/test
diff options
context:
space:
mode:
Diffstat (limited to 'test')
-rw-r--r--test/conftest.py10
-rw-r--r--test/helper.py32
-rw-r--r--test/test_InfoExtractor.py138
-rw-r--r--test/test_YoutubeDL.py45
-rw-r--r--test/test_aes.py12
-rw-r--r--test/test_compat.py10
-rw-r--r--test/test_config.py2
-rw-r--r--test/test_cookies.py133
-rwxr-xr-xtest/test_download.py20
-rw-r--r--test/test_downloader_http.py6
-rw-r--r--test/test_http_proxy.py4
-rw-r--r--test/test_iqiyi_sdk_interpreter.py4
-rw-r--r--test/test_jsinterp.py1
-rw-r--r--test/test_netrc.py2
-rw-r--r--test/test_networking.py56
-rw-r--r--test/test_networking_utils.py12
-rw-r--r--test/test_overwrites.py4
-rw-r--r--test/test_plugins.py2
-rw-r--r--test/test_post_hooks.py2
-rw-r--r--test/test_postprocessors.py137
-rw-r--r--test/test_socks.py8
-rw-r--r--test/test_subtitles.py11
-rw-r--r--test/test_traversal.py6
-rw-r--r--test/test_update.py8
-rw-r--r--test/test_utils.py95
-rw-r--r--test/test_websockets.py4
-rw-r--r--test/test_youtube_misc.py2
-rw-r--r--test/test_youtube_signature.py12
28 files changed, 419 insertions, 359 deletions
diff --git a/test/conftest.py b/test/conftest.py
index decd2c8..a8b92f8 100644
--- a/test/conftest.py
+++ b/test/conftest.py
@@ -22,8 +22,8 @@ def handler(request):
class HandlerWrapper(handler):
RH_KEY = handler.RH_KEY
- def __init__(self, *args, **kwargs):
- super().__init__(logger=FakeLogger, *args, **kwargs)
+ def __init__(self, **kwargs):
+ super().__init__(logger=FakeLogger, **kwargs)
return HandlerWrapper
@@ -54,11 +54,11 @@ def skip_handlers_if(request, handler):
def pytest_configure(config):
config.addinivalue_line(
- "markers", "skip_handler(handler): skip test for the given handler",
+ 'markers', 'skip_handler(handler): skip test for the given handler',
)
config.addinivalue_line(
- "markers", "skip_handler_if(handler): skip test for the given handler if condition is true"
+ 'markers', 'skip_handler_if(handler): skip test for the given handler if condition is true',
)
config.addinivalue_line(
- "markers", "skip_handlers_if(handler): skip test for handlers when the condition is true"
+ 'markers', 'skip_handlers_if(handler): skip test for handlers when the condition is true',
)
diff --git a/test/helper.py b/test/helper.py
index e747312..3b550d1 100644
--- a/test/helper.py
+++ b/test/helper.py
@@ -16,8 +16,8 @@ if 'pytest' in sys.modules:
import pytest
is_download_test = pytest.mark.download
else:
- def is_download_test(testClass):
- return testClass
+ def is_download_test(test_class):
+ return test_class
def get_params(override=None):
@@ -45,10 +45,10 @@ def try_rm(filename):
def report_warning(message, *args, **kwargs):
- '''
+ """
Print the message to stderr, it will be prefixed with 'WARNING:'
If stderr is a tty file the 'WARNING:' will be colored
- '''
+ """
if sys.stderr.isatty() and compat_os_name != 'nt':
_msg_header = '\033[0;33mWARNING:\033[0m'
else:
@@ -138,15 +138,14 @@ def expect_value(self, got, expected, field):
elif isinstance(expected, list) and isinstance(got, list):
self.assertEqual(
len(expected), len(got),
- 'Expect a list of length %d, but got a list of length %d for field %s' % (
- len(expected), len(got), field))
+ f'Expect a list of length {len(expected)}, but got a list of length {len(got)} for field {field}')
for index, (item_got, item_expected) in enumerate(zip(got, expected)):
type_got = type(item_got)
type_expected = type(item_expected)
self.assertEqual(
type_expected, type_got,
- 'Type mismatch for list item at index %d for field %s, expected %r, got %r' % (
- index, field, type_expected, type_got))
+ f'Type mismatch for list item at index {index} for field {field}, '
+ f'expected {type_expected!r}, got {type_got!r}')
expect_value(self, item_got, item_expected, field)
else:
if isinstance(expected, str) and expected.startswith('md5:'):
@@ -224,7 +223,7 @@ def sanitize_got_info_dict(got_dict):
test_info_dict.pop('display_id')
# Remove deprecated fields
- for old in YoutubeDL._deprecated_multivalue_fields.keys():
+ for old in YoutubeDL._deprecated_multivalue_fields:
test_info_dict.pop(old, None)
# release_year may be generated from release_date
@@ -246,11 +245,11 @@ def expect_info_dict(self, got_dict, expected_dict):
if expected_dict.get('ext'):
mandatory_fields.extend(('url', 'ext'))
for key in mandatory_fields:
- self.assertTrue(got_dict.get(key), 'Missing mandatory field %s' % key)
+ self.assertTrue(got_dict.get(key), f'Missing mandatory field {key}')
# Check for mandatory fields that are automatically set by YoutubeDL
if got_dict.get('_type', 'video') == 'video':
for key in ['webpage_url', 'extractor', 'extractor_key']:
- self.assertTrue(got_dict.get(key), 'Missing field: %s' % key)
+ self.assertTrue(got_dict.get(key), f'Missing field: {key}')
test_info_dict = sanitize_got_info_dict(got_dict)
@@ -258,7 +257,7 @@ def expect_info_dict(self, got_dict, expected_dict):
if missing_keys:
def _repr(v):
if isinstance(v, str):
- return "'%s'" % v.replace('\\', '\\\\').replace("'", "\\'").replace('\n', '\\n')
+ return "'{}'".format(v.replace('\\', '\\\\').replace("'", "\\'").replace('\n', '\\n'))
elif isinstance(v, type):
return v.__name__
else:
@@ -275,8 +274,7 @@ def expect_info_dict(self, got_dict, expected_dict):
write_string(info_dict_str.replace('\n', '\n '), out=sys.stderr)
self.assertFalse(
missing_keys,
- 'Missing keys in test definition: %s' % (
- ', '.join(sorted(missing_keys))))
+ 'Missing keys in test definition: {}'.format(', '.join(sorted(missing_keys))))
def assertRegexpMatches(self, text, regexp, msg=None):
@@ -285,9 +283,9 @@ def assertRegexpMatches(self, text, regexp, msg=None):
else:
m = re.match(regexp, text)
if not m:
- note = 'Regexp didn\'t match: %r not found' % (regexp)
+ note = f'Regexp didn\'t match: {regexp!r} not found'
if len(text) < 1000:
- note += ' in %r' % text
+ note += f' in {text!r}'
if msg is None:
msg = note
else:
@@ -310,7 +308,7 @@ def assertLessEqual(self, got, expected, msg=None):
def assertEqual(self, got, expected, msg=None):
- if not (got == expected):
+ if got != expected:
if msg is None:
msg = f'{got!r} not equal to {expected!r}'
self.assertTrue(got == expected, msg)
diff --git a/test/test_InfoExtractor.py b/test/test_InfoExtractor.py
index 744587e..31e8f82 100644
--- a/test/test_InfoExtractor.py
+++ b/test/test_InfoExtractor.py
@@ -262,19 +262,19 @@ class TestInfoExtractor(unittest.TestCase):
''',
{
'chapters': [
- {"title": "Explosie Turnhout", "start_time": 70, "end_time": 440},
- {"title": "Jaarwisseling", "start_time": 440, "end_time": 1179},
- {"title": "Natuurbranden Colorado", "start_time": 1179, "end_time": 1263},
- {"title": "Klimaatverandering", "start_time": 1263, "end_time": 1367},
- {"title": "Zacht weer", "start_time": 1367, "end_time": 1383},
- {"title": "Financiële balans", "start_time": 1383, "end_time": 1484},
- {"title": "Club Brugge", "start_time": 1484, "end_time": 1575},
- {"title": "Mentale gezondheid bij topsporters", "start_time": 1575, "end_time": 1728},
- {"title": "Olympische Winterspelen", "start_time": 1728, "end_time": 1873},
- {"title": "Sober oudjaar in Nederland", "start_time": 1873, "end_time": 2079.23}
+ {'title': 'Explosie Turnhout', 'start_time': 70, 'end_time': 440},
+ {'title': 'Jaarwisseling', 'start_time': 440, 'end_time': 1179},
+ {'title': 'Natuurbranden Colorado', 'start_time': 1179, 'end_time': 1263},
+ {'title': 'Klimaatverandering', 'start_time': 1263, 'end_time': 1367},
+ {'title': 'Zacht weer', 'start_time': 1367, 'end_time': 1383},
+ {'title': 'Financiële balans', 'start_time': 1383, 'end_time': 1484},
+ {'title': 'Club Brugge', 'start_time': 1484, 'end_time': 1575},
+ {'title': 'Mentale gezondheid bij topsporters', 'start_time': 1575, 'end_time': 1728},
+ {'title': 'Olympische Winterspelen', 'start_time': 1728, 'end_time': 1873},
+ {'title': 'Sober oudjaar in Nederland', 'start_time': 1873, 'end_time': 2079.23},
],
- 'title': 'Het journaal - Aflevering 365 (Seizoen 2021)'
- }, {}
+ 'title': 'Het journaal - Aflevering 365 (Seizoen 2021)',
+ }, {},
),
(
# test multiple thumbnails in a list
@@ -301,13 +301,13 @@ class TestInfoExtractor(unittest.TestCase):
'thumbnails': [{'url': 'https://www.rainews.it/cropgd/640x360/dl/img/2021/12/30/1640886376927_GettyImages.jpg'}],
},
{},
- )
+ ),
]
for html, expected_dict, search_json_ld_kwargs in _TESTS:
expect_dict(
self,
self.ie._search_json_ld(html, None, **search_json_ld_kwargs),
- expected_dict
+ expected_dict,
)
def test_download_json(self):
@@ -366,7 +366,7 @@ class TestInfoExtractor(unittest.TestCase):
'height': 740,
'tbr': 1500,
}],
- 'thumbnail': '//pics.r18.com/digital/amateur/mgmr105/mgmr105jp.jpg'
+ 'thumbnail': '//pics.r18.com/digital/amateur/mgmr105/mgmr105jp.jpg',
})
# from https://www.csfd.cz/
@@ -419,9 +419,9 @@ class TestInfoExtractor(unittest.TestCase):
'height': 1080,
}],
'subtitles': {
- 'cs': [{'url': 'https://video.csfd.cz/files/subtitles/163/344/163344115_4c388b.srt'}]
+ 'cs': [{'url': 'https://video.csfd.cz/files/subtitles/163/344/163344115_4c388b.srt'}],
},
- 'thumbnail': 'https://img.csfd.cz/files/images/film/video/preview/163/344/163344118_748d20.png?h360'
+ 'thumbnail': 'https://img.csfd.cz/files/images/film/video/preview/163/344/163344118_748d20.png?h360',
})
# from https://tamasha.com/v/Kkdjw
@@ -452,7 +452,7 @@ class TestInfoExtractor(unittest.TestCase):
'ext': 'mp4',
'format_id': '144p',
'height': 144,
- }]
+ }],
})
# from https://www.directvnow.com
@@ -470,7 +470,7 @@ class TestInfoExtractor(unittest.TestCase):
'formats': [{
'ext': 'mp4',
'url': 'https://cdn.directv.com/content/dam/dtv/prod/website_directvnow-international/videos/DTVN_hdr_HBO_v3.mp4',
- }]
+ }],
})
# from https://www.directvnow.com
@@ -488,7 +488,7 @@ class TestInfoExtractor(unittest.TestCase):
'formats': [{
'url': 'https://cdn.directv.com/content/dam/dtv/prod/website_directvnow-international/videos/DTVN_hdr_HBO_v3.mp4',
'ext': 'mp4',
- }]
+ }],
})
# from https://www.klarna.com/uk/
@@ -547,8 +547,8 @@ class TestInfoExtractor(unittest.TestCase):
'id': 'XEgvuql4',
'formats': [{
'url': 'rtmp://192.138.214.154/live/sjclive',
- 'ext': 'flv'
- }]
+ 'ext': 'flv',
+ }],
})
# from https://www.pornoxo.com/videos/7564/striptease-from-sexy-secretary/
@@ -588,8 +588,8 @@ class TestInfoExtractor(unittest.TestCase):
'thumbnail': 'https://t03.vipstreamservice.com/thumbs/pxo-full/2009-12/14/a4b2157147afe5efa93ce1978e0265289c193874e02597.flv-full-13.jpg',
'formats': [{
'url': 'https://cdn.pornoxo.com/key=MF+oEbaxqTKb50P-w9G3nA,end=1489689259,ip=104.199.146.27/ip=104.199.146.27/speed=6573765/buffer=3.0/2009-12/4b2157147afe5efa93ce1978e0265289c193874e02597.flv',
- 'ext': 'flv'
- }]
+ 'ext': 'flv',
+ }],
})
# from http://www.indiedb.com/games/king-machine/videos
@@ -610,12 +610,12 @@ jwplayer("mediaplayer").setup({"abouttext":"Visit Indie DB","aboutlink":"http:\/
'formats': [{
'url': 'http://cdn.dbolical.com/cache/videos/games/1/50/49678/encode_mp4/king-machine-trailer.mp4',
'height': 360,
- 'ext': 'mp4'
+ 'ext': 'mp4',
}, {
'url': 'http://cdn.dbolical.com/cache/videos/games/1/50/49678/encode720p_mp4/king-machine-trailer.mp4',
'height': 720,
- 'ext': 'mp4'
- }]
+ 'ext': 'mp4',
+ }],
})
def test_parse_m3u8_formats(self):
@@ -866,7 +866,7 @@ jwplayer("mediaplayer").setup({"abouttext":"Visit Indie DB","aboutlink":"http:\/
'height': 1080,
'vcodec': 'avc1.64002a',
}],
- {}
+ {},
),
(
'bipbop_16x9',
@@ -990,45 +990,45 @@ jwplayer("mediaplayer").setup({"abouttext":"Visit Indie DB","aboutlink":"http:\/
'en': [{
'url': 'https://devstreaming-cdn.apple.com/videos/streaming/examples/bipbop_16x9/subtitles/eng/prog_index.m3u8',
'ext': 'vtt',
- 'protocol': 'm3u8_native'
+ 'protocol': 'm3u8_native',
}, {
'url': 'https://devstreaming-cdn.apple.com/videos/streaming/examples/bipbop_16x9/subtitles/eng_forced/prog_index.m3u8',
'ext': 'vtt',
- 'protocol': 'm3u8_native'
+ 'protocol': 'm3u8_native',
}],
'fr': [{
'url': 'https://devstreaming-cdn.apple.com/videos/streaming/examples/bipbop_16x9/subtitles/fra/prog_index.m3u8',
'ext': 'vtt',
- 'protocol': 'm3u8_native'
+ 'protocol': 'm3u8_native',
}, {
'url': 'https://devstreaming-cdn.apple.com/videos/streaming/examples/bipbop_16x9/subtitles/fra_forced/prog_index.m3u8',
'ext': 'vtt',
- 'protocol': 'm3u8_native'
+ 'protocol': 'm3u8_native',
}],
'es': [{
'url': 'https://devstreaming-cdn.apple.com/videos/streaming/examples/bipbop_16x9/subtitles/spa/prog_index.m3u8',
'ext': 'vtt',
- 'protocol': 'm3u8_native'
+ 'protocol': 'm3u8_native',
}, {
'url': 'https://devstreaming-cdn.apple.com/videos/streaming/examples/bipbop_16x9/subtitles/spa_forced/prog_index.m3u8',
'ext': 'vtt',
- 'protocol': 'm3u8_native'
+ 'protocol': 'm3u8_native',
}],
'ja': [{
'url': 'https://devstreaming-cdn.apple.com/videos/streaming/examples/bipbop_16x9/subtitles/jpn/prog_index.m3u8',
'ext': 'vtt',
- 'protocol': 'm3u8_native'
+ 'protocol': 'm3u8_native',
}, {
'url': 'https://devstreaming-cdn.apple.com/videos/streaming/examples/bipbop_16x9/subtitles/jpn_forced/prog_index.m3u8',
'ext': 'vtt',
- 'protocol': 'm3u8_native'
+ 'protocol': 'm3u8_native',
}],
- }
+ },
),
]
for m3u8_file, m3u8_url, expected_formats, expected_subs in _TEST_CASES:
- with open('./test/testdata/m3u8/%s.m3u8' % m3u8_file, encoding='utf-8') as f:
+ with open(f'./test/testdata/m3u8/{m3u8_file}.m3u8', encoding='utf-8') as f:
formats, subs = self.ie._parse_m3u8_formats_and_subtitles(
f.read(), m3u8_url, ext='mp4')
self.ie._sort_formats(formats)
@@ -1366,14 +1366,14 @@ jwplayer("mediaplayer").setup({"abouttext":"Visit Indie DB","aboutlink":"http:\/
'url': 'https://sdn-global-streaming-cache-3qsdn.akamaized.net/stream/3144/files/17/07/672975/3144-kZT4LWMQw6Rh7Kpd.ism/manifest.mpd',
'fragment_base_url': 'https://sdn-global-streaming-cache-3qsdn.akamaized.net/stream/3144/files/17/07/672975/3144-kZT4LWMQw6Rh7Kpd.ism/dash/',
'protocol': 'http_dash_segments',
- }
- ]
+ },
+ ],
},
- )
+ ),
]
for mpd_file, mpd_url, mpd_base_url, expected_formats, expected_subtitles in _TEST_CASES:
- with open('./test/testdata/mpd/%s.mpd' % mpd_file, encoding='utf-8') as f:
+ with open(f'./test/testdata/mpd/{mpd_file}.mpd', encoding='utf-8') as f:
formats, subtitles = self.ie._parse_mpd_formats_and_subtitles(
compat_etree_fromstring(f.read().encode()),
mpd_base_url=mpd_base_url, mpd_url=mpd_url)
@@ -1408,7 +1408,7 @@ jwplayer("mediaplayer").setup({"abouttext":"Visit Indie DB","aboutlink":"http:\/
'sampling_rate': 48000,
'channels': 2,
'bits_per_sample': 16,
- 'nal_unit_length_field': 4
+ 'nal_unit_length_field': 4,
},
}, {
'format_id': 'video-100',
@@ -1431,7 +1431,7 @@ jwplayer("mediaplayer").setup({"abouttext":"Visit Indie DB","aboutlink":"http:\/
'codec_private_data': '00000001674D401FDA0544EFFC2D002CBC40000003004000000C03C60CA80000000168EF32C8',
'channels': 2,
'bits_per_sample': 16,
- 'nal_unit_length_field': 4
+ 'nal_unit_length_field': 4,
},
}, {
'format_id': 'video-326',
@@ -1454,7 +1454,7 @@ jwplayer("mediaplayer").setup({"abouttext":"Visit Indie DB","aboutlink":"http:\/
'codec_private_data': '00000001674D401FDA0241FE23FFC3BC83BA44000003000400000300C03C60CA800000000168EF32C8',
'channels': 2,
'bits_per_sample': 16,
- 'nal_unit_length_field': 4
+ 'nal_unit_length_field': 4,
},
}, {
'format_id': 'video-698',
@@ -1477,7 +1477,7 @@ jwplayer("mediaplayer").setup({"abouttext":"Visit Indie DB","aboutlink":"http:\/
'codec_private_data': '00000001674D401FDA0350BFB97FF06AF06AD1000003000100000300300F1832A00000000168EF32C8',
'channels': 2,
'bits_per_sample': 16,
- 'nal_unit_length_field': 4
+ 'nal_unit_length_field': 4,
},
}, {
'format_id': 'video-1493',
@@ -1500,7 +1500,7 @@ jwplayer("mediaplayer").setup({"abouttext":"Visit Indie DB","aboutlink":"http:\/
'codec_private_data': '00000001674D401FDA011C3DE6FFF0D890D871000003000100000300300F1832A00000000168EF32C8',
'channels': 2,
'bits_per_sample': 16,
- 'nal_unit_length_field': 4
+ 'nal_unit_length_field': 4,
},
}, {
'format_id': 'video-4482',
@@ -1523,7 +1523,7 @@ jwplayer("mediaplayer").setup({"abouttext":"Visit Indie DB","aboutlink":"http:\/
'codec_private_data': '00000001674D401FDA01A816F97FFC1ABC1AB440000003004000000C03C60CA80000000168EF32C8',
'channels': 2,
'bits_per_sample': 16,
- 'nal_unit_length_field': 4
+ 'nal_unit_length_field': 4,
},
}],
{
@@ -1538,10 +1538,10 @@ jwplayer("mediaplayer").setup({"abouttext":"Visit Indie DB","aboutlink":"http:\/
'duration': 8880746666,
'timescale': 10000000,
'fourcc': 'TTML',
- 'codec_private_data': ''
- }
- }
- ]
+ 'codec_private_data': '',
+ },
+ },
+ ],
},
),
(
@@ -1571,7 +1571,7 @@ jwplayer("mediaplayer").setup({"abouttext":"Visit Indie DB","aboutlink":"http:\/
'sampling_rate': 48000,
'channels': 2,
'bits_per_sample': 16,
- 'nal_unit_length_field': 4
+ 'nal_unit_length_field': 4,
},
}, {
'format_id': 'audio_deu_1-224',
@@ -1597,7 +1597,7 @@ jwplayer("mediaplayer").setup({"abouttext":"Visit Indie DB","aboutlink":"http:\/
'sampling_rate': 48000,
'channels': 6,
'bits_per_sample': 16,
- 'nal_unit_length_field': 4
+ 'nal_unit_length_field': 4,
},
}, {
'format_id': 'video_deu-23',
@@ -1622,7 +1622,7 @@ jwplayer("mediaplayer").setup({"abouttext":"Visit Indie DB","aboutlink":"http:\/
'codec_private_data': '000000016742C00CDB06077E5C05A808080A00000300020000030009C0C02EE0177CC6300F142AE00000000168CA8DC8',
'channels': 2,
'bits_per_sample': 16,
- 'nal_unit_length_field': 4
+ 'nal_unit_length_field': 4,
},
}, {
'format_id': 'video_deu-403',
@@ -1647,7 +1647,7 @@ jwplayer("mediaplayer").setup({"abouttext":"Visit Indie DB","aboutlink":"http:\/
'codec_private_data': '00000001674D4014E98323B602D4040405000003000100000300320F1429380000000168EAECF2',
'channels': 2,
'bits_per_sample': 16,
- 'nal_unit_length_field': 4
+ 'nal_unit_length_field': 4,
},
}, {
'format_id': 'video_deu-680',
@@ -1672,7 +1672,7 @@ jwplayer("mediaplayer").setup({"abouttext":"Visit Indie DB","aboutlink":"http:\/
'codec_private_data': '00000001674D401EE981405FF2E02D4040405000000300100000030320F162D3800000000168EAECF2',
'channels': 2,
'bits_per_sample': 16,
- 'nal_unit_length_field': 4
+ 'nal_unit_length_field': 4,
},
}, {
'format_id': 'video_deu-1253',
@@ -1698,7 +1698,7 @@ jwplayer("mediaplayer").setup({"abouttext":"Visit Indie DB","aboutlink":"http:\/
'codec_private_data': '00000001674D401EE981405FF2E02D4040405000000300100000030320F162D3800000000168EAECF2',
'channels': 2,
'bits_per_sample': 16,
- 'nal_unit_length_field': 4
+ 'nal_unit_length_field': 4,
},
}, {
'format_id': 'video_deu-2121',
@@ -1723,7 +1723,7 @@ jwplayer("mediaplayer").setup({"abouttext":"Visit Indie DB","aboutlink":"http:\/
'codec_private_data': '00000001674D401EECA0601BD80B50101014000003000400000300C83C58B6580000000168E93B3C80',
'channels': 2,
'bits_per_sample': 16,
- 'nal_unit_length_field': 4
+ 'nal_unit_length_field': 4,
},
}, {
'format_id': 'video_deu-3275',
@@ -1748,7 +1748,7 @@ jwplayer("mediaplayer").setup({"abouttext":"Visit Indie DB","aboutlink":"http:\/
'codec_private_data': '00000001674D4020ECA02802DD80B501010140000003004000000C83C60C65800000000168E93B3C80',
'channels': 2,
'bits_per_sample': 16,
- 'nal_unit_length_field': 4
+ 'nal_unit_length_field': 4,
},
}, {
'format_id': 'video_deu-5300',
@@ -1773,7 +1773,7 @@ jwplayer("mediaplayer").setup({"abouttext":"Visit Indie DB","aboutlink":"http:\/
'codec_private_data': '00000001674D4028ECA03C0113F2E02D4040405000000300100000030320F18319600000000168E93B3C80',
'channels': 2,
'bits_per_sample': 16,
- 'nal_unit_length_field': 4
+ 'nal_unit_length_field': 4,
},
}, {
'format_id': 'video_deu-8079',
@@ -1798,7 +1798,7 @@ jwplayer("mediaplayer").setup({"abouttext":"Visit Indie DB","aboutlink":"http:\/
'codec_private_data': '00000001674D4028ECA03C0113F2E02D4040405000000300100000030320F18319600000000168E93B3C80',
'channels': 2,
'bits_per_sample': 16,
- 'nal_unit_length_field': 4
+ 'nal_unit_length_field': 4,
},
}],
{},
@@ -1806,7 +1806,7 @@ jwplayer("mediaplayer").setup({"abouttext":"Visit Indie DB","aboutlink":"http:\/
]
for ism_file, ism_url, expected_formats, expected_subtitles in _TEST_CASES:
- with open('./test/testdata/ism/%s.Manifest' % ism_file, encoding='utf-8') as f:
+ with open(f'./test/testdata/ism/{ism_file}.Manifest', encoding='utf-8') as f:
formats, subtitles = self.ie._parse_ism_formats_and_subtitles(
compat_etree_fromstring(f.read().encode()), ism_url=ism_url)
self.ie._sort_formats(formats)
@@ -1827,12 +1827,12 @@ jwplayer("mediaplayer").setup({"abouttext":"Visit Indie DB","aboutlink":"http:\/
'tbr': 2148,
'width': 1280,
'height': 720,
- }]
+ }],
),
]
for f4m_file, f4m_url, expected_formats in _TEST_CASES:
- with open('./test/testdata/f4m/%s.f4m' % f4m_file, encoding='utf-8') as f:
+ with open(f'./test/testdata/f4m/{f4m_file}.f4m', encoding='utf-8') as f:
formats = self.ie._parse_f4m_formats(
compat_etree_fromstring(f.read().encode()),
f4m_url, None)
@@ -1873,13 +1873,13 @@ jwplayer("mediaplayer").setup({"abouttext":"Visit Indie DB","aboutlink":"http:\/
}, {
'manifest_url': 'https://example.org/src/foo_xspf.xspf',
'url': 'https://example.com/track3.mp3',
- }]
- }]
+ }],
+ }],
),
]
for xspf_file, xspf_url, expected_entries in _TEST_CASES:
- with open('./test/testdata/xspf/%s.xspf' % xspf_file, encoding='utf-8') as f:
+ with open(f'./test/testdata/xspf/{xspf_file}.xspf', encoding='utf-8') as f:
entries = self.ie._parse_xspf(
compat_etree_fromstring(f.read().encode()),
xspf_file, xspf_url=xspf_url, xspf_base_url=xspf_url)
@@ -1902,7 +1902,7 @@ jwplayer("mediaplayer").setup({"abouttext":"Visit Indie DB","aboutlink":"http:\/
server_thread.start()
(content, urlh) = self.ie._download_webpage_handle(
- 'http://127.0.0.1:%d/teapot' % port, None,
+ f'http://127.0.0.1:{port}/teapot', None,
expected_status=TEAPOT_RESPONSE_STATUS)
self.assertEqual(content, TEAPOT_RESPONSE_BODY)
diff --git a/test/test_YoutubeDL.py b/test/test_YoutubeDL.py
index 5242cf8..841ce1a 100644
--- a/test/test_YoutubeDL.py
+++ b/test/test_YoutubeDL.py
@@ -8,6 +8,7 @@ import unittest
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
+import contextlib
import copy
import json
@@ -129,8 +130,8 @@ class TestFormatSelection(unittest.TestCase):
'allow_multiple_audio_streams': multi,
})
ydl.process_ie_result(info_dict.copy())
- downloaded = map(lambda x: x['format_id'], ydl.downloaded_info_dicts)
- self.assertEqual(list(downloaded), list(expected))
+ downloaded = [x['format_id'] for x in ydl.downloaded_info_dicts]
+ self.assertEqual(downloaded, list(expected))
test('20/47', '47')
test('20/71/worst', '35')
@@ -515,10 +516,8 @@ class TestFormatSelection(unittest.TestCase):
self.assertEqual(downloaded_ids, ['D', 'C', 'B'])
ydl = YDL({'format': 'best[height<40]'})
- try:
+ with contextlib.suppress(ExtractorError):
ydl.process_ie_result(info_dict)
- except ExtractorError:
- pass
self.assertEqual(ydl.downloaded_info_dicts, [])
def test_default_format_spec(self):
@@ -652,8 +651,8 @@ class TestYoutubeDL(unittest.TestCase):
'formats': [
{'id': 'id 1', 'height': 1080, 'width': 1920},
{'id': 'id 2', 'height': 720},
- {'id': 'id 3'}
- ]
+ {'id': 'id 3'},
+ ],
}
def test_prepare_outtmpl_and_filename(self):
@@ -773,7 +772,7 @@ class TestYoutubeDL(unittest.TestCase):
test('%(formats)j', (json.dumps(FORMATS), None))
test('%(formats)#j', (
json.dumps(FORMATS, indent=4),
- json.dumps(FORMATS, indent=4).replace(':', ':').replace('"', """).replace('\n', ' ')
+ json.dumps(FORMATS, indent=4).replace(':', ':').replace('"', '"').replace('\n', ' '),
))
test('%(title5).3B', 'á')
test('%(title5)U', 'áéí 𝐀')
@@ -843,8 +842,8 @@ class TestYoutubeDL(unittest.TestCase):
# Empty filename
test('%(foo|)s-%(bar|)s.%(ext)s', '-.mp4')
- # test('%(foo|)s.%(ext)s', ('.mp4', '_.mp4')) # fixme
- # test('%(foo|)s', ('', '_')) # fixme
+ # test('%(foo|)s.%(ext)s', ('.mp4', '_.mp4')) # FIXME: ?
+ # test('%(foo|)s', ('', '_')) # FIXME: ?
# Environment variable expansion for prepare_filename
os.environ['__yt_dlp_var'] = 'expanded'
@@ -861,7 +860,7 @@ class TestYoutubeDL(unittest.TestCase):
test('Hello %(title1)s', 'Hello $PATH')
test('Hello %(title2)s', 'Hello %PATH%')
test('%(title3)s', ('foo/bar\\test', 'foo⧸bar⧹test'))
- test('folder/%(title3)s', ('folder/foo/bar\\test', 'folder%sfoo⧸bar⧹test' % os.path.sep))
+ test('folder/%(title3)s', ('folder/foo/bar\\test', f'folder{os.path.sep}foo⧸bar⧹test'))
def test_format_note(self):
ydl = YoutubeDL()
@@ -883,22 +882,22 @@ class TestYoutubeDL(unittest.TestCase):
f.write('EXAMPLE')
return [info['filepath']], info
- def run_pp(params, PP):
+ def run_pp(params, pp):
with open(filename, 'w') as f:
f.write('EXAMPLE')
ydl = YoutubeDL(params)
- ydl.add_post_processor(PP())
+ ydl.add_post_processor(pp())
ydl.post_process(filename, {'filepath': filename})
run_pp({'keepvideo': True}, SimplePP)
- self.assertTrue(os.path.exists(filename), '%s doesn\'t exist' % filename)
- self.assertTrue(os.path.exists(audiofile), '%s doesn\'t exist' % audiofile)
+ self.assertTrue(os.path.exists(filename), f'{filename} doesn\'t exist')
+ self.assertTrue(os.path.exists(audiofile), f'{audiofile} doesn\'t exist')
os.unlink(filename)
os.unlink(audiofile)
run_pp({'keepvideo': False}, SimplePP)
- self.assertFalse(os.path.exists(filename), '%s exists' % filename)
- self.assertTrue(os.path.exists(audiofile), '%s doesn\'t exist' % audiofile)
+ self.assertFalse(os.path.exists(filename), f'{filename} exists')
+ self.assertTrue(os.path.exists(audiofile), f'{audiofile} doesn\'t exist')
os.unlink(audiofile)
class ModifierPP(PostProcessor):
@@ -908,7 +907,7 @@ class TestYoutubeDL(unittest.TestCase):
return [], info
run_pp({'keepvideo': False}, ModifierPP)
- self.assertTrue(os.path.exists(filename), '%s doesn\'t exist' % filename)
+ self.assertTrue(os.path.exists(filename), f'{filename} doesn\'t exist')
os.unlink(filename)
def test_match_filter(self):
@@ -920,7 +919,7 @@ class TestYoutubeDL(unittest.TestCase):
'duration': 30,
'filesize': 10 * 1024,
'playlist_id': '42',
- 'uploader': "變態妍字幕版 太妍 тест",
+ 'uploader': '變態妍字幕版 太妍 тест',
'creator': "тест ' 123 ' тест--",
'webpage_url': 'http://example.com/watch?v=shenanigans',
}
@@ -933,7 +932,7 @@ class TestYoutubeDL(unittest.TestCase):
'description': 'foo',
'filesize': 5 * 1024,
'playlist_id': '43',
- 'uploader': "тест 123",
+ 'uploader': 'тест 123',
'webpage_url': 'http://example.com/watch?v=SHENANIGANS',
}
videos = [first, second]
@@ -1180,7 +1179,7 @@ class TestYoutubeDL(unittest.TestCase):
})
return {
'id': video_id,
- 'title': 'Video %s' % video_id,
+ 'title': f'Video {video_id}',
'formats': formats,
}
@@ -1194,8 +1193,8 @@ class TestYoutubeDL(unittest.TestCase):
'_type': 'url_transparent',
'ie_key': VideoIE.ie_key(),
'id': video_id,
- 'url': 'video:%s' % video_id,
- 'title': 'Video Transparent %s' % video_id,
+ 'url': f'video:{video_id}',
+ 'title': f'Video Transparent {video_id}',
}
def _real_extract(self, url):
diff --git a/test/test_aes.py b/test/test_aes.py
index a26abfd..5f975ef 100644
--- a/test/test_aes.py
+++ b/test/test_aes.py
@@ -87,7 +87,7 @@ class TestAES(unittest.TestCase):
password = intlist_to_bytes(self.key).decode()
encrypted = base64.b64encode(
intlist_to_bytes(self.iv[:8])
- + b'\x17\x15\x93\xab\x8d\x80V\xcdV\xe0\t\xcdo\xc2\xa5\xd8ksM\r\xe27N\xae'
+ + b'\x17\x15\x93\xab\x8d\x80V\xcdV\xe0\t\xcdo\xc2\xa5\xd8ksM\r\xe27N\xae',
).decode()
decrypted = (aes_decrypt_text(encrypted, password, 16))
self.assertEqual(decrypted, self.secret_msg)
@@ -95,7 +95,7 @@ class TestAES(unittest.TestCase):
password = intlist_to_bytes(self.key).decode()
encrypted = base64.b64encode(
intlist_to_bytes(self.iv[:8])
- + b'\x0b\xe6\xa4\xd9z\x0e\xb8\xb9\xd0\xd4i_\x85\x1d\x99\x98_\xe5\x80\xe7.\xbf\xa5\x83'
+ + b'\x0b\xe6\xa4\xd9z\x0e\xb8\xb9\xd0\xd4i_\x85\x1d\x99\x98_\xe5\x80\xe7.\xbf\xa5\x83',
).decode()
decrypted = (aes_decrypt_text(encrypted, password, 32))
self.assertEqual(decrypted, self.secret_msg)
@@ -132,16 +132,16 @@ class TestAES(unittest.TestCase):
block = [0x21, 0xA0, 0x43, 0xFF]
self.assertEqual(pad_block(block, 'pkcs7'),
- block + [0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C])
+ [*block, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C])
self.assertEqual(pad_block(block, 'iso7816'),
- block + [0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00])
+ [*block, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00])
self.assertEqual(pad_block(block, 'whitespace'),
- block + [0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20])
+ [*block, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20])
self.assertEqual(pad_block(block, 'zero'),
- block + [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00])
+ [*block, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00])
block = list(range(16))
for mode in ('pkcs7', 'iso7816', 'whitespace', 'zero'):
diff --git a/test/test_compat.py b/test/test_compat.py
index 71ca7f9..e7d97e3 100644
--- a/test/test_compat.py
+++ b/test/test_compat.py
@@ -15,8 +15,8 @@ from yt_dlp.compat import urllib # isort: split
from yt_dlp.compat import (
compat_etree_fromstring,
compat_expanduser,
- compat_urllib_parse_unquote,
- compat_urllib_parse_urlencode,
+ compat_urllib_parse_unquote, # noqa: TID251
+ compat_urllib_parse_urlencode, # noqa: TID251
)
from yt_dlp.compat.urllib.request import getproxies
@@ -24,15 +24,15 @@ from yt_dlp.compat.urllib.request import getproxies
class TestCompat(unittest.TestCase):
def test_compat_passthrough(self):
with self.assertWarns(DeprecationWarning):
- compat.compat_basestring
+ _ = compat.compat_basestring
with self.assertWarns(DeprecationWarning):
- compat.WINDOWS_VT_MODE
+ _ = compat.WINDOWS_VT_MODE
self.assertEqual(urllib.request.getproxies, getproxies)
with self.assertWarns(DeprecationWarning):
- compat.compat_pycrypto_AES # Must not raise error
+ _ = compat.compat_pycrypto_AES # Must not raise error
def test_compat_expanduser(self):
old_home = os.environ.get('HOME')
diff --git a/test/test_config.py b/test/test_config.py
index a393b65..238ca66 100644
--- a/test/test_config.py
+++ b/test/test_config.py
@@ -71,7 +71,7 @@ def _generate_expected_groups():
Path('/etc/yt-dlp.conf'),
Path('/etc/yt-dlp/config'),
Path('/etc/yt-dlp/config.txt'),
- ]
+ ],
}
diff --git a/test/test_cookies.py b/test/test_cookies.py
index bd61f30..e1271f6 100644
--- a/test/test_cookies.py
+++ b/test/test_cookies.py
@@ -67,6 +67,7 @@ class TestCookies(unittest.TestCase):
({'XDG_CURRENT_DESKTOP': 'GNOME'}, _LinuxDesktopEnvironment.GNOME),
({'XDG_CURRENT_DESKTOP': 'GNOME:GNOME-Classic'}, _LinuxDesktopEnvironment.GNOME),
({'XDG_CURRENT_DESKTOP': 'GNOME : GNOME-Classic'}, _LinuxDesktopEnvironment.GNOME),
+ ({'XDG_CURRENT_DESKTOP': 'ubuntu:GNOME'}, _LinuxDesktopEnvironment.GNOME),
({'XDG_CURRENT_DESKTOP': 'Unity', 'DESKTOP_SESSION': 'gnome-fallback'}, _LinuxDesktopEnvironment.GNOME),
({'XDG_CURRENT_DESKTOP': 'KDE', 'KDE_SESSION_VERSION': '5'}, _LinuxDesktopEnvironment.KDE5),
@@ -106,7 +107,7 @@ class TestCookies(unittest.TestCase):
def test_chrome_cookie_decryptor_windows_v10(self):
with MonkeyPatch(cookies, {
- '_get_windows_v10_key': lambda *args, **kwargs: b'Y\xef\xad\xad\xeerp\xf0Y\xe6\x9b\x12\xc2<z\x16]\n\xbb\xb8\xcb\xd7\x9bA\xc3\x14e\x99{\xd6\xf4&'
+ '_get_windows_v10_key': lambda *args, **kwargs: b'Y\xef\xad\xad\xeerp\xf0Y\xe6\x9b\x12\xc2<z\x16]\n\xbb\xb8\xcb\xd7\x9bA\xc3\x14e\x99{\xd6\xf4&',
}):
encrypted_value = b'v10T\xb8\xf3\xb8\x01\xa7TtcV\xfc\x88\xb8\xb8\xef\x05\xb5\xfd\x18\xc90\x009\xab\xb1\x893\x85)\x87\xe1\xa9-\xa3\xad='
value = '32101439'
@@ -121,17 +122,17 @@ class TestCookies(unittest.TestCase):
self.assertEqual(decryptor.decrypt(encrypted_value), value)
def test_safari_cookie_parsing(self):
- cookies = \
- b'cook\x00\x00\x00\x01\x00\x00\x00i\x00\x00\x01\x00\x01\x00\x00\x00\x10\x00\x00\x00\x00\x00\x00\x00Y' \
- b'\x00\x00\x00\x00\x00\x00\x00 \x00\x00\x00\x00\x00\x00\x008\x00\x00\x00B\x00\x00\x00F\x00\x00\x00H' \
- b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x80\x03\xa5>\xc3A\x00\x00\x80\xc3\x07:\xc3A' \
- b'localhost\x00foo\x00/\x00test%20%3Bcookie\x00\x00\x00\x054\x07\x17 \x05\x00\x00\x00Kbplist00\xd1\x01' \
- b'\x02_\x10\x18NSHTTPCookieAcceptPolicy\x10\x02\x08\x0b&\x00\x00\x00\x00\x00\x00\x01\x01\x00\x00\x00' \
- b'\x00\x00\x00\x00\x03\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00('
+ cookies = (
+ b'cook\x00\x00\x00\x01\x00\x00\x00i\x00\x00\x01\x00\x01\x00\x00\x00\x10\x00\x00\x00\x00\x00\x00\x00Y'
+ b'\x00\x00\x00\x00\x00\x00\x00 \x00\x00\x00\x00\x00\x00\x008\x00\x00\x00B\x00\x00\x00F\x00\x00\x00H'
+ b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x80\x03\xa5>\xc3A\x00\x00\x80\xc3\x07:\xc3A'
+ b'localhost\x00foo\x00/\x00test%20%3Bcookie\x00\x00\x00\x054\x07\x17 \x05\x00\x00\x00Kbplist00\xd1\x01'
+ b'\x02_\x10\x18NSHTTPCookieAcceptPolicy\x10\x02\x08\x0b&\x00\x00\x00\x00\x00\x00\x01\x01\x00\x00\x00'
+ b'\x00\x00\x00\x00\x03\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00(')
jar = parse_safari_cookies(cookies)
self.assertEqual(len(jar), 1)
- cookie = list(jar)[0]
+ cookie = next(iter(jar))
self.assertEqual(cookie.domain, 'localhost')
self.assertEqual(cookie.port, None)
self.assertEqual(cookie.path, '/')
@@ -164,7 +165,7 @@ class TestLenientSimpleCookie(unittest.TestCase):
attributes = {
key: value
for key, value in dict(morsel).items()
- if value != ""
+ if value != ''
}
self.assertEqual(attributes, expected_attributes, message)
@@ -174,133 +175,133 @@ class TestLenientSimpleCookie(unittest.TestCase):
self._run_tests(
# Copied from https://github.com/python/cpython/blob/v3.10.7/Lib/test/test_http_cookies.py
(
- "Test basic cookie",
- "chips=ahoy; vienna=finger",
- {"chips": "ahoy", "vienna": "finger"},
+ 'Test basic cookie',
+ 'chips=ahoy; vienna=finger',
+ {'chips': 'ahoy', 'vienna': 'finger'},
),
(
- "Test quoted cookie",
+ 'Test quoted cookie',
'keebler="E=mc2; L=\\"Loves\\"; fudge=\\012;"',
- {"keebler": 'E=mc2; L="Loves"; fudge=\012;'},
+ {'keebler': 'E=mc2; L="Loves"; fudge=\012;'},
),
(
"Allow '=' in an unquoted value",
- "keebler=E=mc2",
- {"keebler": "E=mc2"},
+ 'keebler=E=mc2',
+ {'keebler': 'E=mc2'},
),
(
"Allow cookies with ':' in their name",
- "key:term=value:term",
- {"key:term": "value:term"},
+ 'key:term=value:term',
+ {'key:term': 'value:term'},
),
(
"Allow '[' and ']' in cookie values",
- "a=b; c=[; d=r; f=h",
- {"a": "b", "c": "[", "d": "r", "f": "h"},
+ 'a=b; c=[; d=r; f=h',
+ {'a': 'b', 'c': '[', 'd': 'r', 'f': 'h'},
),
(
- "Test basic cookie attributes",
+ 'Test basic cookie attributes',
'Customer="WILE_E_COYOTE"; Version=1; Path=/acme',
- {"Customer": ("WILE_E_COYOTE", {"version": "1", "path": "/acme"})},
+ {'Customer': ('WILE_E_COYOTE', {'version': '1', 'path': '/acme'})},
),
(
- "Test flag only cookie attributes",
+ 'Test flag only cookie attributes',
'Customer="WILE_E_COYOTE"; HttpOnly; Secure',
- {"Customer": ("WILE_E_COYOTE", {"httponly": True, "secure": True})},
+ {'Customer': ('WILE_E_COYOTE', {'httponly': True, 'secure': True})},
),
(
- "Test flag only attribute with values",
- "eggs=scrambled; httponly=foo; secure=bar; Path=/bacon",
- {"eggs": ("scrambled", {"httponly": "foo", "secure": "bar", "path": "/bacon"})},
+ 'Test flag only attribute with values',
+ 'eggs=scrambled; httponly=foo; secure=bar; Path=/bacon',
+ {'eggs': ('scrambled', {'httponly': 'foo', 'secure': 'bar', 'path': '/bacon'})},
),
(
"Test special case for 'expires' attribute, 4 digit year",
'Customer="W"; expires=Wed, 01 Jan 2010 00:00:00 GMT',
- {"Customer": ("W", {"expires": "Wed, 01 Jan 2010 00:00:00 GMT"})},
+ {'Customer': ('W', {'expires': 'Wed, 01 Jan 2010 00:00:00 GMT'})},
),
(
"Test special case for 'expires' attribute, 2 digit year",
'Customer="W"; expires=Wed, 01 Jan 98 00:00:00 GMT',
- {"Customer": ("W", {"expires": "Wed, 01 Jan 98 00:00:00 GMT"})},
+ {'Customer': ('W', {'expires': 'Wed, 01 Jan 98 00:00:00 GMT'})},
),
(
- "Test extra spaces in keys and values",
- "eggs = scrambled ; secure ; path = bar ; foo=foo ",
- {"eggs": ("scrambled", {"secure": True, "path": "bar"}), "foo": "foo"},
+ 'Test extra spaces in keys and values',
+ 'eggs = scrambled ; secure ; path = bar ; foo=foo ',
+ {'eggs': ('scrambled', {'secure': True, 'path': 'bar'}), 'foo': 'foo'},
),
(
- "Test quoted attributes",
+ 'Test quoted attributes',
'Customer="WILE_E_COYOTE"; Version="1"; Path="/acme"',
- {"Customer": ("WILE_E_COYOTE", {"version": "1", "path": "/acme"})}
+ {'Customer': ('WILE_E_COYOTE', {'version': '1', 'path': '/acme'})},
),
# Our own tests that CPython passes
(
"Allow ';' in quoted value",
'chips="a;hoy"; vienna=finger',
- {"chips": "a;hoy", "vienna": "finger"},
+ {'chips': 'a;hoy', 'vienna': 'finger'},
),
(
- "Keep only the last set value",
- "a=c; a=b",
- {"a": "b"},
+ 'Keep only the last set value',
+ 'a=c; a=b',
+ {'a': 'b'},
),
)
def test_lenient_parsing(self):
self._run_tests(
(
- "Ignore and try to skip invalid cookies",
+ 'Ignore and try to skip invalid cookies',
'chips={"ahoy;": 1}; vienna="finger;"',
- {"vienna": "finger;"},
+ {'vienna': 'finger;'},
),
(
- "Ignore cookies without a name",
- "a=b; unnamed; c=d",
- {"a": "b", "c": "d"},
+ 'Ignore cookies without a name',
+ 'a=b; unnamed; c=d',
+ {'a': 'b', 'c': 'd'},
),
(
"Ignore '\"' cookie without name",
'a=b; "; c=d',
- {"a": "b", "c": "d"},
+ {'a': 'b', 'c': 'd'},
),
(
- "Skip all space separated values",
- "x a=b c=d x; e=f",
- {"a": "b", "c": "d", "e": "f"},
+ 'Skip all space separated values',
+ 'x a=b c=d x; e=f',
+ {'a': 'b', 'c': 'd', 'e': 'f'},
),
(
- "Skip all space separated values",
+ 'Skip all space separated values',
'x a=b; data={"complex": "json", "with": "key=value"}; x c=d x',
- {"a": "b", "c": "d"},
+ {'a': 'b', 'c': 'd'},
),
(
- "Expect quote mending",
+ 'Expect quote mending',
'a=b; invalid="; c=d',
- {"a": "b", "c": "d"},
+ {'a': 'b', 'c': 'd'},
),
(
- "Reset morsel after invalid to not capture attributes",
- "a=b; invalid; Version=1; c=d",
- {"a": "b", "c": "d"},
+ 'Reset morsel after invalid to not capture attributes',
+ 'a=b; invalid; Version=1; c=d',
+ {'a': 'b', 'c': 'd'},
),
(
- "Reset morsel after invalid to not capture attributes",
- "a=b; $invalid; $Version=1; c=d",
- {"a": "b", "c": "d"},
+ 'Reset morsel after invalid to not capture attributes',
+ 'a=b; $invalid; $Version=1; c=d',
+ {'a': 'b', 'c': 'd'},
),
(
- "Continue after non-flag attribute without value",
- "a=b; path; Version=1; c=d",
- {"a": "b", "c": "d"},
+ 'Continue after non-flag attribute without value',
+ 'a=b; path; Version=1; c=d',
+ {'a': 'b', 'c': 'd'},
),
(
- "Allow cookie attributes with `$` prefix",
+ 'Allow cookie attributes with `$` prefix',
'Customer="WILE_E_COYOTE"; $Version=1; $Secure; $Path=/acme',
- {"Customer": ("WILE_E_COYOTE", {"version": "1", "secure": True, "path": "/acme"})},
+ {'Customer': ('WILE_E_COYOTE', {'version': '1', 'secure': True, 'path': '/acme'})},
),
(
- "Invalid Morsel keys should not result in an error",
- "Key=Value; [Invalid]=Value; Another=Value",
- {"Key": "Value", "Another": "Value"},
+ 'Invalid Morsel keys should not result in an error',
+ 'Key=Value; [Invalid]=Value; Another=Value',
+ {'Key': 'Value', 'Another': 'Value'},
),
)
diff --git a/test/test_download.py b/test/test_download.py
index 2530792..3f36869 100755
--- a/test/test_download.py
+++ b/test/test_download.py
@@ -20,7 +20,6 @@ from test.helper import (
gettestcases,
getwebpagetestcases,
is_download_test,
- report_warning,
try_rm,
)
@@ -94,7 +93,7 @@ def generator(test_case, tname):
'playlist', [] if is_playlist else [test_case])
def print_skipping(reason):
- print('Skipping %s: %s' % (test_case['name'], reason))
+ print('Skipping {}: {}'.format(test_case['name'], reason))
self.skipTest(reason)
if not ie.working():
@@ -117,7 +116,7 @@ def generator(test_case, tname):
for other_ie in other_ies:
if not other_ie.working():
- print_skipping('test depends on %sIE, marked as not WORKING' % other_ie.ie_key())
+ print_skipping(f'test depends on {other_ie.ie_key()}IE, marked as not WORKING')
params = get_params(test_case.get('params', {}))
params['outtmpl'] = tname + '_' + params['outtmpl']
@@ -148,10 +147,7 @@ def generator(test_case, tname):
return False
if err.__class__.__name__ == expected_exception:
return True
- for exc in err.exc_info:
- if exc.__class__.__name__ == expected_exception:
- return True
- return False
+ return any(exc.__class__.__name__ == expected_exception for exc in err.exc_info)
def try_rm_tcs_files(tcs=None):
if tcs is None:
@@ -181,8 +177,7 @@ def generator(test_case, tname):
raise
if try_num == RETRIES:
- report_warning('%s failed due to network errors, skipping...' % tname)
- return
+ raise
print(f'Retrying: {try_num} failed tries\n\n##########\n\n')
@@ -244,9 +239,8 @@ def generator(test_case, tname):
got_fsize = os.path.getsize(tc_filename)
assertGreaterEqual(
self, got_fsize, expected_minsize,
- 'Expected %s to be at least %s, but it\'s only %s ' %
- (tc_filename, format_bytes(expected_minsize),
- format_bytes(got_fsize)))
+ f'Expected {tc_filename} to be at least {format_bytes(expected_minsize)}, '
+ f'but it\'s only {format_bytes(got_fsize)} ')
if 'md5' in tc:
md5_for_file = _file_md5(tc_filename)
self.assertEqual(tc['md5'], md5_for_file)
@@ -255,7 +249,7 @@ def generator(test_case, tname):
info_json_fn = os.path.splitext(tc_filename)[0] + '.info.json'
self.assertTrue(
os.path.exists(info_json_fn),
- 'Missing info file %s' % info_json_fn)
+ f'Missing info file {info_json_fn}')
with open(info_json_fn, encoding='utf-8') as infof:
info_dict = json.load(infof)
expect_info_dict(self, info_dict, tc.get('info_dict', {}))
diff --git a/test/test_downloader_http.py b/test/test_downloader_http.py
index 099ec2f..faba0bc 100644
--- a/test/test_downloader_http.py
+++ b/test/test_downloader_http.py
@@ -38,9 +38,9 @@ class HTTPTestRequestHandler(http.server.BaseHTTPRequestHandler):
end = int(mobj.group(2))
valid_range = start is not None and end is not None
if valid_range:
- content_range = 'bytes %d-%d' % (start, end)
+ content_range = f'bytes {start}-{end}'
if total:
- content_range += '/%d' % total
+ content_range += f'/{total}'
self.send_header('Content-Range', content_range)
return (end - start + 1) if valid_range else total
@@ -84,7 +84,7 @@ class TestHttpFD(unittest.TestCase):
filename = 'testfile.mp4'
try_rm(encodeFilename(filename))
self.assertTrue(downloader.real_download(filename, {
- 'url': 'http://127.0.0.1:%d/%s' % (self.port, ep),
+ 'url': f'http://127.0.0.1:{self.port}/{ep}',
}), ep)
self.assertEqual(os.path.getsize(encodeFilename(filename)), TEST_SIZE, ep)
try_rm(encodeFilename(filename))
diff --git a/test/test_http_proxy.py b/test/test_http_proxy.py
index 1b21fe7..2435c87 100644
--- a/test/test_http_proxy.py
+++ b/test/test_http_proxy.py
@@ -105,7 +105,7 @@ if urllib3:
self.incoming,
self.outgoing,
server_hostname=server_hostname,
- server_side=server_side
+ server_side=server_side,
)
self._ssl_io_loop(self.sslobj.do_handshake)
@@ -333,7 +333,7 @@ class TestHTTPConnectProxy:
@pytest.mark.skip_handler(
'Requests',
- 'bug in urllib3 causes unclosed socket: https://github.com/urllib3/urllib3/issues/3374'
+ 'bug in urllib3 causes unclosed socket: https://github.com/urllib3/urllib3/issues/3374',
)
def test_http_connect_bad_auth(self, handler, ctx):
with ctx.http_server(HTTPConnectProxyHandler, username='test', password='test') as server_address:
diff --git a/test/test_iqiyi_sdk_interpreter.py b/test/test_iqiyi_sdk_interpreter.py
index 47c632a..4e41007 100644
--- a/test/test_iqiyi_sdk_interpreter.py
+++ b/test/test_iqiyi_sdk_interpreter.py
@@ -29,11 +29,11 @@ class WarningLogger:
@is_download_test
class TestIqiyiSDKInterpreter(unittest.TestCase):
def test_iqiyi_sdk_interpreter(self):
- '''
+ """
Test the functionality of IqiyiSDKInterpreter by trying to log in
If `sign` is incorrect, /validate call throws an HTTP 556 error
- '''
+ """
logger = WarningLogger()
ie = IqiyiIE(FakeYDL({'logger': logger}))
ie._perform_login('foo', 'bar')
diff --git a/test/test_jsinterp.py b/test/test_jsinterp.py
index 86928a6..7c556e4 100644
--- a/test/test_jsinterp.py
+++ b/test/test_jsinterp.py
@@ -92,6 +92,7 @@ class TestJSInterpreter(unittest.TestCase):
self._test('function f(){return 0 && 1 || 2;}', 2)
self._test('function f(){return 0 ?? 42;}', 0)
self._test('function f(){return "life, the universe and everything" < 42;}', False)
+ self._test('function f(){return 0 - 7 * - 6;}', 42)
def test_array_access(self):
self._test('function f(){var x = [1,2,3]; x[0] = 4; x[0] = 5; x[2.0] = 7; return x;}', [5, 2, 7])
diff --git a/test/test_netrc.py b/test/test_netrc.py
index dc708d9..1e0f4ee 100644
--- a/test/test_netrc.py
+++ b/test/test_netrc.py
@@ -21,7 +21,7 @@ class TestNetRc(unittest.TestCase):
continue
self.assertTrue(
ie._NETRC_MACHINE,
- 'Extractor %s supports login, but is missing a _NETRC_MACHINE property' % ie.IE_NAME)
+ f'Extractor {ie.IE_NAME} supports login, but is missing a _NETRC_MACHINE property')
if __name__ == '__main__':
diff --git a/test/test_networking.py b/test/test_networking.py
index d127cbb..af3ece3 100644
--- a/test/test_networking.py
+++ b/test/test_networking.py
@@ -375,10 +375,10 @@ class TestHTTPRequestHandler(TestRequestHandlerBase):
with handler() as rh:
for bad_status in (400, 500, 599, 302):
with pytest.raises(HTTPError):
- validate_and_send(rh, Request('http://127.0.0.1:%d/gen_%d' % (self.http_port, bad_status)))
+ validate_and_send(rh, Request(f'http://127.0.0.1:{self.http_port}/gen_{bad_status}'))
# Should not raise an error
- validate_and_send(rh, Request('http://127.0.0.1:%d/gen_200' % self.http_port)).close()
+ validate_and_send(rh, Request(f'http://127.0.0.1:{self.http_port}/gen_200')).close()
def test_response_url(self, handler):
with handler() as rh:
@@ -472,7 +472,7 @@ class TestHTTPRequestHandler(TestRequestHandlerBase):
def test_incompleteread(self, handler):
with handler(timeout=2) as rh:
with pytest.raises(IncompleteRead, match='13 bytes read, 234221 more expected'):
- validate_and_send(rh, Request('http://127.0.0.1:%d/incompleteread' % self.http_port)).read()
+ validate_and_send(rh, Request(f'http://127.0.0.1:{self.http_port}/incompleteread')).read()
def test_cookies(self, handler):
cookiejar = YoutubeDLCookieJar()
@@ -740,7 +740,7 @@ class TestRequestHandlerMisc:
@pytest.mark.parametrize('handler,logger_name', [
('Requests', 'urllib3'),
('Websockets', 'websockets.client'),
- ('Websockets', 'websockets.server')
+ ('Websockets', 'websockets.server'),
], indirect=['handler'])
def test_remove_logging_handler(self, handler, logger_name):
# Ensure any logging handlers, which may contain a YoutubeDL instance,
@@ -794,7 +794,7 @@ class TestUrllibRequestHandler(TestRequestHandlerBase):
with handler() as rh:
with pytest.raises(
CertificateVerifyError,
- match=r'\[SSL: CERTIFICATE_VERIFY_FAILED\] certificate verify failed: self.signed certificate'
+ match=r'\[SSL: CERTIFICATE_VERIFY_FAILED\] certificate verify failed: self.signed certificate',
):
validate_and_send(rh, Request(f'https://127.0.0.1:{self.https_port}/headers'))
@@ -804,14 +804,14 @@ class TestUrllibRequestHandler(TestRequestHandlerBase):
(
Request('http://127.0.0.1', method='GET\n'),
'method can\'t contain control characters',
- lambda v: v < (3, 7, 9) or (3, 8, 0) <= v < (3, 8, 5)
+ lambda v: v < (3, 7, 9) or (3, 8, 0) <= v < (3, 8, 5),
),
# https://github.com/python/cpython/blob/987b712b4aeeece336eed24fcc87a950a756c3e2/Lib/http/client.py#L1265
# bpo-38576: Check implemented in 3.7.8+, 3.8.3+
(
Request('http://127.0.0. 1', method='GET'),
'URL can\'t contain control characters',
- lambda v: v < (3, 7, 8) or (3, 8, 0) <= v < (3, 8, 3)
+ lambda v: v < (3, 7, 8) or (3, 8, 0) <= v < (3, 8, 3),
),
# https://github.com/python/cpython/blob/987b712b4aeeece336eed24fcc87a950a756c3e2/Lib/http/client.py#L1288C31-L1288C50
(Request('http://127.0.0.1', headers={'foo\n': 'bar'}), 'Invalid header name', None),
@@ -840,7 +840,7 @@ class TestRequestsRequestHandler(TestRequestHandlerBase):
(lambda: requests.exceptions.InvalidHeader(), RequestError),
# catch-all: https://github.com/psf/requests/blob/main/src/requests/adapters.py#L535
(lambda: urllib3.exceptions.HTTPError(), TransportError),
- (lambda: requests.exceptions.RequestException(), RequestError)
+ (lambda: requests.exceptions.RequestException(), RequestError),
# (lambda: requests.exceptions.TooManyRedirects(), HTTPError) - Needs a response object
])
def test_request_error_mapping(self, handler, monkeypatch, raised, expected):
@@ -868,12 +868,12 @@ class TestRequestsRequestHandler(TestRequestHandlerBase):
(
lambda: urllib3.exceptions.ProtocolError('error', http.client.IncompleteRead(partial=b'abc', expected=4)),
IncompleteRead,
- '3 bytes read, 4 more expected'
+ '3 bytes read, 4 more expected',
),
(
lambda: urllib3.exceptions.ProtocolError('error', urllib3.exceptions.IncompleteRead(partial=3, expected=5)),
IncompleteRead,
- '3 bytes read, 5 more expected'
+ '3 bytes read, 5 more expected',
),
])
def test_response_error_mapping(self, handler, monkeypatch, raised, expected, match):
@@ -1125,7 +1125,7 @@ class TestRequestHandlerValidation:
('https', False, {}),
]),
(NoCheckRH, [('http', False, {})]),
- (ValidationRH, [('http', UnsupportedRequest, {})])
+ (ValidationRH, [('http', UnsupportedRequest, {})]),
]
PROXY_SCHEME_TESTS = [
@@ -1219,7 +1219,7 @@ class TestRequestHandlerValidation:
({'impersonate': ImpersonateTarget('chrome', None, None, None)}, False),
({'impersonate': ImpersonateTarget(None, None, None, None)}, False),
({'impersonate': ImpersonateTarget()}, False),
- ({'impersonate': 'chrome'}, AssertionError)
+ ({'impersonate': 'chrome'}, AssertionError),
]),
(NoCheckRH, 'http', [
({'cookiejar': 'notacookiejar'}, False),
@@ -1235,7 +1235,7 @@ class TestRequestHandlerValidation:
('Urllib', False, 'http'),
('Requests', False, 'http'),
('CurlCFFI', False, 'http'),
- ('Websockets', False, 'ws')
+ ('Websockets', False, 'ws'),
], indirect=['handler'])
def test_no_proxy(self, handler, fail, scheme):
run_validation(handler, fail, Request(f'{scheme}://', proxies={'no': '127.0.0.1,github.com'}))
@@ -1246,7 +1246,7 @@ class TestRequestHandlerValidation:
(HTTPSupportedRH, 'http'),
('Requests', 'http'),
('CurlCFFI', 'http'),
- ('Websockets', 'ws')
+ ('Websockets', 'ws'),
], indirect=['handler'])
def test_empty_proxy(self, handler, scheme):
run_validation(handler, False, Request(f'{scheme}://', proxies={scheme: None}))
@@ -1258,7 +1258,7 @@ class TestRequestHandlerValidation:
(HTTPSupportedRH, 'http'),
('Requests', 'http'),
('CurlCFFI', 'http'),
- ('Websockets', 'ws')
+ ('Websockets', 'ws'),
], indirect=['handler'])
def test_invalid_proxy_url(self, handler, scheme, proxy_url):
run_validation(handler, UnsupportedRequest, Request(f'{scheme}://', proxies={scheme: proxy_url}))
@@ -1474,7 +1474,7 @@ class TestYoutubeDLNetworking:
@pytest.mark.parametrize('proxy,expected', [
('http://127.0.0.1:8080', {'all': 'http://127.0.0.1:8080'}),
('', {'all': '__noproxy__'}),
- (None, {'http': 'http://127.0.0.1:8081', 'https': 'http://127.0.0.1:8081'}) # env, set https
+ (None, {'http': 'http://127.0.0.1:8081', 'https': 'http://127.0.0.1:8081'}), # env, set https
])
def test_proxy(self, proxy, expected, monkeypatch):
monkeypatch.setenv('HTTP_PROXY', 'http://127.0.0.1:8081')
@@ -1546,7 +1546,7 @@ class TestYoutubeDLNetworking:
with FakeImpersonationRHYDL() as ydl:
with pytest.raises(
RequestError,
- match=r'Impersonate target "test" is not available'
+ match=r'Impersonate target "test" is not available',
):
ydl.urlopen(Request('http://', extensions={'impersonate': ImpersonateTarget('test', None, None, None)}))
@@ -1558,7 +1558,7 @@ class TestYoutubeDLNetworking:
pass
_SUPPORTED_URL_SCHEMES = ('http',)
- _SUPPORTED_IMPERSONATE_TARGET_MAP = {ImpersonateTarget('abc',): 'test'}
+ _SUPPORTED_IMPERSONATE_TARGET_MAP = {ImpersonateTarget('abc'): 'test'}
_SUPPORTED_PROXY_SCHEMES = None
super().__init__(*args, **kwargs)
@@ -1567,14 +1567,14 @@ class TestYoutubeDLNetworking:
with FakeHTTPRHYDL() as ydl:
with pytest.raises(
RequestError,
- match=r'Impersonate target "test" is not available'
+ match=r'Impersonate target "test" is not available',
):
ydl.urlopen(Request('http://', extensions={'impersonate': ImpersonateTarget('test', None, None, None)}))
def test_raise_impersonate_error(self):
with pytest.raises(
YoutubeDLError,
- match=r'Impersonate target "test" is not available'
+ match=r'Impersonate target "test" is not available',
):
FakeYDL({'impersonate': ImpersonateTarget('test', None, None, None)})
@@ -1592,7 +1592,7 @@ class TestYoutubeDLNetworking:
monkeypatch.setattr(FakeYDL, 'build_request_director', lambda cls, handlers, preferences=None: brh(cls, handlers=[IRH]))
with FakeYDL({
- 'impersonate': ImpersonateTarget('abc', None, None, None)
+ 'impersonate': ImpersonateTarget('abc', None, None, None),
}) as ydl:
rh = self.build_handler(ydl, IRH)
assert rh.impersonate == ImpersonateTarget('abc', None, None, None)
@@ -1604,7 +1604,7 @@ class TestYoutubeDLNetworking:
def _send(self, request: Request):
pass
_SUPPORTED_URL_SCHEMES = ('http',)
- _SUPPORTED_IMPERSONATE_TARGET_MAP = {ImpersonateTarget(target_client,): 'test'}
+ _SUPPORTED_IMPERSONATE_TARGET_MAP = {ImpersonateTarget(target_client): 'test'}
RH_KEY = target_client
RH_NAME = target_client
handlers.append(TestRH)
@@ -1614,7 +1614,7 @@ class TestYoutubeDLNetworking:
assert set(ydl._get_available_impersonate_targets()) == {
(ImpersonateTarget('xyz'), 'xyz'),
(ImpersonateTarget('abc'), 'abc'),
- (ImpersonateTarget('asd'), 'asd')
+ (ImpersonateTarget('asd'), 'asd'),
}
assert ydl._impersonate_target_available(ImpersonateTarget('abc'))
assert ydl._impersonate_target_available(ImpersonateTarget())
@@ -1837,7 +1837,7 @@ class TestRequest:
extensions={'cookiejar': CookieJar()},
headers={'Accept-Encoding': 'br'},
proxies={'http': 'http://127.0.0.1'},
- data=[b'123']
+ data=[b'123'],
)
req_copy = req.copy()
assert req_copy is not req
@@ -1863,7 +1863,7 @@ class TestRequest:
assert isinstance(req.copy(), AnotherRequest)
def test_url(self):
- req = Request(url='https://фtest.example.com/ some spaceв?ä=c',)
+ req = Request(url='https://фtest.example.com/ some spaceв?ä=c')
assert req.url == 'https://xn--test-z6d.example.com/%20some%20space%D0%B2?%C3%A4=c'
assert Request(url='//example.com').url == 'http://example.com'
@@ -1878,7 +1878,7 @@ class TestResponse:
('custom', 200, 'custom'),
(None, 404, 'Not Found'), # fallback status
('', 403, 'Forbidden'),
- (None, 999, None)
+ (None, 999, None),
])
def test_reason(self, reason, status, expected):
res = Response(io.BytesIO(b''), url='test://', headers={}, status=status, reason=reason)
@@ -1933,7 +1933,7 @@ class TestImpersonateTarget:
@pytest.mark.parametrize('target_str', [
'-120', ':-12.0', '-12:-12', '-:-',
- '::', 'a-c-d:', 'a-c-d:e-f-g', 'a:b:'
+ '::', 'a-c-d:', 'a-c-d:e-f-g', 'a:b:',
])
def test_target_from_invalid_str(self, target_str):
with pytest.raises(ValueError):
@@ -1949,7 +1949,7 @@ class TestImpersonateTarget:
(ImpersonateTarget('abc', '120', 'xyz', None), 'abc-120:xyz'),
(ImpersonateTarget('abc', None, 'xyz'), 'abc:xyz'),
(ImpersonateTarget(None, None, 'xyz', '6.5'), ':xyz-6.5'),
- (ImpersonateTarget('abc', ), 'abc'),
+ (ImpersonateTarget('abc'), 'abc'),
(ImpersonateTarget(None, None, None, None), ''),
])
def test_str(self, target, expected):
diff --git a/test/test_networking_utils.py b/test/test_networking_utils.py
index b7b7143..204fe87 100644
--- a/test/test_networking_utils.py
+++ b/test/test_networking_utils.py
@@ -39,7 +39,7 @@ class TestNetworkingUtils:
proxies = {
'all': 'socks5://example.com',
'http': 'http://example.com:1080',
- 'no': 'bypass.example.com,yt-dl.org'
+ 'no': 'bypass.example.com,yt-dl.org',
}
assert select_proxy('https://example.com', proxies) == proxies['all']
@@ -54,7 +54,7 @@ class TestNetworkingUtils:
'port': 1080,
'rdns': True,
'username': None,
- 'password': None
+ 'password': None,
}),
('socks5://user:@example.com:5555', {
'proxytype': ProxyType.SOCKS5,
@@ -62,7 +62,7 @@ class TestNetworkingUtils:
'port': 5555,
'rdns': False,
'username': 'user',
- 'password': ''
+ 'password': '',
}),
('socks4://u%40ser:pa%20ss@127.0.0.1:1080', {
'proxytype': ProxyType.SOCKS4,
@@ -70,7 +70,7 @@ class TestNetworkingUtils:
'port': 1080,
'rdns': False,
'username': 'u@ser',
- 'password': 'pa ss'
+ 'password': 'pa ss',
}),
('socks4a://:pa%20ss@127.0.0.1', {
'proxytype': ProxyType.SOCKS4A,
@@ -78,8 +78,8 @@ class TestNetworkingUtils:
'port': 1080,
'rdns': True,
'username': '',
- 'password': 'pa ss'
- })
+ 'password': 'pa ss',
+ }),
])
def test_make_socks_proxy_opts(self, socks_proxy, expected):
assert make_socks_proxy_opts(socks_proxy) == expected
diff --git a/test/test_overwrites.py b/test/test_overwrites.py
index 6954c07..0beafdf 100644
--- a/test/test_overwrites.py
+++ b/test/test_overwrites.py
@@ -27,7 +27,7 @@ class TestOverwrites(unittest.TestCase):
[
sys.executable, 'yt_dlp/__main__.py',
'-o', 'test.webm',
- 'https://www.youtube.com/watch?v=jNQXAC9IVRw'
+ 'https://www.youtube.com/watch?v=jNQXAC9IVRw',
], cwd=root_dir, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
sout, serr = outp.communicate()
self.assertTrue(b'has already been downloaded' in sout)
@@ -39,7 +39,7 @@ class TestOverwrites(unittest.TestCase):
[
sys.executable, 'yt_dlp/__main__.py', '--yes-overwrites',
'-o', 'test.webm',
- 'https://www.youtube.com/watch?v=jNQXAC9IVRw'
+ 'https://www.youtube.com/watch?v=jNQXAC9IVRw',
], cwd=root_dir, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
sout, serr = outp.communicate()
self.assertTrue(b'has already been downloaded' not in sout)
diff --git a/test/test_plugins.py b/test/test_plugins.py
index 6cde579..c82158e 100644
--- a/test/test_plugins.py
+++ b/test/test_plugins.py
@@ -31,7 +31,7 @@ class TestPlugins(unittest.TestCase):
# don't load modules with underscore prefix
self.assertFalse(
- f'{PACKAGE_NAME}.extractor._ignore' in sys.modules.keys(),
+ f'{PACKAGE_NAME}.extractor._ignore' in sys.modules,
'loaded module beginning with underscore')
self.assertNotIn('IgnorePluginIE', plugins_ie.keys())
diff --git a/test/test_post_hooks.py b/test/test_post_hooks.py
index 3778d17..6500dd3 100644
--- a/test/test_post_hooks.py
+++ b/test/test_post_hooks.py
@@ -59,7 +59,7 @@ class TestPostHooks(unittest.TestCase):
def hook_three(self, filename):
self.files.append(filename)
- raise Exception('Test exception for \'%s\'' % filename)
+ raise Exception(f'Test exception for \'{filename}\'')
def tearDown(self):
for f in self.files:
diff --git a/test/test_postprocessors.py b/test/test_postprocessors.py
index 52e5587..603f85c 100644
--- a/test/test_postprocessors.py
+++ b/test/test_postprocessors.py
@@ -9,7 +9,7 @@ sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
from yt_dlp import YoutubeDL
-from yt_dlp.compat import compat_shlex_quote
+from yt_dlp.utils import shell_quote
from yt_dlp.postprocessor import (
ExecPP,
FFmpegThumbnailsConvertorPP,
@@ -65,7 +65,7 @@ class TestExec(unittest.TestCase):
def test_parse_cmd(self):
pp = ExecPP(YoutubeDL(), '')
info = {'filepath': 'file name'}
- cmd = 'echo %s' % compat_shlex_quote(info['filepath'])
+ cmd = 'echo {}'.format(shell_quote(info['filepath']))
self.assertEqual(pp.parse_cmd('echo', info), cmd)
self.assertEqual(pp.parse_cmd('echo {}', info), cmd)
@@ -125,7 +125,8 @@ class TestModifyChaptersPP(unittest.TestCase):
self._remove_marked_arrange_sponsors_test_impl(chapters, chapters, [])
def test_remove_marked_arrange_sponsors_ChapterWithSponsors(self):
- chapters = self._chapters([70], ['c']) + [
+ chapters = [
+ *self._chapters([70], ['c']),
self._sponsor_chapter(10, 20, 'sponsor'),
self._sponsor_chapter(30, 40, 'preview'),
self._sponsor_chapter(50, 60, 'filler')]
@@ -136,7 +137,8 @@ class TestModifyChaptersPP(unittest.TestCase):
self._remove_marked_arrange_sponsors_test_impl(chapters, expected, [])
def test_remove_marked_arrange_sponsors_SponsorBlockChapters(self):
- chapters = self._chapters([70], ['c']) + [
+ chapters = [
+ *self._chapters([70], ['c']),
self._sponsor_chapter(10, 20, 'chapter', title='sb c1'),
self._sponsor_chapter(15, 16, 'chapter', title='sb c2'),
self._sponsor_chapter(30, 40, 'preview'),
@@ -149,10 +151,14 @@ class TestModifyChaptersPP(unittest.TestCase):
self._remove_marked_arrange_sponsors_test_impl(chapters, expected, [])
def test_remove_marked_arrange_sponsors_UniqueNamesForOverlappingSponsors(self):
- chapters = self._chapters([120], ['c']) + [
- self._sponsor_chapter(10, 45, 'sponsor'), self._sponsor_chapter(20, 40, 'selfpromo'),
- self._sponsor_chapter(50, 70, 'sponsor'), self._sponsor_chapter(60, 85, 'selfpromo'),
- self._sponsor_chapter(90, 120, 'selfpromo'), self._sponsor_chapter(100, 110, 'sponsor')]
+ chapters = [
+ *self._chapters([120], ['c']),
+ self._sponsor_chapter(10, 45, 'sponsor'),
+ self._sponsor_chapter(20, 40, 'selfpromo'),
+ self._sponsor_chapter(50, 70, 'sponsor'),
+ self._sponsor_chapter(60, 85, 'selfpromo'),
+ self._sponsor_chapter(90, 120, 'selfpromo'),
+ self._sponsor_chapter(100, 110, 'sponsor')]
expected = self._chapters(
[10, 20, 40, 45, 50, 60, 70, 85, 90, 100, 110, 120],
['c', '[SponsorBlock]: Sponsor', '[SponsorBlock]: Sponsor, Unpaid/Self Promotion',
@@ -172,7 +178,8 @@ class TestModifyChaptersPP(unittest.TestCase):
chapters, self._chapters([40], ['c']), cuts)
def test_remove_marked_arrange_sponsors_ChapterWithSponsorsAndCuts(self):
- chapters = self._chapters([70], ['c']) + [
+ chapters = [
+ *self._chapters([70], ['c']),
self._sponsor_chapter(10, 20, 'sponsor'),
self._sponsor_chapter(30, 40, 'selfpromo', remove=True),
self._sponsor_chapter(50, 60, 'interaction')]
@@ -185,24 +192,29 @@ class TestModifyChaptersPP(unittest.TestCase):
def test_remove_marked_arrange_sponsors_ChapterWithSponsorCutInTheMiddle(self):
cuts = [self._sponsor_chapter(20, 30, 'selfpromo', remove=True),
self._chapter(40, 50, remove=True)]
- chapters = self._chapters([70], ['c']) + [self._sponsor_chapter(10, 60, 'sponsor')] + cuts
+ chapters = [
+ *self._chapters([70], ['c']),
+ self._sponsor_chapter(10, 60, 'sponsor'),
+ *cuts]
expected = self._chapters(
[10, 40, 50], ['c', '[SponsorBlock]: Sponsor', 'c'])
self._remove_marked_arrange_sponsors_test_impl(chapters, expected, cuts)
def test_remove_marked_arrange_sponsors_ChapterWithCutHidingSponsor(self):
cuts = [self._sponsor_chapter(20, 50, 'selfpromo', remove=True)]
- chapters = self._chapters([60], ['c']) + [
+ chapters = [
+ *self._chapters([60], ['c']),
self._sponsor_chapter(10, 20, 'intro'),
self._sponsor_chapter(30, 40, 'sponsor'),
self._sponsor_chapter(50, 60, 'outro'),
- ] + cuts
+ *cuts]
expected = self._chapters(
[10, 20, 30], ['c', '[SponsorBlock]: Intermission/Intro Animation', '[SponsorBlock]: Endcards/Credits'])
self._remove_marked_arrange_sponsors_test_impl(chapters, expected, cuts)
def test_remove_marked_arrange_sponsors_ChapterWithAdjacentSponsors(self):
- chapters = self._chapters([70], ['c']) + [
+ chapters = [
+ *self._chapters([70], ['c']),
self._sponsor_chapter(10, 20, 'sponsor'),
self._sponsor_chapter(20, 30, 'selfpromo'),
self._sponsor_chapter(30, 40, 'interaction')]
@@ -213,7 +225,8 @@ class TestModifyChaptersPP(unittest.TestCase):
self._remove_marked_arrange_sponsors_test_impl(chapters, expected, [])
def test_remove_marked_arrange_sponsors_ChapterWithAdjacentCuts(self):
- chapters = self._chapters([70], ['c']) + [
+ chapters = [
+ *self._chapters([70], ['c']),
self._sponsor_chapter(10, 20, 'sponsor'),
self._sponsor_chapter(20, 30, 'interaction', remove=True),
self._chapter(30, 40, remove=True),
@@ -226,7 +239,8 @@ class TestModifyChaptersPP(unittest.TestCase):
chapters, expected, [self._chapter(20, 50, remove=True)])
def test_remove_marked_arrange_sponsors_ChapterWithOverlappingSponsors(self):
- chapters = self._chapters([70], ['c']) + [
+ chapters = [
+ *self._chapters([70], ['c']),
self._sponsor_chapter(10, 30, 'sponsor'),
self._sponsor_chapter(20, 50, 'selfpromo'),
self._sponsor_chapter(40, 60, 'interaction')]
@@ -238,7 +252,8 @@ class TestModifyChaptersPP(unittest.TestCase):
self._remove_marked_arrange_sponsors_test_impl(chapters, expected, [])
def test_remove_marked_arrange_sponsors_ChapterWithOverlappingCuts(self):
- chapters = self._chapters([70], ['c']) + [
+ chapters = [
+ *self._chapters([70], ['c']),
self._sponsor_chapter(10, 30, 'sponsor', remove=True),
self._sponsor_chapter(20, 50, 'selfpromo', remove=True),
self._sponsor_chapter(40, 60, 'interaction', remove=True)]
@@ -246,7 +261,8 @@ class TestModifyChaptersPP(unittest.TestCase):
chapters, self._chapters([20], ['c']), [self._chapter(10, 60, remove=True)])
def test_remove_marked_arrange_sponsors_ChapterWithRunsOfOverlappingSponsors(self):
- chapters = self._chapters([170], ['c']) + [
+ chapters = [
+ *self._chapters([170], ['c']),
self._sponsor_chapter(0, 30, 'intro'),
self._sponsor_chapter(20, 50, 'sponsor'),
self._sponsor_chapter(40, 60, 'selfpromo'),
@@ -267,7 +283,8 @@ class TestModifyChaptersPP(unittest.TestCase):
self._remove_marked_arrange_sponsors_test_impl(chapters, expected, [])
def test_remove_marked_arrange_sponsors_ChapterWithRunsOfOverlappingCuts(self):
- chapters = self._chapters([170], ['c']) + [
+ chapters = [
+ *self._chapters([170], ['c']),
self._chapter(0, 30, remove=True),
self._sponsor_chapter(20, 50, 'sponsor', remove=True),
self._chapter(40, 60, remove=True),
@@ -284,7 +301,8 @@ class TestModifyChaptersPP(unittest.TestCase):
chapters, self._chapters([20], ['c']), expected_cuts)
def test_remove_marked_arrange_sponsors_OverlappingSponsorsDifferentTitlesAfterCut(self):
- chapters = self._chapters([60], ['c']) + [
+ chapters = [
+ *self._chapters([60], ['c']),
self._sponsor_chapter(10, 60, 'sponsor'),
self._sponsor_chapter(10, 40, 'intro'),
self._sponsor_chapter(30, 50, 'interaction'),
@@ -297,7 +315,8 @@ class TestModifyChaptersPP(unittest.TestCase):
chapters, expected, [self._chapter(30, 50, remove=True)])
def test_remove_marked_arrange_sponsors_SponsorsNoLongerOverlapAfterCut(self):
- chapters = self._chapters([70], ['c']) + [
+ chapters = [
+ *self._chapters([70], ['c']),
self._sponsor_chapter(10, 30, 'sponsor'),
self._sponsor_chapter(20, 50, 'interaction'),
self._sponsor_chapter(30, 50, 'selfpromo', remove=True),
@@ -310,7 +329,8 @@ class TestModifyChaptersPP(unittest.TestCase):
chapters, expected, [self._chapter(30, 50, remove=True)])
def test_remove_marked_arrange_sponsors_SponsorsStillOverlapAfterCut(self):
- chapters = self._chapters([70], ['c']) + [
+ chapters = [
+ *self._chapters([70], ['c']),
self._sponsor_chapter(10, 60, 'sponsor'),
self._sponsor_chapter(20, 60, 'interaction'),
self._sponsor_chapter(30, 50, 'selfpromo', remove=True)]
@@ -321,7 +341,8 @@ class TestModifyChaptersPP(unittest.TestCase):
chapters, expected, [self._chapter(30, 50, remove=True)])
def test_remove_marked_arrange_sponsors_ChapterWithRunsOfOverlappingSponsorsAndCuts(self):
- chapters = self._chapters([200], ['c']) + [
+ chapters = [
+ *self._chapters([200], ['c']),
self._sponsor_chapter(10, 40, 'sponsor'),
self._sponsor_chapter(10, 30, 'intro'),
self._chapter(20, 30, remove=True),
@@ -347,8 +368,9 @@ class TestModifyChaptersPP(unittest.TestCase):
self._remove_marked_arrange_sponsors_test_impl(chapters, expected, expected_cuts)
def test_remove_marked_arrange_sponsors_SponsorOverlapsMultipleChapters(self):
- chapters = (self._chapters([20, 40, 60, 80, 100], ['c1', 'c2', 'c3', 'c4', 'c5'])
- + [self._sponsor_chapter(10, 90, 'sponsor')])
+ chapters = [
+ *self._chapters([20, 40, 60, 80, 100], ['c1', 'c2', 'c3', 'c4', 'c5']),
+ self._sponsor_chapter(10, 90, 'sponsor')]
expected = self._chapters([10, 90, 100], ['c1', '[SponsorBlock]: Sponsor', 'c5'])
self._remove_marked_arrange_sponsors_test_impl(chapters, expected, [])
@@ -359,9 +381,10 @@ class TestModifyChaptersPP(unittest.TestCase):
self._remove_marked_arrange_sponsors_test_impl(chapters, expected, cuts)
def test_remove_marked_arrange_sponsors_SponsorsWithinSomeChaptersAndOverlappingOthers(self):
- chapters = (self._chapters([10, 40, 60, 80], ['c1', 'c2', 'c3', 'c4'])
- + [self._sponsor_chapter(20, 30, 'sponsor'),
- self._sponsor_chapter(50, 70, 'selfpromo')])
+ chapters = [
+ *self._chapters([10, 40, 60, 80], ['c1', 'c2', 'c3', 'c4']),
+ self._sponsor_chapter(20, 30, 'sponsor'),
+ self._sponsor_chapter(50, 70, 'selfpromo')]
expected = self._chapters([10, 20, 30, 40, 50, 70, 80],
['c1', 'c2', '[SponsorBlock]: Sponsor', 'c2', 'c3',
'[SponsorBlock]: Unpaid/Self Promotion', 'c4'])
@@ -374,8 +397,9 @@ class TestModifyChaptersPP(unittest.TestCase):
self._remove_marked_arrange_sponsors_test_impl(chapters, expected, cuts)
def test_remove_marked_arrange_sponsors_ChaptersAfterLastSponsor(self):
- chapters = (self._chapters([20, 40, 50, 60], ['c1', 'c2', 'c3', 'c4'])
- + [self._sponsor_chapter(10, 30, 'music_offtopic')])
+ chapters = [
+ *self._chapters([20, 40, 50, 60], ['c1', 'c2', 'c3', 'c4']),
+ self._sponsor_chapter(10, 30, 'music_offtopic')]
expected = self._chapters(
[10, 30, 40, 50, 60],
['c1', '[SponsorBlock]: Non-Music Section', 'c2', 'c3', 'c4'])
@@ -388,8 +412,9 @@ class TestModifyChaptersPP(unittest.TestCase):
self._remove_marked_arrange_sponsors_test_impl(chapters, expected, cuts)
def test_remove_marked_arrange_sponsors_SponsorStartsAtChapterStart(self):
- chapters = (self._chapters([10, 20, 40], ['c1', 'c2', 'c3'])
- + [self._sponsor_chapter(20, 30, 'sponsor')])
+ chapters = [
+ *self._chapters([10, 20, 40], ['c1', 'c2', 'c3']),
+ self._sponsor_chapter(20, 30, 'sponsor')]
expected = self._chapters([10, 20, 30, 40], ['c1', 'c2', '[SponsorBlock]: Sponsor', 'c3'])
self._remove_marked_arrange_sponsors_test_impl(chapters, expected, [])
@@ -400,8 +425,9 @@ class TestModifyChaptersPP(unittest.TestCase):
self._remove_marked_arrange_sponsors_test_impl(chapters, expected, cuts)
def test_remove_marked_arrange_sponsors_SponsorEndsAtChapterEnd(self):
- chapters = (self._chapters([10, 30, 40], ['c1', 'c2', 'c3'])
- + [self._sponsor_chapter(20, 30, 'sponsor')])
+ chapters = [
+ *self._chapters([10, 30, 40], ['c1', 'c2', 'c3']),
+ self._sponsor_chapter(20, 30, 'sponsor')]
expected = self._chapters([10, 20, 30, 40], ['c1', 'c2', '[SponsorBlock]: Sponsor', 'c3'])
self._remove_marked_arrange_sponsors_test_impl(chapters, expected, [])
@@ -412,8 +438,9 @@ class TestModifyChaptersPP(unittest.TestCase):
self._remove_marked_arrange_sponsors_test_impl(chapters, expected, cuts)
def test_remove_marked_arrange_sponsors_SponsorCoincidesWithChapters(self):
- chapters = (self._chapters([10, 20, 30, 40], ['c1', 'c2', 'c3', 'c4'])
- + [self._sponsor_chapter(10, 30, 'sponsor')])
+ chapters = [
+ *self._chapters([10, 20, 30, 40], ['c1', 'c2', 'c3', 'c4']),
+ self._sponsor_chapter(10, 30, 'sponsor')]
expected = self._chapters([10, 30, 40], ['c1', '[SponsorBlock]: Sponsor', 'c4'])
self._remove_marked_arrange_sponsors_test_impl(chapters, expected, [])
@@ -424,8 +451,9 @@ class TestModifyChaptersPP(unittest.TestCase):
self._remove_marked_arrange_sponsors_test_impl(chapters, expected, cuts)
def test_remove_marked_arrange_sponsors_SponsorsAtVideoBoundaries(self):
- chapters = (self._chapters([20, 40, 60], ['c1', 'c2', 'c3'])
- + [self._sponsor_chapter(0, 10, 'intro'), self._sponsor_chapter(50, 60, 'outro')])
+ chapters = [
+ *self._chapters([20, 40, 60], ['c1', 'c2', 'c3']),
+ self._sponsor_chapter(0, 10, 'intro'), self._sponsor_chapter(50, 60, 'outro')]
expected = self._chapters(
[10, 20, 40, 50, 60], ['[SponsorBlock]: Intermission/Intro Animation', 'c1', 'c2', 'c3', '[SponsorBlock]: Endcards/Credits'])
self._remove_marked_arrange_sponsors_test_impl(chapters, expected, [])
@@ -437,8 +465,10 @@ class TestModifyChaptersPP(unittest.TestCase):
self._remove_marked_arrange_sponsors_test_impl(chapters, expected, cuts)
def test_remove_marked_arrange_sponsors_SponsorsOverlapChaptersAtVideoBoundaries(self):
- chapters = (self._chapters([10, 40, 50], ['c1', 'c2', 'c3'])
- + [self._sponsor_chapter(0, 20, 'intro'), self._sponsor_chapter(30, 50, 'outro')])
+ chapters = [
+ *self._chapters([10, 40, 50], ['c1', 'c2', 'c3']),
+ self._sponsor_chapter(0, 20, 'intro'),
+ self._sponsor_chapter(30, 50, 'outro')]
expected = self._chapters(
[20, 30, 50], ['[SponsorBlock]: Intermission/Intro Animation', 'c2', '[SponsorBlock]: Endcards/Credits'])
self._remove_marked_arrange_sponsors_test_impl(chapters, expected, [])
@@ -450,8 +480,10 @@ class TestModifyChaptersPP(unittest.TestCase):
self._remove_marked_arrange_sponsors_test_impl(chapters, expected, cuts)
def test_remove_marked_arrange_sponsors_EverythingSponsored(self):
- chapters = (self._chapters([10, 20, 30, 40], ['c1', 'c2', 'c3', 'c4'])
- + [self._sponsor_chapter(0, 20, 'intro'), self._sponsor_chapter(20, 40, 'outro')])
+ chapters = [
+ *self._chapters([10, 20, 30, 40], ['c1', 'c2', 'c3', 'c4']),
+ self._sponsor_chapter(0, 20, 'intro'),
+ self._sponsor_chapter(20, 40, 'outro')]
expected = self._chapters([20, 40], ['[SponsorBlock]: Intermission/Intro Animation', '[SponsorBlock]: Endcards/Credits'])
self._remove_marked_arrange_sponsors_test_impl(chapters, expected, [])
@@ -491,38 +523,39 @@ class TestModifyChaptersPP(unittest.TestCase):
chapters, self._chapters([2.5], ['c2']), cuts)
def test_remove_marked_arrange_sponsors_TinyChaptersResultingFromSponsorOverlapAreIgnored(self):
- chapters = self._chapters([1, 3, 4], ['c1', 'c2', 'c3']) + [
+ chapters = [
+ *self._chapters([1, 3, 4], ['c1', 'c2', 'c3']),
self._sponsor_chapter(1.5, 2.5, 'sponsor')]
self._remove_marked_arrange_sponsors_test_impl(
chapters, self._chapters([1.5, 2.5, 4], ['c1', '[SponsorBlock]: Sponsor', 'c3']), [])
def test_remove_marked_arrange_sponsors_TinySponsorsOverlapsAreIgnored(self):
- chapters = self._chapters([2, 3, 5], ['c1', 'c2', 'c3']) + [
+ chapters = [
+ *self._chapters([2, 3, 5], ['c1', 'c2', 'c3']),
self._sponsor_chapter(1, 3, 'sponsor'),
- self._sponsor_chapter(2.5, 4, 'selfpromo')
- ]
+ self._sponsor_chapter(2.5, 4, 'selfpromo')]
self._remove_marked_arrange_sponsors_test_impl(
chapters, self._chapters([1, 3, 4, 5], [
'c1', '[SponsorBlock]: Sponsor', '[SponsorBlock]: Unpaid/Self Promotion', 'c3']), [])
def test_remove_marked_arrange_sponsors_TinySponsorsPrependedToTheNextSponsor(self):
- chapters = self._chapters([4], ['c']) + [
+ chapters = [
+ *self._chapters([4], ['c']),
self._sponsor_chapter(1.5, 2, 'sponsor'),
- self._sponsor_chapter(2, 4, 'selfpromo')
- ]
+ self._sponsor_chapter(2, 4, 'selfpromo')]
self._remove_marked_arrange_sponsors_test_impl(
chapters, self._chapters([1.5, 4], ['c', '[SponsorBlock]: Unpaid/Self Promotion']), [])
def test_remove_marked_arrange_sponsors_SmallestSponsorInTheOverlapGetsNamed(self):
self._pp._sponsorblock_chapter_title = '[SponsorBlock]: %(name)s'
- chapters = self._chapters([10], ['c']) + [
+ chapters = [
+ *self._chapters([10], ['c']),
self._sponsor_chapter(2, 8, 'sponsor'),
- self._sponsor_chapter(4, 6, 'selfpromo')
- ]
+ self._sponsor_chapter(4, 6, 'selfpromo')]
self._remove_marked_arrange_sponsors_test_impl(
chapters, self._chapters([2, 4, 6, 8, 10], [
'c', '[SponsorBlock]: Sponsor', '[SponsorBlock]: Unpaid/Self Promotion',
- '[SponsorBlock]: Sponsor', 'c'
+ '[SponsorBlock]: Sponsor', 'c',
]), [])
def test_make_concat_opts_CommonCase(self):
diff --git a/test/test_socks.py b/test/test_socks.py
index 43d612d..68af19d 100644
--- a/test/test_socks.py
+++ b/test/test_socks.py
@@ -95,7 +95,7 @@ class Socks5ProxyHandler(StreamRequestHandler, SocksProxyHandler):
return
elif Socks5Auth.AUTH_USER_PASS in methods:
- self.connection.sendall(struct.pack("!BB", SOCKS5_VERSION, Socks5Auth.AUTH_USER_PASS))
+ self.connection.sendall(struct.pack('!BB', SOCKS5_VERSION, Socks5Auth.AUTH_USER_PASS))
_, user_len = struct.unpack('!BB', self.connection.recv(2))
username = self.connection.recv(user_len).decode()
@@ -174,7 +174,7 @@ class Socks4ProxyHandler(StreamRequestHandler, SocksProxyHandler):
if 0x0 < dest_ip <= 0xFF:
use_remote_dns = True
else:
- socks_info['ipv4_address'] = socket.inet_ntoa(struct.pack("!I", dest_ip))
+ socks_info['ipv4_address'] = socket.inet_ntoa(struct.pack('!I', dest_ip))
user_id = self._read_until_null().decode()
if user_id != (self.socks_kwargs.get('user_id') or ''):
@@ -291,7 +291,7 @@ def ctx(request):
('Urllib', 'http'),
('Requests', 'http'),
('Websockets', 'ws'),
- ('CurlCFFI', 'http')
+ ('CurlCFFI', 'http'),
], indirect=True)
class TestSocks4Proxy:
def test_socks4_no_auth(self, handler, ctx):
@@ -366,7 +366,7 @@ class TestSocks4Proxy:
('Urllib', 'http'),
('Requests', 'http'),
('Websockets', 'ws'),
- ('CurlCFFI', 'http')
+ ('CurlCFFI', 'http'),
], indirect=True)
class TestSocks5Proxy:
diff --git a/test/test_subtitles.py b/test/test_subtitles.py
index 5736289..f3b0056 100644
--- a/test/test_subtitles.py
+++ b/test/test_subtitles.py
@@ -40,12 +40,11 @@ class BaseTestSubtitles(unittest.TestCase):
self.ie = self.IE()
self.DL.add_info_extractor(self.ie)
if not self.IE.working():
- print('Skipping: %s marked as not _WORKING' % self.IE.ie_key())
+ print(f'Skipping: {self.IE.ie_key()} marked as not _WORKING')
self.skipTest('IE marked as not _WORKING')
def getInfoDict(self):
- info_dict = self.DL.extract_info(self.url, download=False)
- return info_dict
+ return self.DL.extract_info(self.url, download=False)
def getSubtitles(self):
info_dict = self.getInfoDict()
@@ -87,7 +86,7 @@ class TestYoutubeSubtitles(BaseTestSubtitles):
self.assertEqual(md5(subtitles['en']), 'ae1bd34126571a77aabd4d276b28044d')
self.assertEqual(md5(subtitles['it']), '0e0b667ba68411d88fd1c5f4f4eab2f9')
for lang in ['fr', 'de']:
- self.assertTrue(subtitles.get(lang) is not None, 'Subtitles for \'%s\' not extracted' % lang)
+ self.assertTrue(subtitles.get(lang) is not None, f'Subtitles for \'{lang}\' not extracted')
def _test_subtitles_format(self, fmt, md5_hash, lang='en'):
self.DL.params['writesubtitles'] = True
@@ -157,7 +156,7 @@ class TestDailymotionSubtitles(BaseTestSubtitles):
self.assertEqual(md5(subtitles['en']), '976553874490cba125086bbfea3ff76f')
self.assertEqual(md5(subtitles['fr']), '594564ec7d588942e384e920e5341792')
for lang in ['es', 'fr', 'de']:
- self.assertTrue(subtitles.get(lang) is not None, 'Subtitles for \'%s\' not extracted' % lang)
+ self.assertTrue(subtitles.get(lang) is not None, f'Subtitles for \'{lang}\' not extracted')
def test_nosubtitles(self):
self.DL.expect_warning('video doesn\'t have subtitles')
@@ -182,7 +181,7 @@ class TestTedSubtitles(BaseTestSubtitles):
self.assertEqual(md5(subtitles['en']), '4262c1665ff928a2dada178f62cb8d14')
self.assertEqual(md5(subtitles['fr']), '66a63f7f42c97a50f8c0e90bc7797bb5')
for lang in ['es', 'fr', 'de']:
- self.assertTrue(subtitles.get(lang) is not None, 'Subtitles for \'%s\' not extracted' % lang)
+ self.assertTrue(subtitles.get(lang) is not None, f'Subtitles for \'{lang}\' not extracted')
@is_download_test
diff --git a/test/test_traversal.py b/test/test_traversal.py
index 9b2a27b..5d9fbe1 100644
--- a/test/test_traversal.py
+++ b/test/test_traversal.py
@@ -31,7 +31,7 @@ class TestTraversal:
'allow tuple path'
assert traverse_obj(_TEST_DATA, ['str']) == 'str', \
'allow list path'
- assert traverse_obj(_TEST_DATA, (value for value in ("str",))) == 'str', \
+ assert traverse_obj(_TEST_DATA, (value for value in ('str',))) == 'str', \
'allow iterable path'
assert traverse_obj(_TEST_DATA, 'str') == 'str', \
'single items should be treated as a path'
@@ -70,7 +70,7 @@ class TestTraversal:
def test_traversal_set(self):
# transformation/type, like `expected_type`
- assert traverse_obj(_TEST_DATA, (..., {str.upper}, )) == ['STR'], \
+ assert traverse_obj(_TEST_DATA, (..., {str.upper})) == ['STR'], \
'Function in set should be a transformation'
assert traverse_obj(_TEST_DATA, (..., {str})) == ['str'], \
'Type in set should be a type filter'
@@ -276,7 +276,7 @@ class TestTraversal:
'`...` should result in string (same value) if `traverse_string`'
assert traverse_obj(_TRAVERSE_STRING_DATA, ('str', slice(0, None, 2)), traverse_string=True) == 'sr', \
'`slice` should result in string if `traverse_string`'
- assert traverse_obj(_TRAVERSE_STRING_DATA, ('str', lambda i, v: i or v == "s"), traverse_string=True) == 'str', \
+ assert traverse_obj(_TRAVERSE_STRING_DATA, ('str', lambda i, v: i or v == 's'), traverse_string=True) == 'str', \
'function should result in string if `traverse_string`'
assert traverse_obj(_TRAVERSE_STRING_DATA, ('str', (0, 2)), traverse_string=True) == ['s', 'r'], \
'branching should result in list if `traverse_string`'
diff --git a/test/test_update.py b/test/test_update.py
index bc13956..63a21e4 100644
--- a/test/test_update.py
+++ b/test/test_update.py
@@ -78,11 +78,11 @@ TEST_API_DATA = {
TEST_LOCKFILE_COMMENT = '# This file is used for regulating self-update'
-TEST_LOCKFILE_V1 = r'''%s
+TEST_LOCKFILE_V1 = rf'''{TEST_LOCKFILE_COMMENT}
lock 2022.08.18.36 .+ Python 3\.6
lock 2023.11.16 (?!win_x86_exe).+ Python 3\.7
lock 2023.11.16 win_x86_exe .+ Windows-(?:Vista|2008Server)
-''' % TEST_LOCKFILE_COMMENT
+'''
TEST_LOCKFILE_V2_TMPL = r'''%s
lockV2 yt-dlp/yt-dlp 2022.08.18.36 .+ Python 3\.6
@@ -98,12 +98,12 @@ TEST_LOCKFILE_V2 = TEST_LOCKFILE_V2_TMPL % TEST_LOCKFILE_COMMENT
TEST_LOCKFILE_ACTUAL = TEST_LOCKFILE_V2_TMPL % TEST_LOCKFILE_V1.rstrip('\n')
-TEST_LOCKFILE_FORK = r'''%s# Test if a fork blocks updates to non-numeric tags
+TEST_LOCKFILE_FORK = rf'''{TEST_LOCKFILE_ACTUAL}# Test if a fork blocks updates to non-numeric tags
lockV2 fork/yt-dlp pr0000 .+ Python 3.6
lockV2 fork/yt-dlp pr1234 (?!win_x86_exe).+ Python 3\.7
lockV2 fork/yt-dlp pr1234 win_x86_exe .+ Windows-(?:Vista|2008Server)
lockV2 fork/yt-dlp pr9999 .+ Python 3.11
-''' % TEST_LOCKFILE_ACTUAL
+'''
class FakeUpdater(Updater):
diff --git a/test/test_utils.py b/test/test_utils.py
index 77fadbb..3ff1f8b 100644
--- a/test/test_utils.py
+++ b/test/test_utils.py
@@ -130,6 +130,7 @@ from yt_dlp.utils import (
xpath_text,
xpath_with_ns,
)
+from yt_dlp.utils._utils import _UnsafeExtensionError
from yt_dlp.utils.networking import (
HTTPHeaderDict,
escape_rfc3986,
@@ -276,11 +277,18 @@ class TestUtil(unittest.TestCase):
self.assertEqual(expand_path(env('HOME')), os.getenv('HOME'))
self.assertEqual(expand_path('~'), os.getenv('HOME'))
self.assertEqual(
- expand_path('~/%s' % env('yt_dlp_EXPATH_PATH')),
- '%s/expanded' % os.getenv('HOME'))
+ expand_path('~/{}'.format(env('yt_dlp_EXPATH_PATH'))),
+ '{}/expanded'.format(os.getenv('HOME')))
finally:
os.environ['HOME'] = old_home or ''
+ _uncommon_extensions = [
+ ('exe', 'abc.exe.ext'),
+ ('de', 'abc.de.ext'),
+ ('../.mp4', None),
+ ('..\\.mp4', None),
+ ]
+
def test_prepend_extension(self):
self.assertEqual(prepend_extension('abc.ext', 'temp'), 'abc.temp.ext')
self.assertEqual(prepend_extension('abc.ext', 'temp', 'ext'), 'abc.temp.ext')
@@ -289,6 +297,19 @@ class TestUtil(unittest.TestCase):
self.assertEqual(prepend_extension('.abc', 'temp'), '.abc.temp')
self.assertEqual(prepend_extension('.abc.ext', 'temp'), '.abc.temp.ext')
+ # Test uncommon extensions
+ self.assertEqual(prepend_extension('abc.ext', 'bin'), 'abc.bin.ext')
+ for ext, result in self._uncommon_extensions:
+ with self.assertRaises(_UnsafeExtensionError):
+ prepend_extension('abc', ext)
+ if result:
+ self.assertEqual(prepend_extension('abc.ext', ext, 'ext'), result)
+ else:
+ with self.assertRaises(_UnsafeExtensionError):
+ prepend_extension('abc.ext', ext, 'ext')
+ with self.assertRaises(_UnsafeExtensionError):
+ prepend_extension('abc.unexpected_ext', ext, 'ext')
+
def test_replace_extension(self):
self.assertEqual(replace_extension('abc.ext', 'temp'), 'abc.temp')
self.assertEqual(replace_extension('abc.ext', 'temp', 'ext'), 'abc.temp')
@@ -297,6 +318,16 @@ class TestUtil(unittest.TestCase):
self.assertEqual(replace_extension('.abc', 'temp'), '.abc.temp')
self.assertEqual(replace_extension('.abc.ext', 'temp'), '.abc.temp')
+ # Test uncommon extensions
+ self.assertEqual(replace_extension('abc.ext', 'bin'), 'abc.unknown_video')
+ for ext, _ in self._uncommon_extensions:
+ with self.assertRaises(_UnsafeExtensionError):
+ replace_extension('abc', ext)
+ with self.assertRaises(_UnsafeExtensionError):
+ replace_extension('abc.ext', ext, 'ext')
+ with self.assertRaises(_UnsafeExtensionError):
+ replace_extension('abc.unexpected_ext', ext, 'ext')
+
def test_subtitles_filename(self):
self.assertEqual(subtitles_filename('abc.ext', 'en', 'vtt'), 'abc.en.vtt')
self.assertEqual(subtitles_filename('abc.ext', 'en', 'vtt', 'ext'), 'abc.en.vtt')
@@ -356,12 +387,12 @@ class TestUtil(unittest.TestCase):
self.assertEqual(datetime_from_str('now+23hours', precision='hour'), datetime_from_str('now+23hours', precision='auto'))
def test_daterange(self):
- _20century = DateRange("19000101", "20000101")
- self.assertFalse("17890714" in _20century)
- _ac = DateRange("00010101")
- self.assertTrue("19690721" in _ac)
- _firstmilenium = DateRange(end="10000101")
- self.assertTrue("07110427" in _firstmilenium)
+ _20century = DateRange('19000101', '20000101')
+ self.assertFalse('17890714' in _20century)
+ _ac = DateRange('00010101')
+ self.assertTrue('19690721' in _ac)
+ _firstmilenium = DateRange(end='10000101')
+ self.assertTrue('07110427' in _firstmilenium)
def test_unified_dates(self):
self.assertEqual(unified_strdate('December 21, 2010'), '20101221')
@@ -506,7 +537,7 @@ class TestUtil(unittest.TestCase):
self.assertRaises(ExtractorError, xpath_attr, doc, 'div/p', 'y', fatal=True)
def test_smuggle_url(self):
- data = {"ö": "ö", "abc": [3]}
+ data = {'ö': 'ö', 'abc': [3]}
url = 'https://foo.bar/baz?x=y#a'
smug_url = smuggle_url(url, data)
unsmug_url, unsmug_data = unsmuggle_url(smug_url)
@@ -784,7 +815,7 @@ class TestUtil(unittest.TestCase):
def test_strip_jsonp(self):
stripped = strip_jsonp('cb ([ {"id":"532cb",\n\n\n"x":\n3}\n]\n);')
d = json.loads(stripped)
- self.assertEqual(d, [{"id": "532cb", "x": 3}])
+ self.assertEqual(d, [{'id': '532cb', 'x': 3}])
stripped = strip_jsonp('parseMetadata({"STATUS":"OK"})\n\n\n//epc')
d = json.loads(stripped)
@@ -922,19 +953,19 @@ class TestUtil(unittest.TestCase):
def test_normalize_url(self):
self.assertEqual(
normalize_url('http://wowza.imust.org/srv/vod/telemb/new/UPLOAD/UPLOAD/20224_IncendieHavré_FD.mp4'),
- 'http://wowza.imust.org/srv/vod/telemb/new/UPLOAD/UPLOAD/20224_IncendieHavre%CC%81_FD.mp4'
+ 'http://wowza.imust.org/srv/vod/telemb/new/UPLOAD/UPLOAD/20224_IncendieHavre%CC%81_FD.mp4',
)
self.assertEqual(
normalize_url('http://www.ardmediathek.de/tv/Sturm-der-Liebe/Folge-2036-Zu-Mann-und-Frau-erklärt/Das-Erste/Video?documentId=22673108&bcastId=5290'),
- 'http://www.ardmediathek.de/tv/Sturm-der-Liebe/Folge-2036-Zu-Mann-und-Frau-erkl%C3%A4rt/Das-Erste/Video?documentId=22673108&bcastId=5290'
+ 'http://www.ardmediathek.de/tv/Sturm-der-Liebe/Folge-2036-Zu-Mann-und-Frau-erkl%C3%A4rt/Das-Erste/Video?documentId=22673108&bcastId=5290',
)
self.assertEqual(
normalize_url('http://тест.рф/фрагмент'),
- 'http://xn--e1aybc.xn--p1ai/%D1%84%D1%80%D0%B0%D0%B3%D0%BC%D0%B5%D0%BD%D1%82'
+ 'http://xn--e1aybc.xn--p1ai/%D1%84%D1%80%D0%B0%D0%B3%D0%BC%D0%B5%D0%BD%D1%82',
)
self.assertEqual(
normalize_url('http://тест.рф/абв?абв=абв#абв'),
- 'http://xn--e1aybc.xn--p1ai/%D0%B0%D0%B1%D0%B2?%D0%B0%D0%B1%D0%B2=%D0%B0%D0%B1%D0%B2#%D0%B0%D0%B1%D0%B2'
+ 'http://xn--e1aybc.xn--p1ai/%D0%B0%D0%B1%D0%B2?%D0%B0%D0%B1%D0%B2=%D0%B0%D0%B1%D0%B2#%D0%B0%D0%B1%D0%B2',
)
self.assertEqual(normalize_url('http://vimeo.com/56015672#at=0'), 'http://vimeo.com/56015672#at=0')
@@ -979,7 +1010,7 @@ class TestUtil(unittest.TestCase):
'e': 'false',
'f': '"false"',
'g': 'var',
- }
+ },
)),
{
'null': None,
@@ -988,8 +1019,8 @@ class TestUtil(unittest.TestCase):
'trueStr': 'true',
'false': False,
'falseStr': 'false',
- 'unresolvedVar': 'var'
- }
+ 'unresolvedVar': 'var',
+ },
)
self.assertDictEqual(
@@ -1005,14 +1036,14 @@ class TestUtil(unittest.TestCase):
'b': '"123"',
'c': '1.23',
'd': '"1.23"',
- }
+ },
)),
{
'int': 123,
'intStr': '123',
'float': 1.23,
'floatStr': '1.23',
- }
+ },
)
self.assertDictEqual(
@@ -1028,14 +1059,14 @@ class TestUtil(unittest.TestCase):
'b': '"{}"',
'c': '[]',
'd': '"[]"',
- }
+ },
)),
{
'object': {},
'objectStr': '{}',
'array': [],
'arrayStr': '[]',
- }
+ },
)
def test_js_to_json_realworld(self):
@@ -1081,7 +1112,7 @@ class TestUtil(unittest.TestCase):
def test_js_to_json_edgecases(self):
on = js_to_json("{abc_def:'1\\'\\\\2\\\\\\'3\"4'}")
- self.assertEqual(json.loads(on), {"abc_def": "1'\\2\\'3\"4"})
+ self.assertEqual(json.loads(on), {'abc_def': "1'\\2\\'3\"4"})
on = js_to_json('{"abc": true}')
self.assertEqual(json.loads(on), {'abc': True})
@@ -1113,9 +1144,9 @@ class TestUtil(unittest.TestCase):
'c': 0,
'd': 42.42,
'e': [],
- 'f': "abc",
- 'g': "",
- '42': 42
+ 'f': 'abc',
+ 'g': '',
+ '42': 42,
})
on = js_to_json('["abc", "def",]')
@@ -1209,8 +1240,8 @@ class TestUtil(unittest.TestCase):
self.assertEqual(json.loads(js_to_json('Array(5, 10)')), [5, 10])
self.assertEqual(json.loads(js_to_json('new Array(15,5)')), [15, 5])
self.assertEqual(json.loads(js_to_json('new Map([Array(5, 10),new Array(15,5)])')), {'5': 10, '15': 5})
- self.assertEqual(json.loads(js_to_json('new Date("123")')), "123")
- self.assertEqual(json.loads(js_to_json('new Date(\'2023-10-19\')')), "2023-10-19")
+ self.assertEqual(json.loads(js_to_json('new Date("123")')), '123')
+ self.assertEqual(json.loads(js_to_json('new Date(\'2023-10-19\')')), '2023-10-19')
def test_extract_attributes(self):
self.assertEqual(extract_attributes('<e x="y">'), {'x': 'y'})
@@ -1265,7 +1296,7 @@ class TestUtil(unittest.TestCase):
def test_args_to_str(self):
self.assertEqual(
args_to_str(['foo', 'ba/r', '-baz', '2 be', '']),
- 'foo ba/r -baz \'2 be\' \'\'' if compat_os_name != 'nt' else 'foo ba/r -baz "2 be" ""'
+ 'foo ba/r -baz \'2 be\' \'\'' if compat_os_name != 'nt' else 'foo ba/r -baz "2 be" ""',
)
def test_parse_filesize(self):
@@ -1348,10 +1379,10 @@ ffmpeg version 2.4.4 Copyright (c) 2000-2014 the FFmpeg ...'''), '2.4.4')
self.assertTrue(is_html( # UTF-8 with BOM
b'\xef\xbb\xbf<!DOCTYPE foo>\xaaa'))
self.assertTrue(is_html( # UTF-16-LE
- b'\xff\xfe<\x00h\x00t\x00m\x00l\x00>\x00\xe4\x00'
+ b'\xff\xfe<\x00h\x00t\x00m\x00l\x00>\x00\xe4\x00',
))
self.assertTrue(is_html( # UTF-16-BE
- b'\xfe\xff\x00<\x00h\x00t\x00m\x00l\x00>\x00\xe4'
+ b'\xfe\xff\x00<\x00h\x00t\x00m\x00l\x00>\x00\xe4',
))
self.assertTrue(is_html( # UTF-32-BE
b'\x00\x00\xFE\xFF\x00\x00\x00<\x00\x00\x00h\x00\x00\x00t\x00\x00\x00m\x00\x00\x00l\x00\x00\x00>\x00\x00\x00\xe4'))
@@ -1935,7 +1966,7 @@ Line 1
with locked_file(FILE, test_mode, False):
pass
except (BlockingIOError, PermissionError):
- if not testing_write: # FIXME
+ if not testing_write: # FIXME: blocked read access
print(f'Known issue: Exclusive lock ({lock_mode}) blocks read access ({test_mode})')
continue
self.assertTrue(testing_write, f'{test_mode} is blocked by {lock_mode}')
@@ -2003,7 +2034,7 @@ Line 1
msg='int fn with expected_type int should give int')
self.assertEqual(try_call(lambda: 1, expected_type=dict), None,
msg='int fn with wrong expected_type should give None')
- self.assertEqual(try_call(total, args=(0, 1, 0, ), expected_type=int), 1,
+ self.assertEqual(try_call(total, args=(0, 1, 0), expected_type=int), 1,
msg='fn should accept arglist')
self.assertEqual(try_call(total, kwargs={'a': 0, 'b': 1, 'c': 0}, expected_type=int), 1,
msg='fn should accept kwargs')
diff --git a/test/test_websockets.py b/test/test_websockets.py
index aa0dfa2..5f101ab 100644
--- a/test/test_websockets.py
+++ b/test/test_websockets.py
@@ -297,14 +297,14 @@ class TestWebsSocketRequestHandlerConformance:
'client_certificate': os.path.join(MTLS_CERT_DIR, 'client.crt'),
'client_certificate_key': os.path.join(MTLS_CERT_DIR, 'clientencrypted.key'),
'client_certificate_password': 'foobar',
- }
+ },
))
def test_mtls(self, handler, client_cert):
with handler(
# Disable client-side validation of unacceptable self-signed testcert.pem
# The test is of a check on the server side, so unaffected
verify=False,
- client_cert=client_cert
+ client_cert=client_cert,
) as rh:
ws_validate_and_send(rh, Request(self.mtls_wss_base_url)).close()
diff --git a/test/test_youtube_misc.py b/test/test_youtube_misc.py
index 81be5d3..81b1162 100644
--- a/test/test_youtube_misc.py
+++ b/test/test_youtube_misc.py
@@ -13,7 +13,7 @@ from yt_dlp.extractor import YoutubeIE
class TestYoutubeMisc(unittest.TestCase):
def test_youtube_extract(self):
- assertExtractId = lambda url, id: self.assertEqual(YoutubeIE.extract_id(url), id)
+ assertExtractId = lambda url, video_id: self.assertEqual(YoutubeIE.extract_id(url), video_id)
assertExtractId('http://www.youtube.com/watch?&v=BaW_jenozKc', 'BaW_jenozKc')
assertExtractId('https://www.youtube.com/watch?&v=BaW_jenozKc', 'BaW_jenozKc')
assertExtractId('https://www.youtube.com/watch?feature=player_embedded&v=BaW_jenozKc', 'BaW_jenozKc')
diff --git a/test/test_youtube_signature.py b/test/test_youtube_signature.py
index c559284..b0f3269 100644
--- a/test/test_youtube_signature.py
+++ b/test/test_youtube_signature.py
@@ -46,17 +46,17 @@ _SIG_TESTS = [
(
'https://s.ytimg.com/yts/jsbin/html5player-en_US-vflBb0OQx.js',
84,
- '123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQ0STUVWXYZ!"#$%&\'()*+,@./:;<=>'
+ '123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQ0STUVWXYZ!"#$%&\'()*+,@./:;<=>',
),
(
'https://s.ytimg.com/yts/jsbin/html5player-en_US-vfl9FYC6l.js',
83,
- '123456789abcdefghijklmnopqr0tuvwxyzABCDETGHIJKLMNOPQRS>UVWXYZ!"#$%&\'()*+,-./:;<=F'
+ '123456789abcdefghijklmnopqr0tuvwxyzABCDETGHIJKLMNOPQRS>UVWXYZ!"#$%&\'()*+,-./:;<=F',
),
(
'https://s.ytimg.com/yts/jsbin/html5player-en_US-vflCGk6yw/html5player.js',
'4646B5181C6C3020DF1D9C7FCFEA.AD80ABF70C39BD369CCCAE780AFBB98FA6B6CB42766249D9488C288',
- '82C8849D94266724DC6B6AF89BBFA087EACCD963.B93C07FBA084ACAEFCF7C9D1FD0203C6C1815B6B'
+ '82C8849D94266724DC6B6AF89BBFA087EACCD963.B93C07FBA084ACAEFCF7C9D1FD0203C6C1815B6B',
),
(
'https://s.ytimg.com/yts/jsbin/html5player-en_US-vflKjOTVq/html5player.js',
@@ -163,6 +163,10 @@ _NSIG_TESTS = [
'https://www.youtube.com/s/player/b7910ca8/player_ias.vflset/en_US/base.js',
'_hXMCwMt9qE310D', 'LoZMgkkofRMCZQ',
),
+ (
+ 'https://www.youtube.com/s/player/590f65a6/player_ias.vflset/en_US/base.js',
+ '1tm7-g_A9zsI8_Lay_', 'xI4Vem4Put_rOg',
+ ),
]
@@ -207,7 +211,7 @@ class TestSignature(unittest.TestCase):
def t_factory(name, sig_func, url_pattern):
def make_tfunc(url, sig_input, expected_sig):
m = url_pattern.match(url)
- assert m, '%r should follow URL format' % url
+ assert m, f'{url!r} should follow URL format'
test_id = m.group('id')
def test_func(self):