Beispiel #1
0
def print_lines(console_printer, file_dict, sourcerange):
    """
    Prints the lines between the current and the result line. If needed
    they will be shortened.

    :param console_printer: Object to print messages on the console.
    :param file_dict:       A dictionary containing all files as values with
                            filenames as key.
    :param sourcerange:     The SourceRange object referring to the related
                            lines to print.
    """
    no_color = not console_printer.print_colored
    for i in range(sourcerange.start.line, sourcerange.end.line + 1):
        # Print affected file's line number in the sidebar.
        console_printer.print(format_lines(lines='', line_nr=i, symbol='['),
                              color=FILE_LINES_COLOR,
                              end='')

        line = file_dict[sourcerange.file][i - 1].rstrip('\n')
        try:
            lexer = get_lexer_for_filename(sourcerange.file)
        except ClassNotFound:
            lexer = TextLexer()
        lexer.add_filter(
            VisibleWhitespaceFilter(spaces=True,
                                    tabs=True,
                                    tabsize=SpacingHelper.DEFAULT_TAB_WIDTH))
        # highlight() combines lexer and formatter to output a ``str``
        # object.
        printed_chars = 0
        if i == sourcerange.start.line and sourcerange.start.column:
            console_printer.print(highlight_text(
                no_color, line[:sourcerange.start.column - 1],
                BackgroundMessageStyle, lexer),
                                  end='')

            printed_chars = sourcerange.start.column - 1

        if i == sourcerange.end.line and sourcerange.end.column:
            console_printer.print(highlight_text(
                no_color, line[printed_chars:sourcerange.end.column - 1],
                BackgroundSourceRangeStyle, lexer),
                                  end='')

            console_printer.print(highlight_text(
                no_color, line[sourcerange.end.column - 1:],
                BackgroundSourceRangeStyle, lexer),
                                  end='')
            console_printer.print('')
        else:
            console_printer.print(highlight_text(no_color,
                                                 line[printed_chars:],
                                                 BackgroundMessageStyle,
                                                 lexer),
                                  end='')
            console_printer.print('')
def print_lines(console_printer,
                file_dict,
                sourcerange):
    """
    Prints the lines between the current and the result line. If needed
    they will be shortened.

    :param console_printer: Object to print messages on the console.
    :param file_dict:       A dictionary containing all files as values with
                            filenames as key.
    :param sourcerange:     The SourceRange object referring to the related
                            lines to print.
    """
    no_color = not console_printer.print_colored
    for i in range(sourcerange.start.line, sourcerange.end.line + 1):
        # Print affected file's line number in the sidebar.
        console_printer.print(format_lines(lines='', line_nr=i, symbol='['),
                              color=FILE_LINES_COLOR,
                              end='')

        line = file_dict[sourcerange.file][i - 1].rstrip('\n')
        try:
            lexer = get_lexer_for_filename(sourcerange.file)
        except ClassNotFound:
            lexer = TextLexer()
        lexer.add_filter(VisibleWhitespaceFilter(
            spaces=True, tabs=True,
            tabsize=SpacingHelper.DEFAULT_TAB_WIDTH))
        # highlight() combines lexer and formatter to output a ``str``
        # object.
        printed_chars = 0
        if i == sourcerange.start.line and sourcerange.start.column:
            console_printer.print(highlight_text(
                no_color, line[:sourcerange.start.column - 1],
                BackgroundMessageStyle, lexer), end='')

            printed_chars = sourcerange.start.column - 1

        if i == sourcerange.end.line and sourcerange.end.column:
            console_printer.print(highlight_text(
                no_color, line[printed_chars:sourcerange.end.column - 1],
                BackgroundSourceRangeStyle, lexer), end='')

            console_printer.print(highlight_text(
               no_color, line[sourcerange.end.column - 1:],
               BackgroundSourceRangeStyle, lexer), end='')
            console_printer.print('')
        else:
            console_printer.print(highlight_text(
                no_color, line[printed_chars:], BackgroundMessageStyle, lexer),
                                  end='')
            console_printer.print('')
    def run(self):
        self.assert_has_content()
        try:
            lexer = get_lexer_by_name(self.arguments[0])
        except ValueError:
            # no lexer found - use the text one instead of an exception
            lexer = TextLexer()

        lexer.add_filter(ctypes_types_highlighter)
        lexer.add_filter(custom_highlighters)

        # take an arbitrary option if more than one is given
        formatter = self.options and \
                    VARIANTS[self.options.keys()[0]] or \
                    DEFAULT

        print >>open('pygments.css', 'w'), formatter.get_style_defs('.highlight')
        parsed = highlight(u'\n'.join(self.content), lexer, formatter)
        return [nodes.raw('', parsed, format='html')]
Beispiel #4
0
def main(args=sys.argv):
    """
    Main command line entry point.
    """
    # pylint: disable-msg=R0911,R0912,R0915

    usage = USAGE % ((args[0],) * 6)

    try:
        popts, args = getopt.getopt(args[1:], "l:f:F:o:O:P:LS:a:N:hVHgs")
    except getopt.GetoptError:
        print(usage, file=sys.stderr)
        return 2
    opts = {}
    O_opts = []
    P_opts = []
    F_opts = []
    for opt, arg in popts:
        if opt == "-O":
            O_opts.append(arg)
        elif opt == "-P":
            P_opts.append(arg)
        elif opt == "-F":
            F_opts.append(arg)
        opts[opt] = arg

    if opts.pop("-h", None) is not None:
        print(usage)
        return 0

    if opts.pop("-V", None) is not None:
        print("Pygments version %s, (c) 2006-2014 by Georg Brandl." % __version__)
        return 0

    # handle ``pygmentize -L``
    L_opt = opts.pop("-L", None)
    if L_opt is not None:
        if opts:
            print(usage, file=sys.stderr)
            return 2

        # print version
        main(["", "-V"])
        if not args:
            args = ["lexer", "formatter", "filter", "style"]
        for arg in args:
            _print_list(arg.rstrip("s"))
        return 0

    # handle ``pygmentize -H``
    H_opt = opts.pop("-H", None)
    if H_opt is not None:
        if opts or len(args) != 2:
            print(usage, file=sys.stderr)
            return 2

        what, name = args
        if what not in ("lexer", "formatter", "filter"):
            print(usage, file=sys.stderr)
            return 2

        _print_help(what, name)
        return 0

    # parse -O options
    parsed_opts = _parse_options(O_opts)
    opts.pop("-O", None)

    # parse -P options
    for p_opt in P_opts:
        try:
            name, value = p_opt.split("=", 1)
        except ValueError:
            parsed_opts[p_opt] = True
        else:
            parsed_opts[name] = value
    opts.pop("-P", None)

    # encodings
    inencoding = parsed_opts.get("inencoding", parsed_opts.get("encoding"))
    outencoding = parsed_opts.get("outencoding", parsed_opts.get("encoding"))

    # handle ``pygmentize -N``
    infn = opts.pop("-N", None)
    if infn is not None:
        try:
            lexer = get_lexer_for_filename(infn, **parsed_opts)
        except ClassNotFound as err:
            lexer = TextLexer()
        except OptionError as err:
            print("Error:", err, file=sys.stderr)
            return 1

        print(lexer.aliases[0])
        return 0

    # handle ``pygmentize -S``
    S_opt = opts.pop("-S", None)
    a_opt = opts.pop("-a", None)
    if S_opt is not None:
        f_opt = opts.pop("-f", None)
        if not f_opt:
            print(usage, file=sys.stderr)
            return 2
        if opts or args:
            print(usage, file=sys.stderr)
            return 2

        try:
            parsed_opts["style"] = S_opt
            fmter = get_formatter_by_name(f_opt, **parsed_opts)
        except ClassNotFound as err:
            print(err, file=sys.stderr)
            return 1

        arg = a_opt or ""
        try:
            print(fmter.get_style_defs(arg))
        except Exception as err:
            print("Error:", err, file=sys.stderr)
            return 1
        return 0

    # if no -S is given, -a is not allowed
    if a_opt is not None:
        print(usage, file=sys.stderr)
        return 2

    # parse -F options
    F_opts = _parse_filters(F_opts)
    opts.pop("-F", None)

    # select lexer
    lexer = opts.pop("-l", None)
    if lexer:
        try:
            lexer = get_lexer_by_name(lexer, **parsed_opts)
        except (OptionError, ClassNotFound) as err:
            print("Error:", err, file=sys.stderr)
            return 1

    # read input code
    code = None

    if args:
        if len(args) > 1:
            print(usage, file=sys.stderr)
            return 2

        if "-s" in opts:
            print("Error: -s option not usable when input file specified", file=sys.stderr)
            return 1

        infn = args[0]
        try:
            with open(infn, "rb") as infp:
                code = infp.read()
        except Exception as err:
            print("Error: cannot read infile:", err, file=sys.stderr)
            return 1
        if not inencoding:
            code, inencoding = guess_decode(code)

        # do we have to guess the lexer?
        if not lexer:
            try:
                lexer = get_lexer_for_filename(infn, code, **parsed_opts)
            except ClassNotFound as err:
                if "-g" in opts:
                    try:
                        lexer = guess_lexer(code, **parsed_opts)
                    except ClassNotFound:
                        lexer = TextLexer(**parsed_opts)
                else:
                    print("Error:", err, file=sys.stderr)
                    return 1
            except OptionError as err:
                print("Error:", err, file=sys.stderr)
                return 1

    elif "-s" not in opts:  # treat stdin as full file (-s support is later)
        # read code from terminal, always in binary mode since we want to
        # decode ourselves and be tolerant with it
        if sys.version_info > (3,):
            # Python 3: we have to use .buffer to get a binary stream
            code = sys.stdin.buffer.read()
        else:
            code = sys.stdin.read()
        if not inencoding:
            code, inencoding = guess_decode_from_terminal(code, sys.stdin)
            # else the lexer will do the decoding
        if not lexer:
            try:
                lexer = guess_lexer(code, **parsed_opts)
            except ClassNotFound:
                lexer = TextLexer(**parsed_opts)

    # select formatter
    outfn = opts.pop("-o", None)
    fmter = opts.pop("-f", None)
    if fmter:
        try:
            fmter = get_formatter_by_name(fmter, **parsed_opts)
        except (OptionError, ClassNotFound) as err:
            print("Error:", err, file=sys.stderr)
            return 1

    if outfn:
        if not fmter:
            try:
                fmter = get_formatter_for_filename(outfn, **parsed_opts)
            except (OptionError, ClassNotFound) as err:
                print("Error:", err, file=sys.stderr)
                return 1
        try:
            outfile = open(outfn, "wb")
        except Exception as err:
            print("Error: cannot open outfile:", err, file=sys.stderr)
            return 1
    else:
        if not fmter:
            fmter = TerminalFormatter(**parsed_opts)
        if sys.version_info > (3,):
            # Python 3: we have to use .buffer to get a binary stream
            outfile = sys.stdout.buffer
        else:
            outfile = sys.stdout

    # determine output encoding if not explicitly selected
    if not outencoding:
        if outfn:
            # output file? use lexer encoding for now (can still be None)
            fmter.encoding = inencoding
        else:
            # else use terminal encoding
            fmter.encoding = terminal_encoding(sys.stdout)

    # provide coloring under Windows, if possible
    if not outfn and sys.platform in ("win32", "cygwin") and fmter.name in ("Terminal", "Terminal256"):
        # unfortunately colorama doesn't support binary streams on Py3
        if sys.version_info > (3,):
            import io

            outfile = io.TextIOWrapper(outfile, encoding=fmter.encoding)
            fmter.encoding = None
        try:
            import colorama.initialise
        except ImportError:
            pass
        else:
            outfile = colorama.initialise.wrap_stream(outfile, convert=None, strip=None, autoreset=False, wrap=True)

    # When using the LaTeX formatter and the option `escapeinside` is
    # specified, we need a special lexer which collects escaped text
    # before running the chosen language lexer.
    escapeinside = parsed_opts.get("escapeinside", "")
    if len(escapeinside) == 2 and isinstance(fmter, LatexFormatter):
        left = escapeinside[0]
        right = escapeinside[1]
        lexer = LatexEmbeddedLexer(left, right, lexer)

    # ... and do it!
    try:
        # process filters
        for fname, fopts in F_opts:
            lexer.add_filter(fname, **fopts)

        if "-s" not in opts:
            # process whole input as per normal...
            highlight(code, lexer, fmter, outfile)
        else:
            if not lexer:
                print("Error: when using -s a lexer has to be selected with -l", file=sys.stderr)
                return 1
            # line by line processing of stdin (eg: for 'tail -f')...
            try:
                while 1:
                    if sys.version_info > (3,):
                        # Python 3: we have to use .buffer to get a binary stream
                        line = sys.stdin.buffer.readline()
                    else:
                        line = sys.stdin.readline()
                    if not line:
                        break
                    if not inencoding:
                        line = guess_decode_from_terminal(line, sys.stdin)[0]
                    highlight(line, lexer, fmter, outfile)
                    if hasattr(outfile, "flush"):
                        outfile.flush()
            except KeyboardInterrupt:
                return 0

    except Exception:
        raise
        import traceback

        info = traceback.format_exception(*sys.exc_info())
        msg = info[-1].strip()
        if len(info) >= 3:
            # extract relevant file and position info
            msg += "\n   (f%s)" % info[-2].split("\n")[0].strip()[1:]
        print(file=sys.stderr)
        print("*** Error while highlighting:", file=sys.stderr)
        print(msg, file=sys.stderr)
        return 1

    return 0
