Move _match to db.search module

This commit is contained in:
Kovid Goyal 2013-01-20 23:27:30 +05:30
parent e0df1634ab
commit d915e49815
5 changed files with 74 additions and 65 deletions

View File

@ -13,9 +13,15 @@ from datetime import timedelta
from calibre.utils.config_base import prefs
from calibre.utils.date import parse_date, UNDEFINED_DATE, now
from calibre.utils.icu import primary_find
from calibre.utils.search_query_parser import SearchQueryParser, ParseException
# TODO: Thread safety of saved searches
CONTAINS_MATCH = 0
EQUALS_MATCH = 1
REGEXP_MATCH = 2
# Utils {{{
def force_to_bool(val):
if isinstance(val, (str, unicode)):
@ -33,6 +39,45 @@ def force_to_bool(val):
val = None
return val
def _match(query, value, matchkind, use_primary_find_in_search=True):
if query.startswith('..'):
query = query[1:]
sq = query[1:]
internal_match_ok = True
else:
internal_match_ok = False
for t in value:
try: ### ignore regexp exceptions, required because search-ahead tries before typing is finished
t = icu_lower(t)
if (matchkind == EQUALS_MATCH):
if internal_match_ok:
if query == t:
return True
comps = [c.strip() for c in t.split('.') if c.strip()]
for comp in comps:
if sq == comp:
return True
elif query[0] == '.':
if t.startswith(query[1:]):
ql = len(query) - 1
if (len(t) == ql) or (t[ql:ql+1] == '.'):
return True
elif query == t:
return True
elif matchkind == REGEXP_MATCH:
if re.search(query, t, re.I|re.UNICODE):
return True
elif matchkind == CONTAINS_MATCH:
if use_primary_find_in_search:
if primary_find(query, t)[0] != -1:
return True
elif query in t:
return True
except re.error:
pass
return False
# }}}
class DateSearch(object): # {{{
def __init__(self):

View File

@ -16,12 +16,12 @@ from calibre.utils.pyparsing import ParseException
from calibre.ebooks.metadata import fmt_sidx, authors_to_string, string_to_authors
from calibre.ebooks.metadata.book.base import SafeFormat
from calibre.ptempfile import PersistentTemporaryFile
from calibre.utils.config import tweaks, device_prefs
from calibre.utils.config import tweaks, device_prefs, prefs
from calibre.utils.date import dt_factory, qt_to_dt, as_local_time
from calibre.utils.icu import sort_key
from calibre.utils.search_query_parser import SearchQueryParser
from calibre.library.caches import (_match, CONTAINS_MATCH, EQUALS_MATCH,
REGEXP_MATCH, MetadataBackup, force_to_bool)
from calibre.db.search import _match, CONTAINS_MATCH, EQUALS_MATCH, REGEXP_MATCH
from calibre.library.caches import (MetadataBackup, force_to_bool)
from calibre.library.save_to_disk import find_plugboard
from calibre import strftime, isbytestring
from calibre.constants import filesystem_encoding, DEBUG
@ -1037,6 +1037,7 @@ class OnDeviceSearch(SearchQueryParser): # {{{
}
for x in ('author', 'format'):
q[x+'s'] = q[x]
upf = prefs['use_primary_find_in_search']
for index, row in enumerate(self.model.db):
for locvalue in locations:
accessor = q[locvalue]
@ -1063,7 +1064,7 @@ class OnDeviceSearch(SearchQueryParser): # {{{
vals = accessor(row).split(',')
else:
vals = [accessor(row)]
if _match(query, vals, m):
if _match(query, vals, m, use_primary_find_in_search=upf):
matches.add(index)
break
except ValueError: # Unicode errors

View File

@ -10,8 +10,8 @@ from PyQt4.Qt import (Qt, QAbstractItemModel, QIcon, QVariant, QModelIndex, QSiz
from calibre.gui2 import NONE
from calibre.customize.ui import is_disabled, disable_plugin, enable_plugin
from calibre.library.caches import _match, CONTAINS_MATCH, EQUALS_MATCH, \
REGEXP_MATCH
from calibre.db.search import _match, CONTAINS_MATCH, EQUALS_MATCH, REGEXP_MATCH
from calibre.utils.config_base import prefs
from calibre.utils.icu import sort_key
from calibre.utils.search_query_parser import SearchQueryParser
@ -243,6 +243,7 @@ class SearchFilter(SearchQueryParser):
'name': lambda x : x.name.lower(),
}
q['formats'] = q['format']
upf = prefs['use_primary_find_in_search']
for sr in self.srs:
for locvalue in locations:
accessor = q[locvalue]
@ -276,7 +277,7 @@ class SearchFilter(SearchQueryParser):
vals = accessor(sr).split(',')
else:
vals = [accessor(sr)]
if _match(query, vals, m):
if _match(query, vals, m, use_primary_find_in_search=upf):
matches.add(sr)
break
except ValueError: # Unicode errors

View File

