Created
March 5, 2015 18:10
-
-
Save TallJimbo/2c395544d972b1309ab8 to your computer and use it in GitHub Desktop.
LSST DM Fuzzy Comparison Proposal (RFC-28)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class Comparison(object): | |
"""Interface definition for comparison objects. | |
This class doesn't actually have to exist - it's just for exposition. | |
A comparison for a new type can be defined by implementing a class with | |
signatures like this one, then calling ComparisonRegistry.register(). | |
""" | |
def __init__(self, | |
rtol=None, # relative threshold for floating point comparisons | |
atol=None, # absolute threshold for floating point comparisons | |
printDiff=False, # print the difference to this file-like object (e.g. stdout) | |
plotDiff=False, # plot any differences using matplotlib | |
displayDiff=False, # display any differences using ds9 | |
requireEqualTypes=False, # require same types (including C++ types, if applicable) | |
**kwds | |
): | |
"""Constructor signatures for comparison objects. | |
Not all comparison constructors need to take all of these keyword arguments, and they may | |
have additional arguments not listed here. However, | |
- If they have any argument like one of the ones above, they should use the exact name | |
used above and give it the same semantics if at all possible. | |
- All comparison constructors should silently ignore unrecognized **kwd arguments (this | |
allows these to be passed recursively to other comparison constructors without worrying | |
about the details of exactly which options are supported). | |
All of the diff reporting methods should do absolutely nothing when objects are considered | |
equal. | |
""" | |
raise NotImplementedError() | |
def __call__(self, lhs, rhs): | |
"""Compare two objects, returning True if they should be considered equal according to the | |
criteria passed to the constructor, and report any differences as requested by the | |
constructor. | |
""" | |
raise NotImplementedError() | |
class ComparisonRegistry(object): | |
"""Class that manages a registry of fuzzy comparison objects. | |
Instances of this class should never exist; the only useful methods are class methods. | |
""" | |
_registry = {} | |
@classmethod | |
def register(cls, cmpClass, type_): | |
"""Register a comparison class for the given type. | |
""" | |
cls._registry[type_] = cmpClass | |
@classmethod | |
def get(cls, type_): | |
"""Return a comparison class for the given type. | |
""" | |
cmpClass = cls._registry.get(type_, None) | |
if cmpClass is not None: | |
return cmpClass(**kwds) | |
for b in type_.__bases__: | |
cmpClass = cls._registry.get(b, None) | |
if cmpClass is not None: | |
return cmpClass(**kwds) | |
return None | |
def compare(a, b, **kwds): | |
"""High-level interface to fuzzy comparisons: return True if a and b are equal according to criteria | |
defined by **kwds. | |
""" | |
cmpClass = ComparisonRegistry.get(type(a)) or ComparisonRegistry.get(type(b)) | |
comparison = cmpClass(**kwds) | |
return comparison(a, b) | |
class TestCase(unittest.TestCase): # this class already exists in lsst.utils | |
"""Base class for LSST Python unit tests, providing useful extra comparisons. | |
This should be the interface to fuzzy comparisons typically used by test code. | |
""" | |
def assertClose(self, a, b, **kwds): # this method already exists; just adding a hook to the beginning | |
cmpClass = ComparisonRegistry.get(type(a)) or ComparisonRegistry.get(type(b)) | |
if cmpClass is not None: | |
diff = cStringIO.StringIO() | |
kwds.setdefault("printDiff", diff) | |
comparison = cmpClass(**kwds) | |
return self.assertTrue(comparison(a, b), msg=diff.getvalue()) | |
# rest of the existing method continues here, comparing scalars and NumPy arrays | |
pass |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment