Skip to content

Commit 17a5925

Browse files
committed
Issue 10534, difflib: tweak doc; test new SequenceMatcher instance attributes; avoid unneeded lists of SM.b2j keys and items in .__chain_b. Do not backport.
1 parent 50ba19e commit 17a5925

3 files changed

Lines changed: 28 additions & 9 deletions

File tree

Doc/library/difflib.rst

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -359,11 +359,11 @@ The :class:`SequenceMatcher` class has this constructor:
359359
The *autojunk* parameter.
360360

361361
SequenceMatcher objects get three data attributes: *bjunk* is the
362-
set of elements of b for which *isjunk* is True; *bpopular* is the set of non-
363-
junk elements considered popular by the heuristic (if it is not disabled);
364-
*b2j* is a dict mapping the remaining elements of b to a list of positions where
365-
they occur. All three are reset whenever *b* is reset with :meth:`set_seqs`
366-
or :meth:`set_seq2`.
362+
set of elements of *b* for which *isjunk* is True; *bpopular* is the set of
363+
non-junk elements considered popular by the heuristic (if it is not
364+
disabled); *b2j* is a dict mapping the remaining elements of *b* to a list
365+
of positions where they occur. All three are reset whenever *b* is reset
366+
with :meth:`set_seqs` or :meth:`set_seq2`.
367367

368368
.. versionadded:: 3.2
369369
The *bjunk* and *bpopular* attributes.

Lib/difflib.py

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -320,20 +320,22 @@ def __chain_b(self):
320320
self.bjunk = junk = set()
321321
isjunk = self.isjunk
322322
if isjunk:
323-
for elt in list(b2j.keys()): # using list() since b2j is modified
323+
for elt in b2j.keys():
324324
if isjunk(elt):
325325
junk.add(elt)
326-
del b2j[elt]
326+
for elt in junk: # separate loop avoids separate list of keys
327+
del b2j[elt]
327328

328329
# Purge popular elements that are not junk
329330
self.bpopular = popular = set()
330331
n = len(b)
331332
if self.autojunk and n >= 200:
332333
ntest = n // 100 + 1
333-
for elt, idxs in list(b2j.items()):
334+
for elt, idxs in b2j.items():
334335
if len(idxs) > ntest:
335336
popular.add(elt)
336-
del b2j[elt]
337+
for elt in popular: # ditto; as fast for 1% deletion
338+
del b2j[elt]
337339

338340
def isbjunk(self, item):
339341
"Deprecated; use 'item in SequenceMatcher().bjunk'."

Lib/test/test_difflib.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,12 +12,14 @@ def test_one_insert(self):
1212
self.assertEqual(list(sm.get_opcodes()),
1313
[ ('insert', 0, 0, 0, 1),
1414
('equal', 0, 100, 1, 101)])
15+
self.assertEqual(sm.bpopular, set())
1516
sm = difflib.SequenceMatcher(None, 'b' * 100, 'b' * 50 + 'a' + 'b' * 50)
1617
self.assertAlmostEqual(sm.ratio(), 0.995, places=3)
1718
self.assertEqual(list(sm.get_opcodes()),
1819
[ ('equal', 0, 50, 0, 50),
1920
('insert', 50, 50, 50, 51),
2021
('equal', 50, 100, 51, 101)])
22+
self.assertEqual(sm.bpopular, set())
2123

2224
def test_one_delete(self):
2325
sm = difflib.SequenceMatcher(None, 'a' * 40 + 'c' + 'b' * 40, 'a' * 40 + 'b' * 40)
@@ -27,6 +29,19 @@ def test_one_delete(self):
2729
('delete', 40, 41, 40, 40),
2830
('equal', 41, 81, 40, 80)])
2931

32+
def test_bjunk(self):
33+
sm = difflib.SequenceMatcher(isjunk=lambda x: x == ' ',
34+
a='a' * 40 + 'b' * 40, b='a' * 44 + 'b' * 40)
35+
self.assertEqual(sm.bjunk, set())
36+
37+
sm = difflib.SequenceMatcher(isjunk=lambda x: x == ' ',
38+
a='a' * 40 + 'b' * 40, b='a' * 44 + 'b' * 40 + ' ' * 20)
39+
self.assertEqual(sm.bjunk, {' '})
40+
41+
sm = difflib.SequenceMatcher(isjunk=lambda x: x in [' ', 'b'],
42+
a='a' * 40 + 'b' * 40, b='a' * 44 + 'b' * 40 + ' ' * 20)
43+
self.assertEqual(sm.bjunk, {' ', 'b'})
44+
3045

3146
class TestAutojunk(unittest.TestCase):
3247
"""Tests for the autojunk parameter added in 2.7"""
@@ -38,10 +53,12 @@ def test_one_insert_homogenous_sequence(self):
3853

3954
sm = difflib.SequenceMatcher(None, seq1, seq2)
4055
self.assertAlmostEqual(sm.ratio(), 0, places=3)
56+
self.assertEqual(sm.bpopular, {'b'})
4157

4258
# Now turn the heuristic off
4359
sm = difflib.SequenceMatcher(None, seq1, seq2, autojunk=False)
4460
self.assertAlmostEqual(sm.ratio(), 0.9975, places=3)
61+
self.assertEqual(sm.bpopular, set())
4562

4663

4764
class TestSFbugs(unittest.TestCase):

0 commit comments

Comments
 (0)