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
|
#!/usr/bin/env python
#****************************************************************************
# conditional.py, provides a class to store comparison functions
#
# TreeLine, an information storage program
# Copyright (C) 2006, Douglas W. Bell
#
# This is free software; you can redistribute it and/or modify it under the
# terms of the GNU General Public License, either Version 2 or any later
# version. This program is distributed in the hope that it will be useful,
# but WITTHOUT ANY WARRANTY. See the included LICENSE file for details.
#*****************************************************************************
import re
class Conditional(object):
"""Stores & evaluates conditional comparisons for dictionary data"""
parseRe = re.compile(r'((?:and)|(?:or)) (\S+) (.+?) '
r'(?:(?<!\\)"|(?<=\\\\)")(.*?)'
r'(?:(?<!\\)"|(?<=\\\\)")')
def __init__(self, conditionStr=''):
"""Accepts a string in format 'fieldName == "value" and
otherFieldName > "value"'"""
self.conditionList = []
self.formatName = '' # used only for evaluateType()
for boolOper, fieldName, oper, value in \
Conditional.parseRe.findall('and ' + conditionStr):
value = value.replace('\\"', '"').replace('\\\\', '\\')
self.conditionList.append(ConditionLine(boolOper, fieldName,
oper, value))
def evaluate(self, data):
"""Return the boolean result without checking format type"""
result = True
for condition in self.conditionList:
result = condition.evalFunc(data, result)
return result
def evaluateType(self, item):
"""Return the boolean result with a type check"""
if item.formatName == self.formatName:
return self.evaluate(item.data)
return False
def conditionText(self):
"""Return the condition string for this conditional set"""
return ' '.join([cond.conditionText() for cond in
self.conditionList])[4:]
def setupFields(self, nodeFormat):
"""Set fieldNames used in lines to field references"""
for condition in self.conditionList[:]:
condition.setupFields(nodeFormat)
if not condition.field:
self.conditionList.remove(condition)
def __len__(self):
"""Return number of conditions for truth testing"""
return len(self.conditionList)
def __deepcopy__(self, memo):
"""Avoid problems with deepcopy of a ref to instance's own method"""
return Conditional(self.conditionText())
class ConditionLine(object):
"""Stores & evaluates a portion of a conditional comparison"""
def __init__(self, boolOper, fieldName, oper, value):
self.boolOper = boolOper
self.tmpFieldName = fieldName
self.field = None
self.oper = oper
self.valueStr = value
self.value = None
functions = {'==': self.equalFunc, '<': self.lessFunc,
'<=': self.lessEqualFunc, '>': self.greaterFunc,
'>=': self.greaterEqualFunc, '!=': self.notEqualFunc,
'starts with': self.startsWithFunc,
'ends with': self.endsWithFunc,
'contains': self.containsFunc,
'True': self.trueFunc, 'False': self.falseFunc}
self.compareFunc = functions[self.oper]
if self.boolOper == 'and':
self.evalFunc = self.andFunc
else:
self.evalFunc = self.orFunc
def conditionText(self):
"""Return the text line for this condition"""
value = self.valueStr.replace('\\', '\\\\').replace('"', '\\"')
return '%s %s %s "%s"' % (self.boolOper, self.field.name,
self.oper, value)
def setupFields(self, nodeFormat):
"""Set fieldNames used to field references"""
if not self.tmpFieldName:
self.tmpFieldName = self.field.name
self.field = nodeFormat.findField(self.tmpFieldName)
if self.field:
self.value = self.field.sortValue({self.field.name: self.valueStr})
self.tmpFieldName = ''
def andFunc(self, data, prevResult=True):
"""Evaluates boolean combination"""
return prevResult and self.compareFunc(data)
def orFunc(self, data, prevResult=True):
"""Evaluates boolean combination"""
return prevResult or self.compareFunc(data)
def equalFunc(self, data):
"""Evaluates main condition (==)"""
return self.field.sortValue(data) == \
self.field.adjustedCompareValue(self.value)
def lessFunc(self, data):
"""Evaluates main condition (<)"""
return self.field.sortValue(data) < \
self.field.adjustedCompareValue(self.value)
def lessEqualFunc(self, data):
"""Evaluates main condition (<=)"""
return self.field.sortValue(data) <= \
self.field.adjustedCompareValue(self.value)
def greaterFunc(self, data):
"""Evaluates main condition (>)"""
return self.field.sortValue(data) > \
self.field.adjustedCompareValue(self.value)
def greaterEqualFunc(self, data):
"""Evaluates main condition (>=)"""
return self.field.sortValue(data) >= \
self.field.adjustedCompareValue(self.value)
def notEqualFunc(self, data):
"""Evaluates main condition (!=)"""
return self.field.sortValue(data) != \
self.field.adjustedCompareValue(self.value)
def startsWithFunc(self, data):
"""Evaluates main condition (starts with)"""
return unicode(self.field.sortValue(data)).\
startswith(unicode(self.value))
def endsWithFunc(self, data):
"""Evaluates main condition (ends with)"""
return unicode(self.field.sortValue(data)).\
endswith(unicode(self.value))
def containsFunc(self, data):
"""Evaluates main condition (contains)"""
return unicode(self.field.sortValue(data)).\
find(unicode(self.value)) >= 0
def trueFunc(self, data):
"""Evaluates main condition (always true)"""
return True
def falseFunc(self, data):
"""Evaluates main condition (always false)"""
return False
|