def test_render_better_error_message():
    io = BufferedIO()

    try:
        raise Exception("Failed")
    except Exception as e:
        trace = ExceptionTrace(e)

    trace.render(io)

    expected = """\

  Exception

  Failed

  at {}:19 in test_render_better_error_message
       15│ def test_render_better_error_message():
       16│     io = BufferedIO()
       17│ 
       18│     try:
    →  19│         raise Exception("Failed")
       20│     except Exception as e:
       21│         trace = ExceptionTrace(e)
       22│ 
       23│     trace.render(io)
""".format(trace._get_relative_file_path(__file__))
    assert expected == io.fetch_output()
def test_render_falls_back_on_ascii_symbols():
    from crashtest.contracts.base_solution import BaseSolution
    from crashtest.contracts.provides_solution import ProvidesSolution
    from crashtest.solution_providers.solution_provider_repository import (
        SolutionProviderRepository, )

    class CustomError(ProvidesSolution, Exception):
        @property
        def solution(self):
            solution = BaseSolution("Solution Title.", "Solution Description")
            solution.documentation_links.append("https://example.com")
            solution.documentation_links.append("https://example2.com")

            return solution

    io = BufferedIO(supports_utf8=False)

    def call():
        raise CustomError("Error with solution")

    with pytest.raises(CustomError) as e:
        call()

    trace = ExceptionTrace(
        e.value, solution_provider_repository=SolutionProviderRepository())

    trace.render(io)

    expected = """
  CustomError

  Error with solution

  at {}:411 in call
      407| 
      408|     io = BufferedIO(supports_utf8=False)
      409| 
      410|     def call():
    > 411|         raise CustomError("Error with solution")
      412| 
      413|     with pytest.raises(CustomError) as e:
      414|         call()
      415| 

  * Solution Title: Solution Description
    https://example.com,
    https://example2.com
""".format(trace._get_relative_file_path(__file__), )

    assert expected == io.fetch_output()
def test_render_supports_solutions():
    from crashtest.contracts.base_solution import BaseSolution
    from crashtest.contracts.provides_solution import ProvidesSolution
    from crashtest.solution_providers.solution_provider_repository import (
        SolutionProviderRepository, )

    class CustomError(ProvidesSolution, Exception):
        @property
        def solution(self):
            solution = BaseSolution("Solution Title.", "Solution Description")
            solution.documentation_links.append("https://example.com")
            solution.documentation_links.append("https://example2.com")

            return solution

    io = BufferedIO()

    def call():
        raise CustomError("Error with solution")

    with pytest.raises(CustomError) as e:
        call()

    trace = ExceptionTrace(
        e.value, solution_provider_repository=SolutionProviderRepository())

    trace.render(io)

    expected = """
  CustomError

  Error with solution

  at {}:355 in call
      351│ 
      352│     io = BufferedIO()
      353│ 
      354│     def call():
    → 355│         raise CustomError("Error with solution")
      356│ 
      357│     with pytest.raises(CustomError) as e:
      358│         call()
      359│ 

  • Solution Title: Solution Description
    https://example.com,
    https://example2.com
""".format(trace._get_relative_file_path(__file__), )

    assert expected == io.fetch_output()
def test_render_debug_better_error_message_recursion_error_with_multiple_duplicated_frames(
):
    io = BufferedIO()
    io.set_verbosity(Verbosity.VERBOSE)

    with pytest.raises(RecursionError) as e:
        first()

    trace = ExceptionTrace(e.value)

    trace.render(io)

    expected = r"...  Previous 2 frames repeated \d+ times"

    assert re.search(expected, io.fetch_output()) is not None