Beispiel #5
0
        else:
            if sys.version_info < (3, ):
                # use terminal encoding; Python 3's terminals already do that
                lexer.encoding = getattr(sys.stdin, 'encoding',
                                         None) or 'utf-8'
                fmter.encoding = getattr(sys.stdout, 'encoding',
                                         None) or 'utf-8'
    elif not outfn and sys.version_info > (3, ):
        # output to terminal with encoding -> use .buffer
        outfile = sys.stdout.buffer

    # ... and do it!
    try:
        # process filters
        for fname, fopts in F_opts:
            lexer.add_filter(fname, **fopts)
        highlight(code, lexer, fmter, outfile)
    except Exception, err:
        import traceback
        info = traceback.format_exception(*sys.exc_info())
        msg = info[-1].strip()
        if len(info) >= 3:
            # extract relevant file and position info
            msg += '\n   (f%s)' % info[-2].split('\n')[0].strip()[1:]
        print >> sys.stderr
        print >> sys.stderr, '*** Error while highlighting:'
        print >> sys.stderr, msg
        return 1

    return 0
Beispiel #6
0
class ConsoleInteractionTest(unittest.TestCase):

    def setUp(self):
        self.log_printer = ListLogPrinter()
        self.console_printer = ConsolePrinter(print_colored=False)
        self.no_color = not self.console_printer.print_colored
        self.file_diff_dict = {}
        self.section = Section('t')
        self.local_bears = OrderedDict([('default', [SomelocalBear]),
                                        ('test', [SomelocalBear])])
        self.global_bears = OrderedDict([('default', [SomeglobalBear]),
                                         ('test', [SomeglobalBear])])

        self.old_open_editor_applicable = OpenEditorAction.is_applicable
        OpenEditorAction.is_applicable = staticmethod(
            lambda *args: 'OpenEditorAction cannot be applied')

        self.old_apply_patch_applicable = ApplyPatchAction.is_applicable
        ApplyPatchAction.is_applicable = staticmethod(
            lambda *args: 'ApplyPatchAction cannot be applied')

        self.lexer = TextLexer()
        self.lexer.add_filter(VisibleWhitespaceFilter(
            spaces=True,
            tabs=True,
            tabsize=SpacingHelper.DEFAULT_TAB_WIDTH))

    def tearDown(self):
        OpenEditorAction.is_applicable = self.old_open_editor_applicable
        ApplyPatchAction.is_applicable = self.old_apply_patch_applicable

    def test_require_settings(self):
        curr_section = Section('')
        self.assertRaises(TypeError, acquire_settings,
                          self.log_printer, 0, curr_section)

        with simulate_console_inputs(0, 1, 2) as generator:
            self.assertEqual(acquire_settings(self.log_printer,
                                              {'setting': ['help text',
                                                           'SomeBear']},
                                              curr_section),
                             {'setting': 0})

            self.assertEqual(acquire_settings(self.log_printer,
                                              {'setting': ['help text',
                                                           'SomeBear',
                                                           'AnotherBear']},
                                              curr_section),
                             {'setting': 1})

            self.assertEqual(acquire_settings(self.log_printer,
                                              {'setting': ['help text',
                                                           'SomeBear',
                                                           'AnotherBear',
                                                           'YetAnotherBear']},
                                              curr_section),
                             {'setting': 2})

            self.assertEqual(generator.last_input, 2)

    def test_print_diffs_info(self):
        file_dict = {'a': ['a\n', 'b\n', 'c\n'], 'b': ['old_first\n']}
        diff_dict = {'a': Diff(file_dict['a']),
                     'b': Diff(file_dict['b'])}
        diff_dict['a'].add_lines(1, ['test\n'])
        diff_dict['a'].delete_line(3)
        diff_dict['b'].add_lines(0, ['first\n'])
        previous_diffs = {'a': Diff(file_dict['a'])}
        previous_diffs['a'].change_line(2, 'b\n', 'b_changed\n')
        with retrieve_stdout() as stdout:
            print_diffs_info(diff_dict, self.console_printer)
            self.assertEqual(stdout.getvalue(),
                             '|    | +1 -1 in a\n'
                             '|    | +1 -0 in b\n')

    @patch('coalib.output.ConsoleInteraction.acquire_actions_and_apply')
    @patch('coalib.output.ConsoleInteraction.ShowPatchAction.'
           'apply_from_section')
    def test_print_result_interactive_small_patch(self, apply_from_section, _):
        file_dict = {'a': ['a\n', 'b\n', 'c\n'], 'b': ['old_first\n']}
        diff_dict = {'a': Diff(file_dict['a']),
                     'b': Diff(file_dict['b'])}
        diff_dict['a'].add_lines(1, ['test\n'])
        diff_dict['a'].delete_line(3)
        result = Result('origin', 'msg', diffs=diff_dict)
        section = Section('test')

        print_result(self.console_printer,
                     section,
                     self.file_diff_dict,
                     result,
                     file_dict,
                     True)
        apply_from_section.assert_called_once_with(
            result, file_dict, self.file_diff_dict, section)

    @patch('coalib.output.ConsoleInteraction.acquire_actions_and_apply')
    @patch('coalib.output.ConsoleInteraction.print_diffs_info')
    def test_print_result_interactive_big_patch(self, diffs_info, _):
        file_dict = {'a': ['a\n', 'b\n', 'c\n'], 'b': ['old_first\n']}
        diff_dict = {'a': Diff(file_dict['a']),
                     'b': Diff(file_dict['b'])}
        diff_dict['a'].add_lines(1, ['test\n', 'test1\n', 'test2\n'])
        diff_dict['a'].delete_line(3)
        diff_dict['a'].add_lines(3, ['3test\n'])
        result = Result('origin', 'msg', diffs=diff_dict)
        section = Section('test')

        print_result(self.console_printer,
                     section,
                     self.file_diff_dict,
                     result,
                     file_dict,
                     True)
        diffs_info.assert_called_once_with(diff_dict, self.console_printer)

    def test_print_result(self):
        print_result(self.console_printer,
                     None,
                     self.file_diff_dict,
                     'illegal value',
                     {})

        with simulate_console_inputs(0):
            print_result(self.console_printer,
                         self.section,
                         self.file_diff_dict,
                         Result('origin', 'msg', diffs={}),
                         {})

        with make_temp() as testfile_path:
            file_dict = {
                testfile_path: ['1\n', '2\n', '3\n'],
                'f_b': ['1', '2', '3']
            }
            diff = Diff(file_dict[testfile_path])
            diff.delete_line(2)
            diff.change_line(3, '3\n', '3_changed\n')

            ApplyPatchAction.is_applicable = staticmethod(
                lambda *args: True)

            # Interaction must be closed by the user with `0` if it's not a
            # param
            with simulate_console_inputs('INVALID',
                                         -1,
                                         1,
                                         0,
                                         3) as input_generator:
                curr_section = Section('')
                print_section_beginning(self.console_printer, curr_section)
                print_result(self.console_printer,
                             curr_section,
                             self.file_diff_dict,
                             Result('origin', 'msg', diffs={
                                    testfile_path: diff}),
                             file_dict)
                self.assertEqual(input_generator.last_input, 3)

                self.file_diff_dict.clear()

                with open(testfile_path) as f:
                    self.assertEqual(f.readlines(), ['1\n', '3_changed\n'])

                os.remove(testfile_path + '.orig')

                name, section = get_action_info(curr_section,
                                                TestAction().get_metadata(),
                                                failed_actions=set())
                self.assertEqual(input_generator.last_input, 4)
                self.assertEqual(str(section), " {param : '3'}")
                self.assertEqual(name, 'TestAction')

        # Check if the user is asked for the parameter only the first time.
        # Use OpenEditorAction that needs this parameter (editor command).
        with simulate_console_inputs(1, 'test_editor', 0, 1, 0) as generator:
            OpenEditorAction.is_applicable = staticmethod(lambda *args: True)

            patch_result = Result('origin', 'msg', diffs={testfile_path: diff})
            patch_result.file = 'f_b'

            print_result(self.console_printer,
                         curr_section,
                         self.file_diff_dict,
                         patch_result,
                         file_dict)
            # choose action, choose editor, choose no action (-1 -> 2)
            self.assertEqual(generator.last_input, 2)

            # It shoudn't ask for parameter again
            print_result(self.console_printer,
                         curr_section,
                         self.file_diff_dict,
                         patch_result,
                         file_dict)
            self.assertEqual(generator.last_input, 4)

    def test_print_affected_files(self):
        with retrieve_stdout() as stdout, \
                make_temp() as some_file:
            file_dict = {some_file: ['1\n', '2\n', '3\n']}
            affected_code = (SourceRange.from_values(some_file),)
            print_affected_files(self.console_printer,
                                 self.log_printer,
                                 Result('origin',
                                        'message',
                                        affected_code=affected_code),
                                 file_dict)
            self.assertEqual(stdout.getvalue(),
                             '\n'+relpath(some_file)+'\n')

    def test_acquire_actions_and_apply(self):
        with make_temp() as testfile_path:
            file_dict = {testfile_path: ['1\n', '2\n', '3\n']}
            diff = Diff(file_dict[testfile_path])
            diff.delete_line(2)
            diff.change_line(3, '3\n', '3_changed\n')
            with simulate_console_inputs(1, 0) as generator, \
                    retrieve_stdout() as sio:
                ApplyPatchAction.is_applicable = staticmethod(
                    lambda *args: True)
                acquire_actions_and_apply(self.console_printer,
                                          Section(''),
                                          self.file_diff_dict,
                                          Result('origin', 'message', diffs={
                                              testfile_path: diff}),
                                          file_dict)
                self.assertEqual(generator.last_input, 1)
                self.assertIn(ApplyPatchAction.SUCCESS_MESSAGE, sio.getvalue())

            class InvalidateTestAction(ResultAction):

                is_applicable = staticmethod(lambda *args: True)

                def apply(*args, **kwargs):
                    ApplyPatchAction.is_applicable = staticmethod(
                        lambda *args: 'ApplyPatchAction cannot be applied.')

            old_applypatch_is_applicable = ApplyPatchAction.is_applicable
            ApplyPatchAction.is_applicable = staticmethod(lambda *args: True)
            cli_actions = [ApplyPatchAction(), InvalidateTestAction()]

            with simulate_console_inputs(2, 1, 0) as generator, \
                    retrieve_stdout() as sio:
                acquire_actions_and_apply(self.console_printer,
                                          Section(''),
                                          self.file_diff_dict,
                                          Result('origin', 'message',
                                                 diffs={testfile_path: diff}),
                                          file_dict,
                                          cli_actions=cli_actions)
                self.assertEqual(generator.last_input, 2)

                action_fail = 'Failed to execute the action'
                self.assertNotIn(action_fail, sio.getvalue())

                apply_path_desc = ApplyPatchAction().get_metadata().desc
                self.assertEqual(sio.getvalue().count(apply_path_desc), 1)

            ApplyPatchAction.is_applicable = old_applypatch_is_applicable

    def test_ask_for_actions_and_apply(self):
        failed_actions = set()
        action = TestAction()
        args = [self.console_printer, Section(''),
                [action.get_metadata()], {'TestAction': action},
                failed_actions, Result('origin', 'message'), {}, {}]

        with simulate_console_inputs(1, 'param1', 1, 'param2') as generator:
            action.apply = unittest.mock.Mock(side_effect=AssertionError)
            ask_for_action_and_apply(*args)
            self.assertEqual(generator.last_input, 1)
            self.assertIn('TestAction', failed_actions)

            action.apply = lambda *args, **kwargs: {}
            ask_for_action_and_apply(*args)
            self.assertEqual(generator.last_input, 3)
            self.assertNotIn('TestAction', failed_actions)

    def test_default_input(self):
        action = TestAction()
        args = [self.console_printer, Section(''),
                [action.get_metadata()], {'TestAction': action},
                set(), Result('origin', 'message'), {}, {}]

        with simulate_console_inputs('') as generator:
            self.assertFalse(ask_for_action_and_apply(*args))

    def test_print_result_no_input(self):
        with make_temp() as testfile_path:
            file_dict = {testfile_path: ['1\n', '2\n', '3\n']}
            diff = Diff(file_dict[testfile_path])
            diff.delete_line(2)
            diff.change_line(3, '3\n', '3_changed\n')
            with simulate_console_inputs(1, 2, 3) as generator, \
                    retrieve_stdout() as stdout:
                ApplyPatchAction.is_applicable = staticmethod(
                    lambda *args: True)
                print_results_no_input(self.log_printer,
                                       Section('someSection'),
                                       [Result('origin', 'message', diffs={
                                           testfile_path: diff})],
                                       file_dict,
                                       self.file_diff_dict,
                                       self.console_printer)
                self.assertEqual(generator.last_input, -1)
                self.assertEqual(stdout.getvalue(),
                                 """
Project wide:
|    | [NORMAL] origin:
|    | {}\n""".format(highlight_text(self.no_color,
                                     'message', style=BackgroundMessageStyle)))

    def test_print_section_beginning(self):
        with retrieve_stdout() as stdout:
            print_section_beginning(self.console_printer, Section('name'))
            self.assertEqual(stdout.getvalue(), 'Executing section name...\n')

    def test_nothing_done(self):
        nothing_done(self.log_printer)
        self.assertEqual(['No existent section was targeted or enabled. '
                          'Nothing to do.'],
                         [log.message for log in self.log_printer.logs])

    def test_print_results_empty(self):
        with retrieve_stdout() as stdout:
            print_results(self.log_printer, Section(''), [], {}, {},
                          self.console_printer)
            self.assertEqual(stdout.getvalue(), '')

    def test_print_results_project_wide(self):
        with retrieve_stdout() as stdout:
            print_results(self.log_printer,
                          Section(''),
                          [Result('origin', 'message')],
                          {},
                          {},
                          self.console_printer)
            self.assertEqual(
                '\n{}\n|    | [NORMAL] origin:\n|    | {}\n'.format(
                    STR_PROJECT_WIDE,
                    highlight_text(self.no_color,
                                   'message', style=BackgroundMessageStyle)),
                stdout.getvalue())

    def test_print_results_for_file(self):
        with retrieve_stdout() as stdout:
            print_results(
                self.log_printer,
                Section(''),
                [Result.from_values('SpaceConsistencyBear',
                                    'Trailing whitespace found',
                                    file='filename',
                                    line=2)],
                {abspath('filename'): ['test line\n', 'line 2\n', 'line 3\n']},
                {},
                self.console_printer)
            self.assertEqual("""\nfilename
|   2| {}
|    | [NORMAL] SpaceConsistencyBear:
|    | {}\n""".format(highlight_text(self.no_color, 'line 2', self.lexer),
                      highlight_text(self.no_color, 'Trailing whitespace found',
                                     style=BackgroundMessageStyle)),
                stdout.getvalue())

        with retrieve_stdout() as stdout:
            print_results(
                self.log_printer,
                Section(''),
                [Result.from_values('SpaceConsistencyBear',
                                    'Trailing whitespace found',
                                    file='filename',
                                    line=5)],
                {abspath('filename'): ['test line\n',
                                       'line 2\n',
                                       'line 3\n',
                                       'line 4\n',
                                       'line 5\n']},
                {},
                self.console_printer)
            self.assertEqual("""\nfilename
|   5| {}
|    | [NORMAL] SpaceConsistencyBear:
|    | {}\n""".format(highlight_text(self.no_color, 'line 5', self.lexer),
                      highlight_text(self.no_color, 'Trailing whitespace found',
                                     style=BackgroundMessageStyle)),
                stdout.getvalue())

    def test_print_results_sorting(self):
        with retrieve_stdout() as stdout:
            print_results(self.log_printer,
                          Section(''),
                          [Result.from_values('SpaceConsistencyBear',
                                              'Trailing whitespace found',
                                              file='file',
                                              line=5),
                           Result.from_values('SpaceConsistencyBear',
                                              'Trailing whitespace found',
                                              file='file',
                                              line=2)],
                          {abspath('file'): ['test line\n',
                                             '\t\n',
                                             'line 3\n',
                                             'line 4\n',
                                             'line 5\t\n']},
                          {},
                          self.console_printer)

            self.assertEqual("""
file
|   2| {0}
|    | [NORMAL] SpaceConsistencyBear:
|    | {1}

file
|   5| {2}
|    | [NORMAL] SpaceConsistencyBear:
|    | {1}\n""".format(highlight_text(self.no_color, '\t', self.lexer),
                       highlight_text(self.no_color,
                                      'Trailing whitespace found',
                                      style=BackgroundMessageStyle),
                       highlight_text(self.no_color, 'line 5\t', self.lexer)),
                stdout.getvalue())

    def test_print_results_multiple_ranges(self):
        affected_code = (
            SourceRange.from_values('some_file', 5, end_line=7),
            SourceRange.from_values('another_file', 1, 3, 1, 5),
            SourceRange.from_values('another_file', 3, 3, 3, 5))
        with retrieve_stdout() as stdout:
            print_results(
                self.log_printer,
                Section(''),
                [Result('ClangCloneDetectionBear',
                        'Clone Found',
                        affected_code)],
                {abspath('some_file'): ['line ' + str(i + 1) + '\n'
                                        for i in range(10)],
                 abspath('another_file'): ['line ' + str(i + 1)
                                           for i in range(10)]},
                {},
                self.console_printer)
            self.assertEqual("""
another_file
|   1| li{0}{1}

another_file
|   3| li{0}{2}

some_file
|   5| {3}
|   6| {4}
|   7| {5}
|    | [NORMAL] ClangCloneDetectionBear:
|    | {6}\n""".format(highlight_text(self.no_color, 'ne', self.lexer,
                                      BackgroundSourceRangeStyle),
                       highlight_text(self.no_color, ' 1', self.lexer),
                       highlight_text(self.no_color, ' 3', self.lexer),
                       highlight_text(self.no_color, 'line 5', self.lexer),
                       highlight_text(self.no_color, 'line 6', self.lexer),
                       highlight_text(self.no_color, 'line 7', self.lexer),
                       highlight_text(self.no_color, 'Clone Found',
                                      style=BackgroundMessageStyle)),
                stdout.getvalue())

    def test_print_results_missing_file(self):
        self.log_printer.log_level = logging.CRITICAL
        with retrieve_stdout() as stdout:
            print_results(
                self.log_printer,
                Section(''),
                [Result('t', 'msg'),
                 Result.from_values('t', 'msg', file='file', line=5)],
                {},
                {},
                self.console_printer)
            self.assertEqual('\n' + STR_PROJECT_WIDE + '\n'
                             '|    | [NORMAL] t:\n'
                             '|    | {0}\n'
                             # Second results file isn't there, no context is
                             # printed, only a warning log message which we
                             # don't catch
                             '|    | [NORMAL] t:\n'
                             '|    | {0}\n'.format(
                                 highlight_text(self.no_color, 'msg',
                                                style=BackgroundMessageStyle)),
                             stdout.getvalue())

    def test_print_results_missing_line(self):
        with retrieve_stdout() as stdout:
            print_results(
                self.log_printer,
                Section(''),
                [Result.from_values('t', 'msg', file='file', line=5),
                 Result.from_values('t', 'msg', file='file', line=6)],
                {abspath('file'): ['line ' + str(i + 1) for i in range(5)]},
                {},
                self.console_printer)
            self.assertEqual('\n'
                             'file\n'
                             '|   5| {0}\n'
                             '|    | [NORMAL] t:\n'
                             '|    | {1}\n'
                             '\n'
                             'file\n'
                             '|   6| {2}\n'
                             '|    | [NORMAL] t:\n'
                             '|    | {1}\n'.format(
                                 highlight_text(self.no_color,
                                                'line 5', self.lexer),
                                 highlight_text(self.no_color, 'msg',
                                                style=BackgroundMessageStyle),
                                 STR_LINE_DOESNT_EXIST),
                             stdout.getvalue())

    def test_print_results_without_line(self):
        with retrieve_stdout() as stdout:
            print_results(
                self.log_printer,
                Section(''),
                [Result.from_values('t', 'msg', file='file')],
                {abspath('file'): []},
                {},
                self.console_printer)
            self.assertEqual(
                '\nfile\n'
                '|    | [NORMAL] t:\n'
                '|    | {}\n'.format(highlight_text(
                   self.no_color, 'msg', style=BackgroundMessageStyle)),
                stdout.getvalue())
