Skip to content

Commit

Permalink
ENH: Improve logging visibility of errors and filenames (#1225)
Browse files Browse the repository at this point in the history
  • Loading branch information
larsoner committed Nov 10, 2023
1 parent f5cc461 commit b9f3b82
Show file tree
Hide file tree
Showing 4 changed files with 56 additions and 40 deletions.
64 changes: 35 additions & 29 deletions sphinx_gallery/gen_gallery.py
Expand Up @@ -13,14 +13,15 @@
from difflib import get_close_matches
from importlib import import_module
from pathlib import Path
from textwrap import indent
import re
import os
import pathlib
from xml.sax.saxutils import quoteattr, escape

from sphinx.errors import ConfigError, ExtensionError
import sphinx.util
from sphinx.util.console import red
from sphinx.util.console import blue, red, purple, bold
from . import glr_path_static, __version__ as _sg_version
from .utils import _replace_md5, _has_optipng, _has_pypandoc, _has_graphviz
from .backreferences import _finalize_backreferences
Expand Down Expand Up @@ -1332,30 +1333,36 @@ def summarize_failing_examples(app, exception):
gallery_conf
)

idt = " "
if failing_as_expected:
logger.info("Examples failing as expected:", color="brown")
logger.info(bold("Examples failing as expected:"), color="blue")
for fail_example in failing_as_expected:
logger.info("%s failed leaving traceback:", fail_example, color="brown")
logger.info(gallery_conf["failing_examples"][fail_example], color="brown")
path = os.path.relpath(fail_example, gallery_conf["src_dir"])
logger.info(
f"{bold(blue(path))} failed leaving traceback:\n\n"
f"{indent(gallery_conf['failing_examples'][fail_example], idt)}"
)

fail_msgs = []
if failing_unexpectedly:
fail_msgs.append(red("Unexpected failing examples:"))
fail_msgs.append(bold(red("Unexpected failing examples:\n")))
for fail_example in failing_unexpectedly:
path = os.path.relpath(fail_example, gallery_conf["src_dir"])
fail_msgs.append(
fail_example
+ " failed leaving traceback:\n"
+ gallery_conf["failing_examples"][fail_example]
+ "\n"
f" {bold(red(path))} failed leaving traceback:\n\n"
f"{indent(gallery_conf['failing_examples'][fail_example], idt)}"
)

if passing_unexpectedly:
paths = [
os.path.relpath(p, gallery_conf["src_dir"]) for p in passing_unexpectedly
]
fail_msgs.append(
red("Examples expected to fail, but not failing:\n")
+ "Please remove these examples from\n"
+ "sphinx_gallery_conf['expected_failing_examples']\n"
+ "in your conf.py file"
"\n".join(passing_unexpectedly)
bold(red("Examples expected to fail, but not failing:\n\n"))
+ red("\n".join(indent(p, idt) for p in paths))
+ "\n\nPlease remove these examples from "
+ "sphinx_gallery_conf['expected_failing_examples'] "
+ "in your conf.py file."
)

# standard message
Expand All @@ -1380,9 +1387,14 @@ def summarize_failing_examples(app, exception):
)

