Skip to content

gh-134580: Modernizing difflib.HtmlDiff for HTML Output #134581

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
May 28, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions Doc/whatsnew/3.15.rst
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,13 @@ New modules
Improved modules
================

difflib
-------

* Improved the styling of HTML diff pages generated by the :class:`difflib.HtmlDiff`
class, and migrated the output to the HTML5 standard.
(Contributed by Jiahao Li in :gh:`134580`.)

ssl
---

Expand Down
50 changes: 36 additions & 14 deletions Lib/difflib.py
Original file line number Diff line number Diff line change
Expand Up @@ -1615,16 +1615,13 @@ def _line_pair_iterator():


_file_template = """
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html>
<!DOCTYPE html>
<html lang="en">
<head>
<meta http-equiv="Content-Type"
content="text/html; charset=%(charset)s" />
<title></title>
<style type="text/css">%(styles)s
<meta charset="%(charset)s">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Diff comparison</title>
<style>%(styles)s
</style>
</head>
Expand All @@ -1636,20 +1633,45 @@ def _line_pair_iterator():

_styles = """
:root {color-scheme: light dark}
table.diff {font-family: Menlo, Consolas, Monaco, Liberation Mono, Lucida Console, monospace; border:medium}
.diff_header {background-color:#e0e0e0}
td.diff_header {text-align:right}
.diff_next {background-color:#c0c0c0}
table.diff {
font-family: Menlo, Consolas, Monaco, Liberation Mono, Lucida Console, monospace;
border: medium;
}
.diff_header {
background-color: #e0e0e0;
font-weight: bold;
}
td.diff_header {
text-align: right;
padding: 0 8px;
}
.diff_next {
background-color: #c0c0c0;
padding: 4px 0;
}
.diff_add {background-color:palegreen}
.diff_chg {background-color:#ffff77}
.diff_sub {background-color:#ffaaaa}
table.diff[summary="Legends"] {
margin-top: 20px;
border: 1px solid #ccc;
}
table.diff[summary="Legends"] th {
background-color: #e0e0e0;
padding: 4px 8px;
}
table.diff[summary="Legends"] td {
padding: 4px 8px;
}
@media (prefers-color-scheme: dark) {
.diff_header {background-color:#666}
.diff_next {background-color:#393939}
.diff_add {background-color:darkgreen}
.diff_chg {background-color:#847415}
.diff_sub {background-color:darkred}
table.diff[summary="Legends"] {border-color:#555}
table.diff[summary="Legends"] th{background-color:#666}
}"""

_table_template = """
Expand Down Expand Up @@ -1692,7 +1714,7 @@ class HtmlDiff(object):
make_table -- generates HTML for a single side by side table
make_file -- generates complete HTML file with a single side by side table
See tools/scripts/diff.py for an example usage of this class.
See Doc/includes/diff.py for an example usage of this class.
"""

_file_template = _file_template
Expand Down
6 changes: 3 additions & 3 deletions Lib/test/test_difflib.py
Original file line number Diff line number Diff line change
Expand Up @@ -255,21 +255,21 @@ def test_make_file_default_charset(self):
html_diff = difflib.HtmlDiff()
output = html_diff.make_file(patch914575_from1.splitlines(),
patch914575_to1.splitlines())
self.assertIn('content="text/html; charset=utf-8"', output)
self.assertIn('charset="utf-8"', output)

def test_make_file_iso88591_charset(self):
html_diff = difflib.HtmlDiff()
output = html_diff.make_file(patch914575_from1.splitlines(),
patch914575_to1.splitlines(),
charset='iso-8859-1')
self.assertIn('content="text/html; charset=iso-8859-1"', output)
self.assertIn('charset="iso-8859-1"', output)

def test_make_file_usascii_charset_with_nonascii_input(self):
html_diff = difflib.HtmlDiff()
output = html_diff.make_file(patch914575_nonascii_from1.splitlines(),
patch914575_nonascii_to1.splitlines(),
charset='us-ascii')
self.assertIn('content="text/html; charset=us-ascii"', output)
self.assertIn('charset="us-ascii"', output)
self.assertIn('&#305;mpl&#305;c&#305;t', output)

class TestDiffer(unittest.TestCase):
Expand Down
48 changes: 35 additions & 13 deletions Lib/test/test_difflib_expect.html
Original file line number Diff line number Diff line change
@@ -1,29 +1,51 @@

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html>

<!DOCTYPE html>
<html lang="en">
<head>
<meta http-equiv="Content-Type"
content="text/html; charset=utf-8" />
<title></title>
<style type="text/css">
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Diff comparison</title>
<style>
:root {color-scheme: light dark}
table.diff {font-family: Menlo, Consolas, Monaco, Liberation Mono, Lucida Console, monospace; border:medium}
.diff_header {background-color:#e0e0e0}
td.diff_header {text-align:right}
.diff_next {background-color:#c0c0c0}
table.diff {
font-family: Menlo, Consolas, Monaco, Liberation Mono, Lucida Console, monospace;
border: medium;
}
.diff_header {
background-color: #e0e0e0;
font-weight: bold;
}
td.diff_header {
text-align: right;
padding: 0 8px;
}
.diff_next {
background-color: #c0c0c0;
padding: 4px 0;
}
.diff_add {background-color:palegreen}
.diff_chg {background-color:#ffff77}
.diff_sub {background-color:#ffaaaa}
table.diff[summary="Legends"] {
margin-top: 20px;
border: 1px solid #ccc;
}
table.diff[summary="Legends"] th {
background-color: #e0e0e0;
padding: 4px 8px;
}
table.diff[summary="Legends"] td {
padding: 4px 8px;
}

@media (prefers-color-scheme: dark) {
.diff_header {background-color:#666}
.diff_next {background-color:#393939}
.diff_add {background-color:darkgreen}
.diff_chg {background-color:#847415}
.diff_sub {background-color:darkred}
table.diff[summary="Legends"] {border-color:#555}
table.diff[summary="Legends"] th{background-color:#666}
}
</style>
</head>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
Improved the styling of HTML diff pages generated by the
:class:`difflib.HtmlDiff` class, and migrated the output to the HTML5
standard.
Loading