diff --git a/cleo/application.py b/cleo/application.py
index 82180799..8c6683db 100644
--- a/cleo/application.py
+++ b/cleo/application.py
@@ -490,7 +490,8 @@ def render_error(self, error: Exception, io: IO) -> None:
trace = ExceptionTrace(
error, solution_provider_repository=self._solution_provider_repository
)
- trace.render(io.error_output, isinstance(error, CleoSimpleException))
+ simple = not io.is_verbose() or isinstance(error, CleoSimpleException)
+ trace.render(io.error_output, simple)
def _configure_io(self, io: IO) -> None:
if io.input.has_parameter_option("--ansi", True):
diff --git a/cleo/ui/exception_trace.py b/cleo/ui/exception_trace.py
index 0b656adf..b9dad735 100644
--- a/cleo/ui/exception_trace.py
+++ b/cleo/ui/exception_trace.py
@@ -12,7 +12,6 @@
from typing import TYPE_CHECKING
from crashtest.frame_collection import FrameCollection
-from crashtest.inspector import Inspector
from cleo.formatters.formatter import Formatter
@@ -255,9 +254,10 @@ def render(self, io: IO | Output, simple: bool = False) -> None:
if simple:
io.write_line("")
io.write_line(f"{str(self._exception)}")
- return
+ else:
+ self._render_exception(io, self._exception)
- return self._render_exception(io, self._exception)
+ self._render_solution(io, self._exception)
def _render_exception(self, io: IO | Output, exception: Exception) -> None:
from crashtest.inspector import Inspector
@@ -286,8 +286,6 @@ def _render_exception(self, io: IO | Output, exception: Exception) -> None:
current_frame = inspector.frames[-1]
self._render_snippet(io, current_frame)
- self._render_solution(io, inspector)
-
def _render_snippet(self, io: IO | Output, frame: Frame) -> None:
self._render_line(
io,
@@ -306,12 +304,12 @@ def _render_snippet(self, io: IO | Output, frame: Frame) -> None:
for code_line in code_lines:
self._render_line(io, code_line, indent=4)
- def _render_solution(self, io: IO | Output, inspector: Inspector) -> None:
+ def _render_solution(self, io: IO | Output, exception: Exception) -> None:
if self._solution_provider_repository is None:
return
solutions = self._solution_provider_repository.get_solutions_for_exception(
- inspector.exception
+ exception
)
symbol = "•"
if not io.supports_utf8():
@@ -348,7 +346,7 @@ def _render_trace(self, io: IO | Output, frames: FrameCollection) -> None:
stack_frames.append(frame)
remaining_frames_length = len(stack_frames) - 1
- if io.is_verbose() and remaining_frames_length:
+ if io.is_very_verbose() and remaining_frames_length:
self._render_line(io, "Stack trace>:", True)
max_frame_length = len(str(remaining_frames_length))
frame_collections = stack_frames.compact()
diff --git a/tests/ui/test_exception_trace.py b/tests/ui/test_exception_trace.py
index 17ace60c..1388c1f3 100644
--- a/tests/ui/test_exception_trace.py
+++ b/tests/ui/test_exception_trace.py
@@ -144,9 +144,9 @@ def test_render_debug_better_error_message_recursion_error():
assert re.match(expected, io.fetch_output()) is not None
-def test_render_verbose_better_error_message():
+def test_render_very_verbose_better_error_message():
io = BufferedIO()
- io.set_verbosity(Verbosity.VERBOSE)
+ io.set_verbosity(Verbosity.VERY_VERBOSE)
try:
fail()
@@ -158,7 +158,7 @@ def test_render_verbose_better_error_message():
expected = r"""^
Stack trace:
- 1 {}:152 in test_render_verbose_better_error_message
+ 1 {}:152 in test_render_very_verbose_better_error_message
fail\(\)
Exception
@@ -192,7 +192,7 @@ def second():
def test_render_debug_better_error_message_recursion_error_with_multiple_duplicated_frames():
io = BufferedIO()
- io.set_verbosity(Verbosity.VERBOSE)
+ io.set_verbosity(Verbosity.VERY_VERBOSE)
with pytest.raises(RecursionError) as e:
first()
@@ -212,7 +212,7 @@ def test_render_can_ignore_given_files():
from tests.ui.helpers import outer
io = BufferedIO()
- io.set_verbosity(Verbosity.VERBOSE)
+ io.set_verbosity(Verbosity.VERY_VERBOSE)
def call():
def run():
@@ -477,3 +477,60 @@ def test():
" ...",
"",
]
+
+
+def test_simple_render():
+ io = BufferedIO()
+
+ with pytest.raises(Exception) as e:
+ fail()
+
+ trace = ExceptionTrace(e.value)
+
+ trace.render(io, simple=True)
+
+ expected = """
+Failed
+"""
+
+ assert expected == io.fetch_output()
+
+
+def test_simple_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, simple=True)
+
+ expected = """
+Error with solution
+
+ • Solution Title: Solution Description
+ https://example.com,
+ https://example2.com
+"""
+ assert expected == io.fetch_output()