-
Notifications
You must be signed in to change notification settings - Fork 399
/
_rule.py
181 lines (159 loc) · 6.27 KB
/
_rule.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
# -*- coding: utf-8 -*-
#
# Gramps - a GTK+/GNOME based genealogy program
#
# Copyright (C) 2002-2006 Donald N. Allingham
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
#
"""
Base class for filter rules.
"""
#-------------------------------------------------------------------------
#
# Standard Python modules
#
#-------------------------------------------------------------------------
import re
from ...errors import FilterError
from ...const import GRAMPS_LOCALE as glocale
_ = glocale.translation.gettext
#-------------------------------------------------------------------------
#
# enable logging for error handling
#
#-------------------------------------------------------------------------
import logging
LOG = logging.getLogger(".")
#-------------------------------------------------------------------------
#
# Rule
#
#-------------------------------------------------------------------------
class Rule:
"""Base rule class."""
labels = []
name = ''
category = _('Miscellaneous filters')
description = _('No description')
allow_regex = False
def __init__(self, arg, use_regex=False, use_case=False):
self.list = []
self.regex = []
self.match_substring = self.__match_substring
self.set_list(arg)
self.use_regex = use_regex
self.use_case = use_case
self.nrprepare = 0
def is_empty(self):
return False
def requestprepare(self, db, user):
"""
Request that the prepare method of the rule is executed if needed
Special: Custom Filters have fixed values, so only one instance needs to
exists during a search. It is stored in a FilterStore, and initialized
once.
As filters are can be grouped in a group
filter, we request a prepare. Only the first time prepare will be
called
"""
if self.nrprepare == 0:
if self.use_regex:
self.regex = [None]*len(self.labels)
for index, label in enumerate(self.labels):
if self.list[index]:
try:
if self.use_case:
self.regex[index] = re.compile(self.list[index])
else:
self.regex[index] = re.compile(self.list[index], re.I)
except re.error:
self.regex[index] = re.compile('')
self.match_substring = self.match_regex
self.prepare(db, user)
self.nrprepare += 1
if self.nrprepare > 20: # more references to a filter than expected
raise FilterError(_("The filter definition contains a loop."),
_("One rule references another which eventually"
" references the first."))
def prepare(self, db, user):
"""prepare so the rule can be executed efficiently"""
pass
def requestreset(self):
"""
Request that the reset method of the rule is executed if possible
Special: Custom Filters have fixed values, so only one instance needs to
exists during a search. It is stored in a FilterStore, and initialized
once.
As filters are can be grouped in a group
filter, we request a reset. Only the last time reset will be
called
"""
self.nrprepare -= 1
if self.nrprepare == 0:
self.reset()
def reset(self):
"""remove no longer needed memory"""
pass
def set_list(self, arg):
"""Store the values of this rule."""
assert isinstance(arg, list) or arg is None, "Argument is not a list"
if len(arg) != len(self.labels):
LOG.warning(("Number of arguments does not match number of " +
"labels.\n list: %s\n labels: %s") % (arg,
self.labels))
self.list = arg
def values(self):
"""Return the values used by this rule."""
return self.list
def check(self):
"""Verify the number of rule values versus the number of rule labels."""
return len(self.list) == len(self.labels)
def apply(self, dummy_db, dummy_person):
"""Apply the rule to some database entry; must be overwritten."""
return True
def display_values(self):
"""Return the labels and values of this rule."""
l_v = ('%s="%s"' % (_(self.labels[index][0] if
isinstance(self.labels[index], tuple) else
self.labels[index]), item)
for index, item in enumerate(self.list) if item)
return ';'.join(l_v)
def __match_substring(self, param_index, str_var):
"""
Return boolean indicating if database element represented by str_var
matches filter element indicated by param_index using case insensitive
string matching.
"""
# make str_var unicode so that search for ü works
# see issue 3188
str_var = str(str_var)
if self.list[param_index] and \
(str_var.upper().find(self.list[param_index].upper()) == -1):
return False
else:
return True
def match_regex(self, param_index, str_var):
"""
Return boolean indicating if database element represented by str_var
matches filter element indicated by param_index using a regular
expression search.
"""
str_var = str(str_var)
if (self.list[param_index] and self.regex[param_index].search(str_var)
is None):
return False
else:
return True