if fail_msgs:
fail_message = (
"Here is a summary of the problems encountered "
"when running the examples\n\n" + "\n".join(fail_msgs) + "\n" + "-" * 79
fail_message = bold(
purple(
"Here is a summary of the problems encountered "
"when running the examples:\n\n"
+ "\n".join(fail_msgs)
+ "\n"
+ "-" * 79
)
)
if gallery_conf["only_warn_on_example_error"]:
logger.warning(fail_message)
Expand Down Expand Up @@ -1482,13 +1494,11 @@ def setup(app):

# Early filling of sphinx_gallery_conf defaults at config-inited
app.connect("config-inited", fill_gallery_conf_defaults, priority=10)
# Set priority to a small number (higher priority than the default
# priority=500), so that pre_configure_jupyterlite_sphinx is called before
# jupyterlite_sphinx config-inited
# set small priority value, so that pre_configure_jupyterlite_sphinx is
# called before jupyterlite_sphinx config-inited
app.connect("config-inited", pre_configure_jupyterlite_sphinx, priority=100)
# Set priority to a big number (lower priority than the default
# priority=500), so that post_configure_jupyterlite_sphinx is called after
# jupyterlite_sphinx config-inited
# set high priority value, so that post_configure_jupyterlite_sphinx is
# called after jupyterlite_sphinx config-inited
app.connect("config-inited", post_configure_jupyterlite_sphinx, priority=900)

if "sphinx.ext.autodoc" in app.extensions:
Expand All @@ -1505,16 +1515,12 @@ def setup(app):
# Early update of sphinx_gallery_conf at builder-inited
app.connect("builder-inited", update_gallery_conf_builder_inited, priority=10)
app.connect("builder-inited", generate_gallery_rst)

app.connect("build-finished", copy_binder_files)
# Set priority to a small number (higher priority than the default
# priority=500) so that create_jupyterlite_contents runs before
# jupyterlite_sphinx build-finished
app.connect("build-finished", create_jupyterlite_contents, priority=100)
app.connect("build-finished", create_jupyterlite_contents)

app.connect("build-finished", summarize_failing_examples)
app.connect("build-finished", embed_code_links)
app.connect("build-finished", clean_api_usage_files)

metadata = {
"parallel_read_safe": True,
"parallel_write_safe": True,
Expand Down
15 changes: 8 additions & 7 deletions sphinx_gallery/gen_rst.py
Expand Up @@ -32,6 +32,7 @@

from sphinx.errors import ExtensionError
import sphinx.util
from sphinx.util.console import blue, red, bold

from .scrapers import save_figures, ImagePathIterator, clean_modules, _find_image_ext
from .utils import (
Expand Down Expand Up @@ -645,15 +646,15 @@ def handle_exception(exc_info, src_file, script_vars, gallery_conf):
)

expected = src_file in _expected_failing_examples(gallery_conf)
src_file_rel = os.path.relpath(src_file, gallery_conf["src_dir"])
if expected:
func, color = (
logger.info,
"blue",
)
func, color, kind = logger.info, blue, "expectedly"
else:
func, color = logger.warning, "red"
func(
"%s failed to execute correctly: %s", src_file, formatted_exception, color=color
func, color, kind = logger.warning, red, "unexpectedly"
func( # needs leading newline to get away from iterator
f"\n{bold(color('%s'))} {kind} failed to execute correctly:\n\n%s",
src_file_rel,
color(indent(formatted_exception, " ")),
)

except_rst = codestr2rst(formatted_exception, lang="pytb")
Expand Down
11 changes: 7 additions & 4 deletions sphinx_gallery/tests/test_gen_gallery.py
Expand Up @@ -21,6 +21,7 @@
fill_gallery_conf_defaults,
)
from sphinx_gallery.interactive_example import create_jupyterlite_contents
from sphinx_gallery.utils import _escape_ansi


def test_bad_config():
Expand Down Expand Up @@ -441,8 +442,8 @@ def test_only_warn_on_example_error(sphinx_app_wrapper):
fid.write("raise ValueError")
sphinx_app = sphinx_app_wrapper.build_sphinx_app()

build_warn = sphinx_app._warning.getvalue()
assert "plot_3.py failed to execute correctly" in build_warn
build_warn = _escape_ansi(sphinx_app._warning.getvalue())
assert "plot_3.py unexpectedly failed to execute correctly" in build_warn
assert "WARNING: Here is a summary of the problems" in build_warn


Expand All @@ -462,7 +463,8 @@ def test_only_warn_on_example_error_sphinx_warning(sphinx_app_wrapper):
fid.write("raise ValueError")
with pytest.raises(SphinxWarning) as excinfo:
sphinx_app_wrapper.build_sphinx_app()
assert "plot_3.py failed to execute" in str(excinfo.value)
exc = _escape_ansi(str(excinfo.value))
assert "plot_3.py unexpectedly failed to execute" in exc


@pytest.mark.conf_file(
Expand All @@ -476,7 +478,8 @@ def test_only_warn_on_example_error_sphinx_warning(sphinx_app_wrapper):
def test_examples_not_expected_to_pass(sphinx_app_wrapper):
with pytest.raises(ExtensionError) as excinfo:
sphinx_app_wrapper.build_sphinx_app()
assert "expected to fail, but not failing" in str(excinfo.value)
exc = _escape_ansi(str(excinfo.value))
assert "expected to fail, but not failing" in exc


@pytest.mark.conf_file(
Expand Down
6 changes: 6 additions & 0 deletions sphinx_gallery/utils.py
Expand Up @@ -8,6 +8,7 @@

import hashlib
import os
import re
from shutil import move, copyfile
import subprocess

Expand Down Expand Up @@ -189,3 +190,8 @@ def _has_graphviz():
)
return False
return True


def _escape_ansi(s):
"""Remove ANSI terminal formatting characters from a string."""
return re.sub(r"(?:\x1B[@-_]|[\x80-\x9F])[0-?]*[ -/]*[@-~]", "", s)

0 comments on commit b9f3b82

Please sign in to comment.