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

Fix traceback construction in tests using threadpool #128

Merged
merged 1 commit into from
Jun 6, 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
21 changes: 21 additions & 0 deletions examples/test_example_fail_in_thread.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
from concurrent.futures.thread import ThreadPoolExecutor
from threading import Thread


import pytest_check as check


def force_fail(comparison):
check.equal(1 + 1, comparison, f"1 + 1 is 2, not {comparison}")


def test_threadpool():
with ThreadPoolExecutor() as executor:
task = executor.submit(force_fail, 3)
task.result()


def test_threading():
t = Thread(target=force_fail, args=(4, ))
t.start()
t.join()
21 changes: 21 additions & 0 deletions examples/test_example_pass_in_thread.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
from concurrent.futures.thread import ThreadPoolExecutor
from threading import Thread


import pytest_check as check


def always_pass():
check.equal(1 + 1, 2)


def test_threadpool():
with ThreadPoolExecutor() as executor:
task = executor.submit(always_pass)
task.result()


def test_threading():
t = Thread(target=always_pass)
t.start()
t.join()
12 changes: 6 additions & 6 deletions src/pytest_check/pseudo_traceback.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@
_traceback_style = "auto"


def get_full_context(level):
(_, filename, line, funcname, contextlist) = inspect.stack()[level][0:5]
def get_full_context(frame):
(_, filename, line, funcname, contextlist) = frame[0:5]
try:
filename = os.path.relpath(filename)
except ValueError: # pragma: no cover
Expand All @@ -28,11 +28,12 @@ def _build_pseudo_trace_str():
if _traceback_style == "no":
return ""

level = 4
skip_own_frames = 3
pseudo_trace = []
func = ""
while "test_" not in func:
(file, line, func, context) = get_full_context(level)
context_stack = inspect.stack()[skip_own_frames:]
while "test_" not in func and context_stack:
(file, line, func, context) = get_full_context(context_stack.pop(0))
# we want to trace through user code, not 3rd party or builtin libs
if "site-packages" in file:
break
Expand All @@ -41,6 +42,5 @@ def _build_pseudo_trace_str():
break
line = f"{file}:{line} in {func}() -> {context}"
pseudo_trace.append(line)
level += 1

return "\n".join(reversed(pseudo_trace)) + "\n"
12 changes: 12 additions & 0 deletions tests/test_thread.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
def test_failing_threaded_testcode(pytester):
pytester.copy_example("examples/test_example_fail_in_thread.py")
result = pytester.runpytest()
result.assert_outcomes(failed=2, passed=0)
result.stdout.fnmatch_lines(["*1 + 1 is 2, not 3*"])
result.stdout.fnmatch_lines(["*1 + 1 is 2, not 4*"])


def test_passing_threaded_testcode(pytester):
pytester.copy_example("examples/test_example_pass_in_thread.py")
result = pytester.runpytest()
result.assert_outcomes(failed=0, passed=2)