def test_render_debug_better_error_message():
    io = BufferedIO()
    io.set_verbosity(Verbosity.DEBUG)

    try:
        fail()
    except Exception as e:  # Exception
        trace = ExceptionTrace(e)

    trace.render(io)

    expected = r"""^
  Stack trace:

  1  {}:52 in test_render_debug_better_error_message
       50\│ 
       51\│     try:
    →  52\│         fail\(\)
       53\│     except Exception as e:  # Exception
       54\│         trace = ExceptionTrace\(e\)

  Exception

  Failed

  at {}:12 in fail
        8\│ from cleo.ui.exception_trace import ExceptionTrace
        9\│ 
       10\│ 
       11\│ def fail\(\):
    →  12\│     raise Exception\("Failed"\)
       13\│ 
       14\│ 
       15\│ def test_render_better_error_message\(\):
       16\│     io = BufferedIO\(\)
""".format(
        re.escape(trace._get_relative_file_path(__file__)),
        re.escape(trace._get_relative_file_path(__file__)),
    )

    assert re.match(expected, io.fetch_output()) is not None
def test_render_can_ignore_given_files():
    import os

    from .helpers import outer

    io = BufferedIO()
    io.set_verbosity(Verbosity.VERBOSE)

    def call():
        def run():
            outer()

        run()

    with pytest.raises(Exception) as e:
        call()

    trace = ExceptionTrace(e.value)
    helpers_file = os.path.join(os.path.dirname(__file__), "helpers.py")
    trace.ignore_files_in("^{}$".format(re.escape(helpers_file)))

    trace.render(io)

    expected = """
  Stack trace:

  2  {}:224 in test_render_can_ignore_given_files
       call()

  1  {}:221 in call
       run()

  Exception

  Foo

  at {}:3 in inner
        1│ def outer():
        2│     def inner():
    →   3│         raise Exception("Foo")
        4│ 
        5│     inner()
        6│ 
""".format(
        trace._get_relative_file_path(__file__),
        trace._get_relative_file_path(__file__),
        trace._get_relative_file_path(helpers_file),
    )

    assert expected == io.fetch_output()
def test_render_debug_better_error_message_recursion_error():
    io = BufferedIO()
    io.set_verbosity(Verbosity.DEBUG)

    try:
        recursion_error()
    except RecursionError as e:
        trace = ExceptionTrace(e)

    trace.render(io)

    expected = r"""^
  Stack trace:

  \d+  {}:99 in test_render_debug_better_error_message_recursion_error
         97\│ 
         98\│     try:
      →  99\│         recursion_error\(\)
        100\│     except RecursionError as e:
        101\│         trace = ExceptionTrace\(e\)

  ...  Previous frame repeated \d+ times

  \s*\d+  {}:91 in recursion_error
         89\│ 
         90\│ def recursion_error\(\):
      →  91\│     recursion_error\(\)
         92\│ 
         93\│ 

  RecursionError

  maximum recursion depth exceeded

  at {}:91 in recursion_error
       87\│     assert re.match\(expected, io.fetch_output\(\)\) is not None
       88\│ 
       89\│ 
       90\│ def recursion_error\(\):
    →  91\│     recursion_error\(\)
       92\│ 
       93\│ 
       94\│ def test_render_debug_better_error_message_recursion_error\(\):
       95\│     io = BufferedIO\(\)
""".format(
        re.escape(trace._get_relative_file_path(__file__)),
        re.escape(trace._get_relative_file_path(__file__)),
        re.escape(trace._get_relative_file_path(__file__)),
    )

    assert re.match(expected, io.fetch_output()) is not None