Beispiel #7
0
    # stdin/stdout encoding otherwise.
    # (This is a compromise, I'm not too happy with it...)
    if 'encoding' not in parsed_opts and 'outencoding' not in parsed_opts:
        if outfn:
            # encoding pass-through
            fmter.encoding = 'latin1'
        else:
            # use terminal encoding
            lexer.encoding = getattr(sys.stdin, 'encoding', None) or 'ascii'
            fmter.encoding = getattr(sys.stdout, 'encoding', None) or 'ascii'

    # ... and do it!
    try:
        # process filters
        for fname, fopts in F_opts:
            lexer.add_filter(fname, **fopts)
        highlight(code, lexer, fmter, outfile)
    except Exception, err:
        import traceback
        info = traceback.format_exception(*sys.exc_info())
        msg = info[-1].strip()
        if len(info) >= 3:
            # extract relevant file and position info
            msg += '\n   (f%s)' % info[-2].split('\n')[0].strip()[1:]
        print >>sys.stderr
        print >>sys.stderr, '*** Error while highlighting:'
        print >>sys.stderr, msg
        return 1

    return 0
Beispiel #8
0
def main(args=sys.argv):
    """
    Main command line entry point.
    """
    # pylint: disable-msg=R0911,R0912,R0915

    usage = USAGE % ((args[0], ) * 6)

    try:
        popts, args = getopt.getopt(args[1:], "l:f:F:o:O:P:LS:a:N:hVHgs")
    except getopt.GetoptError:
        print(usage, file=sys.stderr)
        return 2
    opts = {}
    O_opts = []
    P_opts = []
    F_opts = []
    for opt, arg in popts:
        if opt == '-O':
            O_opts.append(arg)
        elif opt == '-P':
            P_opts.append(arg)
        elif opt == '-F':
            F_opts.append(arg)
        opts[opt] = arg

    if opts.pop('-h', None) is not None:
        print(usage)
        return 0

    if opts.pop('-V', None) is not None:
        print('Pygments version %s, (c) 2006-2014 by Georg Brandl.' %
              __version__)
        return 0

    # handle ``pygmentize -L``
    L_opt = opts.pop('-L', None)
    if L_opt is not None:
        if opts:
            print(usage, file=sys.stderr)
            return 2

        # print version
        main(['', '-V'])
        if not args:
            args = ['lexer', 'formatter', 'filter', 'style']
        for arg in args:
            _print_list(arg.rstrip('s'))
        return 0

    # handle ``pygmentize -H``
    H_opt = opts.pop('-H', None)
    if H_opt is not None:
        if opts or len(args) != 2:
            print(usage, file=sys.stderr)
            return 2

        what, name = args
        if what not in ('lexer', 'formatter', 'filter'):
            print(usage, file=sys.stderr)
            return 2

        _print_help(what, name)
        return 0

    # parse -O options
    parsed_opts = _parse_options(O_opts)
    opts.pop('-O', None)

    # parse -P options
    for p_opt in P_opts:
        try:
            name, value = p_opt.split('=', 1)
        except ValueError:
            parsed_opts[p_opt] = True
        else:
            parsed_opts[name] = value
    opts.pop('-P', None)

    # encodings
    inencoding = parsed_opts.get('inencoding', parsed_opts.get('encoding'))
    outencoding = parsed_opts.get('outencoding', parsed_opts.get('encoding'))

    # handle ``pygmentize -N``
    infn = opts.pop('-N', None)
    if infn is not None:
        try:
            lexer = get_lexer_for_filename(infn, **parsed_opts)
        except ClassNotFound as err:
            lexer = TextLexer()
        except OptionError as err:
            print('Error:', err, file=sys.stderr)
            return 1

        print(lexer.aliases[0])
        return 0

    # handle ``pygmentize -S``
    S_opt = opts.pop('-S', None)
    a_opt = opts.pop('-a', None)
    if S_opt is not None:
        f_opt = opts.pop('-f', None)
        if not f_opt:
            print(usage, file=sys.stderr)
            return 2
        if opts or args:
            print(usage, file=sys.stderr)
            return 2

        try:
            parsed_opts['style'] = S_opt
            fmter = get_formatter_by_name(f_opt, **parsed_opts)
        except ClassNotFound as err:
            print(err, file=sys.stderr)
            return 1

        arg = a_opt or ''
        try:
            print(fmter.get_style_defs(arg))
        except Exception as err:
            print('Error:', err, file=sys.stderr)
            return 1
        return 0

    # if no -S is given, -a is not allowed
    if a_opt is not None:
        print(usage, file=sys.stderr)
        return 2

    # parse -F options
    F_opts = _parse_filters(F_opts)
    opts.pop('-F', None)

    # select formatter
    outfn = opts.pop('-o', None)
    fmter = opts.pop('-f', None)
    if fmter:
        try:
            fmter = get_formatter_by_name(fmter, **parsed_opts)
        except (OptionError, ClassNotFound) as err:
            print('Error:', err, file=sys.stderr)
            return 1

    if outfn:
        if not fmter:
            try:
                fmter = get_formatter_for_filename(outfn, **parsed_opts)
            except (OptionError, ClassNotFound) as err:
                print('Error:', err, file=sys.stderr)
                return 1
        try:
            outfile = open(outfn, 'wb')
        except Exception as err:
            print('Error: cannot open outfile:', err, file=sys.stderr)
            return 1
    else:
        if not fmter:
            fmter = TerminalFormatter(**parsed_opts)
        if sys.version_info > (3, ):
            # Python 3: we have to use .buffer to get a binary stream
            outfile = sys.stdout.buffer
        else:
            outfile = sys.stdout

    # determine output encoding if not explicitly selected
    if not outencoding:
        if outfn:
            # output file? -> encoding pass-through
            fmter.encoding = inencoding
        else:
            # else use terminal encoding
            fmter.encoding = terminal_encoding(sys.stdout)

    # provide coloring under Windows, if possible
    if not outfn and sys.platform in ('win32', 'cygwin') and \
       fmter.name in ('Terminal', 'Terminal256'):
        # unfortunately colorama doesn't support binary streams on Py3
        if sys.version_info > (3, ):
            import io
            outfile = io.TextIOWrapper(outfile, encoding=fmter.encoding)
            fmter.encoding = None
        try:
            import colorama.initialise
        except ImportError:
            pass
        else:
            outfile = colorama.initialise.wrap_stream(outfile,
                                                      convert=None,
                                                      strip=None,
                                                      autoreset=False,
                                                      wrap=True)

    # select lexer
    lexer = opts.pop('-l', None)
    if lexer:
        try:
            lexer = get_lexer_by_name(lexer, **parsed_opts)
        except (OptionError, ClassNotFound) as err:
            print('Error:', err, file=sys.stderr)
            return 1

    # read input code
    code = None

    if args:
        if len(args) > 1:
            print(usage, file=sys.stderr)
            return 2

        if '-s' in opts:
            print('Error: -s option not usable when input file specified',
                  file=sys.stderr)
            return 1

        infn = args[0]
        try:
            with open(infn, 'rb') as infp:
                code = infp.read()
        except Exception as err:
            print('Error: cannot read infile:', err, file=sys.stderr)
            return 1
        if not inencoding:
            code, inencoding = guess_decode(code)

        # do we have to guess the lexer?
        if not lexer:
            try:
                lexer = get_lexer_for_filename(infn, code, **parsed_opts)
            except ClassNotFound as err:
                if '-g' in opts:
                    try:
                        lexer = guess_lexer(code, **parsed_opts)
                    except ClassNotFound:
                        lexer = TextLexer(**parsed_opts)
                else:
                    print('Error:', err, file=sys.stderr)
                    return 1
            except OptionError as err:
                print('Error:', err, file=sys.stderr)
                return 1

    elif '-s' not in opts:  # treat stdin as full file (-s support is later)
        # read code from terminal, always in binary mode since we want to
        # decode ourselves and be tolerant with it
        if sys.version_info > (3, ):
            # Python 3: we have to use .buffer to get a binary stream
            code = sys.stdin.buffer.read()
        else:
            code = sys.stdin.read()
        if not inencoding:
            code, inencoding = guess_decode_from_terminal(code, sys.stdin)
            # else the lexer will do the decoding
        if not lexer:
            try:
                lexer = guess_lexer(code, **parsed_opts)
            except ClassNotFound:
                lexer = TextLexer(**parsed_opts)

    # When using the LaTeX formatter and the option `escapeinside` is
    # specified, we need a special lexer which collects escaped text
    # before running the chosen language lexer.
    escapeinside = parsed_opts.get('escapeinside', '')
    if len(escapeinside) == 2 and isinstance(fmter, LatexFormatter):
        left = escapeinside[0]
        right = escapeinside[1]
        lexer = LatexEmbeddedLexer(left, right, lexer)

    # ... and do it!
    try:
        # process filters
        for fname, fopts in F_opts:
            lexer.add_filter(fname, **fopts)

        if '-s' not in opts:
            # process whole input as per normal...
            highlight(code, lexer, fmter, outfile)
        else:
            if not lexer:
                print(
                    'Error: when using -s a lexer has to be selected with -l',
                    file=sys.stderr)
                return 1
            # line by line processing of stdin (eg: for 'tail -f')...
            try:
                while 1:
                    if sys.version_info > (3, ):
                        # Python 3: we have to use .buffer to get a binary stream
                        line = sys.stdin.buffer.readline()
                    else:
                        line = sys.stdin.readline()
                    if not line:
                        break
                    if not inencoding:
                        line = guess_decode_from_terminal(line, sys.stdin)[0]
                    highlight(line, lexer, fmter, outfile)
                    if hasattr(outfile, 'flush'):
                        outfile.flush()
            except KeyboardInterrupt:
                return 0

    except Exception:
        import traceback
        info = traceback.format_exception(*sys.exc_info())
        msg = info[-1].strip()
        if len(info) >= 3:
            # extract relevant file and position info
            msg += '\n   (f%s)' % info[-2].split('\n')[0].strip()[1:]
        print(file=sys.stderr)
        print('*** Error while highlighting:', file=sys.stderr)
        print(msg, file=sys.stderr)
        return 1

    return 0
class ConsoleInteractionTest(unittest.TestCase):
    def setUp(self):
        self.log_printer = LogPrinter(ConsolePrinter(print_colored=False))
        self.console_printer = ConsolePrinter(print_colored=False)
        self.file_diff_dict = {}
        self.section = Section("t")
        self.local_bears = OrderedDict([("default", [SomelocalBear]),
                                        ("test", [SomelocalBear])])
        self.global_bears = OrderedDict([("default", [SomeglobalBear]),
                                         ("test", [SomeglobalBear])])

        self.old_open_editor_applicable = OpenEditorAction.is_applicable
        OpenEditorAction.is_applicable = staticmethod(lambda *args: False)

        self.old_apply_patch_applicable = ApplyPatchAction.is_applicable
        ApplyPatchAction.is_applicable = staticmethod(lambda *args: False)
        self.lexer = TextLexer()
        self.lexer.add_filter(
            VisibleWhitespaceFilter(spaces="•",
                                    tabs=True,
                                    tabsize=SpacingHelper.DEFAULT_TAB_WIDTH))

    def tearDown(self):
        OpenEditorAction.is_applicable = self.old_open_editor_applicable
        ApplyPatchAction.is_applicable = self.old_apply_patch_applicable

    def test_require_settings(self):
        self.assertRaises(TypeError, acquire_settings, self.log_printer, 0)

        with simulate_console_inputs(0, 1, 2) as generator:
            self.assertEqual(
                acquire_settings(self.log_printer,
                                 {"setting": ["help text", "SomeBear"]}),
                {"setting": 0})

            self.assertEqual(
                acquire_settings(
                    self.log_printer,
                    {"setting": ["help text", "SomeBear", "AnotherBear"]}),
                {"setting": 1})

            self.assertEqual(
                acquire_settings(
                    self.log_printer, {
                        "setting": [
                            "help text", "SomeBear", "AnotherBear",
                            "YetAnotherBear"
                        ]
                    }), {"setting": 2})

            self.assertEqual(generator.last_input, 2)

    def test_print_diffs_info(self):
        file_dict = {"a": ["a\n", "b\n", "c\n"], "b": ["old_first\n"]}
        diff_dict = {"a": Diff(file_dict['a']), "b": Diff(file_dict['b'])}
        diff_dict["a"].add_lines(1, ["test\n"])
        diff_dict["a"].delete_line(3)
        diff_dict["b"].add_lines(0, ["first\n"])
        previous_diffs = {"a": Diff(file_dict['a'])}
        previous_diffs["a"].change_line(2, "b\n", "b_changed\n")
        with retrieve_stdout() as stdout:
            print_diffs_info(diff_dict, self.console_printer)
            self.assertEqual(stdout.getvalue(), "|    | +1 -1 in a\n"
                             "|    | +1 -0 in b\n")

    @patch("coalib.output.ConsoleInteraction.acquire_actions_and_apply")
    @patch("coalib.output.ConsoleInteraction.ShowPatchAction."
           "apply_from_section")
    def test_print_result_interactive_small_patch(self, apply_from_section, _):
        file_dict = {"a": ["a\n", "b\n", "c\n"], "b": ["old_first\n"]}
        diff_dict = {"a": Diff(file_dict['a']), "b": Diff(file_dict['b'])}
        diff_dict["a"].add_lines(1, ["test\n"])
        diff_dict["a"].delete_line(3)
        result = Result("origin", "msg", diffs=diff_dict)
        section = Section("test")

        print_result(self.console_printer, self.log_printer, section,
                     self.file_diff_dict, result, file_dict, True)
        apply_from_section.assert_called_once_with(result, file_dict,
                                                   self.file_diff_dict,
                                                   section)

    @patch("coalib.output.ConsoleInteraction.acquire_actions_and_apply")
    @patch("coalib.output.ConsoleInteraction.print_diffs_info")
    def test_print_result_interactive_big_patch(self, diffs_info, _):
        file_dict = {"a": ["a\n", "b\n", "c\n"], "b": ["old_first\n"]}
        diff_dict = {"a": Diff(file_dict['a']), "b": Diff(file_dict['b'])}
        diff_dict["a"].add_lines(1, ["test\n", "test1\n", "test2\n"])
        diff_dict["a"].delete_line(3)
        diff_dict["a"].add_lines(3, ["3test\n"])
        result = Result("origin", "msg", diffs=diff_dict)
        section = Section("test")

        print_result(self.console_printer, self.log_printer, section,
                     self.file_diff_dict, result, file_dict, True)
        diffs_info.assert_called_once_with(diff_dict, self.console_printer)

    def test_print_result(self):
        print_result(self.console_printer, self.log_printer, None,
                     self.file_diff_dict, "illegal value", {})

        with simulate_console_inputs(0):
            print_result(self.console_printer, self.log_printer,
                         self.section, self.file_diff_dict,
                         Result("origin", "msg", diffs={}), {})

        with make_temp() as testfile_path:
            file_dict = {
                testfile_path: ["1\n", "2\n", "3\n"],
                "f_b": ["1", "2", "3"]
            }
            diff = Diff(file_dict[testfile_path])
            diff.delete_line(2)
            diff.change_line(3, "3\n", "3_changed\n")

            ApplyPatchAction.is_applicable = staticmethod(lambda *args: True)

            # Interaction must be closed by the user with `0` if it's not a
            # param
            with simulate_console_inputs("INVALID", -1, 1, 0,
                                         3) as input_generator:
                curr_section = Section("")
                print_section_beginning(self.console_printer, curr_section)
                print_result(
                    self.console_printer, self.log_printer, curr_section,
                    self.file_diff_dict,
                    Result("origin", "msg", diffs={testfile_path:
                                                   diff}), file_dict)
                self.assertEqual(input_generator.last_input, 3)

                self.file_diff_dict.clear()

                with open(testfile_path) as f:
                    self.assertEqual(f.readlines(), ["1\n", "3_changed\n"])

                os.remove(testfile_path + ".orig")

                name, section = get_action_info(curr_section,
                                                TestAction().get_metadata(),
                                                failed_actions=set())
                self.assertEqual(input_generator.last_input, 4)
                self.assertEqual(str(section), " {param : '3'}")
                self.assertEqual(name, "TestAction")

        # Check if the user is asked for the parameter only the first time.
        # Use OpenEditorAction that needs this parameter (editor command).
        with simulate_console_inputs(1, "test_editor", 0, 1, 0) as generator:
            OpenEditorAction.is_applicable = staticmethod(lambda *args: True)

            patch_result = Result("origin", "msg", diffs={testfile_path: diff})
            patch_result.file = "f_b"

            print_result(self.console_printer, self.log_printer, curr_section,
                         self.file_diff_dict, patch_result, file_dict)
            # choose action, choose editor, choose no action (-1 -> 2)
            self.assertEqual(generator.last_input, 2)

            # It shoudn't ask for parameter again
            print_result(self.console_printer, self.log_printer, curr_section,
                         self.file_diff_dict, patch_result, file_dict)
            self.assertEqual(generator.last_input, 4)

    def test_print_affected_files(self):
        with retrieve_stdout() as stdout, \
                make_temp() as some_file:
            file_dict = {some_file: ["1\n", "2\n", "3\n"]}
            affected_code = (SourceRange.from_values(some_file), )
            print_affected_files(self.console_printer,
                                 self.log_printer,
                                 Section(""),
                                 Result("origin",
                                        "message",
                                        affected_code=affected_code),
                                 file_dict,
                                 color=True)
            self.assertEqual(stdout.getvalue(),
                             "\n" + relpath(some_file) + "\n")

    def test_acquire_actions_and_apply(self):
        with make_temp() as testfile_path:
            file_dict = {testfile_path: ["1\n", "2\n", "3\n"]}
            diff = Diff(file_dict[testfile_path])
            diff.delete_line(2)
            diff.change_line(3, "3\n", "3_changed\n")
            with simulate_console_inputs(1, 0) as generator, \
                    retrieve_stdout() as sio:
                ApplyPatchAction.is_applicable = staticmethod(
                    lambda *args: True)
                acquire_actions_and_apply(
                    self.console_printer, self.log_printer, Section(""),
                    self.file_diff_dict,
                    Result("origin", "message", diffs={testfile_path:
                                                       diff}), file_dict)
                self.assertEqual(generator.last_input, 1)
                self.assertIn(ApplyPatchAction.SUCCESS_MESSAGE, sio.getvalue())

            class InvalidateTestAction(ResultAction):

                is_applicable = staticmethod(lambda *args: True)

                def apply(*args, **kwargs):
                    ApplyPatchAction.is_applicable = staticmethod(
                        lambda *args: False)

            old_applypatch_is_applicable = ApplyPatchAction.is_applicable
            ApplyPatchAction.is_applicable = staticmethod(lambda *args: True)
            cli_actions = [ApplyPatchAction(), InvalidateTestAction()]

            with simulate_console_inputs(2, 1, 0) as generator, \
                    retrieve_stdout() as sio:
                acquire_actions_and_apply(self.console_printer,
                                          self.log_printer,
                                          Section(""),
                                          self.file_diff_dict,
                                          Result("origin",
                                                 "message",
                                                 diffs={testfile_path: diff}),
                                          file_dict,
                                          cli_actions=cli_actions)
                self.assertEqual(generator.last_input, 2)

                action_fail = "Failed to execute the action"
                self.assertNotIn(action_fail, sio.getvalue())

                apply_path_desc = ApplyPatchAction().get_metadata().desc
                self.assertEqual(sio.getvalue().count(apply_path_desc), 1)

            ApplyPatchAction.is_applicable = old_applypatch_is_applicable

    def test_ask_for_actions_and_apply(self):
        failed_actions = set()
        action = TestAction()
        args = [
            self.log_printer, self.console_printer,
            Section(""), [action.get_metadata()], {
                'TestAction': action
            }, failed_actions,
            Result("origin", "message"), {}, {}
        ]

        with simulate_console_inputs(1, 'param1', 1, 'param2') as generator:
            action.apply = unittest.mock.Mock(side_effect=AssertionError)
            ask_for_action_and_apply(*args)
            self.assertEqual(generator.last_input, 1)
            self.assertIn('TestAction', failed_actions)

            action.apply = lambda *args, **kwargs: {}
            ask_for_action_and_apply(*args)
            self.assertEqual(generator.last_input, 3)
            self.assertNotIn('TestAction', failed_actions)

    def test_default_input(self):
        action = TestAction()
        args = [
            self.log_printer, self.console_printer,
            Section(""), [action.get_metadata()], {
                'TestAction': action
            },
            set(),
            Result("origin", "message"), {}, {}
        ]

        with simulate_console_inputs("") as generator:
            self.assertFalse(ask_for_action_and_apply(*args))

    def test_print_result_no_input(self):
        with make_temp() as testfile_path:
            file_dict = {testfile_path: ["1\n", "2\n", "3\n"]}
            diff = Diff(file_dict[testfile_path])
            diff.delete_line(2)
            diff.change_line(3, "3\n", "3_changed\n")
            with simulate_console_inputs(1, 2, 3) as generator, \
                    retrieve_stdout() as stdout:
                ApplyPatchAction.is_applicable = staticmethod(
                    lambda *args: True)
                print_results_no_input(
                    self.log_printer,
                    Section("someSection"),
                    [Result("origin", "message", diffs={testfile_path: diff})],
                    file_dict,
                    self.file_diff_dict,
                    color=False)
                self.assertEqual(generator.last_input, -1)
                self.assertEqual(
                    stdout.getvalue(), """
Project wide:
|    | [NORMAL] origin:
|    | {}\n""".format(highlight_text("message", style=BackgroundMessageStyle)))

    def test_print_section_beginning(self):
        with retrieve_stdout() as stdout:
            print_section_beginning(self.console_printer, Section("name"))
            self.assertEqual(stdout.getvalue(), "Executing section name...\n")

    def test_nothing_done(self):
        with retrieve_stdout() as stdout:
            nothing_done(self.log_printer)
            self.assertIn(
                "No existent section was targeted or enabled. "
                "Nothing to do.\n", stdout.getvalue())

    def test_print_results_empty(self):
        with retrieve_stdout() as stdout:
            print_results(self.log_printer, Section(""), [], {}, {})
            self.assertEqual(stdout.getvalue(), "")

    def test_print_results_project_wide(self):
        with retrieve_stdout() as stdout:
            print_results(self.log_printer,
                          Section(""), [Result("origin", "message")], {}, {},
                          color=False)
            self.assertEqual(
                "\n{}\n|    | [NORMAL] origin:\n|    | {}\n".format(
                    STR_PROJECT_WIDE,
                    highlight_text("message", style=BackgroundMessageStyle)),
                stdout.getvalue())

    def test_print_results_for_file(self):
        with retrieve_stdout() as stdout:
            print_results(
                self.log_printer,
                Section(""), [
                    Result.from_values("SpaceConsistencyBear",
                                       "Trailing whitespace found",
                                       file="filename",
                                       line=2)
                ],
                {abspath("filename"): ["test line\n", "line 2\n", "line 3\n"]},
                {},
                color=False)
            self.assertEqual(
                """\nfilename
|   2| {}
|    | [NORMAL] SpaceConsistencyBear:
|    | {}\n""".format(
                    highlight_text('line 2', self.lexer),
                    highlight_text("Trailing whitespace found",
                                   style=BackgroundMessageStyle)),
                stdout.getvalue())

        with retrieve_stdout() as stdout:
            print_results(self.log_printer,
                          Section(""), [
                              Result.from_values("SpaceConsistencyBear",
                                                 "Trailing whitespace found",
                                                 file="filename",
                                                 line=5)
                          ], {
                              abspath("filename"): [
                                  "test line\n", "line 2\n", "line 3\n",
                                  "line 4\n", "line 5\n"
                              ]
                          }, {},
                          color=False)
            self.assertEqual(
                """\nfilename
|   5| {}
|    | [NORMAL] SpaceConsistencyBear:
|    | {}\n""".format(
                    highlight_text('line 5', self.lexer),
                    highlight_text("Trailing whitespace found",
                                   style=BackgroundMessageStyle)),
                stdout.getvalue())

    def test_print_results_sorting(self):
        with retrieve_stdout() as stdout:
            print_results(self.log_printer,
                          Section(""), [
                              Result.from_values("SpaceConsistencyBear",
                                                 "Trailing whitespace found",
                                                 file="file",
                                                 line=5),
                              Result.from_values("SpaceConsistencyBear",
                                                 "Trailing whitespace found",
                                                 file="file",
                                                 line=2)
                          ], {
                              abspath("file"): [
                                  "test line\n", "\t\n", "line 3\n",
                                  "line 4\n", "line 5\t\n"
                              ]
                          }, {},
                          color=False)

            self.assertEqual(
                """
file
|   2| {0}
|    | [NORMAL] SpaceConsistencyBear:
|    | {1}

file
|   5| {2}
|    | [NORMAL] SpaceConsistencyBear:
|    | {1}\n""".format(
                    highlight_text('\t', self.lexer),
                    highlight_text("Trailing whitespace found",
                                   style=BackgroundMessageStyle),
                    highlight_text('line 5\t', self.lexer)), stdout.getvalue())

    def test_print_results_multiple_ranges(self):
        affected_code = (SourceRange.from_values("some_file", 5, end_line=7),
                         SourceRange.from_values("another_file", 1, 3, 1, 5),
                         SourceRange.from_values("another_file", 3, 3, 3, 5))
        with retrieve_stdout() as stdout:
            print_results(self.log_printer,
                          Section(""), [
                              Result("ClangCloneDetectionBear", "Clone Found",
                                     affected_code)
                          ], {
                              abspath("some_file"):
                              ["line " + str(i + 1) + "\n" for i in range(10)],
                              abspath("another_file"):
                              ["line " + str(i + 1) for i in range(10)]
                          }, {},
                          color=False)
            self.assertEqual(
                """
another_file
|   1| li{0}{1}

another_file
|   3| li{0}{2}

some_file
|   5| {3}
|   6| {4}
|   7| {5}
|    | [NORMAL] ClangCloneDetectionBear:
|    | {6}\n""".format(
                    highlight_text('ne', self.lexer,
                                   BackgroundSourceRangeStyle),
                    highlight_text(' 1', self.lexer),
                    highlight_text(' 3', self.lexer),
                    highlight_text('line 5', self.lexer),
                    highlight_text('line 6', self.lexer),
                    highlight_text('line 7', self.lexer),
                    highlight_text("Clone Found",
                                   style=BackgroundMessageStyle)),
                stdout.getvalue())

    def test_print_results_missing_file(self):
        self.log_printer = LogPrinter(NullPrinter())
        with retrieve_stdout() as stdout:
            print_results(
                self.log_printer,
                Section(""), [
                    Result("t", "msg"),
                    Result.from_values("t", "msg", file="file", line=5)
                ], {}, {},
                color=False)
            self.assertEqual(
                "\n" + STR_PROJECT_WIDE + "\n"
                "|    | [NORMAL] t:\n"
                "|    | {0}\n"
                # Second results file isn't there, no context is
                # printed, only a warning log message which we
                # don't catch
                "|    | [NORMAL] t:\n"
                "|    | {0}\n".format(
                    highlight_text("msg", style=BackgroundMessageStyle)),
                stdout.getvalue())

    def test_print_results_missing_line(self):
        with retrieve_stdout() as stdout:
            print_results(
                self.log_printer,
                Section(""), [
                    Result.from_values("t", "msg", file="file", line=5),
                    Result.from_values("t", "msg", file="file", line=6)
                ], {abspath("file"): ["line " + str(i + 1) for i in range(5)]},
                {},
                color=False)
            self.assertEqual(
                "\n"
                "file\n"
                "|   5| {0}\n"
                "|    | [NORMAL] t:\n"
                "|    | {1}\n"
                "\n"
                "file\n"
                "|   6| {2}\n"
                "|    | [NORMAL] t:\n"
                "|    | {1}\n".format(
                    highlight_text('line 5', self.lexer),
                    highlight_text("msg", style=BackgroundMessageStyle),
                    STR_LINE_DOESNT_EXIST), stdout.getvalue())

    def test_print_results_without_line(self):
        with retrieve_stdout() as stdout:
            print_results(self.log_printer,
                          Section(""),
                          [Result.from_values("t", "msg", file="file")],
                          {abspath("file"): []}, {},
                          color=False)
            self.assertEqual(
                "\nfile\n"
                "|    | [NORMAL] t:\n"
                "|    | {}\n".format(
                    highlight_text("msg", style=BackgroundMessageStyle)),
                stdout.getvalue())
