From 51bf6a1c9ffd7f8c4e10511eb58a5284248594ec Mon Sep 17 00:00:00 2001 From: Diego Moreda Date: Fri, 20 Nov 2015 18:06:22 +0100 Subject: [PATCH] Add documentation for NotQuery, cleanup * Add changelog and query.rst documentation entries for the usage of negated queries. * Cleanup NotQuery class as suggested during code review (PEP conforming docstring, clarification on empty clause match behaviour). --- beets/dbcore/query.py | 6 ++++-- docs/changelog.rst | 4 ++++ docs/reference/query.rst | 29 +++++++++++++++++++++++++++++ test/test_query.py | 2 -- 4 files changed, 37 insertions(+), 4 deletions(-) diff --git a/beets/dbcore/query.py b/beets/dbcore/query.py index b4c1d1445..348394f0a 100644 --- a/beets/dbcore/query.py +++ b/beets/dbcore/query.py @@ -449,7 +449,8 @@ class OrQuery(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 @@ -458,7 +459,8 @@ class NotQuery(Query): if clause: return 'not ({0})'.format(clause), subvals else: - # special case for RegexpQuery, (None, ()) + # If there is no clause, there is nothing to negate. All the logic + # is handled by match() for slow queries. return clause, subvals def match(self, item): diff --git a/docs/changelog.rst b/docs/changelog.rst index 700a16d6d..81dcdd2b7 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -20,6 +20,10 @@ New: :doc:`/plugins/discogs` also adopts the same setting. * :doc:`/plugins/embyupdate`: A plugin to trigger a library refresh on a `Emby Server`_ if database changed. +* Queries can now use "not" logic: if you prepend a query term with "-" or + "^", items or albums matching that term will be excluded from the results. + For example, ``beet ls foo ^artist:bar`` will get all the items matching + `foo` but whose artist do not match `bar`. See :ref:`not_query`. :bug:`819` For developers: diff --git a/docs/reference/query.rst b/docs/reference/query.rst index 452681c35..6d83537d1 100644 --- a/docs/reference/query.rst +++ b/docs/reference/query.rst @@ -181,6 +181,35 @@ Find all items with a file modification time between 2008-12-01 and $ beet ls 'mtime:2008-12-01..2008-12-02' +.. _not_query: + +Query Term Negation +------------------- + +Query terms can also be negated, acting like a Boolean "not", by prepending +them with ``-`` or ``^``. This has the effect of returning all the items that +do **not** match the query term. For example, this command:: + + $ beet list ^love + +matches all the songs in the library that do not have "love" in any of their +fields. + +Negation can be combined with the rest of the query mechanisms, allowing to +negate specific fields, regular expressions, etc. For example, this command:: + + $ beet list -a artist:dylan ^year:1980..1990 "^album::the(y)?" + +matches all the albums with an artist containing "dylan", but excluding those +released on the eighties and those that have "the" or "they" on the title. + +Note that the ``-`` character is treated by most shells as a reserved character +for passing arguments, and as such needs to be escaped if using it for query +negation. In most UNIX derivatives shells, using a double dash ``--`` +(indicating that everything after that point should not be treated as +arguments) before the query terms should prevent conflicts, such as:: + + $ beet list -a -- artist:dylan -year:1980..1990 "-album::the(y)?" .. _pathquery: diff --git a/test/test_query.py b/test/test_query.py index c415b7f1c..e6b2d0499 100644 --- a/test/test_query.py +++ b/test/test_query.py @@ -782,8 +782,6 @@ class NotQueryTest(DummyDataTestCase): """Test `query.NotQuery` against the dummy data: - `test_type_xxx`: tests for the negation of a particular XxxQuery class. - `test_get_yyy`: tests on query strings (similar to `GetTest`) - - TODO: add test_type_bytes, for ByteQuery? """ def assertNegationProperties(self, q): """Given a Query `q`, assert that: