diff --git a/Lib/test/test_textwrap.py b/Lib/test/test_textwrap.py --- a/Lib/test/test_textwrap.py +++ b/Lib/test/test_textwrap.py @@ -636,16 +636,38 @@ def foo(): text = " \t hello there\n \t how are you?" self.assertEqual(expect, dedent(text)) text = " \thello there\n \t how are you?" expect = "hello there\n how are you?" self.assertEqual(expect, dedent(text)) + # dedent() should handle CRLF and CR line endings + def test_dedent_line_endings(self): + # test CRLF line endings + text = " Hello there.\r\n How are ya?\r\n Oh good." + expect = "Hello there.\r\nHow are ya?\r\nOh good." + self.assertEqual(expect, dedent(text)) + + # test CR line endings + text = " Hello there.\r How are ya?\r Oh good." + expect = "Hello there.\rHow are ya?\rOh good." + self.assertEqual(expect, dedent(text)) + + # test mixed line endings + text = " Hello there.\r\n How are ya?\r Oh,\n good." + expect = "Hello there.\r\nHow are ya?\rOh,\ngood." + self.assertEqual(expect, dedent(text)) + + # test mixed line endings with blank lines + text = " Hello\n \r\n \r there.\r\n" + expect = " Hello\n\r\n\rthere.\r\n" + self.assertEqual(expect, dedent(text)) + # Test textwrap.indent class IndentTestCase(unittest.TestCase): # The examples used for tests. If any of these change, the expected # results in the various test cases must also be updated. # The roundtrip cases are separate, because textwrap.dedent doesn't # handle Windows line endings ROUNDTRIP_CASES = ( diff --git a/Lib/textwrap.py b/Lib/textwrap.py --- a/Lib/textwrap.py +++ b/Lib/textwrap.py @@ -330,37 +330,34 @@ def fill(text, width=70, **kwargs): available keyword args to customize wrapping behaviour. """ w = TextWrapper(width=width, **kwargs) return w.fill(text) # -- Loosely related functionality ------------------------------------- -_whitespace_only_re = re.compile('^[ \t]+$', re.MULTILINE) -_leading_whitespace_re = re.compile('(^[ \t]*)(?:[^ \t\n])', re.MULTILINE) - def dedent(text): """Remove any common leading whitespace from every line in `text`. This can be used to make triple-quoted strings line up with the left edge of the display, while still presenting them in the source code in indented form. Note that tabs and spaces are both treated as whitespace, but they are not equal: the lines " hello" and "\thello" are considered to have no common leading whitespace. (This behaviour is new in Python 2.5; older versions of this module incorrectly expanded tabs before searching for common leading whitespace.) """ # Look for the longest leading string of spaces and tabs common to # all lines. margin = None - text = _whitespace_only_re.sub('', text) - indents = _leading_whitespace_re.findall(text) + indents = [line[:-len(line.lstrip())] for line in text.splitlines() if + line.strip()] for indent in indents: if margin is None: margin = indent # Current line more deeply indented than previous winner: # no change (previous winner is still on top). elif indent.startswith(margin): pass @@ -377,18 +374,19 @@ def dedent(text): break # sanity check (testing/debugging only) if 0 and margin: for line in text.split("\n"): assert not line or line.startswith(margin), \ "line = %r, margin = %r" % (line, margin) - if margin: - text = re.sub(r'(?m)^' + margin, '', text) + text = ''.join([line[len(margin):] if line.strip() else + line[len(line.splitlines()[0]):] for + line in (text+'\n').splitlines(True)])[:-1] return text def indent(text, prefix, predicate=None): """Adds 'prefix' to the beginning of selected lines in 'text'. If 'predicate' is provided, 'prefix' will only be added to the lines where 'predicate(line)' is True. If 'predicate' is not provided,