Beispiel #10
0
def main(args=sys.argv):
    """
    Main command line entry point.
    """
    # pylint: disable-msg=R0911,R0912,R0915

    usage = USAGE % ((args[0],) * 6)

    if sys.platform in ['win32', 'cygwin']:
        try:
            # Provide coloring under Windows, if possible
            import colorama
            colorama.init()
        except ImportError:
            pass

    try:
        popts, args = getopt.getopt(args[1:], "l:f:F:o:O:P:LS:a:N:hVHg")
    except getopt.GetoptError:
        print(usage, file=sys.stderr)
        return 2
    opts = {}
    O_opts = []
    P_opts = []
    F_opts = []
    for opt, arg in popts:
        if opt == '-O':
            O_opts.append(arg)
        elif opt == '-P':
            P_opts.append(arg)
        elif opt == '-F':
            F_opts.append(arg)
        opts[opt] = arg

    if not opts and not args:
        print(usage)
        return 0

    if opts.pop('-h', None) is not None:
        print(usage)
        return 0

    if opts.pop('-V', None) is not None:
        print('Pygments version %s, (c) 2006-2014 by Georg Brandl.' % __version__)
        return 0

    # handle ``pygmentize -L``
    L_opt = opts.pop('-L', None)
    if L_opt is not None:
        if opts:
            print(usage, file=sys.stderr)
            return 2

        # print version
        main(['', '-V'])
        if not args:
            args = ['lexer', 'formatter', 'filter', 'style']
        for arg in args:
            _print_list(arg.rstrip('s'))
        return 0

    # handle ``pygmentize -H``
    H_opt = opts.pop('-H', None)
    if H_opt is not None:
        if opts or len(args) != 2:
            print(usage, file=sys.stderr)
            return 2

        what, name = args
        if what not in ('lexer', 'formatter', 'filter'):
            print(usage, file=sys.stderr)
            return 2

        _print_help(what, name)
        return 0

    # parse -O options
    parsed_opts = _parse_options(O_opts)
    opts.pop('-O', None)

    # parse -P options
    for p_opt in P_opts:
        try:
            name, value = p_opt.split('=', 1)
        except ValueError:
            parsed_opts[p_opt] = True
        else:
            parsed_opts[name] = value
    opts.pop('-P', None)

    # handle ``pygmentize -N``
    infn = opts.pop('-N', None)
    if infn is not None:
        try:
            lexer = get_lexer_for_filename(infn, **parsed_opts)
        except ClassNotFound as err:
            lexer = TextLexer()
        except OptionError as err:
            print('Error:', err, file=sys.stderr)
            return 1

        print(lexer.aliases[0])
        return 0

    # handle ``pygmentize -S``
    S_opt = opts.pop('-S', None)
    a_opt = opts.pop('-a', None)
    if S_opt is not None:
        f_opt = opts.pop('-f', None)
        if not f_opt:
            print(usage, file=sys.stderr)
            return 2
        if opts or args:
            print(usage, file=sys.stderr)
            return 2

        try:
            parsed_opts['style'] = S_opt
            fmter = get_formatter_by_name(f_opt, **parsed_opts)
        except ClassNotFound as err:
            print(err, file=sys.stderr)
            return 1

        arg = a_opt or ''
        try:
            print(fmter.get_style_defs(arg))
        except Exception as err:
            print('Error:', err, file=sys.stderr)
            return 1
        return 0

    # if no -S is given, -a is not allowed
    if a_opt is not None:
        print(usage, file=sys.stderr)
        return 2

    # parse -F options
    F_opts = _parse_filters(F_opts)
    opts.pop('-F', None)

    # select formatter
    outfn = opts.pop('-o', None)
    fmter = opts.pop('-f', None)
    if fmter:
        try:
            fmter = get_formatter_by_name(fmter, **parsed_opts)
        except (OptionError, ClassNotFound) as err:
            print('Error:', err, file=sys.stderr)
            return 1

    if outfn:
        if not fmter:
            try:
                fmter = get_formatter_for_filename(outfn, **parsed_opts)
            except (OptionError, ClassNotFound) as err:
                print('Error:', err, file=sys.stderr)
                return 1
        try:
            outfile = open(outfn, 'wb')
        except Exception as err:
            print('Error: cannot open outfile:', err, file=sys.stderr)
            return 1
    else:
        if not fmter:
            fmter = TerminalFormatter(**parsed_opts)
        outfile = sys.stdout

    # select lexer
    lexer = opts.pop('-l', None)
    if lexer:
        try:
            lexer = get_lexer_by_name(lexer, **parsed_opts)
        except (OptionError, ClassNotFound) as err:
            print('Error:', err, file=sys.stderr)
            return 1

    if args:
        if len(args) > 1:
            print(usage, file=sys.stderr)
            return 2

        infn = args[0]
        try:
            code = open(infn, 'rb').read()
        except Exception as err:
            print('Error: cannot read infile:', err, file=sys.stderr)
            return 1

        if not lexer:
            try:
                lexer = get_lexer_for_filename(infn, code, **parsed_opts)
            except ClassNotFound as err:
                if '-g' in opts:
                    try:
                        lexer = guess_lexer(code, **parsed_opts)
                    except ClassNotFound:
                        lexer = TextLexer(**parsed_opts)
                else:
                    print('Error:', err, file=sys.stderr)
                    return 1
            except OptionError as err:
                print('Error:', err, file=sys.stderr)
                return 1

    else:
        if '-g' in opts:
            code = sys.stdin.read()
            try:
                lexer = guess_lexer(code, **parsed_opts)
            except ClassNotFound:
                lexer = TextLexer(**parsed_opts)
        elif not lexer:
            print('Error: no lexer name given and reading ' + \
                                'from stdin (try using -g or -l <lexer>)', file=sys.stderr)
            return 2
        else:
            code = sys.stdin.read()

    # No encoding given? Use latin1 if output file given,
    # stdin/stdout encoding otherwise.
    # (This is a compromise, I'm not too happy with it...)
    if 'encoding' not in parsed_opts and 'outencoding' not in parsed_opts:
        if outfn:
            # encoding pass-through
            fmter.encoding = 'latin1'
        else:
            if sys.version_info < (3,):
                # use terminal encoding; Python 3's terminals already do that
                lexer.encoding = getattr(sys.stdin, 'encoding',
                                         None) or 'ascii'
                fmter.encoding = getattr(sys.stdout, 'encoding',
                                         None) or 'ascii'
    elif not outfn and sys.version_info > (3,):
        # output to terminal with encoding -> use .buffer
        outfile = sys.stdout.buffer

    # ... and do it!
    try:
        # process filters
        for fname, fopts in F_opts:
            lexer.add_filter(fname, **fopts)
        highlight(code, lexer, fmter, outfile)
    except Exception:
        import traceback
        info = traceback.format_exception(*sys.exc_info())
        msg = info[-1].strip()
        if len(info) >= 3:
            # extract relevant file and position info
            msg += '\n   (f%s)' % info[-2].split('\n')[0].strip()[1:]
        print(file=sys.stderr)
        print('*** Error while highlighting:', file=sys.stderr)
        print(msg, file=sys.stderr)
        return 1

    return 0
