Module EDAssert
[hide private]
[frames] | no frames]

Source Code for Module EDAssert

  1  # coding: utf8 
  2  # 
  3  #    Project: The EDNA Kernel 
  4  #             http://www.edna-site.org 
  5  # 
  6  #    File: "$Id$" 
  7  # 
  8  #    Copyright (C) 2008-2009 European Synchrotron Radiation Facility 
  9  #                            Grenoble, France 
 10  # 
 11  #    Principal authors: Marie-Francoise Incardona (incardon@esrf.fr) 
 12  #                       Olof Svensson (svensson@esrf.fr)  
 13  #                       Jérôme Kieffer (kieffer@esrf.fr) 
 14  # 
 15  #    This program is free software: you can redistribute it and/or modify 
 16  #    it under the terms of the GNU Lesser General Public License as published 
 17  #    by the Free Software Foundation, either version 3 of the License, or 
 18  #    (at your option) any later version. 
 19  # 
 20  #    This program is distributed in the hope that it will be useful, 
 21  #    but WITHOUT ANY WARRANTY; without even the implied warranty of 
 22  #    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
 23  #    GNU Lesser General Public License for more details. 
 24  # 
 25  #    You should have received a copy of the GNU General Public License 
 26  #    and the GNU Lesser General Public License  along with this program.   
 27  #    If not, see <http://www.gnu.org/licenses/>. 
 28  # 
 29   
 30  """ 
 31  This static class is used for comparing two objects. 
 32  """ 
 33   
 34   
 35  __authors__ = [ "Marie-Francoise Incardona", "Olof Svensson", "Jérôme Kieffer" ] 
 36  __contact__ = "svensson@esrf.fr" 
 37  __license__ = "LGPLv3+" 
 38  __copyright__ = "European Synchrotron Radiation Facility, Grenoble, France" 
 39   
 40   
 41  import os, tempfile, types 
 42  from difflib import SequenceMatcher 
 43  from EDVerbose import EDVerbose 
