From abe33caddc381cbae03a9ad41fa36ed4c9b562e0 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 9 Apr 2026 14:40:00 +0000 Subject: [PATCH 1/3] Initial plan From 8b1291f18477ef42e5d5c9b05218a2d9798ba837 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 9 Apr 2026 15:11:56 +0000 Subject: [PATCH 2/3] Suppress verbose tracebacks by default, show only with -vv Install a custom sys.excepthook in the fre() entry point that suppresses Python tracebacks at default and -v verbosity levels. At -vv (DEBUG), the full traceback is shown. At lower levels, only the exception type and message are printed, along with a hint to use 'fre -vv ...' for more detail. Closes #793 Agent-Logs-Url: https://github.com/NOAA-GFDL/fre-cli/sessions/d594a572-8566-467b-9a96-4b233d712582 Co-authored-by: ilaflott <6273252+ilaflott@users.noreply.github.com> --- docs/tools.rst | 1 + fre/fre.py | 11 +++++++++- fre/tests/test_fre_cli.py | 43 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 54 insertions(+), 1 deletion(-) diff --git a/docs/tools.rst b/docs/tools.rst index 8388ad560..afa5ae730 100644 --- a/docs/tools.rst +++ b/docs/tools.rst @@ -20,6 +20,7 @@ arguments * (optional) ``-v[v]``, verbosity flag, up to two - increments ``fre``'s verbosity from the default ``logging.WARNING`` to ``logging.INFO`` with one ``-v``, and again to ``logging.DEBUG`` with ``-vv`` + - at default verbosity or ``-v``, unhandled exceptions print only the error message; use ``-vv`` to show the full traceback * (optional) ``-q``, quiet flag, up to one diff --git a/fre/fre.py b/fre/fre.py index 25b717504..334258b85 100644 --- a/fre/fre.py +++ b/fre/fre.py @@ -5,6 +5,7 @@ """ import logging +import sys import click @@ -38,7 +39,8 @@ ) @click.option( '-v', '--verbose', default = 0, required = False, count = True, type = int, help = "Increment logging verbosity from default (logging.WARNING) to logging.INFO. " + \ - "use -vv for logging.DEBUG. will be overridden by -q/--quiet" ) + "use -vv for logging.DEBUG and to show full tracebacks on errors. " + \ + "will be overridden by -q/--quiet" ) @click.option( '-q', '--quiet', default = False, required = False, is_flag = True, type = bool, help = "Set logging verbosity from default (logging.WARNING) to logging.ERROR, printing " + \ "less output to screen. overrides -v[v]/--verbose" ) @@ -79,3 +81,10 @@ def fre(verbose = 0, quiet = False, log_file = None): fre_logger.info('fre_file_handler added to base_fre_logger') fre_logger.debug('click entry-point function call done.') + + # install custom exception hook to suppress tracebacks unless -vv is used + if log_level > logging.DEBUG: + def _brief_excepthook(exc_type, exc_value, exc_tb): + click.echo(f"{exc_type.__name__}: {exc_value}", err=True) + click.echo("(use 'fre -vv ...' for the full traceback)", err=True) + sys.excepthook = _brief_excepthook diff --git a/fre/tests/test_fre_cli.py b/fre/tests/test_fre_cli.py index f7fa283e8..56ad10fc0 100644 --- a/fre/tests/test_fre_cli.py +++ b/fre/tests/test_fre_cli.py @@ -10,6 +10,7 @@ right and thinks the tool has a --optionDNE option) - fre --version, checking for version GTE current version (fails if version isn't defined) """ +import sys import subprocess from click.testing import CliRunner @@ -50,3 +51,45 @@ def test_cli_fre_version(): # latest_testing_tag = result.stdout.split('\n')[0] # # assert '2026.01.alpha2' == latest_testing_tag + +# ---- traceback suppression tests ---- +# These tests verify that unhandled exceptions print a clean error message +# at default verbosity, and the full traceback only at -vv. + +_CLI_SCRIPT = """\ +import sys +sys.argv = {argv!r} +from fre.fre import fre +fre(standalone_mode=True) +""" + +def _run_fre_subprocess(argv): + """Helper: run fre via subprocess so sys.excepthook is exercised.""" + return subprocess.run( + [sys.executable, "-c", _CLI_SCRIPT.format(argv=argv)], + capture_output=True, text=True + ) + +def test_traceback_suppressed_by_default(): + '''fre run function — default verbosity should suppress traceback''' + result = _run_fre_subprocess(["fre", "run", "function"]) + assert result.returncode != 0 + assert "NotImplementedError" in result.stderr + assert "Traceback" not in result.stderr + assert "fre -vv" in result.stderr + +def test_traceback_suppressed_with_single_v(): + '''fre -v run function — single -v should still suppress traceback''' + result = _run_fre_subprocess(["fre", "-v", "run", "function"]) + assert result.returncode != 0 + assert "NotImplementedError" in result.stderr + assert "Traceback" not in result.stderr + assert "fre -vv" in result.stderr + +def test_traceback_shown_with_vv(): + '''fre -vv run function — double -v should show full traceback''' + result = _run_fre_subprocess(["fre", "-vv", "run", "function"]) + assert result.returncode != 0 + assert "NotImplementedError" in result.stderr + assert "Traceback" in result.stderr + assert "fre -vv" not in result.stderr From cf83c57424baf4e9d7b1f009c9fc1c8198a22546 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 9 Apr 2026 15:13:17 +0000 Subject: [PATCH 3/3] Fix em dashes in test docstrings per code review Agent-Logs-Url: https://github.com/NOAA-GFDL/fre-cli/sessions/d594a572-8566-467b-9a96-4b233d712582 Co-authored-by: ilaflott <6273252+ilaflott@users.noreply.github.com> --- fre/tests/test_fre_cli.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/fre/tests/test_fre_cli.py b/fre/tests/test_fre_cli.py index 56ad10fc0..1d4131e6a 100644 --- a/fre/tests/test_fre_cli.py +++ b/fre/tests/test_fre_cli.py @@ -71,7 +71,7 @@ def _run_fre_subprocess(argv): ) def test_traceback_suppressed_by_default(): - '''fre run function — default verbosity should suppress traceback''' + '''fre run function - default verbosity should suppress traceback''' result = _run_fre_subprocess(["fre", "run", "function"]) assert result.returncode != 0 assert "NotImplementedError" in result.stderr @@ -79,7 +79,7 @@ def test_traceback_suppressed_by_default(): assert "fre -vv" in result.stderr def test_traceback_suppressed_with_single_v(): - '''fre -v run function — single -v should still suppress traceback''' + '''fre -v run function - single -v should still suppress traceback''' result = _run_fre_subprocess(["fre", "-v", "run", "function"]) assert result.returncode != 0 assert "NotImplementedError" in result.stderr @@ -87,7 +87,7 @@ def test_traceback_suppressed_with_single_v(): assert "fre -vv" in result.stderr def test_traceback_shown_with_vv(): - '''fre -vv run function — double -v should show full traceback''' + '''fre -vv run function - double -v should show full traceback''' result = _run_fre_subprocess(["fre", "-vv", "run", "function"]) assert result.returncode != 0 assert "NotImplementedError" in result.stderr