Beispiel #11
0
class ConsoleInteractionTest(unittest.TestCase):

    def setUp(self):
        self.log_printer = LogPrinter(ConsolePrinter(print_colored=False))
        self.console_printer = ConsolePrinter(print_colored=False)
        self.file_diff_dict = {}
        self.section = Section("t")
        self.local_bears = OrderedDict([("default", [SomelocalBear]),
                                        ("test", [SomelocalBear])])
        self.global_bears = OrderedDict([("default", [SomeglobalBear]),
                                         ("test", [SomeglobalBear])])

        self.old_open_editor_applicable = OpenEditorAction.is_applicable
        OpenEditorAction.is_applicable = staticmethod(lambda *args: False)

        self.old_apply_patch_applicable = ApplyPatchAction.is_applicable
        ApplyPatchAction.is_applicable = staticmethod(lambda *args: False)
        self.lexer = TextLexer()
        self.lexer.add_filter(VisibleWhitespaceFilter(
            spaces="•",
            tabs=True,
            tabsize=SpacingHelper.DEFAULT_TAB_WIDTH))

    def tearDown(self):
        OpenEditorAction.is_applicable = self.old_open_editor_applicable
        ApplyPatchAction.is_applicable = self.old_apply_patch_applicable

    def test_require_settings(self):
        self.assertRaises(TypeError, acquire_settings, self.log_printer, 0)

        with simulate_console_inputs(0, 1, 2) as generator:
            self.assertEqual(acquire_settings(self.log_printer,
                                              {"setting": ["help text",
                                                           "SomeBear"]}),
                             {"setting": 0})

            self.assertEqual(acquire_settings(self.log_printer,
                                              {"setting": ["help text",
                                                           "SomeBear",
                                                           "AnotherBear"]}),
                             {"setting": 1})

            self.assertEqual(acquire_settings(self.log_printer,
                                              {"setting": ["help text",
                                                           "SomeBear",
                                                           "AnotherBear",
                                                           "YetAnotherBear"]}),
                             {"setting": 2})

            self.assertEqual(generator.last_input, 2)

    def test_print_diffs_info(self):
        file_dict = {"a": ["a\n", "b\n", "c\n"], "b": ["old_first\n"]}
        diff_dict = {"a": Diff(file_dict['a']),
                     "b": Diff(file_dict['b'])}
        diff_dict["a"].add_lines(1, ["test\n"])
        diff_dict["a"].delete_line(3)
        diff_dict["b"].add_lines(0, ["first\n"])
        previous_diffs = {"a": Diff(file_dict['a'])}
        previous_diffs["a"].change_line(2, "b\n", "b_changed\n")
        with retrieve_stdout() as stdout:
            print_diffs_info(diff_dict, self.console_printer)
            self.assertEqual(stdout.getvalue(),
                             "|    | +1 -1 in a\n"
                             "|    | +1 -0 in b\n")

    @patch("coalib.output.ConsoleInteraction.acquire_actions_and_apply")
    @patch("coalib.output.ConsoleInteraction.ShowPatchAction."
           "apply_from_section")
    def test_print_result_interactive_small_patch(self, apply_from_section, _):
        file_dict = {"a": ["a\n", "b\n", "c\n"], "b": ["old_first\n"]}
        diff_dict = {"a": Diff(file_dict['a']),
                     "b": Diff(file_dict['b'])}
        diff_dict["a"].add_lines(1, ["test\n"])
        diff_dict["a"].delete_line(3)
        result = Result("origin", "msg", diffs=diff_dict)
        section = Section("test")

        print_result(self.console_printer,
                     self.log_printer,
                     section,
                     self.file_diff_dict,
                     result,
                     file_dict,
                     True)
        apply_from_section.assert_called_once_with(
            result, file_dict, self.file_diff_dict, section)

    @patch("coalib.output.ConsoleInteraction.acquire_actions_and_apply")
    @patch("coalib.output.ConsoleInteraction.print_diffs_info")
    def test_print_result_interactive_big_patch(self, diffs_info, _):
        file_dict = {"a": ["a\n", "b\n", "c\n"], "b": ["old_first\n"]}
        diff_dict = {"a": Diff(file_dict['a']),
                     "b": Diff(file_dict['b'])}
        diff_dict["a"].add_lines(1, ["test\n", "test1\n", "test2\n"])
        diff_dict["a"].delete_line(3)
        diff_dict["a"].add_lines(3, ["3test\n"])
        result = Result("origin", "msg", diffs=diff_dict)
        section = Section("test")

        print_result(self.console_printer,
                     self.log_printer,
                     section,
                     self.file_diff_dict,
                     result,
                     file_dict,
                     True)
        diffs_info.assert_called_once_with(diff_dict, self.console_printer)

    def test_print_result(self):
        print_result(self.console_printer,
                     self.log_printer,
                     None,
                     self.file_diff_dict,
                     "illegal value",
                     {})

        with simulate_console_inputs(0):
            print_result(self.console_printer,
                         self.log_printer,
                         self.section,
                         self.file_diff_dict,
                         Result("origin", "msg", diffs={}),
                         {})

        with make_temp() as testfile_path:
            file_dict = {
                testfile_path: ["1\n", "2\n", "3\n"],
                "f_b": ["1", "2", "3"]
            }
            diff = Diff(file_dict[testfile_path])
            diff.delete_line(2)
            diff.change_line(3, "3\n", "3_changed\n")

            ApplyPatchAction.is_applicable = staticmethod(
                lambda *args: True)

            # Interaction must be closed by the user with `0` if it's not a
            # param
            with simulate_console_inputs("INVALID",
                                         -1,
                                         1,
                                         0,
                                         3) as input_generator:
                curr_section = Section("")
                print_section_beginning(self.console_printer, curr_section)
                print_result(self.console_printer,
                             self.log_printer,
                             curr_section,
                             self.file_diff_dict,
                             Result("origin", "msg", diffs={
                                    testfile_path: diff}),
                             file_dict)
                self.assertEqual(input_generator.last_input, 3)

                self.file_diff_dict.clear()

                with open(testfile_path) as f:
                    self.assertEqual(f.readlines(), ["1\n", "3_changed\n"])

                os.remove(testfile_path + ".orig")

                name, section = get_action_info(curr_section,
                                                TestAction().get_metadata(),
                                                failed_actions=set())
                self.assertEqual(input_generator.last_input, 4)
                self.assertEqual(str(section), " {param : '3'}")
                self.assertEqual(name, "TestAction")

        # Check if the user is asked for the parameter only the first time.
        # Use OpenEditorAction that needs this parameter (editor command).
        with simulate_console_inputs(1, "test_editor", 0, 1, 0) as generator:
            OpenEditorAction.is_applicable = staticmethod(lambda *args: True)

            patch_result = Result("origin", "msg", diffs={testfile_path: diff})
            patch_result.file = "f_b"

            print_result(self.console_printer,
                         self.log_printer,
                         curr_section,
                         self.file_diff_dict,
                         patch_result,
                         file_dict)
            # choose action, choose editor, choose no action (-1 -> 2)
            self.assertEqual(generator.last_input, 2)

            # It shoudn't ask for parameter again
            print_result(self.console_printer,
                         self.log_printer,
                         curr_section,
                         self.file_diff_dict,
                         patch_result,
                         file_dict)
            self.assertEqual(generator.last_input, 4)

    def test_print_affected_files(self):
        with retrieve_stdout() as stdout, \
                make_temp() as some_file:
            file_dict = {some_file: ["1\n", "2\n", "3\n"]}
            affected_code = (SourceRange.from_values(some_file),)
            print_affected_files(self.console_printer,
                                 self.log_printer,
                                 Section(""),
                                 Result("origin",
                                        "message",
                                        affected_code=affected_code),
                                 file_dict,
                                 color=True)
            self.assertEqual(stdout.getvalue(),
                             "\n"+relpath(some_file)+"\n")

    def test_acquire_actions_and_apply(self):
        with make_temp() as testfile_path:
            file_dict = {testfile_path: ["1\n", "2\n", "3\n"]}
            diff = Diff(file_dict[testfile_path])
            diff.delete_line(2)
            diff.change_line(3, "3\n", "3_changed\n")
            with simulate_console_inputs(1, 0) as generator, \
                    retrieve_stdout() as sio:
                ApplyPatchAction.is_applicable = staticmethod(
                    lambda *args: True)
                acquire_actions_and_apply(self.console_printer,
                                          self.log_printer,
                                          Section(""),
                                          self.file_diff_dict,
                                          Result("origin", "message", diffs={
                                              testfile_path: diff}),
                                          file_dict)
                self.assertEqual(generator.last_input, 1)
                self.assertIn(ApplyPatchAction.SUCCESS_MESSAGE, sio.getvalue())

            class InvalidateTestAction(ResultAction):

                is_applicable = staticmethod(lambda *args: True)

                def apply(*args, **kwargs):
                    ApplyPatchAction.is_applicable = staticmethod(
                        lambda *args: False)

            old_applypatch_is_applicable = ApplyPatchAction.is_applicable
            ApplyPatchAction.is_applicable = staticmethod(lambda *args: True)
            cli_actions = [ApplyPatchAction(), InvalidateTestAction()]

            with simulate_console_inputs(2, 1, 0) as generator, \
                    retrieve_stdout() as sio:
                acquire_actions_and_apply(self.console_printer,
                                          self.log_printer,
                                          Section(""),
                                          self.file_diff_dict,
                                          Result("origin", "message",
                                                 diffs={testfile_path: diff}),
                                          file_dict,
                                          cli_actions=cli_actions)
                self.assertEqual(generator.last_input, 2)

                action_fail = "Failed to execute the action"
                self.assertNotIn(action_fail, sio.getvalue())

                apply_path_desc = ApplyPatchAction().get_metadata().desc
                self.assertEqual(sio.getvalue().count(apply_path_desc), 1)

            ApplyPatchAction.is_applicable = old_applypatch_is_applicable

    def test_ask_for_actions_and_apply(self):
        failed_actions = set()
        action = TestAction()
        args = [self.log_printer, self.console_printer, Section(""),
                [action.get_metadata()], {'TestAction': action},
                failed_actions, Result("origin", "message"), {}, {}]

        with simulate_console_inputs(1, 'param1', 1, 'param2') as generator:
            action.apply = unittest.mock.Mock(side_effect=AssertionError)
            ask_for_action_and_apply(*args)
            self.assertEqual(generator.last_input, 1)
            self.assertIn('TestAction', failed_actions)

            action.apply = lambda *args, **kwargs: {}
            ask_for_action_and_apply(*args)
            self.assertEqual(generator.last_input, 3)
            self.assertNotIn('TestAction', failed_actions)

    def test_print_result_no_input(self):
        with make_temp() as testfile_path:
            file_dict = {testfile_path: ["1\n", "2\n", "3\n"]}
            diff = Diff(file_dict[testfile_path])
            diff.delete_line(2)
            diff.change_line(3, "3\n", "3_changed\n")
            with simulate_console_inputs(1, 2, 3) as generator, \
                    retrieve_stdout() as stdout:
                ApplyPatchAction.is_applicable = staticmethod(
                    lambda *args: True)
                print_results_no_input(self.log_printer,
                                       Section("someSection"),
                                       [Result("origin", "message", diffs={
                                           testfile_path: diff})],
                                       file_dict,
                                       self.file_diff_dict,
                                       color=False)
                self.assertEqual(generator.last_input, -1)
                self.assertEqual(stdout.getvalue(),
                                 """
Project wide:
|    | [NORMAL] origin:
|    | {}\n""".format(highlight_text("message", style=BackgroundMessageStyle)))

    def test_print_section_beginning(self):
        with retrieve_stdout() as stdout:
            print_section_beginning(self.console_printer, Section("name"))
            self.assertEqual(stdout.getvalue(), "Executing section name...\n")

    def test_nothing_done(self):
        with retrieve_stdout() as stdout:
            nothing_done(self.log_printer)
            self.assertIn("No existent section was targeted or enabled. "
                          "Nothing to do.\n",
                          stdout.getvalue())

    def test_print_results_empty(self):
        with retrieve_stdout() as stdout:
            print_results(self.log_printer, Section(""), [], {}, {})
            self.assertEqual(stdout.getvalue(), "")

    def test_print_results_project_wide(self):
        with retrieve_stdout() as stdout:
            print_results(self.log_printer,
                          Section(""),
                          [Result("origin", "message")],
                          {},
                          {},
                          color=False)
            self.assertEqual(
                "\n{}\n|    | [NORMAL] origin:\n|    | {}\n".format(
                    STR_PROJECT_WIDE,
                    highlight_text("message", style=BackgroundMessageStyle)),
                stdout.getvalue())

    def test_print_results_for_file(self):
        with retrieve_stdout() as stdout:
            print_results(
                self.log_printer,
                Section(""),
                [Result.from_values("SpaceConsistencyBear",
                                    "Trailing whitespace found",
                                    file="filename",
                                    line=2)],
                {abspath("filename"): ["test line\n", "line 2\n", "line 3\n"]},
                {},
                color=False)
            self.assertEqual("""\nfilename
|   2| {}
|    | [NORMAL] SpaceConsistencyBear:
|    | {}\n""".format(highlight_text('line 2', self.lexer),
                      highlight_text("Trailing whitespace found",
                                     style=BackgroundMessageStyle)),
                stdout.getvalue())

        with retrieve_stdout() as stdout:
            print_results(
                self.log_printer,
                Section(""),
                [Result.from_values("SpaceConsistencyBear",
                                    "Trailing whitespace found",
                                    file="filename",
                                    line=5)],
                {abspath("filename"): ["test line\n",
                                       "line 2\n",
                                       "line 3\n",
                                       "line 4\n",
                                       "line 5\n"]},
                {},
                color=False)
            self.assertEqual("""\nfilename
|   5| {}
|    | [NORMAL] SpaceConsistencyBear:
|    | {}\n""".format(highlight_text('line 5', self.lexer),
                      highlight_text("Trailing whitespace found",
                                     style=BackgroundMessageStyle)),
                stdout.getvalue())

    def test_print_results_sorting(self):
        with retrieve_stdout() as stdout:
            print_results(self.log_printer,
                          Section(""),
                          [Result.from_values("SpaceConsistencyBear",
                                              "Trailing whitespace found",
                                              file="file",
                                              line=5),
                           Result.from_values("SpaceConsistencyBear",
                                              "Trailing whitespace found",
                                              file="file",
                                              line=2)],
                          {abspath("file"): ["test line\n",
                                             "\t\n",
                                             "line 3\n",
                                             "line 4\n",
                                             "line 5\t\n"]},
                          {},
                          color=False)

            self.assertEqual("""
file
|   2| {0}
|    | [NORMAL] SpaceConsistencyBear:
|    | {1}

file
|   5| {2}
|    | [NORMAL] SpaceConsistencyBear:
|    | {1}\n""".format(highlight_text('\t', self.lexer),
                       highlight_text("Trailing whitespace found",
                                      style=BackgroundMessageStyle),
                       highlight_text('line 5\t', self.lexer)),
                stdout.getvalue())

    def test_print_results_multiple_ranges(self):
        affected_code = (
            SourceRange.from_values("some_file", 5, end_line=7),
            SourceRange.from_values("another_file", 1, 3, 1, 5),
            SourceRange.from_values("another_file", 3, 3, 3, 5))
        with retrieve_stdout() as stdout:
            print_results(
                self.log_printer,
                Section(""),
                [Result("ClangCloneDetectionBear",
                        "Clone Found",
                        affected_code)],
                {abspath("some_file"): ["line " + str(i + 1) + "\n"
                                        for i in range(10)],
                 abspath("another_file"): ["line " + str(i + 1)
                                           for i in range(10)]},
                {},
                color=False)
            self.assertEqual("""
another_file
|   1| li{0}{1}

another_file
|   3| li{0}{2}

some_file
|   5| {3}
|   6| {4}
|   7| {5}
|    | [NORMAL] ClangCloneDetectionBear:
|    | {6}\n""".format(highlight_text('ne', self.lexer,
                                      BackgroundSourceRangeStyle),
                       highlight_text(' 1', self.lexer),
                       highlight_text(' 3', self.lexer),
                       highlight_text('line 5', self.lexer),
                       highlight_text('line 6', self.lexer),
                       highlight_text('line 7', self.lexer),
                       highlight_text("Clone Found",
                                      style=BackgroundMessageStyle)),
                stdout.getvalue())

    def test_print_results_missing_file(self):
        self.log_printer = LogPrinter(NullPrinter())
        with retrieve_stdout() as stdout:
            print_results(
                self.log_printer,
                Section(""),
                [Result("t", "msg"),
                 Result.from_values("t", "msg", file="file", line=5)],
                {},
                {},
                color=False)
            self.assertEqual("\n" + STR_PROJECT_WIDE + "\n"
                             "|    | [NORMAL] t:\n"
                             "|    | {0}\n"
                             # Second results file isn't there, no context is
                             # printed, only a warning log message which we
                             # don't catch
                             "|    | [NORMAL] t:\n"
                             "|    | {0}\n".format(
                                 highlight_text("msg",
                                                style=BackgroundMessageStyle)),
                             stdout.getvalue())

    def test_print_results_missing_line(self):
        with retrieve_stdout() as stdout:
            print_results(
                self.log_printer,
                Section(""),
                [Result.from_values("t", "msg", file="file", line=5),
                 Result.from_values("t", "msg", file="file", line=6)],
                {abspath("file"): ["line " + str(i + 1) for i in range(5)]},
                {},
                color=False)
            self.assertEqual("\n"
                             "file\n"
                             "|   5| {0}\n"
                             "|    | [NORMAL] t:\n"
                             "|    | {1}\n"
                             "\n"
                             "file\n"
                             "|   6| {2}\n"
                             "|    | [NORMAL] t:\n"
                             "|    | {1}\n".format(
                                 highlight_text('line 5', self.lexer),
                                 highlight_text("msg",
                                                style=BackgroundMessageStyle),
                                 STR_LINE_DOESNT_EXIST),
                             stdout.getvalue())

    def test_print_results_without_line(self):
        with retrieve_stdout() as stdout:
            print_results(
                self.log_printer,
                Section(""),
                [Result.from_values("t", "msg", file="file")],
                {abspath("file"): []},
                {},
                color=False)
            self.assertEqual(
                "\nfile\n"
                "|    | [NORMAL] t:\n"
                "|    | {}\n".format(highlight_text(
                    "msg", style=BackgroundMessageStyle)),
                stdout.getvalue())
