Better error handling of syntax errors in -f

This commit is contained in:
pukkandan 2021-06-11 19:13:22 +05:30
parent 4ba001080f
commit 187986a857
No known key found for this signature in database
GPG Key ID: 0F00D95A001F4698
2 changed files with 20 additions and 19 deletions

View File

@ -461,14 +461,13 @@ class TestFormatSelection(unittest.TestCase):
def test_invalid_format_specs(self): def test_invalid_format_specs(self):
def assert_syntax_error(format_spec): def assert_syntax_error(format_spec):
ydl = YDL({'format': format_spec}) self.assertRaises(SyntaxError, YDL, {'format': format_spec})
info_dict = _make_result([{'format_id': 'foo', 'url': TEST_URL}])
self.assertRaises(SyntaxError, ydl.process_ie_result, info_dict)
assert_syntax_error('bestvideo,,best') assert_syntax_error('bestvideo,,best')
assert_syntax_error('+bestaudio') assert_syntax_error('+bestaudio')
assert_syntax_error('bestvideo+') assert_syntax_error('bestvideo+')
assert_syntax_error('/') assert_syntax_error('/')
assert_syntax_error('[720<height]')
def test_format_filtering(self): def test_format_filtering(self):
formats = [ formats = [

View File

@ -538,6 +538,11 @@ class YoutubeDL(object):
self.outtmpl_dict = self.parse_outtmpl() self.outtmpl_dict = self.parse_outtmpl()
# Creating format selector here allows us to catch syntax errors before the extraction
self.format_selector = (
None if self.params.get('format') is None
else self.build_format_selector(self.params['format']))
self._setup_opener() self._setup_opener()
"""Preload the archive, if any is specified""" """Preload the archive, if any is specified"""
@ -1487,12 +1492,11 @@ class YoutubeDL(object):
'!=': operator.ne, '!=': operator.ne,
} }
operator_rex = re.compile(r'''(?x)\s* operator_rex = re.compile(r'''(?x)\s*
(?P<key>width|height|tbr|abr|vbr|asr|filesize|filesize_approx|fps) (?P<key>width|height|tbr|abr|vbr|asr|filesize|filesize_approx|fps)\s*
\s*(?P<op>%s)(?P<none_inclusive>\s*\?)?\s* (?P<op>%s)(?P<none_inclusive>\s*\?)?\s*
(?P<value>[0-9.]+(?:[kKmMgGtTpPeEzZyY]i?[Bb]?)?) (?P<value>[0-9.]+(?:[kKmMgGtTpPeEzZyY]i?[Bb]?)?)\s*
$
''' % '|'.join(map(re.escape, OPERATORS.keys()))) ''' % '|'.join(map(re.escape, OPERATORS.keys())))
m = operator_rex.search(filter_spec) m = operator_rex.fullmatch(filter_spec)
if m: if m:
try: try:
comparison_value = int(m.group('value')) comparison_value = int(m.group('value'))
@ -1513,13 +1517,12 @@ class YoutubeDL(object):
'$=': lambda attr, value: attr.endswith(value), '$=': lambda attr, value: attr.endswith(value),
'*=': lambda attr, value: value in attr, '*=': lambda attr, value: value in attr,
} }
str_operator_rex = re.compile(r'''(?x) str_operator_rex = re.compile(r'''(?x)\s*
\s*(?P<key>[a-zA-Z0-9._-]+) (?P<key>[a-zA-Z0-9._-]+)\s*
\s*(?P<negation>!\s*)?(?P<op>%s)(?P<none_inclusive>\s*\?)? (?P<negation>!\s*)?(?P<op>%s)(?P<none_inclusive>\s*\?)?\s*
\s*(?P<value>[a-zA-Z0-9._-]+) (?P<value>[a-zA-Z0-9._-]+)\s*
\s*$
''' % '|'.join(map(re.escape, STR_OPERATORS.keys()))) ''' % '|'.join(map(re.escape, STR_OPERATORS.keys())))
m = str_operator_rex.search(filter_spec) m = str_operator_rex.fullmatch(filter_spec)
if m: if m:
comparison_value = m.group('value') comparison_value = m.group('value')
str_op = STR_OPERATORS[m.group('op')] str_op = STR_OPERATORS[m.group('op')]
@ -1529,7 +1532,7 @@ class YoutubeDL(object):
op = str_op op = str_op
if not m: if not m:
raise ValueError('Invalid filter specification %r' % filter_spec) raise SyntaxError('Invalid filter specification %r' % filter_spec)
def _filter(f): def _filter(f):
actual_value = f.get(m.group('key')) actual_value = f.get(m.group('key'))
@ -2118,12 +2121,11 @@ class YoutubeDL(object):
self.list_formats(info_dict) self.list_formats(info_dict)
return return
req_format = self.params.get('format') format_selector = self.format_selector
if req_format is None: if format_selector is None:
req_format = self._default_format_spec(info_dict, download=download) req_format = self._default_format_spec(info_dict, download=download)
self.write_debug('Default format spec: %s' % req_format) self.write_debug('Default format spec: %s' % req_format)
format_selector = self.build_format_selector(req_format)
format_selector = self.build_format_selector(req_format)
# While in format selection we may need to have an access to the original # While in format selection we may need to have an access to the original
# format set in order to calculate some metrics or do some processing. # format set in order to calculate some metrics or do some processing.