Skip to content

Commit

Permalink
pythongh-115801: Only allow sequence of strings as input for difflib.…
Browse files Browse the repository at this point in the history
…unified_diff (pythonGH-118333)
  • Loading branch information
eendebakpt authored and mrahtz committed Jun 30, 2024
1 parent 788b517 commit c793adb
Show file tree
Hide file tree
Showing 3 changed files with 31 additions and 6 deletions.
6 changes: 6 additions & 0 deletions Lib/difflib.py
Original file line number Diff line number Diff line change
Expand Up @@ -1264,6 +1264,12 @@ def _check_types(a, b, *args):
if b and not isinstance(b[0], str):
raise TypeError('lines to compare must be str, not %s (%r)' %
(type(b[0]).__name__, b[0]))
if isinstance(a, str):
raise TypeError('input must be a sequence of strings, not %s' %
type(a).__name__)
if isinstance(b, str):
raise TypeError('input must be a sequence of strings, not %s' %
type(b).__name__)
for arg in args:
if not isinstance(arg, str):
raise TypeError('all arguments must be str, not: %r' % (arg,))
Expand Down
30 changes: 24 additions & 6 deletions Lib/test/test_difflib.py
Original file line number Diff line number Diff line change
Expand Up @@ -295,7 +295,7 @@ def test_close_matches_aligned(self):

class TestOutputFormat(unittest.TestCase):
def test_tab_delimiter(self):
args = ['one', 'two', 'Original', 'Current',
args = [['one'], ['two'], 'Original', 'Current',
'2005-01-26 23:30:50', '2010-04-02 10:20:52']
ud = difflib.unified_diff(*args, lineterm='')
self.assertEqual(list(ud)[0:2], [
Expand All @@ -307,7 +307,7 @@ def test_tab_delimiter(self):
"--- Current\t2010-04-02 10:20:52"])

def test_no_trailing_tab_on_empty_filedate(self):
args = ['one', 'two', 'Original', 'Current']
args = [['one'], ['two'], 'Original', 'Current']
ud = difflib.unified_diff(*args, lineterm='')
self.assertEqual(list(ud)[0:2], ["--- Original", "+++ Current"])

Expand Down Expand Up @@ -447,6 +447,28 @@ def assertDiff(expect, actual):
lineterm=b'')
assertDiff(expect, actual)


class TestInputTypes(unittest.TestCase):
def _assert_type_error(self, msg, generator, *args):
with self.assertRaises(TypeError) as ctx:
list(generator(*args))
self.assertEqual(msg, str(ctx.exception))

def test_input_type_checks(self):
unified = difflib.unified_diff
context = difflib.context_diff

expect = "input must be a sequence of strings, not str"
self._assert_type_error(expect, unified, 'a', ['b'])
self._assert_type_error(expect, context, 'a', ['b'])

self._assert_type_error(expect, unified, ['a'], 'b')
self._assert_type_error(expect, context, ['a'], 'b')

expect = "lines to compare must be str, not NoneType (None)"
self._assert_type_error(expect, unified, ['a'], [None])
self._assert_type_error(expect, context, ['a'], [None])

def test_mixed_types_content(self):
# type of input content must be consistent: all str or all bytes
a = [b'hello']
Expand Down Expand Up @@ -495,10 +517,6 @@ def test_mixed_types_dates(self):
b = ['bar\n']
list(difflib.unified_diff(a, b, 'a', 'b', datea, dateb))

def _assert_type_error(self, msg, generator, *args):
with self.assertRaises(TypeError) as ctx:
list(generator(*args))
self.assertEqual(msg, str(ctx.exception))

class TestJunkAPIs(unittest.TestCase):
def test_is_line_junk_true(self):
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Raise ``TypeError`` when passing a string to :func:`difflib.unified_diff` and :func:`difflib.context_diff`.

0 comments on commit c793adb

Please sign in to comment.