diff --git a/beets/dbcore/__init__.py b/beets/dbcore/__init__.py index 100f546b5..093591882 100644 --- a/beets/dbcore/__init__.py +++ b/beets/dbcore/__init__.py @@ -23,5 +23,6 @@ from .types import Type from .queryparse import query_from_strings from .queryparse import sort_from_strings from .queryparse import parse_sorted_query +from .query import InvalidQueryError # flake8: noqa diff --git a/beets/dbcore/query.py b/beets/dbcore/query.py index 2f90e0398..8d9c1929c 100644 --- a/beets/dbcore/query.py +++ b/beets/dbcore/query.py @@ -24,11 +24,17 @@ from datetime import datetime, timedelta class InvalidQueryError(ValueError): + def __init__(self, query, explanation): + message = "Invalid query '{0}': {1}".format(query, explanation) + super(InvalidQueryError, self).__init__(message) + + +class InvalidQueryArgumentTypeError(InvalidQueryError, TypeError): def __init__(self, what, expected, detail=None): message = "'{0}' is not {1}".format(what, expected) if detail: message = "{0}: {1}".format(message, detail) - super(InvalidQueryError, self).__init__(message) + super(InvalidQueryArgumentTypeError, self).__init__(None, message) class Query(object): @@ -160,8 +166,9 @@ class RegexpQuery(StringFieldQuery): self.pattern = re.compile(self.pattern) except re.error as exc: # Invalid regular expression. - raise InvalidQueryError(pattern, "a regular expression", - format(exc)) + raise InvalidQueryArgumentTypeError(pattern, + "a regular expression", + format(exc)) @classmethod def string_match(cls, pattern, value): @@ -228,7 +235,7 @@ class NumericQuery(FieldQuery): try: return float(s) except ValueError: - raise InvalidQueryError(s, "an int or a float") + raise InvalidQueryArgumentTypeError(s, "an int or a float") def __init__(self, field, pattern, fast=True): super(NumericQuery, self).__init__(field, pattern, fast) diff --git a/beets/library.py b/beets/library.py index 40051c354..a9885918b 100644 --- a/beets/library.py +++ b/beets/library.py @@ -1085,7 +1085,7 @@ def parse_query_string(s, model_cls): try: parts = [p.decode('utf8') for p in shlex.split(s)] except ValueError as exc: - raise ValueError("Cannot parse {0!r} (error was: {1})".format(s, exc)) + raise dbcore.InvalidQueryError(s, exc) return parse_query_parts(parts, model_cls) diff --git a/test/test_library.py b/test/test_library.py index 3848f2b7c..d3bfe1373 100644 --- a/test/test_library.py +++ b/test/test_library.py @@ -31,6 +31,7 @@ from test._common import unittest from test._common import item import beets.library import beets.mediafile +import beets.dbcore from beets import util from beets import plugins from beets import config @@ -1171,6 +1172,12 @@ class ItemReadTest(unittest.TestCase): item.read('/thisfiledoesnotexist') +class ParseQueryTest(unittest.TestCase): + def test_parse_invalid_query_string(self): + with self.assertRaises(beets.dbcore.InvalidQueryError): + beets.library.parse_query_string('foo"', None) + + def suite(): return unittest.TestLoader().loadTestsFromName(__name__) diff --git a/test/test_query.py b/test/test_query.py index 55450d0ad..077518c36 100644 --- a/test/test_query.py +++ b/test/test_query.py @@ -23,8 +23,8 @@ from test import helper import beets.library from beets import dbcore -from beets.dbcore import types -from beets.dbcore.query import NoneQuery, InvalidQueryError +from beets.dbcore import types, InvalidQueryError +from beets.dbcore.query import NoneQuery, InvalidQueryArgumentTypeError from beets.library import Library, Item @@ -282,14 +282,15 @@ class GetTest(DummyDataTestCase): self.assertFalse(results) def test_invalid_query(self): - with self.assertRaises(InvalidQueryError) as raised: + with self.assertRaises(InvalidQueryArgumentTypeError) as raised: dbcore.query.NumericQuery('year', '199a') self.assertIn('not an int', unicode(raised.exception)) - with self.assertRaises(InvalidQueryError) as raised: + with self.assertRaises(InvalidQueryArgumentTypeError) as raised: dbcore.query.RegexpQuery('year', '199(') self.assertIn('not a regular expression', unicode(raised.exception)) self.assertIn('unbalanced parenthesis', unicode(raised.exception)) + self.assertIsInstance(raised.exception, (InvalidQueryError, TypeError)) class MatchTest(_common.TestCase):