Skip to content
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
1 change: 1 addition & 0 deletions py/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ TEST_DEPS = [
requirement("pytest-instafail"),
requirement("pytest-trio"),
requirement("pytest-mock"),
requirement("rich"),
requirement("zipp"),
"@rules_python//python/runfiles",
]
Expand Down
61 changes: 61 additions & 0 deletions py/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,13 @@
import socketserver
import sys
import threading
import types
from dataclasses import dataclass
from pathlib import Path

import pytest
import rich.console
import rich.traceback

from selenium import webdriver
from selenium.common.exceptions import WebDriverException
Expand All @@ -44,6 +47,64 @@
)


TRACEBACK_WIDTH = 130
# don't force colors on RBE since errors get redirected to a log file
force_terminal = "REMOTE_BUILD" not in os.environ
console = rich.console.Console(force_terminal=force_terminal, width=TRACEBACK_WIDTH)


def extract_traceback_frames(tb):
"""Extract frames from a traceback object."""
frames = []
while tb:
if hasattr(tb, "tb_frame") and hasattr(tb, "tb_lineno"):
# Skip frames without source files
if Path(tb.tb_frame.f_code.co_filename).exists():
frames.append((tb.tb_frame, tb.tb_lineno, getattr(tb, "tb_lasti", 0)))
tb = getattr(tb, "tb_next", None)
return frames


def filter_frames(frames):
"""Filter out frames from pytest internals."""
skip_modules = ["pytest", "_pytest", "pluggy"]
filtered = []
for frame, lineno, lasti in reversed(frames):
mod_name = frame.f_globals.get("__name__", "")
if not any(skip in mod_name for skip in skip_modules):
filtered.append((frame, lineno, lasti))
return filtered


def rebuild_traceback(frames):
"""Rebuild a traceback object from frames list."""
new_tb = None
for frame, lineno, lasti in frames:
new_tb = types.TracebackType(new_tb, frame, lasti, lineno)
return new_tb


def pytest_runtest_makereport(item, call):
"""Hook to print Rich traceback for test failures."""
if call.excinfo is None:
return
exc_type = call.excinfo.type
exc_value = call.excinfo.value
exc_tb = call.excinfo.tb
frames = extract_traceback_frames(exc_tb)
filtered_frames = filter_frames(frames)
new_tb = rebuild_traceback(filtered_frames)
tb = rich.traceback.Traceback.from_exception(
exc_type,
exc_value,
new_tb,
show_locals=False,
max_frames=5,
width=TRACEBACK_WIDTH,
)
console.print("\n", tb)


def pytest_addoption(parser):
parser.addoption(
"--driver",
Expand Down
4 changes: 4 additions & 0 deletions py/pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,10 @@ console_output_style = "progress"
faulthandler_timeout = "60"
log_cli = true
trio_mode = true
addopts = ["-s", "--tb=no"]
filterwarnings = [
"ignore::DeprecationWarning",
]
markers = [
"xfail_chrome: Tests expected to fail in Chrome",
"xfail_edge: Tests expected to fail in Edge",
Expand Down