GV

GeezerVison

The World Wide Web, restored to 800 pixels of glory.

Home|About|Gaming cabinet|Archives|How it works|Starter sites

On this site

  • Sign in
  • ActionsCI/CD and automation
  • CodespacesCloud development environments
  • All Features
  • Documentation
  • Training
  • Certifications
  • Build with Copilot
  • Customize Copilot
  • Integrations
  • Trending repos
  • GitHub Sponsors
  • Developer articles
  • Enterprises

This view

  • Original page
  • New address

GeezerVison is showing github.com — difflib.HtmlDiff produces different output from difflib.ndiff · Issue #71896 · python/cpython

difflib.HtmlDiff produces different output from difflib.ndiff #71896

New issue
Copy link
New issue
Copy link
Closed
Closed
difflib.HtmlDiff produces different output from difflib.ndiff#71896
Copy link
Labels
sprintstdlibStandard Library Python modules in the Lib/ directoryStandard Library Python modules in the Lib/ directorytype-bugAn unexpected behavior, bug, or errorAn unexpected behavior, bug, or error

Description

SilentGhost
mannequin
opened on Aug 8, 2016
Issue body actions
BPO 27709
Nosy @loewis, @terryjreedy, @j, @tirkarthi

Note: these values reflect the state of the issue at the time it was migrated and might not reflect the current state.

Show more details

GitHub fields:

assignee = None
closed_at = None
created_at = <Date 2016-08-08.15:40:57.110>
labels = ['type-bug', 'library']
title = 'difflib.HtmlDiff produces different output from difflib.ndiff'
updated_at = <Date 2018-09-22.18:00:18.520>
user = 'https://bugs.python.org/SilentGhost'

bugs.python.org fields:

activity = <Date 2018-09-22.18:00:18.520>
actor = 'xtreak'
assignee = 'none'
closed = False
closed_date = None
closer = None
components = ['Library (Lib)']
creation = <Date 2016-08-08.15:40:57.110>
creator = 'SilentGhost'
dependencies = []
files = []
hgrepos = []
issue_num = 27709
keywords = ['patch']
message_count = 2.0
messages = ['272173', '272196']
nosy_count = 6.0
nosy_names = ['loewis', 'terry.reedy', 'eli.bendersky', 'SilentGhost', 'jlwing', 'xtreak']
pr_nums = []
priority = 'normal'
resolution = None
stage = 'needs patch'
status = 'open'
superseder = None
type = 'behavior'
url = 'https://bugs.python.org/issue27709'
versions = ['Python 3.5', 'Python 3.6']

Linked PRs

  • gh-71896: warn in doc about trailing newlines ignored by HtmlDiff #153930
  • [3.15] gh-71896: Add a docs warning about trailing newlines ignored by difflib.HtmlDiff (GH-153930) #153965
  • [3.14] gh-71896: Add a docs warning about trailing newlines ignored by difflib.HtmlDiff (GH-153930) #153966
  • [3.13] gh-71896: Add a docs warning about trailing newlines ignored by difflib.HtmlDiff (GH-153930) #153968

