From 17e9b515493d0cdb07480aab31f592c8bf040d29 Mon Sep 17 00:00:00 2001 From: Daira Hopwood Date: Mon, 19 Oct 2015 11:33:31 +0100 Subject: [PATCH 1/2] Allow tests to read/write files in binary mode, and to expect an error return from main. Signed-off-by: Daira Hopwood --- tests/utils.py | 36 +++++++++++++++++++++++++++--------- 1 file changed, 27 insertions(+), 9 deletions(-) diff --git a/tests/utils.py b/tests/utils.py index ed82bd3..ee2932f 100644 --- a/tests/utils.py +++ b/tests/utils.py @@ -1,5 +1,6 @@ from __future__ import absolute_import +import sys import os.path import tempfile import shutil @@ -7,7 +8,7 @@ from libmodernize.main import main as modernize_main -def check_on_input(input_content, expected_content, extra_flags = []): +def check_on_input(input_content, expected_content, extra_flags=[], mode="t"): """ Check that input_content is fixed to expected_content, idempotently. @@ -19,20 +20,23 @@ def check_on_input(input_content, expected_content, extra_flags = []): tmpdirname = tempfile.mkdtemp() try: test_input_name = os.path.join(tmpdirname, "input.py") - with open(test_input_name, "wt") as input_file: + with open(test_input_name, "w" + mode) as input_file: input_file.write(input_content) def _check(this_input_content, which_check): - modernize_main(extra_flags + ["-w", test_input_name]) + ret = modernize_main(extra_flags + ["-w", test_input_name]) + if ret != 0: + raise AssertionError("didn't expect to fail (returned %r)" % (ret,)) - output_content = "" - with open(test_input_name, "rt") as output_file: - for line in output_file: - if line: - output_content += line + with open(test_input_name, "r" + mode) as output_file: + if mode == "b": + output_content = output_file.read() + else: + output_content = "".join([line for line in output_file if line]) if output_content != expected_content: - raise AssertionError("%s\nInput:\n%sOutput:\n%s\nExpecting:\n%s" % + fmt = "%r" if mode == "b" else "%s" + raise AssertionError(("%s\nInput:\n"+fmt+"\nOutput:\n"+fmt+"\nExpecting:\n"+fmt) % (which_check, this_input_content, output_content, expected_content)) _check(input_content, "output check failed") @@ -40,3 +44,17 @@ def _check(this_input_content, which_check): _check(expected_content, "idempotence check failed") finally: shutil.rmtree(tmpdirname) + + +def expect_error(input_content, extra_flags=[], mode="t"): + tmpdirname = tempfile.mkdtemp() + try: + test_input_name = os.path.join(tmpdirname, "input.py") + with open(test_input_name, "w" + mode) as input_file: + input_file.write(input_content) + + ret = modernize_main(extra_flags + ["-w", test_input_name]) + if ret == 0: + raise AssertionError("didn't expect to succeed") + finally: + shutil.rmtree(tmpdirname) From 6b6341900ea80d27f7dada676e6f28f9058964d6 Mon Sep 17 00:00:00 2001 From: Daira Hopwood Date: Mon, 19 Oct 2015 11:37:47 +0100 Subject: [PATCH 2/2] Add options to override how line endings are written. fixes #121 Signed-off-by: Daira Hopwood --- docs/fixers.rst | 11 +++++++++++ libmodernize/main.py | 34 ++++++++++++++++++++++++++++++++++ tests/test_newlines.py | 30 ++++++++++++++++++++++++++++++ 3 files changed, 75 insertions(+) create mode 100644 tests/test_newlines.py diff --git a/docs/fixers.rst b/docs/fixers.rst index b2afd71..18fff04 100644 --- a/docs/fixers.rst +++ b/docs/fixers.rst @@ -39,6 +39,17 @@ using ``-f``/``--fix``. The ``--six-unicode`` and ``--future-unicode`` options also disable fixers that are not applicable for those options. +Options affecting all fixers +---------------------------- + +Normally, output files are written with the usual line endings for the platform +that python-modernize is run on (LF for Unix / Mac OS X, or CRLF for Windows). + +The ``--unix-line-endings`` option writes Unix line endings regardless of the +curent platform. Similarly, the ``--windows-line-endings`` option writes Windows +line endings regardless of the current platform. + + Fixers requiring six ++++++++++++++++++++ diff --git a/libmodernize/main.py b/libmodernize/main.py index 4fe934c..a16050b 100644 --- a/libmodernize/main.py +++ b/libmodernize/main.py @@ -8,6 +8,7 @@ from __future__ import absolute_import, print_function import sys +import os import logging import optparse @@ -63,6 +64,10 @@ def main(args=None): "(only useful for Python 2.6+).") parser.add_option("--no-six", action="store_true", default=False, help="Exclude fixes that depend on the six package.") + parser.add_option("--unix-line-endings", action="store_true", default=False, + help="Write files with Unix (LF) line endings.") + parser.add_option("--windows-line-endings", action="store_true", default=False, + help="Write files with Windows (CRLF) line endings.") fixer_pkg = 'libmodernize.fixes' avail_fixes = set(refactor.get_fixers_from_package(fixer_pkg)) @@ -94,6 +99,15 @@ def main(args=None): if options.print_function: flags["print_function"] = True + if options.unix_line_endings and options.windows_line_endings: + print("--unix-line-endings and --windows-line-endings options conflict.") + return 2 + linesep = None + if options.unix_line_endings: + linesep = '\n' + if options.windows_line_endings: + linesep = '\r\n' + # Set up logging handler level = logging.DEBUG if options.verbose else logging.INFO logging.basicConfig(format='%(name)s: %(message)s', level=level) @@ -125,6 +139,26 @@ def main(args=None): else: requested = default_fixes fixer_names = requested.difference(unwanted_fixes) + + parameters = (fixer_names, flags, explicit, options, refactor_stdin, args) + if linesep is None or linesep == os.linesep: + return do_refactoring(*parameters) + else: + if not hasattr(refactor, '_to_system_newlines'): + print("Cannot override newline mode due to a change in lib2to3.") + return 2 + + old_to_system_newlines = refactor._to_system_newlines + def _to_system_newlines(s): + return s.replace('\r', '').replace('\n', linesep) + refactor._to_system_newlines = _to_system_newlines + try: + return do_refactoring(*parameters) + finally: + refactor._to_system_newlines = old_to_system_newlines + + +def do_refactoring(fixer_names, flags, explicit, options, refactor_stdin, args): rt = StdoutRefactoringTool(sorted(fixer_names), flags, sorted(explicit), options.nobackups, not options.no_diffs) diff --git a/tests/test_newlines.py b/tests/test_newlines.py new file mode 100644 index 0000000..a15ffa5 --- /dev/null +++ b/tests/test_newlines.py @@ -0,0 +1,30 @@ +from __future__ import absolute_import + +import os +from utils import check_on_input, expect_error +from test_fix_basestring import BASESTRING + +TESTCASE = [x.encode('ascii') for x in BASESTRING] + + +def test_mixed_to_native_line_endings(): + check_on_input(b'#\r\n' + TESTCASE[0], + (b'#\n' + TESTCASE[1]).replace(b'\n', os.linesep.encode('ascii')), + mode="b") + +def test_windows_to_unix_line_endings(): + check_on_input(TESTCASE[0].replace(b'\n', b'\r\n'), + TESTCASE[1], + extra_flags=['--unix-line-endings'], + mode="b") + +def test_unix_to_windows_line_endings(): + check_on_input(TESTCASE[0], + TESTCASE[1].replace(b'\n', b'\r\n'), + extra_flags=['--windows-line-endings'], + mode="b") + +def test_options_conflict(): + expect_error(TESTCASE[0], + extra_flags=['--unix-line-endings', '--windows-line-endings'], + mode="b")