Skip to content

gh-118150: difflib: expose autojunk flag from SequenceMatcher to public methods and functions#153959

Open
faithlesstomas wants to merge 9 commits into
python:mainfrom
faithlesstomas:gh-118150-expose-autojunk
Open

gh-118150: difflib: expose autojunk flag from SequenceMatcher to public methods and functions#153959
faithlesstomas wants to merge 9 commits into
python:mainfrom
faithlesstomas:gh-118150-expose-autojunk

Conversation

@faithlesstomas

@faithlesstomas faithlesstomas commented Jul 18, 2026

Copy link
Copy Markdown

Until now difflib methods and functions took SequenceMatcher class kwarg autojunk by default which is set up to be True in this class.. This PR aims to expose this flag to the public methods and functions of this module, in order that user can choose behavior of this option in SequenceMatcher.

Issue: #118150
Related PR: #153892

@python-cla-bot

python-cla-bot Bot commented Jul 18, 2026

Copy link
Copy Markdown

All commit authors signed the Contributor License Agreement.

CLA signed

@bedevere-app

bedevere-app Bot commented Jul 18, 2026

Copy link
Copy Markdown

Most changes to Python require a NEWS entry. Add one using the blurb_it web app or the blurb command-line tool.

If this change has little impact on Python users, wait for a maintainer to apply the skip news label instead.

@faithlesstomas

faithlesstomas commented Jul 18, 2026

Copy link
Copy Markdown
Author

Quick check if this works for the original issue test:

 #!/usr/bin/python3                                                                                                                                                          
                                                                                                                                                                              
  import difflib                                                                                                                                                              
                                                                                                                                                                              
  def get_lines(filename):                                                                                                                                                    
      with open(filename, 'r', encoding='utf8') as fd:                                                                                                                        
          return fd.readlines()                                                                                                                                               
                                                                                                                                                                              
  for autojunk in (True, False):                                                                                                                                              
                                                                                                                                                                              
      old_new = list(difflib.unified_diff(                                                                                                                                    
          get_lines('small.external.old.json'),                                                                                                                               
          get_lines('small.external.new.json'),                                                                                                                               
          autojunk=autojunk                                                                                                                                                   
      ))                                                                                                                                                                      
      new_old = list(difflib.unified_diff(                                                                                                                                    
          get_lines('small.external.new.json'),                                                                                                                               
          get_lines('small.external.old.json'),                                                                                                                               
          autojunk=autojunk                                                                                                                                                   
      ))                                                                                                                                                                      
                                                                                                                                                                              
      print('Autojunk flag:', autojunk)                                                                                                                                       
      print('diff external.old external.new.json | wc -l')                                                                                                                    
      print(len(old_new))                                                                                                                                                     
      print('diff external.new external.old.json | wc -l')                                                                                                                    
      print(len(new_old))                                                                                                                                                     
Autojunk flag: True
diff external.old external.new.json | wc -l
90
diff -u external.new external.old.json | wc -l
25
Autojunk flag: False
diff external.old external.new.json | wc -l
25
diff -u external.new external.old.json | wc -l
25

#118150 (comment)

@faithlesstomas faithlesstomas changed the title difflib: expose autojunk flag from SequenceMatcher to public methods and functions gh-118150: difflib: expose autojunk flag from SequenceMatcher to public methods and functions Jul 18, 2026
@Lenormju

Copy link
Copy Markdown
Contributor

I think the Documentation (Doc/library/difflib.rst) should get updated too to include this new parameter.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@faithlesstomas you should review this file, it seems to have been very badly AI-generated.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Lenormju I wouldn't have thought that my bad English could be considered to be AI generated :) Do you have any specific suggestion what should be improved in this description?

BTW, nothing in this PR was AI generated.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@faithlesstomas The commit was titled difflib - fix NEWS issue with ref. not found which I found strange that a human would commit "ref. not found". Also the NEWS file contain these comments :

# # Uncomment one of these "section:" lines to specify which section # this
entry should go in in Misc/NEWS.d. # #.. section: Security #.. section: Core
and Builtins #.. section: Library #.. section: Documentation #.. section:
Tests #.. section: Build #.. section: Windows #.. section: macOS #..
section: IDLE #.. section: Tools/Demos #.. section: C API

# Write your Misc/NEWS.d entry below.  It should be a simple ReST paragraph.
# Don't start with "- Issue #<n>: " or "- gh-issue-<n>: " or that sort of
stuff.
###########################################################################

Which look like a template you did not erase.

I was not basing myself on the English, instead on all the rest. But if it wasn't, sorry.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Lenormju Sorry, that was my mistake - I thought this comment is to be left there. Also I didn't know how properly reference a class in ReST... But besides that, does this PR look good now?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The blurb CLI uses .. section: Library to decide which directory to put the news file, in this case it's already in Misc/NEWS.d/next/Library/ as expected.

