def are_equal(*sequences, easy_types=(sequence_tools.CuteRange,)): ''' Are the given sequences equal? This tries to make a cheap comparison between the sequences if possible, but if not, it goes over the sequences in parallel item-by-item and checks whether the items are all equal. A cheap comparison is attempted only if the sequences are all of the same type, and that type is in `easy_types`. (It's important to restrict `easy_types` only to types where equality between the sequences is the same as equality between every item in the sequences.) ''' from python_toolbox import logic_tools sequence_types = set(map(type, sequences)) # Trying cheap comparison: if len(sequence_types) == 1 and issubclass( get_single_if_any(sequence_types), easy_types): return logic_tools.all_equal(sequences) # If cheap comparison didn't work, trying item-by-item comparison: zipped = itertools.zip_longest(*sequences, fillvalue=_EMPTY_SENTINEL) for values in zipped: # No need to explicitly check for `_EMPTY_SENTINEL`, it would just make # the following condition `False`, because it's impossible for all # values to be the sentinel. if not logic_tools.all_equal(values): return False else: return True
def test_exhaustive_true(): '''Test `all_equal` in cases where `exhaustive=True` is relevant.''' class FunkyFloat(float): def __eq__(self, other): return (abs(self - other) <= 2) funky_floats = [FunkyFloat(1), FunkyFloat(2), FunkyFloat(3), FunkyFloat(4)] assert all_equal(funky_floats) assert not all_equal(funky_floats, exhaustive=True)
def test_exhaustive(): """Test `all_equal` in cases where `exhaustive=True` is relevant.""" class FunkyFloat(float): def __eq__(self, other): return abs(self - other) <= 2 funky_floats = [FunkyFloat(1), FunkyFloat(2), FunkyFloat(3), FunkyFloat(4)] assert all_equal(funky_floats) assert not all_equal(funky_floats, exhaustive=True)
def cute_equal(*items): # For testing purposes, we need `nan == nan`, so we use `cute_equal`. if all(isinstance(item, numbers.Number) for item in items): if all(map(math.isnan, items)): return True else: return logic_tools.all_equal(items) else: assert all(isinstance(item, tuple) for item in items) return all(cute_equal(*sub_items) for sub_items in zip(*items))
def test_illegal_cases(): illegal_cases = ((4, 0), (infinity, 0), (-infinity, 0)) for illegal_case in illegal_cases: with cute_testing.RaiseAssertor() as raise_assertor_0: cute_divmod(*illegal_case) with cute_testing.RaiseAssertor() as raise_assertor_1: divmod(*illegal_case) with cute_testing.RaiseAssertor() as raise_assertor_2: cute_floor_div(*illegal_case) assert logic_tools.all_equal(( type(raise_assertor_0.exception), type(raise_assertor_1.exception), type(raise_assertor_2.exception), )) assert logic_tools.all_equal(( raise_assertor_0.exception.args, raise_assertor_1.exception.args, raise_assertor_2.exception.args, ))
def test_illegal_cases(): illegal_cases = ( (4, 0), (infinity, 0), (-infinity, 0) ) for illegal_case in illegal_cases: with cute_testing.RaiseAssertor() as raise_assertor_0: cute_divmod(*illegal_case) with cute_testing.RaiseAssertor() as raise_assertor_1: divmod(*illegal_case) with cute_testing.RaiseAssertor() as raise_assertor_2: cute_floor_div(*illegal_case) assert logic_tools.all_equal(( type(raise_assertor_0.exception), type(raise_assertor_1.exception), type(raise_assertor_2.exception), )) assert logic_tools.all_equal(( raise_assertor_0.exception.args, raise_assertor_1.exception.args, raise_assertor_2.exception.args, ))
def zip_non_equal(iterables, lazy_tuple=False): ''' Zip the iterables, but only yield the tuples where the items aren't equal. ''' from python_toolbox import logic_tools iterator = (items for items in zip(*iterables) if not logic_tools.all_equal(items)) if lazy_tuple: from python_toolbox import nifty_collections return nifty_collections.LazyTuple(iterator) else: return iterator
def call_and_check_if_profiled(f): '''Call the function `f` and return whether it profiled itself.''' with OutputCapturer() as output_capturer: f() output = output_capturer.output segments_found = [(segment in output) for segment in segments] if not logic_tools.all_equal(segments_found): raise Exception("Some segments were found, but some weren't; can't " "know if this was a profiled call or not. Possibly " "some of our segments are wrong.") return segments_found[0]
def assert_same_signature(*callables): """Assert that all the `callables` have the same function signature.""" arg_specs = [cute_inspect.getargspec(callable_) for callable_ in callables] if not logic_tools.all_equal(arg_specs, exhaustive=True): raise Failure("Not all the callables have the same signature.")
def _check(exhaustive): '''Check the basic working of `all_equal` with given `exhaustive` flag.''' assert all_equal([1, 1, 1, 1], exhaustive) assert all_equal([1, 1, 1.0, 1], exhaustive) assert all_equal(((1 + 0j), 1, 1.0, 1), exhaustive) assert all_equal([], exhaustive) assert all_equal(iter([1, 1, 1.0, 1]), exhaustive) assert all_equal({'meow'}, exhaustive) assert all_equal(['frr', 'frr', 'frr', 'frr'], exhaustive) assert not all_equal([1, 1, 2, 1], exhaustive) assert not all_equal([1, 1, 1.001, 1], exhaustive) assert not all_equal(((1 + 0j), 3, 1.0, 1), exhaustive) assert not all_equal(range(7), exhaustive) assert not all_equal(iter([1, 17, 1.0, 1]), exhaustive) assert not all_equal({'meow', 'grr'}, exhaustive) assert not all_equal(['frr', 'frr', {}, 'frr', 'frr'], exhaustive) assert not all_equal(itertools.count()) # Not using given `exhaustive`
def assert_same_signature(*callables): '''Assert that all the `callables` have the same function signature.''' arg_specs = [cute_inspect.getargspec(callable_) for callable_ in callables] if not logic_tools.all_equal(arg_specs, exhaustive=True): raise Failure('Not all the callables have the same signature.')
def _check(exhaustive): """Check the basic working of `all_equal` with given `exhaustive` flag.""" assert all_equal([1, 1, 1, 1], exhaustive) assert all_equal([1, 1, 1.0, 1], exhaustive) assert all_equal(((1 + 0j), 1, 1.0, 1), exhaustive) assert all_equal([], exhaustive) assert all_equal(iter([1, 1, 1.0, 1]), exhaustive) assert all_equal({"meow"}, exhaustive) assert all_equal(["frr", "frr", "frr", "frr"], exhaustive) assert not all_equal([1, 1, 2, 1], exhaustive) assert not all_equal([1, 1, 1.001, 1], exhaustive) assert not all_equal(((1 + 0j), 3, 1.0, 1), exhaustive) assert not all_equal(range(7), exhaustive) assert not all_equal(iter([1, 17, 1.0, 1]), exhaustive) assert not all_equal({"meow", "grr"}, exhaustive) assert not all_equal(["frr", "frr", {}, "frr", "frr"], exhaustive) assert not all_equal(itertools.count()) # Not using given `exhaustive`