Method: difflib.Differ._fancy_replace
Calls: 100, Exceptions: 0, Paths: 9Back
Path 1: 45 calls (0.45)
['line 0', '1234567890123456789012345689012345', 'line 1', 'line 2', 'line 3', 'line 4 changed', 'line 5 changed', 'line 6 changed', 'line 7', '...
1 (13) 11 (7) 16 (4) 31 (4) 0 (4) 5 (3) 6 (3) 7 (3) 3 (2) 26 (1)
8 (9) 3 (7) 2 (5) 18 (4) 33 (4) 4 (4) 15 (3) 14 (3) 5 (2) 13 (1)
['line 0', '1234567890123456789012345689012345', 'line 1', 'line 2 added', 'line 3', 'line 4 chanGEd', 'line 5a chanGed', 'line 6a changEd', 'l...
1 (13) 11 (7) 16 (4) 31 (4) 0 (4) 5 (3) 6 (3) 7 (3) 3 (2) 26 (1)
2 (9) 8 (9) 17 (4) 32 (4) 4 (4) 1 (4) 15 (3) 14 (3) 5 (2) 12 (1)
None (45) '? ^^\n' (34) '- 1. Beautiful is beTTer than ugly.' (18) '? ^ ^\n' (18) '+ 1. Beautiful is better tha...
1def _fancy_replace(self, a, alo, ahi, b, blo, bhi):
2 r"""
3 When replacing one block of lines with another, search the blocks
4 for *similar* lines; the best-matching pair (if any) is used as a
5 synch point, and intraline difference marking is done on the
6 similar pair. Lots of work, but often worth it.
7
8 Example:
9
10 >>> d = Differ()
11 >>> results = d._fancy_replace(['abcDefghiJkl\n'], 0, 1,
12 ... ['abcdefGhijkl\n'], 0, 1)
13 >>> print(''.join(results), end="")
14 - abcDefghiJkl
15 ? ^ ^ ^
16 + abcdefGhijkl
17 ? ^ ^ ^
18 """
19
20 # don't synch up unless the lines have a similarity score of at
21 # least cutoff; best_ratio tracks the best score seen so far
22 best_ratio, cutoff = 0.74, 0.75
23 cruncher = SequenceMatcher(self.charjunk)
24 eqi, eqj = None, None # 1st indices of equal lines (if any)
25
26 # search for the pair that matches best without being identical
27 # (identical lines must be junk lines, & we don't want to synch up
28 # on junk -- unless we have to)
29 for j in range(blo, bhi):
30 bj = b[j]
31 cruncher.set_seq2(bj)
32 for i in range(alo, ahi):
33 ai = a[i]
34 if ai == bj:
35 if eqi is None:
36 eqi, eqj = i, j
37 continue
38 cruncher.set_seq1(ai)
39 # computing similarity is expensive, so use the quick
40 # upper bounds first -- have seen this speed up messy
41 # compares by a factor of 3.
42 # note that ratio() is only expensive to compute the first
43 # time it's called on a sequence pair; the expensive part
44 # of the computation is cached by cruncher
45 if cruncher.real_quick_ratio() > best_ratio and \
46 cruncher.quick_ratio() > best_ratio and \
47 cruncher.ratio() > best_ratio:
48 best_ratio, best_i, best_j = cruncher.ratio(), i, j
49 if best_ratio < cutoff:
50 # no non-identical "pretty close" pair
51 if eqi is None:
52 # no identical pair either -- treat it as a straight replace
53 yield from self._plain_replace(a, alo, ahi, b, blo, bhi)
54 return
55 # no close pair, but an identical pair -- synch up on that
56 best_i, best_j, best_ratio = eqi, eqj, 1.0
57 else:
58 # there's a close pair, so forget the identical pair (if any)
59 eqi = None
60
61 # a[best_i] very similar to b[best_j]; eqi is None iff they're not
62 # identical
63
64 # pump out diffs from before the synch point
65 yield from self._fancy_helper(a, alo, best_i, b, blo, best_j)
66
67 # do intraline marking on the synch pair
68 aelt, belt = a[best_i], b[best_j]
69 if eqi is None:
70 # pump out a '-', '?', '+', '?' quad for the synched lines
71 atags = btags = ""
72 cruncher.set_seqs(aelt, belt)
73 for tag, ai1, ai2, bj1, bj2 in cruncher.get_opcodes():
74 la, lb = ai2 - ai1, bj2 - bj1
75 if tag == 'replace':
76 atags += '^' * la
77 btags += '^' * lb
78 elif tag == 'delete':
79 atags += '-' * la
80 elif tag == 'insert':
81 btags += '+' * lb
82 elif tag == 'equal':
83 atags += ' ' * la
84 btags += ' ' * lb
85 else:
86 raise ValueError('unknown tag %r' % (tag,))
87 yield from self._qformat(aelt, belt, atags, btags)
88 else:
89 # the synch pair is identical
90 yield ' ' + aelt
91
92 # pump out diffs from after the synch point
93 yield from self._fancy_helper(a, best_i+1, ahi, b, best_j+1, bhi)
Path 2: 19 calls (0.19)
['', ' 1. Beautiful is beTTer than ugly.', ' 2. Explicit is better than implicit.', ' 3. Simple is better than complex.', ' 4. Complex is bett...
1 (7) 16 (4) 31 (4) 0 (1) 11 (1) 26 (1) 41 (1)
5 (6) 20 (4) 35 (4) 1 (1) 15 (1) 30 (1) 45 (1) 4 (1)
['', ' 1. Beautiful is better than ugly.', ' 3. Simple is better than complex.', ' 4. Complicated is better than complex.', ' 5. Flat is bet...
1 (7) 16 (4) 31 (4) 0 (1) 11 (1) 26 (1) 41 (1)
5 (6) 20 (4) 35 (4) 1 (1) 15 (1) 30 (1) 45 (1) 4 (1)
'? ^^\n' (34) None (19) '- 1. Beautiful is beTTer than ugly.' (17) '+ 1. Beautiful is better than ugly.' (17) '- 2. Expl...
1def _fancy_replace(self, a, alo, ahi, b, blo, bhi):
2 r"""
3 When replacing one block of lines with another, search the blocks
4 for *similar* lines; the best-matching pair (if any) is used as a
5 synch point, and intraline difference marking is done on the
6 similar pair. Lots of work, but often worth it.
7
8 Example:
9
10 >>> d = Differ()
11 >>> results = d._fancy_replace(['abcDefghiJkl\n'], 0, 1,
12 ... ['abcdefGhijkl\n'], 0, 1)
13 >>> print(''.join(results), end="")
14 - abcDefghiJkl
15 ? ^ ^ ^
16 + abcdefGhijkl
17 ? ^ ^ ^
18 """
19
20 # don't synch up unless the lines have a similarity score of at
21 # least cutoff; best_ratio tracks the best score seen so far
22 best_ratio, cutoff = 0.74, 0.75
23 cruncher = SequenceMatcher(self.charjunk)
24 eqi, eqj = None, None # 1st indices of equal lines (if any)
25
26 # search for the pair that matches best without being identical
27 # (identical lines must be junk lines, & we don't want to synch up
28 # on junk -- unless we have to)
29 for j in range(blo, bhi):
30 bj = b[j]
31 cruncher.set_seq2(bj)
32 for i in range(alo, ahi):
33 ai = a[i]
34 if ai == bj:
35 if eqi is None:
36 eqi, eqj = i, j
37 continue
38 cruncher.set_seq1(ai)
39 # computing similarity is expensive, so use the quick
40 # upper bounds first -- have seen this speed up messy
41 # compares by a factor of 3.
42 # note that ratio() is only expensive to compute the first
43 # time it's called on a sequence pair; the expensive part
44 # of the computation is cached by cruncher
45 if cruncher.real_quick_ratio() > best_ratio and \
46 cruncher.quick_ratio() > best_ratio and \
47 cruncher.ratio() > best_ratio:
48 best_ratio, best_i, best_j = cruncher.ratio(), i, j
49 if best_ratio < cutoff:
50 # no non-identical "pretty close" pair
51 if eqi is None:
52 # no identical pair either -- treat it as a straight replace
53 yield from self._plain_replace(a, alo, ahi, b, blo, bhi)
54 return
55 # no close pair, but an identical pair -- synch up on that
56 best_i, best_j, best_ratio = eqi, eqj, 1.0
57 else:
58 # there's a close pair, so forget the identical pair (if any)
59 eqi = None
60
61 # a[best_i] very similar to b[best_j]; eqi is None iff they're not
62 # identical
63
64 # pump out diffs from before the synch point
65 yield from self._fancy_helper(a, alo, best_i, b, blo, best_j)
66
67 # do intraline marking on the synch pair
68 aelt, belt = a[best_i], b[best_j]
69 if eqi is None:
70 # pump out a '-', '?', '+', '?' quad for the synched lines
71 atags = btags = ""
72 cruncher.set_seqs(aelt, belt)
73 for tag, ai1, ai2, bj1, bj2 in cruncher.get_opcodes():
74 la, lb = ai2 - ai1, bj2 - bj1
75 if tag == 'replace':
76 atags += '^' * la
77 btags += '^' * lb
78 elif tag == 'delete':
79 atags += '-' * la
80 elif tag == 'insert':
81 btags += '+' * lb
82 elif tag == 'equal':
83 atags += ' ' * la
84 btags += ' ' * lb
85 else:
86 raise ValueError('unknown tag %r' % (tag,))
87 yield from self._qformat(aelt, belt, atags, btags)
88 else:
89 # the synch pair is identical
90 yield ' ' + aelt
91
92 # pump out diffs from after the synch point
93 yield from self._fancy_helper(a, best_i+1, ahi, b, best_j+1, bhi)
Path 3: 18 calls (0.18)
['', ' 1. Beautiful is beTTer than ugly.', ' 2. Explicit is better than implicit.', ' 3. Simple is better than complex.', ' 4. Complex is bett...
4 (7) 19 (4) 34 (4) 14 (1) 29 (1) 44 (1)
5 (7) 20 (4) 35 (4) 15 (1) 30 (1) 45 (1)
['', ' 1. Beautiful is better than ugly.', ' 3. Simple is better than complex.', ' 4. Complicated is better than complex.', ' 5. Flat is bet...
3 (7) 18 (4) 33 (4) 13 (1) 28 (1) 43 (1)
5 (7) 20 (4) 35 (4) 15 (1) 30 (1) 45 (1)
'- 4. Complex is better than complicated.' (18) '+ 5. Flat is better than nested.' (18) '+ 4. Complicated is better than complex.' (17) '+ ...
None (18)
1def _fancy_replace(self, a, alo, ahi, b, blo, bhi):
2 r"""
3 When replacing one block of lines with another, search the blocks
4 for *similar* lines; the best-matching pair (if any) is used as a
5 synch point, and intraline difference marking is done on the
6 similar pair. Lots of work, but often worth it.
7
8 Example:
9
10 >>> d = Differ()
11 >>> results = d._fancy_replace(['abcDefghiJkl\n'], 0, 1,
12 ... ['abcdefGhijkl\n'], 0, 1)
13 >>> print(''.join(results), end="")
14 - abcDefghiJkl
15 ? ^ ^ ^
16 + abcdefGhijkl
17 ? ^ ^ ^
18 """
19
20 # don't synch up unless the lines have a similarity score of at
21 # least cutoff; best_ratio tracks the best score seen so far
22 best_ratio, cutoff = 0.74, 0.75
23 cruncher = SequenceMatcher(self.charjunk)
24 eqi, eqj = None, None # 1st indices of equal lines (if any)
25
26 # search for the pair that matches best without being identical
27 # (identical lines must be junk lines, & we don't want to synch up
28 # on junk -- unless we have to)
29 for j in range(blo, bhi):
30 bj = b[j]
31 cruncher.set_seq2(bj)
32 for i in range(alo, ahi):
33 ai = a[i]
34 if ai == bj:
35 if eqi is None:
36 eqi, eqj = i, j
37 continue
38 cruncher.set_seq1(ai)
39 # computing similarity is expensive, so use the quick
40 # upper bounds first -- have seen this speed up messy
41 # compares by a factor of 3.
42 # note that ratio() is only expensive to compute the first
43 # time it's called on a sequence pair; the expensive part
44 # of the computation is cached by cruncher
45 if cruncher.real_quick_ratio() > best_ratio and \
46 cruncher.quick_ratio() > best_ratio and \
47 cruncher.ratio() > best_ratio:
48 best_ratio, best_i, best_j = cruncher.ratio(), i, j
49 if best_ratio < cutoff:
50 # no non-identical "pretty close" pair
51 if eqi is None:
52 # no identical pair either -- treat it as a straight replace
53 yield from self._plain_replace(a, alo, ahi, b, blo, bhi)
54 return
55 # no close pair, but an identical pair -- synch up on that
56 best_i, best_j, best_ratio = eqi, eqj, 1.0
57 else:
58 # there's a close pair, so forget the identical pair (if any)
59 eqi = None
60
61 # a[best_i] very similar to b[best_j]; eqi is None iff they're not
62 # identical
63
64 # pump out diffs from before the synch point
65 yield from self._fancy_helper(a, alo, best_i, b, blo, best_j)
66
67 # do intraline marking on the synch pair
68 aelt, belt = a[best_i], b[best_j]
69 if eqi is None:
70 # pump out a '-', '?', '+', '?' quad for the synched lines
71 atags = btags = ""
72 cruncher.set_seqs(aelt, belt)
73 for tag, ai1, ai2, bj1, bj2 in cruncher.get_opcodes():
74 la, lb = ai2 - ai1, bj2 - bj1
75 if tag == 'replace':
76 atags += '^' * la
77 btags += '^' * lb
78 elif tag == 'delete':
79 atags += '-' * la
80 elif tag == 'insert':
81 btags += '+' * lb
82 elif tag == 'equal':
83 atags += ' ' * la
84 btags += ' ' * lb
85 else:
86 raise ValueError('unknown tag %r' % (tag,))
87 yield from self._qformat(aelt, belt, atags, btags)
88 else:
89 # the synch pair is identical
90 yield ' ' + aelt
91
92 # pump out diffs from after the synch point
93 yield from self._fancy_helper(a, best_i+1, ahi, b, best_j+1, bhi)
Path 4: 6 calls (0.06)
['line 0', '1234567890123456789012345689012345', 'line 1', 'line 2', 'line 3', 'line 4 changed', 'line 5 changed', 'line 6 changed', 'line 7', '...
3 (3) 9 (3)
4 (3) 10 (3)
['line 0', '1234567890123456789012345689012345', 'line 1', 'line 2 added', 'line 3', 'line 4 chanGEd', 'line 5a chanGed', 'line 6a changEd', 'l...
3 (3) 9 (3)
4 (3) 10 (3)
'- line 2' (3) '+ line 2 added' (3) '- line 8 subtracted' (3) '+ line 8' (3)
None (6)
1def _fancy_replace(self, a, alo, ahi, b, blo, bhi):
2 r"""
3 When replacing one block of lines with another, search the blocks
4 for *similar* lines; the best-matching pair (if any) is used as a
5 synch point, and intraline difference marking is done on the
6 similar pair. Lots of work, but often worth it.
7
8 Example:
9
10 >>> d = Differ()
11 >>> results = d._fancy_replace(['abcDefghiJkl\n'], 0, 1,
12 ... ['abcdefGhijkl\n'], 0, 1)
13 >>> print(''.join(results), end="")
14 - abcDefghiJkl
15 ? ^ ^ ^
16 + abcdefGhijkl
17 ? ^ ^ ^
18 """
19
20 # don't synch up unless the lines have a similarity score of at
21 # least cutoff; best_ratio tracks the best score seen so far
22 best_ratio, cutoff = 0.74, 0.75
23 cruncher = SequenceMatcher(self.charjunk)
24 eqi, eqj = None, None # 1st indices of equal lines (if any)
25
26 # search for the pair that matches best without being identical
27 # (identical lines must be junk lines, & we don't want to synch up
28 # on junk -- unless we have to)
29 for j in range(blo, bhi):
30 bj = b[j]
31 cruncher.set_seq2(bj)
32 for i in range(alo, ahi):
33 ai = a[i]
34 if ai == bj:
35 if eqi is None:
36 eqi, eqj = i, j
37 continue
38 cruncher.set_seq1(ai)
39 # computing similarity is expensive, so use the quick
40 # upper bounds first -- have seen this speed up messy
41 # compares by a factor of 3.
42 # note that ratio() is only expensive to compute the first
43 # time it's called on a sequence pair; the expensive part
44 # of the computation is cached by cruncher
45 if cruncher.real_quick_ratio() > best_ratio and \
46 cruncher.quick_ratio() > best_ratio and \
47 cruncher.ratio() > best_ratio:
48 best_ratio, best_i, best_j = cruncher.ratio(), i, j
49 if best_ratio < cutoff:
50 # no non-identical "pretty close" pair
51 if eqi is None:
52 # no identical pair either -- treat it as a straight replace
53 yield from self._plain_replace(a, alo, ahi, b, blo, bhi)
54 return
55 # no close pair, but an identical pair -- synch up on that
56 best_i, best_j, best_ratio = eqi, eqj, 1.0
57 else:
58 # there's a close pair, so forget the identical pair (if any)
59 eqi = None
60
61 # a[best_i] very similar to b[best_j]; eqi is None iff they're not
62 # identical
63
64 # pump out diffs from before the synch point
65 yield from self._fancy_helper(a, alo, best_i, b, blo, best_j)
66
67 # do intraline marking on the synch pair
68 aelt, belt = a[best_i], b[best_j]
69 if eqi is None:
70 # pump out a '-', '?', '+', '?' quad for the synched lines
71 atags = btags = ""
72 cruncher.set_seqs(aelt, belt)
73 for tag, ai1, ai2, bj1, bj2 in cruncher.get_opcodes():
74 la, lb = ai2 - ai1, bj2 - bj1
75 if tag == 'replace':
76 atags += '^' * la
77 btags += '^' * lb
78 elif tag == 'delete':
79 atags += '-' * la
80 elif tag == 'insert':
81 btags += '+' * lb
82 elif tag == 'equal':
83 atags += ' ' * la
84 btags += ' ' * lb
85 else:
86 raise ValueError('unknown tag %r' % (tag,))
87 yield from self._qformat(aelt, belt, atags, btags)
88 else:
89 # the synch pair is identical
90 yield ' ' + aelt
91
92 # pump out diffs from after the synch point
93 yield from self._fancy_helper(a, best_i+1, ahi, b, best_j+1, bhi)
Path 5: 5 calls (0.05)
['one\n', 'two\n', 'three\n'] (3) ['', '\t\t\t\tLine 1: preceded by from:[tt] to:[ssss]', ' \t\t\t\tLine 2: preceded by from:[sstt] to:[sssst]', ' \...
0 (3) 1 (2)
3 (3) 6 (2)
['ore\n', 'tree\n', 'emu\n'] (3) ['', ' Line 1: preceded by from:[tt] to:[ssss]', ' \t\tLine 2: preceded by from:[sstt] to:[sssst]', ' Line...
0 (3) 1 (2)
3 (3) 6 (2)
'? ^\n' (6) None (5) '? ^^^^\n' (3) '? ^^\n' (3) '? ^^^^\n' (3) '? ^\n' (3) '- one\n' (3) '+ ore\n' (3) '- two\n' (3) '- three\n' (3)
1def _fancy_replace(self, a, alo, ahi, b, blo, bhi):
2 r"""
3 When replacing one block of lines with another, search the blocks
4 for *similar* lines; the best-matching pair (if any) is used as a
5 synch point, and intraline difference marking is done on the
6 similar pair. Lots of work, but often worth it.
7
8 Example:
9
10 >>> d = Differ()
11 >>> results = d._fancy_replace(['abcDefghiJkl\n'], 0, 1,
12 ... ['abcdefGhijkl\n'], 0, 1)
13 >>> print(''.join(results), end="")
14 - abcDefghiJkl
15 ? ^ ^ ^
16 + abcdefGhijkl
17 ? ^ ^ ^
18 """
19
20 # don't synch up unless the lines have a similarity score of at
21 # least cutoff; best_ratio tracks the best score seen so far
22 best_ratio, cutoff = 0.74, 0.75
23 cruncher = SequenceMatcher(self.charjunk)
24 eqi, eqj = None, None # 1st indices of equal lines (if any)
25
26 # search for the pair that matches best without being identical
27 # (identical lines must be junk lines, & we don't want to synch up
28 # on junk -- unless we have to)
29 for j in range(blo, bhi):
30 bj = b[j]
31 cruncher.set_seq2(bj)
32 for i in range(alo, ahi):
33 ai = a[i]
34 if ai == bj:
35 if eqi is None:
36 eqi, eqj = i, j
37 continue
38 cruncher.set_seq1(ai)
39 # computing similarity is expensive, so use the quick
40 # upper bounds first -- have seen this speed up messy
41 # compares by a factor of 3.
42 # note that ratio() is only expensive to compute the first
43 # time it's called on a sequence pair; the expensive part
44 # of the computation is cached by cruncher
45 if cruncher.real_quick_ratio() > best_ratio and \
46 cruncher.quick_ratio() > best_ratio and \
47 cruncher.ratio() > best_ratio:
48 best_ratio, best_i, best_j = cruncher.ratio(), i, j
49 if best_ratio < cutoff:
50 # no non-identical "pretty close" pair
51 if eqi is None:
52 # no identical pair either -- treat it as a straight replace
53 yield from self._plain_replace(a, alo, ahi, b, blo, bhi)
54 return
55 # no close pair, but an identical pair -- synch up on that
56 best_i, best_j, best_ratio = eqi, eqj, 1.0
57 else:
58 # there's a close pair, so forget the identical pair (if any)
59 eqi = None
60
61 # a[best_i] very similar to b[best_j]; eqi is None iff they're not
62 # identical
63
64 # pump out diffs from before the synch point
65 yield from self._fancy_helper(a, alo, best_i, b, blo, best_j)
66
67 # do intraline marking on the synch pair
68 aelt, belt = a[best_i], b[best_j]
69 if eqi is None:
70 # pump out a '-', '?', '+', '?' quad for the synched lines
71 atags = btags = ""
72 cruncher.set_seqs(aelt, belt)
73 for tag, ai1, ai2, bj1, bj2 in cruncher.get_opcodes():
74 la, lb = ai2 - ai1, bj2 - bj1
75 if tag == 'replace':
76 atags += '^' * la
77 btags += '^' * lb
78 elif tag == 'delete':
79 atags += '-' * la
80 elif tag == 'insert':
81 btags += '+' * lb
82 elif tag == 'equal':
83 atags += ' ' * la
84 btags += ' ' * lb
85 else:
86 raise ValueError('unknown tag %r' % (tag,))
87 yield from self._qformat(aelt, belt, atags, btags)
88 else:
89 # the synch pair is identical
90 yield ' ' + aelt
91
92 # pump out diffs from after the synch point
93 yield from self._fancy_helper(a, best_i+1, ahi, b, best_j+1, bhi)
Path 6: 4 calls (0.04)
['line 0', '1234567890123456789012345689012345', 'line 1', 'line 2', 'line 3', 'line 4 changed', 'line 5 changed', 'line 6 changed', 'line 7', '...
11 (3) 0 (1)
13 (3) 1 (1)
['line 0', '1234567890123456789012345689012345', 'line 1', 'line 2 added', 'line 3', 'line 4 chanGEd', 'line 5a chanGed', 'line 6a changEd', 'l...
11 (3) 0 (1)
13 (3) 1 (1)
'- 1234567890123456789012345689012345' (3) '- short line' (3) '+ 1234567890' (3) '+ another long line that needs to be wrapped' (3) '- 2' (1) '+ 3' (1...
None (4)
1def _fancy_replace(self, a, alo, ahi, b, blo, bhi):
2 r"""
3 When replacing one block of lines with another, search the blocks
4 for *similar* lines; the best-matching pair (if any) is used as a
5 synch point, and intraline difference marking is done on the
6 similar pair. Lots of work, but often worth it.
7
8 Example:
9
10 >>> d = Differ()
11 >>> results = d._fancy_replace(['abcDefghiJkl\n'], 0, 1,
12 ... ['abcdefGhijkl\n'], 0, 1)
13 >>> print(''.join(results), end="")
14 - abcDefghiJkl
15 ? ^ ^ ^
16 + abcdefGhijkl
17 ? ^ ^ ^
18 """
19
20 # don't synch up unless the lines have a similarity score of at
21 # least cutoff; best_ratio tracks the best score seen so far
22 best_ratio, cutoff = 0.74, 0.75
23 cruncher = SequenceMatcher(self.charjunk)
24 eqi, eqj = None, None # 1st indices of equal lines (if any)
25
26 # search for the pair that matches best without being identical
27 # (identical lines must be junk lines, & we don't want to synch up
28 # on junk -- unless we have to)
29 for j in range(blo, bhi):
30 bj = b[j]
31 cruncher.set_seq2(bj)
32 for i in range(alo, ahi):
33 ai = a[i]
34 if ai == bj:
35 if eqi is None:
36 eqi, eqj = i, j
37 continue
38 cruncher.set_seq1(ai)
39 # computing similarity is expensive, so use the quick
40 # upper bounds first -- have seen this speed up messy
41 # compares by a factor of 3.
42 # note that ratio() is only expensive to compute the first
43 # time it's called on a sequence pair; the expensive part
44 # of the computation is cached by cruncher
45 if cruncher.real_quick_ratio() > best_ratio and \
46 cruncher.quick_ratio() > best_ratio and \
47 cruncher.ratio() > best_ratio:
48 best_ratio, best_i, best_j = cruncher.ratio(), i, j
49 if best_ratio < cutoff:
50 # no non-identical "pretty close" pair
51 if eqi is None:
52 # no identical pair either -- treat it as a straight replace
53 yield from self._plain_replace(a, alo, ahi, b, blo, bhi)
54 return
55 # no close pair, but an identical pair -- synch up on that
56 best_i, best_j, best_ratio = eqi, eqj, 1.0
57 else:
58 # there's a close pair, so forget the identical pair (if any)
59 eqi = None
60
61 # a[best_i] very similar to b[best_j]; eqi is None iff they're not
62 # identical
63
64 # pump out diffs from before the synch point
65 yield from self._fancy_helper(a, alo, best_i, b, blo, best_j)
66
67 # do intraline marking on the synch pair
68 aelt, belt = a[best_i], b[best_j]
69 if eqi is None:
70 # pump out a '-', '?', '+', '?' quad for the synched lines
71 atags = btags = ""
72 cruncher.set_seqs(aelt, belt)
73 for tag, ai1, ai2, bj1, bj2 in cruncher.get_opcodes():
74 la, lb = ai2 - ai1, bj2 - bj1
75 if tag == 'replace':
76 atags += '^' * la
77 btags += '^' * lb
78 elif tag == 'delete':
79 atags += '-' * la
80 elif tag == 'insert':
81 btags += '+' * lb
82 elif tag == 'equal':
83 atags += ' ' * la
84 btags += ' ' * lb
85 else:
86 raise ValueError('unknown tag %r' % (tag,))
87 yield from self._qformat(aelt, belt, atags, btags)
88 else:
89 # the synch pair is identical
90 yield ' ' + aelt
91
92 # pump out diffs from after the synch point
93 yield from self._fancy_helper(a, best_i+1, ahi, b, best_j+1, bhi)
Path 7: 1 calls (0.01)
['\tI am a buggy'] (1)
0 (1)
1 (1)
['\t\tI am a bug'] (1)
0 (1)
1 (1)
'- \tI am a buggy' (1) '? \t --\n' (1) '+ \t\tI am a bug' (1) '? +\n' (1) None (1)
1def _fancy_replace(self, a, alo, ahi, b, blo, bhi):
2 r"""
3 When replacing one block of lines with another, search the blocks
4 for *similar* lines; the best-matching pair (if any) is used as a
5 synch point, and intraline difference marking is done on the
6 similar pair. Lots of work, but often worth it.
7
8 Example:
9
10 >>> d = Differ()
11 >>> results = d._fancy_replace(['abcDefghiJkl\n'], 0, 1,
12 ... ['abcdefGhijkl\n'], 0, 1)
13 >>> print(''.join(results), end="")
14 - abcDefghiJkl
15 ? ^ ^ ^
16 + abcdefGhijkl
17 ? ^ ^ ^
18 """
19
20 # don't synch up unless the lines have a similarity score of at
21 # least cutoff; best_ratio tracks the best score seen so far
22 best_ratio, cutoff = 0.74, 0.75
23 cruncher = SequenceMatcher(self.charjunk)
24 eqi, eqj = None, None # 1st indices of equal lines (if any)
25
26 # search for the pair that matches best without being identical
27 # (identical lines must be junk lines, & we don't want to synch up
28 # on junk -- unless we have to)
29 for j in range(blo, bhi):
30 bj = b[j]
31 cruncher.set_seq2(bj)
32 for i in range(alo, ahi):
33 ai = a[i]
34 if ai == bj:
35 if eqi is None:
36 eqi, eqj = i, j
37 continue
38 cruncher.set_seq1(ai)
39 # computing similarity is expensive, so use the quick
40 # upper bounds first -- have seen this speed up messy
41 # compares by a factor of 3.
42 # note that ratio() is only expensive to compute the first
43 # time it's called on a sequence pair; the expensive part
44 # of the computation is cached by cruncher
45 if cruncher.real_quick_ratio() > best_ratio and \
46 cruncher.quick_ratio() > best_ratio and \
47 cruncher.ratio() > best_ratio:
48 best_ratio, best_i, best_j = cruncher.ratio(), i, j
49 if best_ratio < cutoff:
50 # no non-identical "pretty close" pair
51 if eqi is None:
52 # no identical pair either -- treat it as a straight replace
53 yield from self._plain_replace(a, alo, ahi, b, blo, bhi)
54 return
55 # no close pair, but an identical pair -- synch up on that
56 best_i, best_j, best_ratio = eqi, eqj, 1.0
57 else:
58 # there's a close pair, so forget the identical pair (if any)
59 eqi = None
60
61 # a[best_i] very similar to b[best_j]; eqi is None iff they're not
62 # identical
63
64 # pump out diffs from before the synch point
65 yield from self._fancy_helper(a, alo, best_i, b, blo, best_j)
66
67 # do intraline marking on the synch pair
68 aelt, belt = a[best_i], b[best_j]
69 if eqi is None:
70 # pump out a '-', '?', '+', '?' quad for the synched lines
71 atags = btags = ""
72 cruncher.set_seqs(aelt, belt)
73 for tag, ai1, ai2, bj1, bj2 in cruncher.get_opcodes():
74 la, lb = ai2 - ai1, bj2 - bj1
75 if tag == 'replace':
76 atags += '^' * la
77 btags += '^' * lb
78 elif tag == 'delete':
79 atags += '-' * la
80 elif tag == 'insert':
81 btags += '+' * lb
82 elif tag == 'equal':
83 atags += ' ' * la
84 btags += ' ' * lb
85 else:
86 raise ValueError('unknown tag %r' % (tag,))
87 yield from self._qformat(aelt, belt, atags, btags)
88 else:
89 # the synch pair is identical
90 yield ' ' + aelt
91
92 # pump out diffs from after the synch point
93 yield from self._fancy_helper(a, best_i+1, ahi, b, best_j+1, bhi)
Path 8: 1 calls (0.01)
['', ' 1. Beautiful is beTTer than ugly.', ' 2. Explicit is better than ımplıcıt.', ' 3. Simple is better than complex.', ' 4. Complex is bett...
1 (1)
5 (1)
['', ' 1. Beautiful is better than ügly.', ' 3. Sımple is better than complex.', ' 4. Complicated is better than cömplex.', ' 5. Flat is bet...
1 (1)
5 (1)
'? ^^ ^\n' (2) '- 1. Beautiful is beTTer than ugly.' (1) '+ 1. Beautiful is better than ügly.' (1) '- 2. Explicit...
1def _fancy_replace(self, a, alo, ahi, b, blo, bhi):
2 r"""
3 When replacing one block of lines with another, search the blocks
4 for *similar* lines; the best-matching pair (if any) is used as a
5 synch point, and intraline difference marking is done on the
6 similar pair. Lots of work, but often worth it.
7
8 Example:
9
10 >>> d = Differ()
11 >>> results = d._fancy_replace(['abcDefghiJkl\n'], 0, 1,
12 ... ['abcdefGhijkl\n'], 0, 1)
13 >>> print(''.join(results), end="")
14 - abcDefghiJkl
15 ? ^ ^ ^
16 + abcdefGhijkl
17 ? ^ ^ ^
18 """
19
20 # don't synch up unless the lines have a similarity score of at
21 # least cutoff; best_ratio tracks the best score seen so far
22 best_ratio, cutoff = 0.74, 0.75
23 cruncher = SequenceMatcher(self.charjunk)
24 eqi, eqj = None, None # 1st indices of equal lines (if any)
25
26 # search for the pair that matches best without being identical
27 # (identical lines must be junk lines, & we don't want to synch up
28 # on junk -- unless we have to)
29 for j in range(blo, bhi):
30 bj = b[j]
31 cruncher.set_seq2(bj)
32 for i in range(alo, ahi):
33 ai = a[i]
34 if ai == bj:
35 if eqi is None:
36 eqi, eqj = i, j
37 continue
38 cruncher.set_seq1(ai)
39 # computing similarity is expensive, so use the quick
40 # upper bounds first -- have seen this speed up messy
41 # compares by a factor of 3.
42 # note that ratio() is only expensive to compute the first
43 # time it's called on a sequence pair; the expensive part
44 # of the computation is cached by cruncher
45 if cruncher.real_quick_ratio() > best_ratio and \
46 cruncher.quick_ratio() > best_ratio and \
47 cruncher.ratio() > best_ratio:
48 best_ratio, best_i, best_j = cruncher.ratio(), i, j
49 if best_ratio < cutoff:
50 # no non-identical "pretty close" pair
51 if eqi is None:
52 # no identical pair either -- treat it as a straight replace
53 yield from self._plain_replace(a, alo, ahi, b, blo, bhi)
54 return
55 # no close pair, but an identical pair -- synch up on that
56 best_i, best_j, best_ratio = eqi, eqj, 1.0
57 else:
58 # there's a close pair, so forget the identical pair (if any)
59 eqi = None
60
61 # a[best_i] very similar to b[best_j]; eqi is None iff they're not
62 # identical
63
64 # pump out diffs from before the synch point
65 yield from self._fancy_helper(a, alo, best_i, b, blo, best_j)
66
67 # do intraline marking on the synch pair
68 aelt, belt = a[best_i], b[best_j]
69 if eqi is None:
70 # pump out a '-', '?', '+', '?' quad for the synched lines
71 atags = btags = ""
72 cruncher.set_seqs(aelt, belt)
73 for tag, ai1, ai2, bj1, bj2 in cruncher.get_opcodes():
74 la, lb = ai2 - ai1, bj2 - bj1
75 if tag == 'replace':
76 atags += '^' * la
77 btags += '^' * lb
78 elif tag == 'delete':
79 atags += '-' * la
80 elif tag == 'insert':
81 btags += '+' * lb
82 elif tag == 'equal':
83 atags += ' ' * la
84 btags += ' ' * lb
85 else:
86 raise ValueError('unknown tag %r' % (tag,))
87 yield from self._qformat(aelt, belt, atags, btags)
88 else:
89 # the synch pair is identical
90 yield ' ' + aelt
91
92 # pump out diffs from after the synch point
93 yield from self._fancy_helper(a, best_i+1, ahi, b, best_j+1, bhi)
Path 9: 1 calls (0.01)
[' 1. Beautiful is better than ugly.\n', ' 2. Explicit is better than implicit.\n', ' 3. Simple is better than complex.\n', ' 4. Complex is better...
3 (1)
4 (1)
[' 1. Beautiful is better than ugly.\n', ' 3. Simple is better than complex.\n', ' 4. Complicated is better than complex.\n', ' 5. Flat is bette...
2 (1)
4 (1)
'- 4. Complex is better than complicated.\n' (1) '? ^ ---- ^\n' (1) '+ 4. Complicated is better than complex.\n' (1...
1def _fancy_replace(self, a, alo, ahi, b, blo, bhi):
2 r"""
3 When replacing one block of lines with another, search the blocks
4 for *similar* lines; the best-matching pair (if any) is used as a
5 synch point, and intraline difference marking is done on the
6 similar pair. Lots of work, but often worth it.
7
8 Example:
9
10 >>> d = Differ()
11 >>> results = d._fancy_replace(['abcDefghiJkl\n'], 0, 1,
12 ... ['abcdefGhijkl\n'], 0, 1)
13 >>> print(''.join(results), end="")
14 - abcDefghiJkl
15 ? ^ ^ ^
16 + abcdefGhijkl
17 ? ^ ^ ^
18 """
19
20 # don't synch up unless the lines have a similarity score of at
21 # least cutoff; best_ratio tracks the best score seen so far
22 best_ratio, cutoff = 0.74, 0.75
23 cruncher = SequenceMatcher(self.charjunk)
24 eqi, eqj = None, None # 1st indices of equal lines (if any)
25
26 # search for the pair that matches best without being identical
27 # (identical lines must be junk lines, & we don't want to synch up
28 # on junk -- unless we have to)
29 for j in range(blo, bhi):
30 bj = b[j]
31 cruncher.set_seq2(bj)
32 for i in range(alo, ahi):
33 ai = a[i]
34 if ai == bj:
35 if eqi is None:
36 eqi, eqj = i, j
37 continue
38 cruncher.set_seq1(ai)
39 # computing similarity is expensive, so use the quick
40 # upper bounds first -- have seen this speed up messy
41 # compares by a factor of 3.
42 # note that ratio() is only expensive to compute the first
43 # time it's called on a sequence pair; the expensive part
44 # of the computation is cached by cruncher
45 if cruncher.real_quick_ratio() > best_ratio and \
46 cruncher.quick_ratio() > best_ratio and \
47 cruncher.ratio() > best_ratio:
48 best_ratio, best_i, best_j = cruncher.ratio(), i, j
49 if best_ratio < cutoff:
50 # no non-identical "pretty close" pair
51 if eqi is None:
52 # no identical pair either -- treat it as a straight replace
53 yield from self._plain_replace(a, alo, ahi, b, blo, bhi)
54 return
55 # no close pair, but an identical pair -- synch up on that
56 best_i, best_j, best_ratio = eqi, eqj, 1.0
57 else:
58 # there's a close pair, so forget the identical pair (if any)
59 eqi = None
60
61 # a[best_i] very similar to b[best_j]; eqi is None iff they're not
62 # identical
63
64 # pump out diffs from before the synch point
65 yield from self._fancy_helper(a, alo, best_i, b, blo, best_j)
66
67 # do intraline marking on the synch pair
68 aelt, belt = a[best_i], b[best_j]
69 if eqi is None:
70 # pump out a '-', '?', '+', '?' quad for the synched lines
71 atags = btags = ""
72 cruncher.set_seqs(aelt, belt)
73 for tag, ai1, ai2, bj1, bj2 in cruncher.get_opcodes():
74 la, lb = ai2 - ai1, bj2 - bj1
75 if tag == 'replace':
76 atags += '^' * la
77 btags += '^' * lb
78 elif tag == 'delete':
79 atags += '-' * la
80 elif tag == 'insert':
81 btags += '+' * lb
82 elif tag == 'equal':
83 atags += ' ' * la
84 btags += ' ' * lb
85 else:
86 raise ValueError('unknown tag %r' % (tag,))
87 yield from self._qformat(aelt, belt, atags, btags)
88 else:
89 # the synch pair is identical
90 yield ' ' + aelt
91
92 # pump out diffs from after the synch point
93 yield from self._fancy_helper(a, best_i+1, ahi, b, best_j+1, bhi)