Beispiel #12
0
def main(args=sys.argv):
    """
    Main command line entry point.
    """
    # pylint: disable-msg=R0911,R0912,R0915

    usage = USAGE % ((args[0],) * 6)

    if sys.platform in ['win32', 'cygwin']:
        try:
            # Provide coloring under Windows, if possible
            import colorama
            colorama.init()
        except ImportError:
            pass

    try:
        popts, args = getopt.getopt(args[1:], "l:f:F:o:O:P:LS:a:N:hVHg")
    except getopt.GetoptError as err:
        print(usage, file=sys.stderr)
        return 2
    opts = {}
    O_opts = []
    P_opts = []
    F_opts = []
    for opt, arg in popts:
        if opt == '-O':
            O_opts.append(arg)
        elif opt == '-P':
            P_opts.append(arg)
        elif opt == '-F':
            F_opts.append(arg)
        opts[opt] = arg

    if not opts and not args:
        print(usage)
        return 0

    if opts.pop('-h', None) is not None:
        print(usage)
        return 0

    if opts.pop('-V', None) is not None:
        print('Pygments version %s, (c) 2006-2013 by Georg Brandl.' % __version__)
        return 0

    # handle ``pygmentize -L``
    L_opt = opts.pop('-L', None)
    if L_opt is not None:
        if opts:
            print(usage, file=sys.stderr)
            return 2

        # print version
        main(['', '-V'])
        if not args:
            args = ['lexer', 'formatter', 'filter', 'style']
        for arg in args:
            _print_list(arg.rstrip('s'))
        return 0

    # handle ``pygmentize -H``
    H_opt = opts.pop('-H', None)
    if H_opt is not None:
        if opts or len(args) != 2:
            print(usage, file=sys.stderr)
            return 2

        what, name = args
        if what not in ('lexer', 'formatter', 'filter'):
            print(usage, file=sys.stderr)
            return 2

        _print_help(what, name)
        return 0

    # parse -O options
    parsed_opts = _parse_options(O_opts)
    opts.pop('-O', None)

    # parse -P options
    for p_opt in P_opts:
        try:
            name, value = p_opt.split('=', 1)
        except ValueError:
            parsed_opts[p_opt] = True
        else:
            parsed_opts[name] = value
    opts.pop('-P', None)

    # handle ``pygmentize -N``
    infn = opts.pop('-N', None)
    if infn is not None:
        try:
            lexer = get_lexer_for_filename(infn, **parsed_opts)
        except ClassNotFound as err:
            lexer = TextLexer()
        except OptionError as err:
            print('Error:', err, file=sys.stderr)
            return 1

        print(lexer.aliases[0])
        return 0

    # handle ``pygmentize -S``
    S_opt = opts.pop('-S', None)
    a_opt = opts.pop('-a', None)
    if S_opt is not None:
        f_opt = opts.pop('-f', None)
        if not f_opt:
            print(usage, file=sys.stderr)
            return 2
        if opts or args:
            print(usage, file=sys.stderr)
            return 2

        try:
            parsed_opts['style'] = S_opt
            fmter = get_formatter_by_name(f_opt, **parsed_opts)
        except ClassNotFound as err:
            print(err, file=sys.stderr)
            return 1

        arg = a_opt or ''
        try:
            print(fmter.get_style_defs(arg))
        except Exception as err:
            print('Error:', err, file=sys.stderr)
            return 1
        return 0

    # if no -S is given, -a is not allowed
    if a_opt is not None:
        print(usage, file=sys.stderr)
        return 2

    # parse -F options
    F_opts = _parse_filters(F_opts)
    opts.pop('-F', None)

    # select formatter
    outfn = opts.pop('-o', None)
    fmter = opts.pop('-f', None)
    if fmter:
        try:
            fmter = get_formatter_by_name(fmter, **parsed_opts)
        except (OptionError, ClassNotFound) as err:
            print('Error:', err, file=sys.stderr)
            return 1

    if outfn:
        if not fmter:
            try:
                fmter = get_formatter_for_filename(outfn, **parsed_opts)
            except (OptionError, ClassNotFound) as err:
                print('Error:', err, file=sys.stderr)
                return 1
        try:
            outfile = open(outfn, 'wb')
        except Exception as err:
            print('Error: cannot open outfile:', err, file=sys.stderr)
            return 1
    else:
        if not fmter:
            fmter = TerminalFormatter(**parsed_opts)
        outfile = sys.stdout

    # select lexer
    lexer = opts.pop('-l', None)
    if lexer:
        try:
            lexer = get_lexer_by_name(lexer, **parsed_opts)
        except (OptionError, ClassNotFound) as err:
            print('Error:', err, file=sys.stderr)
            return 1

    if args:
        if len(args) > 1:
            print(usage, file=sys.stderr)
            return 2

        infn = args[0]
        try:
            code = open(infn, 'rb').read()
        except Exception as err:
            print('Error: cannot read infile:', err, file=sys.stderr)
            return 1

        if not lexer:
            try:
                lexer = get_lexer_for_filename(infn, code, **parsed_opts)
            except ClassNotFound as err:
                if '-g' in opts:
                    try:
                        lexer = guess_lexer(code, **parsed_opts)
                    except ClassNotFound:
                        lexer = TextLexer(**parsed_opts)
                else:
                    print('Error:', err, file=sys.stderr)
                    return 1
            except OptionError as err:
                print('Error:', err, file=sys.stderr)
                return 1

    else:
        if '-g' in opts:
            code = sys.stdin.read()
            try:
                lexer = guess_lexer(code, **parsed_opts)
            except ClassNotFound:
                lexer = TextLexer(**parsed_opts)
        elif not lexer:
            print('Error: no lexer name given and reading ' + \
                                'from stdin (try using -g or -l <lexer>)', file=sys.stderr)
            return 2
        else:
            code = sys.stdin.read()

    # No encoding given? Use latin1 if output file given,
    # stdin/stdout encoding otherwise.
    # (This is a compromise, I'm not too happy with it...)
    if 'encoding' not in parsed_opts and 'outencoding' not in parsed_opts:
        if outfn:
            # encoding pass-through
            fmter.encoding = 'latin1'
        else:
            if sys.version_info < (3,):
                # use terminal encoding; Python 3's terminals already do that
                lexer.encoding = getattr(sys.stdin, 'encoding',
                                         None) or 'ascii'
                fmter.encoding = getattr(sys.stdout, 'encoding',
                                         None) or 'ascii'
    elif not outfn and sys.version_info > (3,):
        # output to terminal with encoding -> use .buffer
        outfile = sys.stdout.buffer

    # ... and do it!
    try:
        # process filters
        for fname, fopts in F_opts:
            lexer.add_filter(fname, **fopts)
        highlight(code, lexer, fmter, outfile)
    except Exception as err:
        import traceback
        info = traceback.format_exception(*sys.exc_info())
        msg = info[-1].strip()
        if len(info) >= 3:
            # extract relevant file and position info
            msg += '\n   (f%s)' % info[-2].split('\n')[0].strip()[1:]
        print(file=sys.stderr)
        print('*** Error while highlighting:', file=sys.stderr)
        print(msg, file=sys.stderr)
        return 1

    return 0