@ -11,8 +11,8 @@ from operator import attrgetter
from PyQt4.Qt import (Qt, QAbstractItemModel, QModelIndex, QVariant, pyqtSignal)
from calibre.gui2 import NONE
from calibre.library.caches import _match, CONTAINS_MATCH, EQUALS_MATCH, \
REGEXP_MATCH
from calibre.db.search import _match, CONTAINS_MATCH, EQUALS_MATCH, REGEXP_MATCH
from calibre.utils.config_base import prefs
from calibre.utils.icu import sort_key
from calibre.utils.search_query_parser import SearchQueryParser
@ -161,6 +161,7 @@ class SearchFilter(SearchQueryParser):
}
for x in ('author', 'format'):
q[x+'s'] = q[x]
upf = prefs['use_primary_find_in_search']
for sr in self.srs:
for locvalue in locations:
accessor = q[locvalue]
@ -182,7 +183,7 @@ class SearchFilter(SearchQueryParser):
m = matchkind
vals = [accessor(sr)]
if _match(query, vals, m):
if _match(query, vals, m, use_primary_find_in_search=upf):
matches.add(sr)
break
except ValueError: # Unicode errors

View File

@ -6,7 +6,7 @@ __license__ = 'GPL v3'
__copyright__ = '2010, Kovid Goyal <kovid@kovidgoyal.net>'
__docformat__ = 'restructuredtext en'
import re, itertools, time, traceback, locale
import itertools, time, traceback, locale
from itertools import repeat, izip, imap
from datetime import timedelta
from threading import Thread
@ -16,10 +16,10 @@ from calibre.utils.date import parse_date, now, UNDEFINED_DATE, clean_date_for_s
from calibre.utils.search_query_parser import SearchQueryParser
from calibre.utils.pyparsing import ParseException
from calibre.utils.localization import (canonicalize_lang, lang_map, get_udc)
from calibre.db.search import CONTAINS_MATCH, EQUALS_MATCH, REGEXP_MATCH, _match
from calibre.ebooks.metadata import title_sort, author_to_author_sort
from calibre.ebooks.metadata.opf2 import metadata_to_opf
from calibre import prints
from calibre.utils.icu import primary_find
class MetadataBackup(Thread): # {{{
'''
@ -118,7 +118,6 @@ class MetadataBackup(Thread): # {{{
# }}}
### Global utility function for get_match here and in gui2/library.py
# This is a global for performance
pref_use_primary_find_in_search = False
@ -127,47 +126,6 @@ def set_use_primary_find_in_search(toWhat):
global pref_use_primary_find_in_search
pref_use_primary_find_in_search = toWhat
CONTAINS_MATCH = 0
EQUALS_MATCH = 1
REGEXP_MATCH = 2
def _match(query, value, matchkind):
if query.startswith('..'):
query = query[1:]
sq = query[1:]
internal_match_ok = True
else:
internal_match_ok = False
for t in value:
try: ### ignore regexp exceptions, required because search-ahead tries before typing is finished
t = icu_lower(t)
if (matchkind == EQUALS_MATCH):
if internal_match_ok:
if query == t:
return True
comps = [c.strip() for c in t.split('.') if c.strip()]
for comp in comps:
if sq == comp:
return True
elif query[0] == '.':
if t.startswith(query[1:]):
ql = len(query) - 1
if (len(t) == ql) or (t[ql:ql+1] == '.'):
return True
elif query == t:
return True
elif matchkind == REGEXP_MATCH:
if re.search(query, t, re.I|re.UNICODE):
return True
elif matchkind == CONTAINS_MATCH:
if pref_use_primary_find_in_search:
if primary_find(query, t)[0] != -1:
return True
elif query in t:
return True
except re.error:
pass
return False
def force_to_bool(val):
if isinstance(val, (str, unicode)):
try:
@ -576,7 +534,8 @@ class ResultCache(SearchQueryParser): # {{{
continue
k = parts[:1]
v = parts[1:]
if keyq and not _match(keyq, k, keyq_mkind):
if keyq and not _match(keyq, k, keyq_mkind,
use_primary_find_in_search=pref_use_primary_find_in_search):
continue
if valq:
if valq == 'true':
@ -586,7 +545,8 @@ class ResultCache(SearchQueryParser): # {{{
if v:
add_if_nothing_matches = False
continue
elif not _match(valq, v, valq_mkind):
elif not _match(valq, v, valq_mkind,
use_primary_find_in_search=pref_use_primary_find_in_search):
continue
matches.add(id_)
@ -851,7 +811,8 @@ class ResultCache(SearchQueryParser): # {{{
vals = [v.strip() for v in item[loc].split(is_multiple_cols[loc])]
else:
vals = [item[loc]] ### make into list to make _match happy
if _match(q, vals, matchkind):
if _match(q, vals, matchkind,
use_primary_find_in_search=pref_use_primary_find_in_search):
matches.add(item[0])
continue
current_candidates -= matches