Please remove .. section: Library and dedent the next paragraph. News files are usually fairly short, often just a line or two, so we could do the same here.

See some other examples in https://github.com/python/cpython/tree/main/Misc/NEWS.d/next/Library

Please also add a What's New entry to https://github.com/python/cpython/blob/main/Doc/whatsnew/3.16.rst, this can be a bit longer if needed.

@hugovk hugovk left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please could you add tests to Lib/test/test_difflib.py?

build-ubuntu-ssltests,
test-hypothesis,
cifuzz,
cifuzz

@hugovk hugovk Jul 24, 2026

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What's this change for?

Suggested change
cifuzz
cifuzz,

Comment thread Lib/difflib.py


def get_close_matches(word, possibilities, n=3, cutoff=0.6):
def get_close_matches(word, possibilities, n=3, cutoff=0.6, autojunk=True):

@hugovk hugovk Jul 24, 2026

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shall we make this keyword only? It can be useful as the list gets longer, and especially for Booleans.

Suggested change
def get_close_matches(word, possibilities, n=3, cutoff=0.6, autojunk=True):
def get_close_matches(word, possibilities, n=3, cutoff=0.6, *, autojunk=True):

Also update the docstring.

Comment thread Lib/difflib.py
"""

def __init__(self, linejunk=None, charjunk=None):
def __init__(self, linejunk=None, charjunk=None, autojunk=True):

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And here?

Suggested change
def __init__(self, linejunk=None, charjunk=None, autojunk=True):
def __init__(self, linejunk=None, charjunk=None, *, autojunk=True):

Comment thread Lib/difflib.py

def unified_diff(a, b, fromfile='', tofile='', fromfiledate='',
tofiledate='', n=3, lineterm='\n', *, color=False):
tofiledate='', n=3, lineterm='\n', *, color=False, autojunk=True):

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These are already keyword-only, and don't have any special order, so could alphabetise? If so, update docstring to match.

Suggested change
tofiledate='', n=3, lineterm='\n', *, color=False, autojunk=True):
tofiledate='', n=3, lineterm='\n', *, autojunk=True, color=False):

Comment thread Lib/difflib.py
_check_types(a, b, fromfile, tofile, fromfiledate, tofiledate, lineterm)
started = False
for group in SequenceMatcher(None,a,b).get_grouped_opcodes(n):
for group in SequenceMatcher(None,a,b,autojunk=autojunk).get_grouped_opcodes(n):

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
for group in SequenceMatcher(None,a,b,autojunk=autojunk).get_grouped_opcodes(n):
for group in SequenceMatcher(None, a, b, autojunk=autojunk).get_grouped_opcodes(n):

Comment thread Lib/difflib.py
# See http://www.unix.org/single_unix_specification/
def context_diff(a, b, fromfile='', tofile='',
fromfiledate='', tofiledate='', n=3, lineterm='\n'):
fromfiledate='', tofiledate='', n=3, lineterm='\n', autojunk=True):

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And here?

Suggested change
fromfiledate='', tofiledate='', n=3, lineterm='\n', autojunk=True):
fromfiledate='', tofiledate='', n=3, lineterm='\n', *, autojunk=True):

Comment thread Lib/difflib.py
yield line.encode('ascii', 'surrogateescape')

def ndiff(a, b, linejunk=None, charjunk=IS_CHARACTER_JUNK):
def ndiff(a, b, linejunk=None, charjunk=IS_CHARACTER_JUNK, autojunk=True):

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
def ndiff(a, b, linejunk=None, charjunk=IS_CHARACTER_JUNK, autojunk=True):
def ndiff(a, b, linejunk=None, charjunk=IS_CHARACTER_JUNK, *, autojunk=True):

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The blurb CLI uses .. section: Library to decide which directory to put the news file, in this case it's already in Misc/NEWS.d/next/Library/ as expected.

Please remove .. section: Library and dedent the next paragraph. News files are usually fairly short, often just a line or two, so we could do the same here.

See some other examples in https://github.com/python/cpython/tree/main/Misc/NEWS.d/next/Library

Please also add a What's New entry to https://github.com/python/cpython/blob/main/Doc/whatsnew/3.16.rst, this can be a bit longer if needed.

Comment thread Lib/difflib.py
prefix = dict(insert='+ ', delete='- ', replace='! ', equal=' ')
started = False
for group in SequenceMatcher(None,a,b).get_grouped_opcodes(n):
for group in SequenceMatcher(None,a,b, autojunk=autojunk).get_grouped_opcodes(n):

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
for group in SequenceMatcher(None,a,b, autojunk=autojunk).get_grouped_opcodes(n):
for group in SequenceMatcher(None, a, b, autojunk=autojunk).get_grouped_opcodes(n):

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

Status: Todo

Development

Successfully merging this pull request may close these issues.

4 participants