Beispiel #13
0
def main_inner(popts, args, usage):
    opts = {}
    O_opts = []
    P_opts = []
    F_opts = []
    for opt, arg in popts:
        if opt == '-O':
            O_opts.append(arg)
        elif opt == '-P':
            P_opts.append(arg)
        elif opt == '-F':
            F_opts.append(arg)
        opts[opt] = arg

    if opts.pop('-h', None) is not None:
        print(usage)
        return 0

    if opts.pop('-V', None) is not None:
        print('Pygments version %s, (c) 2006-2014 by Georg Brandl.' % __version__)
        return 0

    # handle ``pygmentize -L``
    L_opt = opts.pop('-L', None)
    if L_opt is not None:
        if opts:
            print(usage, file=sys.stderr)
            return 2

        # print version
        main(['', '-V'])
        if not args:
            args = ['lexer', 'formatter', 'filter', 'style']
        for arg in args:
            _print_list(arg.rstrip('s'))
        return 0

    # handle ``pygmentize -H``
    H_opt = opts.pop('-H', None)
    if H_opt is not None:
        if opts or len(args) != 2:
            print(usage, file=sys.stderr)
            return 2

        what, name = args
        if what not in ('lexer', 'formatter', 'filter'):
            print(usage, file=sys.stderr)
            return 2

        return _print_help(what, name)

    # parse -O options
    parsed_opts = _parse_options(O_opts)
    opts.pop('-O', None)

    # parse -P options
    for p_opt in P_opts:
        try:
            name, value = p_opt.split('=', 1)
        except ValueError:
            parsed_opts[p_opt] = True
        else:
            parsed_opts[name] = value
    opts.pop('-P', None)

    # encodings
    inencoding  = parsed_opts.get('inencoding', parsed_opts.get('encoding'))
    outencoding = parsed_opts.get('outencoding', parsed_opts.get('encoding'))

    # handle ``pygmentize -N``
    infn = opts.pop('-N', None)
    if infn is not None:
        lexer = find_lexer_class_for_filename(infn)
        if lexer is None:
            lexer = TextLexer

        print(lexer.aliases[0])
        return 0

    # handle ``pygmentize -S``
    S_opt = opts.pop('-S', None)
    a_opt = opts.pop('-a', None)
    if S_opt is not None:
        f_opt = opts.pop('-f', None)
        if not f_opt:
            print(usage, file=sys.stderr)
            return 2
        if opts or args:
            print(usage, file=sys.stderr)
            return 2

        try:
            parsed_opts['style'] = S_opt
            fmter = get_formatter_by_name(f_opt, **parsed_opts)
        except ClassNotFound as err:
            print(err, file=sys.stderr)
            return 1

        print(fmter.get_style_defs(a_opt or ''))
        return 0

    # if no -S is given, -a is not allowed
    if a_opt is not None:
        print(usage, file=sys.stderr)
        return 2

    # parse -F options
    F_opts = _parse_filters(F_opts)
    opts.pop('-F', None)

    # select lexer
    lexer = None

    # given by name?
    lexername = opts.pop('-l', None)
    if lexername:
        try:
            lexer = get_lexer_by_name(lexername, **parsed_opts)
        except (OptionError, ClassNotFound) as err:
            print('Error:', err, file=sys.stderr)
            return 1

    # read input code
    code = None

    if args:
        if len(args) > 1:
            print(usage, file=sys.stderr)
            return 2

        if '-s' in opts:
            print('Error: -s option not usable when input file specified',
                  file=sys.stderr)
            return 2

        infn = args[0]
        try:
            with open(infn, 'rb') as infp:
                code = infp.read()
        except Exception as err:
            print('Error: cannot read infile:', err, file=sys.stderr)
            return 1
        if not inencoding:
            code, inencoding = guess_decode(code)

        # do we have to guess the lexer?
        if not lexer:
            try:
                lexer = get_lexer_for_filename(infn, code, **parsed_opts)
            except ClassNotFound as err:
                if '-g' in opts:
                    try:
                        lexer = guess_lexer(code, **parsed_opts)
                    except ClassNotFound:
                        lexer = TextLexer(**parsed_opts)
                else:
                    print('Error:', err, file=sys.stderr)
                    return 1
            except OptionError as err:
                print('Error:', err, file=sys.stderr)
                return 1

    elif '-s' not in opts:  # treat stdin as full file (-s support is later)
        # read code from terminal, always in binary mode since we want to
        # decode ourselves and be tolerant with it
        if sys.version_info > (3,):
            # Python 3: we have to use .buffer to get a binary stream
            code = sys.stdin.buffer.read()
        else:
            code = sys.stdin.read()
        if not inencoding:
            code, inencoding = guess_decode_from_terminal(code, sys.stdin)
            # else the lexer will do the decoding
        if not lexer:
            try:
                lexer = guess_lexer(code, **parsed_opts)
            except ClassNotFound:
                lexer = TextLexer(**parsed_opts)

    else:  # -s option needs a lexer with -l
        if not lexer:
            print('Error: when using -s a lexer has to be selected with -l',
                  file=sys.stderr)
            return 2

    # process filters
    for fname, fopts in F_opts:
        try:
            lexer.add_filter(fname, **fopts)
        except ClassNotFound as err:
            print('Error:', err, file=sys.stderr)
            return 1

    # select formatter
    outfn = opts.pop('-o', None)
    fmter = opts.pop('-f', None)
    if fmter:
        try:
            fmter = get_formatter_by_name(fmter, **parsed_opts)
        except (OptionError, ClassNotFound) as err:
            print('Error:', err, file=sys.stderr)
            return 1

    if outfn:
        if not fmter:
            try:
                fmter = get_formatter_for_filename(outfn, **parsed_opts)
            except (OptionError, ClassNotFound) as err:
                print('Error:', err, file=sys.stderr)
                return 1
        try:
            outfile = open(outfn, 'wb')
        except Exception as err:
            print('Error: cannot open outfile:', err, file=sys.stderr)
            return 1
    else:
        if not fmter:
            fmter = TerminalFormatter(**parsed_opts)
        if sys.version_info > (3,):
            # Python 3: we have to use .buffer to get a binary stream
            outfile = sys.stdout.buffer
        else:
            outfile = sys.stdout

    # determine output encoding if not explicitly selected
    if not outencoding:
        if outfn:
            # output file? use lexer encoding for now (can still be None)
            fmter.encoding = inencoding
        else:
            # else use terminal encoding
            fmter.encoding = terminal_encoding(sys.stdout)

    # provide coloring under Windows, if possible
    if not outfn and sys.platform in ('win32', 'cygwin') and \
       fmter.name in ('Terminal', 'Terminal256'):  # pragma: no cover
        # unfortunately colorama doesn't support binary streams on Py3
        if sys.version_info > (3,):
            from pygments.util import UnclosingTextIOWrapper
            outfile = UnclosingTextIOWrapper(outfile, encoding=fmter.encoding)
            fmter.encoding = None
        try:
            import colorama.initialise
        except ImportError:
            pass
        else:
            outfile = colorama.initialise.wrap_stream(
                outfile, convert=None, strip=None, autoreset=False, wrap=True)

    # When using the LaTeX formatter and the option `escapeinside` is
    # specified, we need a special lexer which collects escaped text
    # before running the chosen language lexer.
    escapeinside = parsed_opts.get('escapeinside', '')
    if len(escapeinside) == 2 and isinstance(fmter, LatexFormatter):
        left = escapeinside[0]
        right = escapeinside[1]
        lexer = LatexEmbeddedLexer(left, right, lexer)

    # ... and do it!
    if '-s' not in opts:
        # process whole input as per normal...
        highlight(code, lexer, fmter, outfile)
        return 0
    else:
        # line by line processing of stdin (eg: for 'tail -f')...
        try:
            while 1:
                if sys.version_info > (3,):
                    # Python 3: we have to use .buffer to get a binary stream
                    line = sys.stdin.buffer.readline()
                else:
                    line = sys.stdin.readline()
                if not line:
                    break
                if not inencoding:
                    line = guess_decode_from_terminal(line, sys.stdin)[0]
                highlight(line, lexer, fmter, outfile)
                if hasattr(outfile, 'flush'):
                    outfile.flush()
            return 0
        except KeyboardInterrupt:  # pragma: no cover
            return 0
Beispiel #14
0
def main(args=sys.argv):
    """
    Main command line entry point.
    """
    # pylint: disable-msg=R0911,R0912,R0915

    usage = USAGE % ((args[0],) * 6)

    if sys.platform in ["win32", "cygwin"]:
        try:
            # Provide coloring under Windows, if possible
            import colorama

            colorama.init()
        except ImportError:
            pass

    try:
        popts, args = getopt.getopt(args[1:], "l:f:F:o:O:P:LS:a:N:hVHg")
    except getopt.GetoptError as err:
        print(usage, file=sys.stderr)
        return 2
    opts = {}
    O_opts = []
    P_opts = []
    F_opts = []
    for opt, arg in popts:
        if opt == "-O":
            O_opts.append(arg)
        elif opt == "-P":
            P_opts.append(arg)
        elif opt == "-F":
            F_opts.append(arg)
        opts[opt] = arg

    if not opts and not args:
        print(usage)
        return 0

    if opts.pop("-h", None) is not None:
        print(usage)
        return 0

    if opts.pop("-V", None) is not None:
        print("Pygments version %s, (c) 2006-2013 by Georg Brandl." % __version__)
        return 0

    # handle ``pygmentize -L``
    L_opt = opts.pop("-L", None)
    if L_opt is not None:
        if opts:
            print(usage, file=sys.stderr)
            return 2

        # print version
        main(["", "-V"])
        if not args:
            args = ["lexer", "formatter", "filter", "style"]
        for arg in args:
            _print_list(arg.rstrip("s"))
        return 0

    # handle ``pygmentize -H``
    H_opt = opts.pop("-H", None)
    if H_opt is not None:
        if opts or len(args) != 2:
            print(usage, file=sys.stderr)
            return 2

        what, name = args
        if what not in ("lexer", "formatter", "filter"):
            print(usage, file=sys.stderr)
            return 2

        _print_help(what, name)
        return 0

    # parse -O options
    parsed_opts = _parse_options(O_opts)
    opts.pop("-O", None)

    # parse -P options
    for p_opt in P_opts:
        try:
            name, value = p_opt.split("=", 1)
        except ValueError:
            parsed_opts[p_opt] = True
        else:
            parsed_opts[name] = value
    opts.pop("-P", None)

    # handle ``pygmentize -N``
    infn = opts.pop("-N", None)
    if infn is not None:
        try:
            lexer = get_lexer_for_filename(infn, **parsed_opts)
        except ClassNotFound as err:
            lexer = TextLexer()
        except OptionError as err:
            print("Error:", err, file=sys.stderr)
            return 1

        print(lexer.aliases[0])
        return 0

    # handle ``pygmentize -S``
    S_opt = opts.pop("-S", None)
    a_opt = opts.pop("-a", None)
    if S_opt is not None:
        f_opt = opts.pop("-f", None)
        if not f_opt:
            print(usage, file=sys.stderr)
            return 2
        if opts or args:
            print(usage, file=sys.stderr)
            return 2

        try:
            parsed_opts["style"] = S_opt
            fmter = get_formatter_by_name(f_opt, **parsed_opts)
        except ClassNotFound as err:
            print(err, file=sys.stderr)
            return 1

        arg = a_opt or ""
        try:
            print(fmter.get_style_defs(arg))
        except Exception as err:
            print("Error:", err, file=sys.stderr)
            return 1
        return 0

    # if no -S is given, -a is not allowed
    if a_opt is not None:
        print(usage, file=sys.stderr)
        return 2

    # parse -F options
    F_opts = _parse_filters(F_opts)
    opts.pop("-F", None)

    # select formatter
    outfn = opts.pop("-o", None)
    fmter = opts.pop("-f", None)
    if fmter:
        try:
            fmter = get_formatter_by_name(fmter, **parsed_opts)
        except (OptionError, ClassNotFound) as err:
            print("Error:", err, file=sys.stderr)
            return 1

    if outfn:
        if not fmter:
            try:
                fmter = get_formatter_for_filename(outfn, **parsed_opts)
            except (OptionError, ClassNotFound) as err:
                print("Error:", err, file=sys.stderr)
                return 1
        try:
            outfile = open(outfn, "wb")
        except Exception as err:
            print("Error: cannot open outfile:", err, file=sys.stderr)
            return 1
    else:
        if not fmter:
            fmter = TerminalFormatter(**parsed_opts)
        outfile = sys.stdout

    # select lexer
    lexer = opts.pop("-l", None)
    if lexer:
        try:
            lexer = get_lexer_by_name(lexer, **parsed_opts)
        except (OptionError, ClassNotFound) as err:
            print("Error:", err, file=sys.stderr)
            return 1

    if args:
        if len(args) > 1:
            print(usage, file=sys.stderr)
            return 2

        infn = args[0]
        try:
            code = open(infn, "rb").read()
        except Exception as err:
            print("Error: cannot read infile:", err, file=sys.stderr)
            return 1

        if not lexer:
            try:
                lexer = get_lexer_for_filename(infn, code, **parsed_opts)
            except ClassNotFound as err:
                if "-g" in opts:
                    try:
                        lexer = guess_lexer(code, **parsed_opts)
                    except ClassNotFound:
                        lexer = TextLexer(**parsed_opts)
                else:
                    print("Error:", err, file=sys.stderr)
                    return 1
            except OptionError as err:
                print("Error:", err, file=sys.stderr)
                return 1

    else:
        if "-g" in opts:
            code = sys.stdin.read()
            try:
                lexer = guess_lexer(code, **parsed_opts)
            except ClassNotFound:
                lexer = TextLexer(**parsed_opts)
        elif not lexer:
            print(
                "Error: no lexer name given and reading " + "from stdin (try using -g or -l <lexer>)", file=sys.stderr
            )
            return 2
        else:
            code = sys.stdin.read()

    # No encoding given? Use latin1 if output file given,
    # stdin/stdout encoding otherwise.
    # (This is a compromise, I'm not too happy with it...)
    if "encoding" not in parsed_opts and "outencoding" not in parsed_opts:
        if outfn:
            # encoding pass-through
            fmter.encoding = "latin1"
        else:
            if sys.version_info < (3,):
                # use terminal encoding; Python 3's terminals already do that
                lexer.encoding = getattr(sys.stdin, "encoding", None) or "ascii"
                fmter.encoding = getattr(sys.stdout, "encoding", None) or "ascii"
    elif not outfn and sys.version_info > (3,):
        # output to terminal with encoding -> use .buffer
        outfile = sys.stdout.buffer

    # ... and do it!
    try:
        # process filters
        for fname, fopts in F_opts:
            lexer.add_filter(fname, **fopts)
        highlight(code, lexer, fmter, outfile)
    except Exception as err:
        import traceback

        info = traceback.format_exception(*sys.exc_info())
        msg = info[-1].strip()
        if len(info) >= 3:
            # extract relevant file and position info
            msg += "\n   (f%s)" % info[-2].split("\n")[0].strip()[1:]
        print(file=sys.stderr)
        print("*** Error while highlighting:", file=sys.stderr)
        print(msg, file=sys.stderr)
        return 1

    return 0