Example #8
0
    def _execute_operation(self, operation: "OperationTypes") -> None:
        try:
            if self.supports_fancy_output():
                if id(operation) not in self._sections:
                    if self._should_write_operation(operation):
                        with self._lock:
                            self._sections[id(operation)] = self._io.section()
                            self._sections[id(operation)].write_line(
                                "  <fg=blue;options=bold>•</> {message}: <fg=blue>Pending...</>"
                                .format(message=self.get_operation_message(
                                    operation), ), )
            else:
                if self._should_write_operation(operation):
                    if not operation.skipped:
                        self._io.write_line(
                            "  <fg=blue;options=bold>•</> {message}".format(
                                message=self.get_operation_message(
                                    operation), ), )
                    else:
                        self._io.write_line(
                            "  <fg=default;options=bold,dark>•</> {message}: "
                            "<fg=default;options=bold,dark>Skipped</> "
                            "<fg=default;options=dark>for the following reason:</> "
                            "<fg=default;options=bold,dark>{reason}</>".format(
                                message=self.get_operation_message(operation),
                                reason=operation.skip_reason,
                            ))

            try:
                result = self._do_execute_operation(operation)
            except EnvCommandError as e:
                if e.e.returncode == -2:
                    result = -2
                else:
                    raise

            # If we have a result of -2 it means a KeyboardInterrupt
            # in the any python subprocess, so we raise a KeyboardInterrupt
            # error to be picked up by the error handler.
            if result == -2:
                raise KeyboardInterrupt
        except Exception as e:
            try:
                from cleo.ui.exception_trace import ExceptionTrace

                if not self.supports_fancy_output():
                    io = self._io
                else:
                    message = (
                        "  <error>•</error> {message}: <error>Failed</error>".
                        format(message=self.get_operation_message(
                            operation, error=True), ))
                    self._write(operation, message)
                    io = self._sections.get(id(operation), self._io)

                with self._lock:
                    trace = ExceptionTrace(e)
                    trace.render(io)
                    io.write_line("")
            finally:
                with self._lock:
                    self._shutdown = True
        except KeyboardInterrupt:
            try:
                message = "  <warning>•</warning> {message}: <warning>Cancelled</warning>".format(
                    message=self.get_operation_message(operation,
                                                       warning=True), )
                if not self.supports_fancy_output():
                    self._io.write_line(message)
                else:
                    self._write(operation, message)
            finally:
                with self._lock:
                    self._shutdown = True
Example #9
0
    def render_error(self, error: Exception, io: IO) -> None:
        from cleo.ui.exception_trace import ExceptionTrace

        trace = ExceptionTrace(error)
        trace.render(io.error_output, isinstance(error, CleoSimpleException))
Example #10
0
def test_render_shows_ignored_files_if_in_debug_mode():
    import os

    from .helpers import outer

    io = BufferedIO()
    io.set_verbosity(Verbosity.DEBUG)

    def call():
        def run():
            outer()

        run()

    with pytest.raises(Exception) as e:
        call()

    trace = ExceptionTrace(e.value)
    helpers_file = os.path.join(os.path.dirname(__file__), "helpers.py")
    trace.ignore_files_in("^{}$".format(re.escape(helpers_file)))

    trace.render(io)

    expected = """
  Stack trace:

  4  {}:276 in test_render_shows_ignored_files_if_in_debug_mode
      274│ 
      275│     with pytest.raises(Exception) as e:
    → 276│         call()
      277│ 
      278│     trace = ExceptionTrace(e.value)

  3  {}:273 in call
      271│             outer()
      272│ 
    → 273│         run()
      274│ 
      275│     with pytest.raises(Exception) as e:

  2  {}:271 in run
      269│     def call():
      270│         def run():
    → 271│             outer()
      272│ 
      273│         run()

  1  {}:5 in outer
        3│         raise Exception("Foo")
        4│ 
    →   5│     inner()
        6│ 

  Exception

  Foo

  at {}:3 in inner
        1│ def outer():
        2│     def inner():
    →   3│         raise Exception("Foo")
        4│ 
        5│     inner()
        6│ 
""".format(
        trace._get_relative_file_path(__file__),
        trace._get_relative_file_path(__file__),
        trace._get_relative_file_path(__file__),
        trace._get_relative_file_path(helpers_file),
        trace._get_relative_file_path(helpers_file),
    )

    assert expected == io.fetch_output()