# coding: utf-8 # Copyright (c) Jupyter Development Team. # Distributed under the terms of the Modified BSD License. import operator from collections import defaultdict from .config import DiffConfig from .seq_difflib import diff_sequence_difflib from .seq_bruteforce import diff_sequence_bruteforce from .seq_myers import diff_sequence_myers __all__ = ["diff_strings_by_char", "diff_sequence", "diff_strings_linewise"] # TODO: Configuration framework? # legal_diff_sequence_algorithms = ["bruteforce", "difflib", "myers"] diff_sequence_algorithm = "bruteforce" def diff_sequence(a, b, compare=operator.__eq__): """Compute a shallow diff of two sequences. I.e. these algorithms do not recursively diff elements of the sequences. This is a wrapper for alternative diff implementations. """ if diff_sequence_algorithm == "difflib": if compare is not operator.__eq__: raise RuntimeError("Cannot use difflib with comparison other than ==.") return diff_sequence_difflib(a, b) elif diff_sequence_algorithm == "bruteforce": return diff_sequence_bruteforce(a, b, compare) elif diff_sequence_algorithm == "myers": return diff_sequence_myers(a, b, compare) else: raise RuntimeError("Unknown diff_sequence_algorithm {}.".format(diff_sequence_algorithm)) def diff_strings_by_char(a, b, path="", config=None): "Compute char-based diff of two strings." assert isinstance(a, str) and isinstance(b, str), ( 'Arguments need to be string types. Got %r and %r' % (a, b)) if a == b: return [] else: return diff_sequence_difflib(a, b) def diff_strings_linewise(a, b): """Do a line-wise diff of two strings """ assert isinstance(a, str) and isinstance(b, str), ( 'Arguments need to be string types. Got %r and %r' % (a, b)) if a == b: return [] lines_a = a.splitlines(True) lines_b = b.splitlines(True) from .generic import diff_lists, compare_strings_approximate config = DiffConfig( predicates=defaultdict(lambda: [ compare_strings_approximate, operator.__eq__]), differs=defaultdict(lambda: diff_strings_by_char) ) return diff_lists(lines_a, lines_b, config=config)