def test_instantiation(self): DataError('column names', xMissing('foo')) DataError('column names', [xMissing('foo')]) DataError('column names', {'foo': xMissing('bar')}) DataError('column names', {('foo', 'bar'): xMissing('baz')}) with self.assertRaises(ValueError, msg='Empty error should raise exception.'): DataError(msg='', differences={})
def test_allow_all(self): differences = [Missing('xxx'), Extra('yyy')] with allow_only(differences): raise DataError('example error', [Missing('xxx'), Extra('yyy')]) # Order of differences should not matter! differences = [Extra('yyy'), Missing('xxx')] with allow_only(differences): raise DataError('example error', reversed(differences))
def test_kwds_all_ok(self): function = lambda iterable: list() # <- Accepts everything. in_diffs = [ Missing('foo', aaa='x', bbb='y'), Missing('bar', aaa='x', bbb='z'), ] # Using keyword aaa='x' should accept all in_diffs. with allow_iter(function, 'example message', aaa='x'): raise DataError('example error', in_diffs) # Using keyword bbb=['y', 'z'] should also accept all in_diffs. with allow_iter(function, 'example message', bbb=['y', 'z']): raise DataError('example error', in_diffs)
def test_verbose_repr(self): reference = 'reference-data-source' subject = 'subject-data-source' error = DataError('different columns', [xMissing('foo')], subject, reference) error._verbose = True # <- Set verbose flag, here! pattern = ("DataError: different columns:\n" " xMissing('foo')\n" "\n" "SUBJECT:\n" "subject-data-source\n" "REQUIRED:\n" "reference-data-source") self.assertEqual(repr(error), pattern)
def __exit__(self, exc_type, exc_value, tb): if exc_type is None: # <- Values are None when no exeption was raised. if self.msg: msg = self.msg else: msg = getattr(self.function, '__name__', str(self.function)) exc = AssertionError('No differences found: ' + str(msg)) exc.__cause__ = None raise exc if not issubclass(exc_type, DataError): raise exc_value # If not DataError, re-raise without changes. diffs = exc_value.differences rejected_kwds, accepted_kwds = self._partition_kwds(diffs, **self.kwds) rejected_func = self.function(accepted_kwds) # <- Apply function! not_allowed = itertools.chain(rejected_kwds, rejected_func) not_allowed = list(not_allowed) if not_allowed: msg = [self.msg, getattr(exc_value, 'msg')] msg = ': '.join(x for x in msg if x) exc = DataError(msg, not_allowed) exc.__cause__ = None # <- Suppress context using verbose raise exc # alternative to support older Python # versions--see PEP 415 (same as # effect as "raise ... from None"). return True # <- Suppress original exception.
def test_allow_one_but_find_duplicate(self): with self.assertRaises(DataError) as cm: with allow_only(Extra('xxx')): raise DataError('example error', [Extra('xxx'), Extra('xxx')]) result_string = str(cm.exception) self.assertEqual("example error:\n xExtra('xxx')", result_string)
def test_method2(_self): with _self.allowExtra(): # <- allow unlimited number. differences = [ datatest.Extra('foo'), datatest.Missing('bar'), datatest.Missing('baz'), ] raise DataError('some differences', differences)
def test_method1(_self): with _self.allowExtra(3): differences = [ datatest.Extra('foo'), datatest.Missing('bar'), datatest.Missing('baz'), ] raise DataError('some differences', differences)
def test_method(_self): with _self.allowAny(2): # <- allow two differences = [ datatest.Missing('foo'), datatest.Missing('bar'), datatest.Missing('baz'), ] raise DataError('some differences', differences)
def function(iterable): allowed = self._walk_diff(differences) # <- Closes over *differences*. allowed = Counter(allowed) not_allowed = [] for x in iterable: if allowed[x]: allowed[x] -= 1 else: not_allowed.append(x) if not_allowed: return not_allowed # <- EXIT! not_found = list(allowed.elements()) if not_found: exc = DataError('Allowed difference not found', not_found) exc.__cause__ = None raise exc return iter([])
def test_method2(_self): with _self.allowAny(4): # <- allow four differences = [ datatest.Extra('foo'), datatest.Missing('bar'), datatest.Invalid('baz'), ] raise DataError('some differences', differences)
def test_allow_duplicate_but_find_only_one(self): with self.assertRaises(DataError) as cm: with allow_only([Extra('xxx'), Extra('xxx')]): raise DataError('example error', [Extra('xxx')]) result_string = str(cm.exception) self.assertEqual("Allowed difference not found:\n xExtra('xxx')", result_string)
def test_passing(_self): with _self.allowAny( 3, label1='a'): # <- allow 3 where label1 equals 'a' differences = [ datatest.Deviation(-1, 3, label1='a', label2='x'), datatest.Deviation(+1, 4, label1='a', label2='y'), datatest.Deviation(-2, 5, label1='a', label2='z'), ] raise DataError('some differences', differences)
def test_allow_some(self): differences = [Extra('xxx'), Missing('yyy')] with self.assertRaises(DataError) as cm: with allow_limit(1): # <- Allows only 1 but there are 2! raise DataError('example error', differences) rejected = list(cm.exception.differences) self.assertEqual(differences, rejected)
def test_allow_some(self): differences = [Extra('xxx'), Missing('yyy')] with self.assertRaises(DataError) as cm: with allow_missing(): raise DataError('example error', differences) rejected = list(cm.exception.differences) self.assertEqual(rejected, [Extra('xxx')])
def test_not_found(self): with self.assertRaises(DataError) as cm: with allow_only([Extra('xxx'), Missing('yyy')]): raise DataError('example error', [Extra('xxx')]) result_str = str(cm.exception) self.assertTrue(result_str.startswith('Allowed difference not found')) result_diffs = list(cm.exception.differences) self.assertEqual([Missing('yyy')], result_diffs)
def test_fail_with_nonmatched(_self): with _self.allowAny( label1='a' ): # <- allow unlimited where label1 equals 'a' differences = [ datatest.Deviation(-1, 3, label1='a', label2='x'), datatest.Deviation(+1, 4, label1='a', label2='y'), datatest.Deviation(-2, 5, label1='b', label2='z'), # <- label='b' ] raise DataError('some differences', differences)
def test_kwds(self): diff_set = set([ Missing('xxx', aaa='foo'), Missing('yyy', aaa='bar'), Extra('zzz', aaa='foo'), ]) with self.assertRaises(DataError) as cm: # Allows 2 with aaa='foo' and there are two (only aaa='bar' is rejected). with allow_limit(2, 'example message', aaa='foo'): raise DataError('example error', diff_set) rejected = set(cm.exception.differences) self.assertEqual(rejected, set([Missing('yyy', aaa='bar')])) with self.assertRaises(DataError) as cm: # Allows 1 with aaa='foo' but there are 2 (all are rejected)! with allow_limit(1, 'example message', aaa='foo'): raise DataError('example error', diff_set) rejected = set(cm.exception.differences) self.assertEqual(rejected, diff_set)
def test_kwds(self): in_diffs = [ Extra('xxx', aaa='foo'), Extra('yyy', aaa='bar'), Missing('zzz', aaa='foo'), ] with self.assertRaises(DataError) as cm: with allow_any('example message', aaa='foo'): raise DataError('example error', in_diffs) rejected = list(cm.exception.differences) self.assertEqual(rejected, [Extra('yyy', aaa='bar')])
def test_allow_some(self): with self.assertRaises(DataError) as cm: with allow_only(Extra('xxx'), 'example message'): raise DataError('example error', [Extra('xxx'), Missing('yyy')]) result_str = str(cm.exception) self.assertEqual("example message: example error:\n xMissing('yyy')", result_str) result_diffs = list(cm.exception.differences) self.assertEqual([Missing('yyy')], result_diffs)
def test_function_some_ok(self): function = lambda iterable: (x for x in iterable if x.value != 'bar') in_diffs = [ Missing('foo'), Missing('bar'), ] with self.assertRaises(DataError) as cm: with allow_iter(function, 'example message'): raise DataError('example error', in_diffs) rejected = list(cm.exception.differences) self.assertEqual(rejected, [Missing('foo')])
def test_allow_some(self): function = lambda x: x.value == 'bar' in_diffs = [ Missing('foo'), Missing('bar'), ] with self.assertRaises(DataError) as cm: with allow_each(function, 'example message'): raise DataError('example error', in_diffs) rejected = list(cm.exception.differences) self.assertEqual(rejected, [Missing('foo')])
def test_no_kwds(self): in_diffs = [ Extra('xxx', aaa='foo'), Extra('yyy', aaa='bar'), ] with self.assertRaises(TypeError) as cm: with allow_any('example message'): # <- Missing keyword argument! raise DataError('example error', in_diffs) result = cm.exception expected = 'requires 1 or more keyword arguments (0 given)' self.assertEqual(expected, str(result))
def test_function_all_bad(self): function = lambda iterable: iterable # <- Rejects everything. in_diffs = [ Extra('foo'), Extra('bar'), ] with self.assertRaises(DataError) as cm: with allow_iter(function, 'example message'): raise DataError('example error', in_diffs) rejected = cm.exception.differences self.assertEqual(rejected, in_diffs)
def test_empty_value_handling(self): # Test NoneType. with allow_percent_deviation(0): # <- Pass without failure. raise DataError('example error', [xDeviation(None, 0)]) with allow_percent_deviation(0): # <- Pass without failure. raise DataError('example error', [xDeviation(0, None)]) # Test empty string. with allow_percent_deviation(0): # <- Pass without failure. raise DataError('example error', [xDeviation('', 0)]) with allow_percent_deviation(0): # <- Pass without failure. raise DataError('example error', [xDeviation(0, '')]) # Test NaN (not a number) values. with self.assertRaises( DataError): # <- NaN values should not be caught! with allow_percent_deviation(0): raise DataError('example error', [xDeviation(float('nan'), 0)]) with self.assertRaises( DataError): # <- NaN values should not be caught! with allow_percent_deviation(0): raise DataError('example error', [xDeviation(0, float('nan'))])
def test_kwds_all_bad(self): function = lambda iterable: list() # <- Accepts everything. in_diffs = [ Missing('foo', aaa='x', bbb='y'), Missing('bar', aaa='x', bbb='z'), ] with self.assertRaises(DataError) as cm: # Using keyword bbb='j' should reject all in_diffs. with allow_iter(function, 'example allowance', bbb='j'): raise DataError('example error', in_diffs) rejected = list(cm.exception.differences) self.assertEqual(rejected, in_diffs)
def test_repr(self): error = DataError('different columns', [xMissing('foo')]) pattern = "DataError: different columns:\n xMissing('foo')" self.assertEqual(repr(error), pattern) error = DataError('different columns', xMissing('foo')) pattern = "DataError: different columns:\n xMissing('foo')" self.assertEqual(repr(error), pattern) # Test pprint lists. error = DataError('different columns', [xMissing('foo'), xMissing('bar')]) pattern = ("DataError: different columns:\n" " xMissing('foo'),\n" " xMissing('bar')") self.assertEqual(repr(error), pattern) # Test dictionary. error = DataError('different columns', {'FOO': xMissing('bar')}) pattern = ("DataError: different columns:\n" " 'FOO': xMissing('bar')") self.assertEqual(repr(error), pattern)
def fail(self, msg, differences=None): if differences: try: subject = self.subject except NameError: subject = None try: required = self.reference except NameError: required = None raise DataError(msg, differences, subject, required) else: raise self.failureException(msg)
def test_kwds_some_ok(self): function = lambda iterable: list() # <- Accepts everything. in_diffs = [ Missing('foo', aaa='x', bbb='y'), Missing('bar', aaa='x', bbb='z'), ] with self.assertRaises(DataError) as cm: # Keyword bbb='y' should reject second in_diffs element. with allow_iter(function, 'example message', bbb='y'): raise DataError('example error', in_diffs) rejected = list(cm.exception.differences) self.assertEqual(rejected, [Missing('bar', aaa='x', bbb='z')])
def test_nested_acceptances(self): """A quick integration test to make sure acceptances nest as required. """ with allow_only(xDeviation(-4, 70, label1='b')): # <- specified diff only with allow_deviation(3): # <- tolerance of +/- 3 with allow_percent_deviation(0.02): # <- tolerance of +/- 2% differences = [ xDeviation(+3, 65, label1='a'), xDeviation(-4, 70, label1='b'), xDeviation(+5, 250, label1='c'), ] raise DataError('example error', differences)