mirror of
https://github.com/beetbox/beets.git
synced 2025-12-07 17:16:07 +01:00
Make NotQuery subclass Query, update tests
* Modify NotQuery so it subclasses Query instead of MutableCollectionQuery. * Update instances where NotQuery objects are created on tests and queryparse, as NotQuery expects a single Query as a parameter to the constructor instead of a list of Queries.
This commit is contained in:
parent
f2c8e9ff07
commit
dd8b80e320
3 changed files with 49 additions and 40 deletions
|
|
@ -447,14 +447,14 @@ class OrQuery(MutableCollectionQuery):
|
|||
return any([q.match(item) for q in self.subqueries])
|
||||
|
||||
|
||||
class NotQuery(MutableCollectionQuery):
|
||||
class NotQuery(Query):
|
||||
"""A query that matches the negation of its `subquery`, as a shorcut for
|
||||
performing `not(subquery)` without using regular expressions.
|
||||
performing `not(subquery)` without using regular expressions."""
|
||||
def __init__(self, subquery):
|
||||
self.subquery = subquery
|
||||
|
||||
TODO: revise class hierarchy, probably limiting to one subquery
|
||||
"""
|
||||
def clause(self):
|
||||
clause, subvals = self.clause_with_joiner('TODO')
|
||||
clause, subvals = self.subquery.clause()
|
||||
if clause:
|
||||
return 'not ({0})'.format(clause), subvals
|
||||
else:
|
||||
|
|
@ -462,7 +462,17 @@ class NotQuery(MutableCollectionQuery):
|
|||
return clause, subvals
|
||||
|
||||
def match(self, item):
|
||||
return not all([q.match(item) for q in self.subqueries])
|
||||
return not self.subquery.match(item)
|
||||
|
||||
def __repr__(self):
|
||||
return "{0.__class__.__name__}({0.subquery})".format(self)
|
||||
|
||||
def __eq__(self, other):
|
||||
return super(NotQuery, self).__eq__(other) and \
|
||||
self.subquery == other.subquery
|
||||
|
||||
def __hash__(self):
|
||||
return hash(('not', hash(self.subquery)))
|
||||
|
||||
|
||||
class TrueQuery(Query):
|
||||
|
|
|
|||
|
|
@ -110,22 +110,21 @@ def construct_query_part(model_cls, prefixes, query_part):
|
|||
q = query.AnyFieldQuery(pattern, model_cls._search_fields,
|
||||
query_class)
|
||||
if negate:
|
||||
return query.NotQuery([q])
|
||||
return query.NotQuery(q)
|
||||
else:
|
||||
return q
|
||||
else:
|
||||
# Other query type.
|
||||
if negate:
|
||||
return query.NotQuery([query_class(pattern)])
|
||||
return query.NotQuery(query_class(pattern))
|
||||
else:
|
||||
return query_class(pattern)
|
||||
else:
|
||||
if negate:
|
||||
return query.NotQuery([query_class(key.lower(), pattern,
|
||||
key in model_cls._fields)])
|
||||
|
||||
key = key.lower()
|
||||
return query_class(key.lower(), pattern, key in model_cls._fields)
|
||||
q = query_class(key.lower(), pattern, key in model_cls._fields)
|
||||
if negate:
|
||||
return query.NotQuery(q)
|
||||
return q
|
||||
|
||||
|
||||
def query_from_strings(query_cls, model_cls, prefixes, query_parts):
|
||||
|
|
|
|||
|
|
@ -726,56 +726,56 @@ class NotQueryMatchTest(_common.TestCase):
|
|||
def test_regex_match_positive(self):
|
||||
q = dbcore.query.RegexpQuery('album', '^the album$')
|
||||
self.assertTrue(q.match(self.item))
|
||||
self.assertFalse(dbcore.query.NotQuery((q,)).match(self.item))
|
||||
self.assertFalse(dbcore.query.NotQuery(q).match(self.item))
|
||||
|
||||
def test_regex_match_negative(self):
|
||||
q = dbcore.query.RegexpQuery('album', '^album$')
|
||||
self.assertFalse(q.match(self.item))
|
||||
self.assertTrue(dbcore.query.NotQuery((q,)).match(self.item))
|
||||
self.assertTrue(dbcore.query.NotQuery(q).match(self.item))
|
||||
|
||||
def test_regex_match_non_string_value(self):
|
||||
q = dbcore.query.RegexpQuery('disc', '^6$')
|
||||
self.assertTrue(q.match(self.item))
|
||||
self.assertFalse(dbcore.query.NotQuery((q,)).match(self.item))
|
||||
self.assertFalse(dbcore.query.NotQuery(q).match(self.item))
|
||||
|
||||
def test_substring_match_positive(self):
|
||||
q = dbcore.query.SubstringQuery('album', 'album')
|
||||
self.assertTrue(q.match(self.item))
|
||||
self.assertFalse(dbcore.query.NotQuery((q,)).match(self.item))
|
||||
self.assertFalse(dbcore.query.NotQuery(q).match(self.item))
|
||||
|
||||
def test_substring_match_negative(self):
|
||||
q = dbcore.query.SubstringQuery('album', 'ablum')
|
||||
self.assertFalse(q.match(self.item))
|
||||
self.assertTrue(dbcore.query.NotQuery((q,)).match(self.item))
|
||||
self.assertTrue(dbcore.query.NotQuery(q).match(self.item))
|
||||
|
||||
def test_substring_match_non_string_value(self):
|
||||
q = dbcore.query.SubstringQuery('disc', '6')
|
||||
self.assertTrue(q.match(self.item))
|
||||
self.assertFalse(dbcore.query.NotQuery((q,)).match(self.item))
|
||||
self.assertFalse(dbcore.query.NotQuery(q).match(self.item))
|
||||
|
||||
def test_year_match_positive(self):
|
||||
q = dbcore.query.NumericQuery('year', '1')
|
||||
self.assertTrue(q.match(self.item))
|
||||
self.assertFalse(dbcore.query.NotQuery((q,)).match(self.item))
|
||||
self.assertFalse(dbcore.query.NotQuery(q).match(self.item))
|
||||
|
||||
def test_year_match_negative(self):
|
||||
q = dbcore.query.NumericQuery('year', '10')
|
||||
self.assertFalse(q.match(self.item))
|
||||
self.assertTrue(dbcore.query.NotQuery((q,)).match(self.item))
|
||||
self.assertTrue(dbcore.query.NotQuery(q).match(self.item))
|
||||
|
||||
def test_bitrate_range_positive(self):
|
||||
q = dbcore.query.NumericQuery('bitrate', '100000..200000')
|
||||
self.assertTrue(q.match(self.item))
|
||||
self.assertFalse(dbcore.query.NotQuery((q,)).match(self.item))
|
||||
self.assertFalse(dbcore.query.NotQuery(q).match(self.item))
|
||||
|
||||
def test_bitrate_range_negative(self):
|
||||
q = dbcore.query.NumericQuery('bitrate', '200000..300000')
|
||||
self.assertFalse(q.match(self.item))
|
||||
self.assertTrue(dbcore.query.NotQuery((q,)).match(self.item))
|
||||
self.assertTrue(dbcore.query.NotQuery(q).match(self.item))
|
||||
|
||||
def test_open_range(self):
|
||||
q = dbcore.query.NumericQuery('bitrate', '100000..')
|
||||
dbcore.query.NotQuery((q,))
|
||||
dbcore.query.NotQuery(q)
|
||||
|
||||
|
||||
class NotQueryTest(DummyDataTestCase):
|
||||
|
|
@ -790,7 +790,7 @@ class NotQueryTest(DummyDataTestCase):
|
|||
- q AND not(q) == 0
|
||||
- not(not(q)) == q
|
||||
"""
|
||||
not_q = dbcore.query.NotQuery([q])
|
||||
not_q = dbcore.query.NotQuery(q)
|
||||
# assert using OrQuery, AndQuery
|
||||
q_or = dbcore.query.OrQuery([q, not_q])
|
||||
q_and = dbcore.query.AndQuery([q, not_q])
|
||||
|
|
@ -805,7 +805,7 @@ class NotQueryTest(DummyDataTestCase):
|
|||
self.assertEqual(q_results.intersection(not_q_results), set())
|
||||
|
||||
# round trip
|
||||
not_not_q = dbcore.query.NotQuery([not_q])
|
||||
not_not_q = dbcore.query.NotQuery(not_q)
|
||||
self.assertEqual([i.title for i in self.lib.items(q)],
|
||||
[i.title for i in self.lib.items(not_not_q)])
|
||||
|
||||
|
|
@ -813,50 +813,50 @@ class NotQueryTest(DummyDataTestCase):
|
|||
# not(a and b) <-> not(a) or not(b)
|
||||
q = dbcore.query.AndQuery([dbcore.query.BooleanQuery('comp', True),
|
||||
dbcore.query.NumericQuery('year', '2002')])
|
||||
not_results = self.lib.items(dbcore.query.NotQuery([q]))
|
||||
not_results = self.lib.items(dbcore.query.NotQuery(q))
|
||||
self.assert_items_matched(not_results, ['foo bar', 'beets 4 eva'])
|
||||
self.assertNegationProperties(q)
|
||||
|
||||
def test_type_anyfield(self):
|
||||
q = dbcore.query.AnyFieldQuery('foo', ['title', 'artist', 'album'],
|
||||
dbcore.query.SubstringQuery)
|
||||
not_results = self.lib.items(dbcore.query.NotQuery([q]))
|
||||
not_results = self.lib.items(dbcore.query.NotQuery(q))
|
||||
self.assert_items_matched(not_results, ['baz qux'])
|
||||
self.assertNegationProperties(q)
|
||||
|
||||
def test_type_boolean(self):
|
||||
q = dbcore.query.BooleanQuery('comp', True)
|
||||
not_results = self.lib.items(dbcore.query.NotQuery([q]))
|
||||
not_results = self.lib.items(dbcore.query.NotQuery(q))
|
||||
self.assert_items_matched(not_results, ['beets 4 eva'])
|
||||
self.assertNegationProperties(q)
|
||||
|
||||
def test_type_date(self):
|
||||
q = dbcore.query.DateQuery('mtime', '0.0')
|
||||
not_results = self.lib.items(dbcore.query.NotQuery([q]))
|
||||
not_results = self.lib.items(dbcore.query.NotQuery(q))
|
||||
self.assert_items_matched(not_results, [])
|
||||
self.assertNegationProperties(q)
|
||||
|
||||
def test_type_false(self):
|
||||
q = dbcore.query.FalseQuery()
|
||||
not_results = self.lib.items(dbcore.query.NotQuery([q]))
|
||||
not_results = self.lib.items(dbcore.query.NotQuery(q))
|
||||
self.assert_items_matched_all(not_results)
|
||||
self.assertNegationProperties(q)
|
||||
|
||||
def test_type_match(self):
|
||||
q = dbcore.query.MatchQuery('year', '2003')
|
||||
not_results = self.lib.items(dbcore.query.NotQuery([q]))
|
||||
not_results = self.lib.items(dbcore.query.NotQuery(q))
|
||||
self.assert_items_matched(not_results, ['foo bar', 'baz qux'])
|
||||
self.assertNegationProperties(q)
|
||||
|
||||
def test_type_none(self):
|
||||
q = dbcore.query.NoneQuery('rg_track_gain')
|
||||
not_results = self.lib.items(dbcore.query.NotQuery([q]))
|
||||
not_results = self.lib.items(dbcore.query.NotQuery(q))
|
||||
self.assert_items_matched(not_results, [])
|
||||
self.assertNegationProperties(q)
|
||||
|
||||
def test_type_numeric(self):
|
||||
q = dbcore.query.NumericQuery('year', '2001..2002')
|
||||
not_results = self.lib.items(dbcore.query.NotQuery([q]))
|
||||
not_results = self.lib.items(dbcore.query.NotQuery(q))
|
||||
self.assert_items_matched(not_results, ['beets 4 eva'])
|
||||
self.assertNegationProperties(q)
|
||||
|
||||
|
|
@ -864,25 +864,25 @@ class NotQueryTest(DummyDataTestCase):
|
|||
# not(a or b) <-> not(a) and not(b)
|
||||
q = dbcore.query.OrQuery([dbcore.query.BooleanQuery('comp', True),
|
||||
dbcore.query.NumericQuery('year', '2002')])
|
||||
not_results = self.lib.items(dbcore.query.NotQuery([q]))
|
||||
not_results = self.lib.items(dbcore.query.NotQuery(q))
|
||||
self.assert_items_matched(not_results, ['beets 4 eva'])
|
||||
self.assertNegationProperties(q)
|
||||
|
||||
def test_type_regexp(self):
|
||||
q = dbcore.query.RegexpQuery('artist', '^t')
|
||||
not_results = self.lib.items(dbcore.query.NotQuery([q]))
|
||||
not_results = self.lib.items(dbcore.query.NotQuery(q))
|
||||
self.assert_items_matched(not_results, ['foo bar'])
|
||||
self.assertNegationProperties(q)
|
||||
|
||||
def test_type_substring(self):
|
||||
q = dbcore.query.SubstringQuery('album', 'ba')
|
||||
not_results = self.lib.items(dbcore.query.NotQuery([q]))
|
||||
not_results = self.lib.items(dbcore.query.NotQuery(q))
|
||||
self.assert_items_matched(not_results, ['beets 4 eva'])
|
||||
self.assertNegationProperties(q)
|
||||
|
||||
def test_type_true(self):
|
||||
q = dbcore.query.TrueQuery()
|
||||
not_results = self.lib.items(dbcore.query.NotQuery([q]))
|
||||
not_results = self.lib.items(dbcore.query.NotQuery(q))
|
||||
self.assert_items_matched(not_results, [])
|
||||
self.assertNegationProperties(q)
|
||||
|
||||
|
|
@ -903,8 +903,8 @@ class NotQueryTest(DummyDataTestCase):
|
|||
(dbcore.query.SubstringQuery, ['title', 'x'])]
|
||||
|
||||
for klass, args in classes:
|
||||
q_fast = dbcore.query.NotQuery([klass(*(args + [True]))])
|
||||
q_slow = dbcore.query.NotQuery([klass(*(args + [False]))])
|
||||
q_fast = dbcore.query.NotQuery(klass(*(args + [True])))
|
||||
q_slow = dbcore.query.NotQuery(klass(*(args + [False])))
|
||||
|
||||
try:
|
||||
self.assertEqual([i.title for i in self.lib.items(q_fast)],
|
||||
|
|
|
|||
Loading…
Reference in a new issue