44 45 46 -class EDAssert:
47 """ 48 This static class is used for comparing two objects. 49 """ 50 51 52 @staticmethod
53 - def equal(_oExpected, _oObtained, _strComment="Equal", _fMaxDelta=1e-6):
54 """ 55 Fail if the two objects are unequal as determined by the '==' operator. 56 Saves the two objects to the current working directory using an unique identifier 57 appended with "_obtained.txt" and "_expected.txt". 58 @param _oExpected: any python object used as reference 59 @param _oObtained: any python object to be compared with the reference 60 @param _strComment: a comment to make your assertion more understandable to the user 61 @type _strComment: python string or unicode string. 62 @param _fMaxDelta: epsilon to check equivalence for float 63 @param _fMaxDelta: float 64 """ 65 bAlmostEqual = True 66 67 if (_oExpected != _oObtained): 68 if isinstance(_oExpected, float): 69 if abs(_oExpected - _oObtained) > _fMaxDelta: 70 bAlmostEqual = False 71 elif isinstance(_oExpected, dict) and isinstance(_oObtained, dict): 72 listExpKeys = list(_oExpected.keys()) 73 listExpKeys.sort() 74 listObtKeys = list(_oObtained.keys()) 75 listObtKeys.sort() 76 if listObtKeys == listExpKeys: 77 for key in listObtKeys: 78 oExpectedValue = _oExpected[key] 79 oObtainedValue = _oObtained[key] 80 if oExpectedValue != oObtainedValue: 81 if isinstance(oExpectedValue, float) and isinstance(oObtainedValue, float): 82 if abs(oExpectedValue - oObtainedValue) > _fMaxDelta: 83 bAlmostEqual = False 84 break 85 else: 86 bAlmostEqual = False 87 break 88 else: 89 bAlmostEqual = False 90 else: 91 bAlmostEqual = False 92 if bAlmostEqual: 93 EDVerbose.ASSERT("OK " + _strComment) 94 else: 95 strExpectedFileName = tempfile.mktemp(suffix="_expected.txt", dir=os.getcwd()) 96 strUniqueIndentifier = strExpectedFileName.split("_expected.txt")[0] 97 f = open(strExpectedFileName , "w") 98 if isinstance(_oExpected, dict): 99 f.write("#Dict:" + os.linesep) 100 keys = _oExpected.keys() 101 keys.sort() 102 f.write(os.linesep.join(["%s:%s" % (i, _oExpected[i]) for i in keys ])) 103 else: 104 f. write(str(_oExpected)) 105 106 f.close() 107 strObtainedFileName = strUniqueIndentifier + "_obtained.txt" 108 f = open(strObtainedFileName, "w") 109 if isinstance(_oObtained, dict): 110 f.write("#Dict:" + os.linesep) 111 keys = _oObtained.keys() 112 keys.sort() 113 print 114 f.write(os.linesep.join(["%s:%s" % (i, _oObtained[i]) for i in keys ])) 115 else: 116 f. write(str(_oObtained)) 117 f.close() 118 EQUAL_ERROR_ASSERT_MESSAGE = _strComment + " FAILURE: Expected different from obtained - identifier %s" % strUniqueIndentifier 119 EDVerbose.ASSERT(EQUAL_ERROR_ASSERT_MESSAGE) 120 raise AssertionError, EQUAL_ERROR_ASSERT_MESSAGE
121 122 123 @staticmethod
124 - def strAlmostEqual(_oExpected, _oObtained, _strComment="Strings are similar", _fRelError=1e-2, _fAbsError=1e-4, _fStrSimilar=1.0, _strExcluded=None, _lstExcluded=[]):
125 """ 126 Check if two strings (or XML strings) are almost equal, which means that: 127 - all pure text part are equal 128 - floats do not differ more than 1% by default or 0.0001 in absolute difference 129 130 Saves the two objects to the current working directory using an unique identifier 131 appended with "_obtained.txt" and "_expected.txt". 132 @param _oExpected: any python object used as reference, probably a string or an unicode string 133 @param _oObtained: any python object to be compared with the reference, probably a string or an unicode string 134 @param _strComment: a comment to make your assertion more understandable to the user 135 @type _strComment: python string or unicode string. 136 @param _fRelError: maximum relative error defined as a float 137 @param _fAbsError: maximum absolute error defined as a float 138 @param _strExcluded: if a "word" contains this string, it is not taken into account for the comparison 139 @type _strExcluded: string 140 @param _lstExcluded: list of words to be excluded for the comparison 141 @type _lstExcluded: list of strings 142 143 """ 144 bAlmostEqual = True 145 ERROR_ASSERT_MESSAGE = _strComment + ". " 146 if _oExpected != _oObtained: 147 if _oExpected.__class__ != _oObtained.__class__: 148 EDVerbose.WARNING("Expected is type %s and Obtained is type: %s" % (_oExpected.__class__, _oObtained.__class__)) 149 _oExpected = str(_oExpected) 150 _oObtained = str(_oObtained) 151 lstDataReference = _oExpected.replace(">", " ").replace("<", " ").split() 152 lstDataObtained = _oObtained.replace(">", " ").replace("<", " ").split() 153 if len(lstDataReference) == len(lstDataObtained): 154 EDVerbose.DEBUG("Checking for small numerical error...Relative:%s Absolute: %s and similarity in strings >= %s%%" % (_fRelError, _fAbsError, _fStrSimilar * 100)) 155 for i in xrange(len(lstDataReference)): 156 dataReference = lstDataReference[i] 157 dataObtained = lstDataObtained[i] 158 if dataReference != dataObtained: 159 if (_strExcluded is not None) and (_strExcluded in dataReference or _strExcluded in dataObtained): 160 continue 161 if len(_lstExcluded) > 0: 162 bFound = False 163 for key in _lstExcluded: 164 if (key in dataReference) or (key in dataObtained): 165 bFound = True 166 break 167 if bFound: 168 continue 169 try: 170 fRefValue = float(dataReference) 171 fObtValue = float(dataObtained) 172 except ValueError: 173 fSimilarity = SequenceMatcher(None, dataReference, dataObtained).quick_ratio() 174 if fSimilarity < _fStrSimilar: 175 if max(len(dataReference), len(dataObtained)) < 100: 176 ERROR_ASSERT_MESSAGE += "\nMismatch on %ith word, between ref: %s, and obt: %s." % (i, dataReference, dataObtained) 177 else: 178 ERROR_ASSERT_MESSAGE += "\nMismatch on %ith word, Similarity of BIG string is %s < %s" % (i, fSimilarity, _fStrSimilar) 179 bAlmostEqual = False 180 break 181 else: 182 EDVerbose.DEBUG("Checking for similarity on %i th word: obtained %.4f%% >= %.4f%%" % (i, fSimilarity * 100.0, _fStrSimilar * 100.0)) 183 continue 184 if (fObtValue != fRefValue) and \ 185 (2 * abs(fRefValue - fObtValue) / (fObtValue + fRefValue) > _fRelError) and \ 186 abs(fRefValue - fObtValue) > _fAbsError: 187 188 ERROR_ASSERT_MESSAGE += "\nMismatch on word %i between ref: %s, and obt: %s." % (i, fRefValue, fObtValue) 189 bAlmostEqual = False 190 break 191 else: 192 ERROR_ASSERT_MESSAGE += "\nStrings do not have the same number of words." 193 bAlmostEqual = False 194 195 if not bAlmostEqual: 196 strExpectedFileName = tempfile.mktemp(suffix="_expected.txt", dir=os.getcwd()) 197 strUniqueIndentifier = strExpectedFileName.split("_expected.txt")[0] 198 f = open(strExpectedFileName , "w") 199 f. write(str(_oExpected)) 200 f.close() 201 strObtainedFileName = strUniqueIndentifier + "_obtained.txt" 202 f = open(strObtainedFileName, "w") 203 f. write(str(_oObtained)) 204 f.close() 205 EQUAL_ERROR_ASSERT_MESSAGE = "FAILURE: %s \nIdentifier %s" % (ERROR_ASSERT_MESSAGE, strUniqueIndentifier) 206 EDVerbose.ASSERT(EQUAL_ERROR_ASSERT_MESSAGE) 207 raise AssertionError, EQUAL_ERROR_ASSERT_MESSAGE 208 else: 209 EDVerbose.ASSERT("OK " + _strComment)
210 211 212 @staticmethod
213 - def isFile(_strFilename, _strComment=""):
214 """ 215 Fail if the filename does not exist. 216 @param _strFilename: any python string representing a file that shoul exist 217 @param _strComment: a comment to make your assertion more understandable to the user 218 @type _strComment: python string or unicode string. 219 """ 220 if not os.path.isfile(_strFilename): 221 EQUAL_ERROR_ASSERT_MESSAGE = "FAILURE: " + _strComment + "\n Filename does not exist " + _strFilename 222 EDVerbose.ASSERT(EQUAL_ERROR_ASSERT_MESSAGE) 223 raise AssertionError, EQUAL_ERROR_ASSERT_MESSAGE 224 else: 225 EDVerbose.ASSERT("OK " + _strComment)
226 227 228 @staticmethod
229 - def lowerThan(_fValue, _fReference=1.0, _strComment="Lower than"):
230 """ 231 Fails if the _fValue is greater (or equal) than the reference. 232 @param _fValue: any python object that can be compared ... 233 @param _strComment: a comment to make your assertion more understandable to the user 234 @type _strComment: python string or unicode string. 235 """ 236 if _fValue >= _fReference: 237 EQUAL_ERROR_ASSERT_MESSAGE = "FAILURE: %s\n Obtained value %s should be lower than %s !!" % (_strComment, _fValue, _fReference) 238 EDVerbose.ASSERT(EQUAL_ERROR_ASSERT_MESSAGE) 239 raise AssertionError, EQUAL_ERROR_ASSERT_MESSAGE 240 else: 241 EDVerbose.ASSERT("OK " + _strComment)
242 243 244 @staticmethod
245 - def greaterThan(_fValue, _fReference=1.0, _strComment="Greater than"):
246 """ 247 Fails if the _fValue is greater (or equal) than the reference. 248 @param _fValue: any python object that can be compared ... 249 @param _strComment: a comment to make your assertion more understandable to the user 250 @type _strComment: python string or unicode string. 251 """ 252 if _fValue <= _fReference: 253 EQUAL_ERROR_ASSERT_MESSAGE = "FAILURE: %s\n Obtained value %s should be greater than %s !!" % (_strComment, _fValue, _fReference) 254 EDVerbose.ASSERT(EQUAL_ERROR_ASSERT_MESSAGE) 255 raise AssertionError, EQUAL_ERROR_ASSERT_MESSAGE 256 else: 257 EDVerbose.ASSERT("OK " + _strComment)
258 259 260 @staticmethod
261 - def arraySimilar(_npaValue, _npaRef, _strComment="Arrays are similar", _fAbsMaxDelta=None, _fRelMaxDelta=None, _fRfactor=None, _fScaledMaxDelta=None):
262 """ 263 Tests if two arrays are similar. 264 Two arrays (vectors, matrices, tensors, ...) if the have : 265 * same shape (always tested), 266 * max(abs(Value - Ref)) < _fAbsMaxDelta if _fAbsMaxDelta is defined 267 * max(abs(Value - Ref)/max(abs(Value),abs(Ref)) < _fRelMaxDelta if _fRelMaxDelta is defined 268 * Sigma(abs(Value - Ref)/max(abs(Value),abs(Ref)) < _fRfactor1 if _fRfactor1 is defined 269 270 271 @param _npaRef: reference array 272 @type _npaRef: Numpy like array 273 @param _npaValue: array to be compared with the reference 274 @param _strComment: a comment to make your assertion more understandable to the user 275 @type _strComment: python string or unicode string. 276 @type _fAbsMaxDelta: Float 277 @type _fRelMaxDelta: Float 278 @type _fRfactor1: Float 279 """ 280 bAlmostEqual = True 281 try: 282 refShape = _npaRef.shape 283 valShape = _npaValue.shape 284 except Exception: 285 bAlmostEqual = False 286 ERROR_ASSERT_MESSAGE = "Objects passed have no shape attribute" 287 288 if bAlmostEqual and not (refShape == valShape): 289 bAlmostEqual = False 290 ERROR_ASSERT_MESSAGE = "Arrays have different shapes Ref: %s, Obt: %s" % (refShape, valShape) 291 292 if bAlmostEqual and _fAbsMaxDelta is not None: 293 fval = (abs(_npaRef - _npaValue)).max() 294 EDVerbose.DEBUG("Obtained Absolute Max Delta: %.4f" % fval) 295 if fval > _fAbsMaxDelta: 296 ERROR_ASSERT_MESSAGE = "Max delta obtained: %s larger than allowed: %s" % (fval, _fAbsMaxDelta) 297 bAlmostEqual = False 298 299 if bAlmostEqual and _fRelMaxDelta is not None: 300 fval = (abs(_npaRef - _npaValue) / abs(_npaRef)).max() 301 EDVerbose.DEBUG("Obtained Relative Max Delta: %.4f" % fval) 302 if fval > _fRelMaxDelta: 303 ERROR_ASSERT_MESSAGE = "Max relative delta obtained: %s larger than allowed: %s" % (fval, _fRelMaxDelta) 304 bAlmostEqual = False 305 306 if bAlmostEqual and _fRfactor is not None: 307 fval = (abs(_npaRef - _npaValue) / abs(_npaRef)).sum() / len(_npaRef) 308 EDVerbose.DEBUG("Obtained R-factor: %.4f" % fval) 309 if fval > _fRfactor: 310 ERROR_ASSERT_MESSAGE = "R factor obtained: %s larger than allowed: %s" % (fval, _fRfactor) 311 bAlmostEqual = False 312 313 if bAlmostEqual and _fScaledMaxDelta is not None: 314 fval = (abs(_npaRef - _npaValue).max()) / (_npaRef.max() - _npaRef.min()) 315 EDVerbose.DEBUG("Obtained Scaled Max Delta: %.4f" % fval) 316 if fval > _fScaledMaxDelta: 317 ERROR_ASSERT_MESSAGE = "Scaled delta obtained: %s larger than allowed: %s" % (fval, _fScaledMaxDelta) 318 bAlmostEqual = False 319 320 321 if not bAlmostEqual: 322 EDVerbose.ASSERT("FAILURE: %s, %s " % (_strComment, ERROR_ASSERT_MESSAGE)) 323 raise AssertionError, ERROR_ASSERT_MESSAGE 324 else: 325 EDVerbose.ASSERT("OK " + _strComment)
326