Activity

  1. SilentGhost commented on Aug 8, 2016

    @SilentGhost
    SilentGhostmannequin
    on Aug 8, 2016
    MannequinAuthor
    More actions

    msg264842 in bpo-26945 reports an odd results of HtmlDiff.make_file, digging into it I've noticed couple of things: different output to one generated directly from difflib.ndiff and underlying issue further up the stack that generates same faulty output with a slightly modified files.

    The patch I'm attaching fixes the issue with different outputs, from make_file and ndiff, by not removing EOL characters, I had to re-generate expected test output file.

  2. SilentGhost
    added
    stdlibStandard Library Python modules in the Lib/ directoryStandard Library Python modules in the Lib/ directory
    type-bugAn unexpected behavior, bug, or errorAn unexpected behavior, bug, or error
    on Aug 8, 2016
  3. SilentGhost commented on Aug 8, 2016

    @SilentGhost
    SilentGhostmannequin
    on Aug 8, 2016
    MannequinAuthor
    More actions

    The degenerate behaviour appears ultimately due to the autojunk heuristic. Given that autojunk defaults to True and there isn't any way to change via most user-facing functions, I don't think there is an easy resolution that can be found here. I'm going to withdraw the earlier patch, since it feels like a half-measure which enable correct behaviour by accident.

  4. ezio-melotti
    transferred this issue fromon Apr 10, 2022
  5. Lenormju commented on Jul 18, 2026

    @Lenormju
    Lenormju
    on Jul 18, 2026
    Contributor
    More actions

    As described in the #118150 issue and handled there, yes the autojunk behavior is surprising at times.
    But there is also another issue here (reproduced using 3.13, 3.14 and 3.15):

    import difflib
    
    A = ["same\n", "diffme\n"]
    B = ["same", "diffme\n"]   # line 0 differs only by trailing newline
    
    print(difflib.SequenceMatcher(None, A, B).get_opcodes())  # [('replace', 0, 1, 0, 1), ('equal', 1, 2, 1, 2)]
    print(list(difflib.ndiff(A, B)))  # ['- same\n', '?     -\n', '+ same', '  diffme\n']
    print(list(difflib.unified_diff(A, B, lineterm='')))  # [..., '-same\n', '+same', ' diffme\n']
    print(list(difflib.context_diff(A, B, lineterm='')))  # [..., '! same\n', ..., '! same', '  diffme\n']
    print(difflib.HtmlDiff().make_file(A, B))  # no line is marked as changed/added/removed (classes diff_add/diff_chg/diff_sub)
    
    A_stripped = [elem.rstrip() for elem in A]
    B_stripped = [elem.rstrip() for elem in B]
    
    print(difflib.SequenceMatcher(None, A_stripped, B_stripped).get_opcodes())  # [('equal', 0, 2, 0, 2)]
    print(list(difflib.ndiff(A_stripped, B_stripped)))  # ['  same', '  diffme']
    print(list(difflib.unified_diff(A_stripped, B_stripped, lineterm='')))  # []
    print(list(difflib.context_diff(A_stripped, B_stripped, lineterm='')))  # []
    print(difflib.HtmlDiff().make_file(A_stripped, B_stripped))  # still no line is marked as changed/added/removed

    The HtmlDiff is the only one that does end-of-line stripping from the whole difflib. To me, this is a bug because it hides actual differences.
    It is caused by the _tab_newline_replace method being called before _mdiff.

  6. Lenormju commented on Jul 18, 2026

    @Lenormju
    Lenormju
    on Jul 18, 2026
    Contributor
    More actions

    Petr Viktorin just told me we should NOT fix the issue (which dates back tot he original implementation in 2004, 22 years ago, cf e064b41). Instead, I will add a warning about it, and an automated test to prevent unexpected regression (if someone would fix the bug).

  7. ZeroIntensity
    added a commit that references this issue on Jul 18, 2026

    gh-71896: Add a docs warning about trailing newlines ignored by `diff…

    755d971
  8. ZeroIntensity
    added
    sprint
    on Jul 18, 2026
  9. github-project-automation
    added this to Sprinton Jul 18, 2026
  10. github-project-automation
    moved this to Todo in Sprinton Jul 18, 2026
  11. ZeroIntensity
    added 3 commits that reference this issue on Jul 18, 2026

    [3.15] gh-71896: Add a docs warning about trailing newlines ignored b…

    b6a140b

    [3.13] gh-71896: Add a docs warning about trailing newlines ignored b…

    75b6789

    [3.14] gh-71896: Add a docs warning about trailing newlines ignored b…

    1f3814f
  12. encukou
    closed this as completedon Aug 10, 2026
  13. github-project-automation
    moved this from Todo to Done in Sprinton Aug 10, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    sprintstdlibStandard Library Python modules in the Lib/ directoryStandard Library Python modules in the Lib/ directorytype-bugAn unexpected behavior, bug, or errorAn unexpected behavior, bug, or error

    Projects

    • Sprint
      Status
      Done
      Show more project fields

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions

    You are visitor 01402503 — GeezerVison does not store the pages you look up.
    Best viewed with Netscape Navigator 4.7 or Internet Explorer 6 at 800×600. No cookies required.