Support keyword filtering (records having keywords a and b but not c and d) (#256)

* Support keyword filtering (records having keywords a and b but not c and d)

* Remove debug statements.

* Left a pass statement by mistake.

* Update cli help to show word list '[...]' after search options.

* Add space after method doc.

* Change cli option '-W --without' to '-x --exclude'
This commit is contained in:
SaltyCatFish 2018-03-25 13:40:06 -04:00 committed by Arun Prakash Jana
parent 474c403521
commit e12d2f95f0
2 changed files with 57 additions and 3 deletions

39
buku.py
View File

@ -1273,6 +1273,25 @@ class BukuDb:
stag_results = self.search_by_tag(''.join(stag))
return list(set(keyword_results) & set(stag_results))
def exclude_results_from_search(self, search_results, without, deep):
"""Excludes records that match keyword search using without parameters
Parameters
----------
search_results : list
List of search results
without : list of str
Keywords to search.
deep : bool, optional
True to search for matching substrings.
Returns
-------
list or None
List of search results, or None if no matches.
"""
return list(set(search_results) - set(self.searchdb(without, False, deep)))
def compactdb(self, index, delay_commit=False):
"""When an entry at index is deleted, move the
last entry in DB to index, if index is lesser.
@ -4089,14 +4108,16 @@ POSITIONAL ARGUMENTS:
search_grp = argparser.add_argument_group(
title='SEARCH OPTIONS',
description=''' -s, --sany find records with ANY matching keyword
description=''' -s, --sany [...] find records with ANY matching keyword
this is the default search option
-S, --sall find records matching ALL the keywords
-S, --sall [...] find records matching ALL the keywords
special keywords -
"blank": entries with empty title/tag
"immutable": entries with locked title
-x, --exclude [...] combine with keyword search to exclude
records
--deep match substrings ('pen' matches 'opens')
-r, --sreg run a regex search
-r, --sreg [...] run a regex search
-t, --stag [tag [,|+] ...] [- tag, ...]
search bookmarks by tags
use ',' to find entries matching ANY tag
@ -4109,6 +4130,7 @@ POSITIONAL ARGUMENTS:
addarg('-r', '--sreg', nargs='*', help=HIDE)
addarg('--deep', action='store_true', help=HIDE)
addarg('-t', '--stag', nargs='*', help=HIDE)
addarg('-x', '--exclude', nargs='*', help=HIDE)
# ------------------------
# ENCRYPTION OPTIONS GROUP
@ -4352,6 +4374,7 @@ POSITIONAL ARGUMENTS:
search_opted = True
update_search_results = False
tags_search = True if (args.stag is not None and len(args.stag)) else False
exclude_results = True if (args.exclude is not None and len(args.exclude)) else False
if args.sany is not None:
if len(args.sany):
@ -4361,6 +4384,8 @@ POSITIONAL ARGUMENTS:
else:
# Search URLs, titles, tags for any keyword
search_results = bdb.searchdb(args.sany, False, args.deep)
if exclude_results:
search_results = bdb.exclude_results_from_search(search_results, args.exclude, args.deep)
else:
logerr('no keyword')
elif args.sall is not None:
@ -4371,8 +4396,16 @@ POSITIONAL ARGUMENTS:
else:
# Search URLs, titles, tags with all keywords
search_results = bdb.searchdb(args.sall, True, args.deep)
if exclude_results:
search_results = bdb.exclude_results_from_search(search_results, args.exclude, args.deep)
else:
logerr('no keyword')
elif args.exclude is not None:
if len(args.exclude) and len(search_results):
exclude_results = bdb.search_keywords_and_filter_by_tags(args.exclude, True, args.deep, False, None)
search_results = list(set(search_results) - set(exclude_results))
elif args.sreg is not None:
if len(args.sreg):
# Apply tag filtering, if opted

View File

@ -1330,6 +1330,27 @@ def test_search_keywords_and_filter_by_tags(keyword_results, stag_results, exp_r
assert exp_res == res
@pytest.mark.parametrize(
'search_results, exclude_results, exp_res',
[
([], [], []),
(['item1', 'item2'], ['item2'], ['item1']),
(['item2'], ['item1'], ['item2']),
(['item1', 'item2'], ['item1', 'item2'], []),
]
)
def test_exclude_results_from_search(search_results, exclude_results, exp_res):
"""test method."""
# init
import buku
bdb = buku.BukuDb()
bdb.searchdb = mock.Mock(return_value=exclude_results)
# test
res = bdb.exclude_results_from_search(
search_results, [], True)
assert exp_res == res
# Helper functions for testcases