Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

verbose tracebacks #13226

Merged
merged 1 commit into from
Feb 27, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion conan/cli/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
from inspect import getmembers

from conan.api.conan_api import ConanAPI
from conan.api.output import ConanOutput, Color, cli_out_write
from conan.api.output import ConanOutput, Color, cli_out_write, LEVEL_TRACE
from conan.cli.command import ConanSubCommand
from conan.cli.exit_codes import SUCCESS, ERROR_MIGRATION, ERROR_GENERAL, USER_CTRL_C, \
ERROR_SIGTERM, USER_CTRL_BREAK, ERROR_INVALID_CONFIGURATION, ERROR_UNEXPECTED
Expand Down Expand Up @@ -166,6 +166,10 @@ def run(self, *args):
try:
command.run(self._conan_api, self._commands[command_argument].parser, args[0][1:])
except Exception as e:
# must be a local-import to get updated value
from conan.api.output import conan_output_level
if conan_output_level <= LEVEL_TRACE:
print(traceback.format_exc())
self._conan2_migrate_recipe_msg(e)
raise

Expand Down
8 changes: 4 additions & 4 deletions conans/errors.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,6 @@
"""
from contextlib import contextmanager

from conans.util.env import get_env


@contextmanager
def conanfile_remove_attr(conanfile, names, method):
Expand Down Expand Up @@ -42,6 +40,10 @@ def conanfile_exception_formatter(conanfile_name, func_name):
"""

def _raise_conanfile_exc(e):
from conan.api.output import LEVEL_DEBUG, conan_output_level
if conan_output_level <= LEVEL_DEBUG:
import traceback
raise ConanExceptionInUserConanfileMethod(traceback.format_exc())
m = _format_conanfile_exception(conanfile_name, func_name, e)
raise ConanExceptionInUserConanfileMethod(m)

Expand Down Expand Up @@ -72,8 +74,6 @@ def _format_conanfile_exception(scope, method, exception):
"""
import sys
import traceback
if get_env("CONAN_VERBOSE_TRACEBACK", False):
return traceback.format_exc()
try:
conanfile_reached = False
tb = sys.exc_info()[2]
Expand Down
62 changes: 34 additions & 28 deletions conans/test/integration/conanfile/test_exception_printing.py
Original file line number Diff line number Diff line change
@@ -1,16 +1,10 @@
import pytest
from parameterized import parameterized

from conans.paths import CONANFILE
from conans.test.utils.tools import TestClient
from conans.util.env import environment_update

conanfile = """
from conan import ConanFile

class DRLException(Exception):
pass

class ExceptionsTest(ConanFile):
name = "exceptions"
version = "0.1"
Expand All @@ -19,34 +13,46 @@ def {method}(self):
{method_contents}

def _aux_method(self):
raise DRLException('Oh! an error!')
raise Exception('Oh! an error!')
"""


@parameterized.expand([(True,), (False,)])
@pytest.mark.xfail(reason="cache2.0 build_id not working, revisit")
def test_all_methods(direct):
@pytest.mark.parametrize("direct", [True, False])
@pytest.mark.parametrize("method",
["source", "build", "package", "package_info", "configure", "build_id",
"package_id", "requirements", "config_options", "layout", "generate",
"export", "export_sources", "build_requirements", "init"])
def test_all_methods(direct, method):
client = TestClient()
if direct:
throw = "raise DRLException('Oh! an error!')"
throw = "raise Exception('Oh! an error!')"
else:
throw = "self._aux_method()"
for method in ["source", "build", "package", "package_info", "configure", "build_id",
"package_id", "requirements", "config_options", "layout", "generate", "export",
"export_sources"]:
client.save({CONANFILE: conanfile.format(method=method, method_contents=throw)})
client.run("create . ", assert_error=True)
assert "exceptions/0.1: Error in %s() method, line 12" % method in client.out
assert "DRLException: Oh! an error!" in client.out
if not direct:
assert "while calling '_aux_method', line 15" in client.out


def test_complete_traceback():

client.save({"conanfile.py": conanfile.format(method=method, method_contents=throw)})
client.run("create . ", assert_error=True)
assert "Error in %s() method, line 9" % method in client.out
assert "Oh! an error!" in client.out
if not direct:
assert "while calling '_aux_method', line 12" in client.out


def test_complete_traceback_debug():
"""
in debug level (-vv), the trace is shown (this is for recipe methods exceptions)
"""
client = TestClient()
throw = "self._aux_method()"
client.save({CONANFILE: conanfile.format(method="source", method_contents=throw)})
with environment_update({"CONAN_VERBOSE_TRACEBACK": "1"}):
client.run("create . ", assert_error=True)
assert "DRLException: Oh! an error!" in client.out
assert "ERROR: Traceback (most recent call last):" in client.out
client.save({"conanfile.py": conanfile.format(method="source", method_contents=throw)})
client.run("create . -vv", assert_error=True)
assert "Exception: Oh! an error!" in client.out
assert "ERROR: Traceback (most recent call last):" in client.out


def test_complete_traceback_trace():
"""
in debug level (-vvv), the full trace is shown for ConanExceptions
"""
client = TestClient()
client.run("install --requires=pkg/1.0 -vvv", assert_error=True)
assert "Traceback (most recent call last)" in client.out