Use serialization hooks from pytest 4.4
This commit is contained in:
5
changelog/426.feature.rst
Normal file
5
changelog/426.feature.rst
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
``pytest-xdist`` now uses the new ``pytest_report_to_serializable`` and ``pytest_report_from_serializable``
|
||||||
|
from ``pytest 4.4`` (still experimental). This will make report serialization more reliable and
|
||||||
|
extensible.
|
||||||
|
|
||||||
|
This also means that ``pytest-xdist`` now also requires ``pytest>=4.4``.
|
||||||
2
setup.py
2
setup.py
@@ -1,6 +1,6 @@
|
|||||||
from setuptools import setup, find_packages
|
from setuptools import setup, find_packages
|
||||||
|
|
||||||
install_requires = ["execnet>=1.1", "pytest>=3.6.0", "pytest-forked", "six"]
|
install_requires = ["execnet>=1.1", "pytest>=4.4.0", "pytest-forked", "six"]
|
||||||
|
|
||||||
|
|
||||||
with open("README.rst") as f:
|
with open("README.rst") as f:
|
||||||
|
|||||||
@@ -3,8 +3,7 @@ import pprint
|
|||||||
import pytest
|
import pytest
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
from xdist.workermanage import WorkerController, unserialize_report
|
from xdist.workermanage import WorkerController
|
||||||
from xdist.remote import serialize_report
|
|
||||||
import execnet
|
import execnet
|
||||||
import marshal
|
import marshal
|
||||||
|
|
||||||
@@ -81,187 +80,17 @@ def test_remoteinitconfig(testdir):
|
|||||||
assert config2.pluginmanager.getplugin("terminal") in (-1, None)
|
assert config2.pluginmanager.getplugin("terminal") in (-1, None)
|
||||||
|
|
||||||
|
|
||||||
class TestReportSerialization:
|
|
||||||
def test_xdist_longrepr_to_str_issue_241(self, testdir):
|
|
||||||
testdir.makepyfile(
|
|
||||||
"""
|
|
||||||
import os
|
|
||||||
def test_a(): assert False
|
|
||||||
def test_b(): pass
|
|
||||||
"""
|
|
||||||
)
|
|
||||||
testdir.makeconftest(
|
|
||||||
"""
|
|
||||||
def pytest_runtest_logreport(report):
|
|
||||||
print(report.longrepr)
|
|
||||||
"""
|
|
||||||
)
|
|
||||||
res = testdir.runpytest("-n1", "-s")
|
|
||||||
res.stdout.fnmatch_lines(["*1 failed, 1 passed *"])
|
|
||||||
|
|
||||||
def test_xdist_report_longrepr_reprcrash_130(self, testdir):
|
|
||||||
reprec = testdir.inline_runsource(
|
|
||||||
"""
|
|
||||||
import py
|
|
||||||
def test_fail(): assert False, 'Expected Message'
|
|
||||||
"""
|
|
||||||
)
|
|
||||||
reports = reprec.getreports("pytest_runtest_logreport")
|
|
||||||
assert len(reports) == 3
|
|
||||||
rep = reports[1]
|
|
||||||
added_section = ("Failure Metadata", str("metadata metadata"), "*")
|
|
||||||
rep.longrepr.sections.append(added_section)
|
|
||||||
d = serialize_report(rep)
|
|
||||||
check_marshallable(d)
|
|
||||||
a = unserialize_report("testreport", d)
|
|
||||||
# Check assembled == rep
|
|
||||||
assert a.__dict__.keys() == rep.__dict__.keys()
|
|
||||||
for key in rep.__dict__.keys():
|
|
||||||
if key != "longrepr":
|
|
||||||
assert getattr(a, key) == getattr(rep, key)
|
|
||||||
assert rep.longrepr.reprcrash.lineno == a.longrepr.reprcrash.lineno
|
|
||||||
assert rep.longrepr.reprcrash.message == a.longrepr.reprcrash.message
|
|
||||||
assert rep.longrepr.reprcrash.path == a.longrepr.reprcrash.path
|
|
||||||
assert rep.longrepr.reprtraceback.entrysep == a.longrepr.reprtraceback.entrysep
|
|
||||||
assert (
|
|
||||||
rep.longrepr.reprtraceback.extraline == a.longrepr.reprtraceback.extraline
|
|
||||||
)
|
|
||||||
assert rep.longrepr.reprtraceback.style == a.longrepr.reprtraceback.style
|
|
||||||
assert rep.longrepr.sections == a.longrepr.sections
|
|
||||||
# Missing section attribute PR171
|
|
||||||
assert added_section in a.longrepr.sections
|
|
||||||
|
|
||||||
def test_reprentries_serialization_170(self, testdir):
|
|
||||||
from _pytest._code.code import ReprEntry
|
|
||||||
|
|
||||||
reprec = testdir.inline_runsource(
|
|
||||||
"""
|
|
||||||
def test_repr_entry():
|
|
||||||
x = 0
|
|
||||||
assert x
|
|
||||||
""",
|
|
||||||
"--showlocals",
|
|
||||||
)
|
|
||||||
reports = reprec.getreports("pytest_runtest_logreport")
|
|
||||||
assert len(reports) == 3
|
|
||||||
rep = reports[1]
|
|
||||||
d = serialize_report(rep)
|
|
||||||
a = unserialize_report("testreport", d)
|
|
||||||
|
|
||||||
rep_entries = rep.longrepr.reprtraceback.reprentries
|
|
||||||
a_entries = a.longrepr.reprtraceback.reprentries
|
|
||||||
for i in range(len(a_entries)):
|
|
||||||
assert isinstance(rep_entries[i], ReprEntry)
|
|
||||||
assert rep_entries[i].lines == a_entries[i].lines
|
|
||||||
assert rep_entries[i].reprfileloc.lineno == a_entries[i].reprfileloc.lineno
|
|
||||||
assert (
|
|
||||||
rep_entries[i].reprfileloc.message == a_entries[i].reprfileloc.message
|
|
||||||
)
|
|
||||||
assert rep_entries[i].reprfileloc.path == a_entries[i].reprfileloc.path
|
|
||||||
assert rep_entries[i].reprfuncargs.args == a_entries[i].reprfuncargs.args
|
|
||||||
assert rep_entries[i].reprlocals.lines == a_entries[i].reprlocals.lines
|
|
||||||
assert rep_entries[i].style == a_entries[i].style
|
|
||||||
|
|
||||||
def test_reprentries_serialization_196(self, testdir):
|
|
||||||
from _pytest._code.code import ReprEntryNative
|
|
||||||
|
|
||||||
reprec = testdir.inline_runsource(
|
|
||||||
"""
|
|
||||||
def test_repr_entry_native():
|
|
||||||
x = 0
|
|
||||||
assert x
|
|
||||||
""",
|
|
||||||
"--tb=native",
|
|
||||||
)
|
|
||||||
reports = reprec.getreports("pytest_runtest_logreport")
|
|
||||||
assert len(reports) == 3
|
|
||||||
rep = reports[1]
|
|
||||||
d = serialize_report(rep)
|
|
||||||
a = unserialize_report("testreport", d)
|
|
||||||
|
|
||||||
rep_entries = rep.longrepr.reprtraceback.reprentries
|
|
||||||
a_entries = a.longrepr.reprtraceback.reprentries
|
|
||||||
for i in range(len(a_entries)):
|
|
||||||
assert isinstance(rep_entries[i], ReprEntryNative)
|
|
||||||
assert rep_entries[i].lines == a_entries[i].lines
|
|
||||||
|
|
||||||
def test_itemreport_outcomes(self, testdir):
|
|
||||||
reprec = testdir.inline_runsource(
|
|
||||||
"""
|
|
||||||
import py
|
|
||||||
def test_pass(): pass
|
|
||||||
def test_fail(): 0/0
|
|
||||||
@py.test.mark.skipif("True")
|
|
||||||
def test_skip(): pass
|
|
||||||
def test_skip_imperative():
|
|
||||||
py.test.skip("hello")
|
|
||||||
@py.test.mark.xfail("True")
|
|
||||||
def test_xfail(): 0/0
|
|
||||||
def test_xfail_imperative():
|
|
||||||
py.test.xfail("hello")
|
|
||||||
"""
|
|
||||||
)
|
|
||||||
reports = reprec.getreports("pytest_runtest_logreport")
|
|
||||||
assert len(reports) == 17 # with setup/teardown "passed" reports
|
|
||||||
for rep in reports:
|
|
||||||
d = serialize_report(rep)
|
|
||||||
check_marshallable(d)
|
|
||||||
newrep = unserialize_report("testreport", d)
|
|
||||||
assert newrep.passed == rep.passed
|
|
||||||
assert newrep.failed == rep.failed
|
|
||||||
assert newrep.skipped == rep.skipped
|
|
||||||
if newrep.skipped and not hasattr(newrep, "wasxfail"):
|
|
||||||
assert len(newrep.longrepr) == 3
|
|
||||||
assert newrep.outcome == rep.outcome
|
|
||||||
assert newrep.when == rep.when
|
|
||||||
assert newrep.keywords == rep.keywords
|
|
||||||
if rep.failed:
|
|
||||||
assert newrep.longreprtext == rep.longreprtext
|
|
||||||
|
|
||||||
def test_collectreport_passed(self, testdir):
|
|
||||||
reprec = testdir.inline_runsource("def test_func(): pass")
|
|
||||||
reports = reprec.getreports("pytest_collectreport")
|
|
||||||
for rep in reports:
|
|
||||||
d = serialize_report(rep)
|
|
||||||
check_marshallable(d)
|
|
||||||
newrep = unserialize_report("collectreport", d)
|
|
||||||
assert newrep.passed == rep.passed
|
|
||||||
assert newrep.failed == rep.failed
|
|
||||||
assert newrep.skipped == rep.skipped
|
|
||||||
|
|
||||||
def test_collectreport_fail(self, testdir):
|
|
||||||
reprec = testdir.inline_runsource("qwe abc")
|
|
||||||
reports = reprec.getreports("pytest_collectreport")
|
|
||||||
assert reports
|
|
||||||
for rep in reports:
|
|
||||||
d = serialize_report(rep)
|
|
||||||
check_marshallable(d)
|
|
||||||
newrep = unserialize_report("collectreport", d)
|
|
||||||
assert newrep.passed == rep.passed
|
|
||||||
assert newrep.failed == rep.failed
|
|
||||||
assert newrep.skipped == rep.skipped
|
|
||||||
if rep.failed:
|
|
||||||
assert newrep.longrepr == str(rep.longrepr)
|
|
||||||
|
|
||||||
def test_extended_report_deserialization(self, testdir):
|
|
||||||
reprec = testdir.inline_runsource("qwe abc")
|
|
||||||
reports = reprec.getreports("pytest_collectreport")
|
|
||||||
assert reports
|
|
||||||
for rep in reports:
|
|
||||||
rep.extra = True
|
|
||||||
d = serialize_report(rep)
|
|
||||||
check_marshallable(d)
|
|
||||||
newrep = unserialize_report("collectreport", d)
|
|
||||||
assert newrep.extra
|
|
||||||
assert newrep.passed == rep.passed
|
|
||||||
assert newrep.failed == rep.failed
|
|
||||||
assert newrep.skipped == rep.skipped
|
|
||||||
if rep.failed:
|
|
||||||
assert newrep.longrepr == str(rep.longrepr)
|
|
||||||
|
|
||||||
|
|
||||||
class TestWorkerInteractor:
|
class TestWorkerInteractor:
|
||||||
def test_basic_collect_and_runtests(self, worker):
|
@pytest.fixture
|
||||||
|
def unserialize_report(self, pytestconfig):
|
||||||
|
def unserialize(data):
|
||||||
|
return pytestconfig.hook.pytest_report_from_serializable(
|
||||||
|
config=pytestconfig, data=data
|
||||||
|
)
|
||||||
|
|
||||||
|
return unserialize
|
||||||
|
|
||||||
|
def test_basic_collect_and_runtests(self, worker, unserialize_report):
|
||||||
worker.testdir.makepyfile(
|
worker.testdir.makepyfile(
|
||||||
"""
|
"""
|
||||||
def test_func():
|
def test_func():
|
||||||
@@ -286,14 +115,14 @@ class TestWorkerInteractor:
|
|||||||
ev = worker.popevent("testreport") # setup
|
ev = worker.popevent("testreport") # setup
|
||||||
ev = worker.popevent("testreport")
|
ev = worker.popevent("testreport")
|
||||||
assert ev.name == "testreport"
|
assert ev.name == "testreport"
|
||||||
rep = unserialize_report(ev.name, ev.kwargs["data"])
|
rep = unserialize_report(ev.kwargs["data"])
|
||||||
assert rep.nodeid.endswith("::test_func")
|
assert rep.nodeid.endswith("::test_func")
|
||||||
assert rep.passed
|
assert rep.passed
|
||||||
assert rep.when == "call"
|
assert rep.when == "call"
|
||||||
ev = worker.popevent("workerfinished")
|
ev = worker.popevent("workerfinished")
|
||||||
assert "workeroutput" in ev.kwargs
|
assert "workeroutput" in ev.kwargs
|
||||||
|
|
||||||
def test_remote_collect_skip(self, worker):
|
def test_remote_collect_skip(self, worker, unserialize_report):
|
||||||
worker.testdir.makepyfile(
|
worker.testdir.makepyfile(
|
||||||
"""
|
"""
|
||||||
import pytest
|
import pytest
|
||||||
@@ -305,25 +134,25 @@ class TestWorkerInteractor:
|
|||||||
assert not ev.kwargs
|
assert not ev.kwargs
|
||||||
ev = worker.popevent()
|
ev = worker.popevent()
|
||||||
assert ev.name == "collectreport"
|
assert ev.name == "collectreport"
|
||||||
rep = unserialize_report(ev.name, ev.kwargs["data"])
|
rep = unserialize_report(ev.kwargs["data"])
|
||||||
assert rep.skipped
|
assert rep.skipped
|
||||||
assert rep.longrepr[2] == "Skipped: hello"
|
assert rep.longrepr[2] == "Skipped: hello"
|
||||||
ev = worker.popevent("collectionfinish")
|
ev = worker.popevent("collectionfinish")
|
||||||
assert not ev.kwargs["ids"]
|
assert not ev.kwargs["ids"]
|
||||||
|
|
||||||
def test_remote_collect_fail(self, worker):
|
def test_remote_collect_fail(self, worker, unserialize_report):
|
||||||
worker.testdir.makepyfile("""aasd qwe""")
|
worker.testdir.makepyfile("""aasd qwe""")
|
||||||
worker.setup()
|
worker.setup()
|
||||||
ev = worker.popevent("collectionstart")
|
ev = worker.popevent("collectionstart")
|
||||||
assert not ev.kwargs
|
assert not ev.kwargs
|
||||||
ev = worker.popevent()
|
ev = worker.popevent()
|
||||||
assert ev.name == "collectreport"
|
assert ev.name == "collectreport"
|
||||||
rep = unserialize_report(ev.name, ev.kwargs["data"])
|
rep = unserialize_report(ev.kwargs["data"])
|
||||||
assert rep.failed
|
assert rep.failed
|
||||||
ev = worker.popevent("collectionfinish")
|
ev = worker.popevent("collectionfinish")
|
||||||
assert not ev.kwargs["ids"]
|
assert not ev.kwargs["ids"]
|
||||||
|
|
||||||
def test_runtests_all(self, worker):
|
def test_runtests_all(self, worker, unserialize_report):
|
||||||
worker.testdir.makepyfile(
|
worker.testdir.makepyfile(
|
||||||
"""
|
"""
|
||||||
def test_func(): pass
|
def test_func(): pass
|
||||||
@@ -345,7 +174,7 @@ class TestWorkerInteractor:
|
|||||||
for i in range(3): # setup/call/teardown
|
for i in range(3): # setup/call/teardown
|
||||||
ev = worker.popevent("testreport")
|
ev = worker.popevent("testreport")
|
||||||
assert ev.name == "testreport"
|
assert ev.name == "testreport"
|
||||||
rep = unserialize_report(ev.name, ev.kwargs["data"])
|
rep = unserialize_report(ev.kwargs["data"])
|
||||||
assert rep.nodeid.endswith(func)
|
assert rep.nodeid.endswith(func)
|
||||||
ev = worker.popevent("workerfinished")
|
ev = worker.popevent("workerfinished")
|
||||||
assert "workeroutput" in ev.kwargs
|
assert "workeroutput" in ev.kwargs
|
||||||
|
|||||||
@@ -104,7 +104,9 @@ class WorkerInteractor(object):
|
|||||||
self.sendevent("logfinish", nodeid=nodeid, location=location)
|
self.sendevent("logfinish", nodeid=nodeid, location=location)
|
||||||
|
|
||||||
def pytest_runtest_logreport(self, report):
|
def pytest_runtest_logreport(self, report):
|
||||||
data = serialize_report(report)
|
data = self.config.hook.pytest_report_to_serializable(
|
||||||
|
config=self.config, report=report
|
||||||
|
)
|
||||||
data["item_index"] = self.item_index
|
data["item_index"] = self.item_index
|
||||||
data["worker_id"] = self.workerid
|
data["worker_id"] = self.workerid
|
||||||
assert self.session.items[self.item_index].nodeid == report.nodeid
|
assert self.session.items[self.item_index].nodeid == report.nodeid
|
||||||
@@ -113,7 +115,9 @@ class WorkerInteractor(object):
|
|||||||
def pytest_collectreport(self, report):
|
def pytest_collectreport(self, report):
|
||||||
# send only reports that have not passed to master as optimization (#330)
|
# send only reports that have not passed to master as optimization (#330)
|
||||||
if not report.passed:
|
if not report.passed:
|
||||||
data = serialize_report(report)
|
data = self.config.hook.pytest_report_to_serializable(
|
||||||
|
config=self.config, report=report
|
||||||
|
)
|
||||||
self.sendevent("collectreport", data=data)
|
self.sendevent("collectreport", data=data)
|
||||||
|
|
||||||
# the pytest_logwarning hook was deprecated since pytest 4.0
|
# the pytest_logwarning hook was deprecated since pytest 4.0
|
||||||
@@ -143,47 +147,6 @@ class WorkerInteractor(object):
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def serialize_report(rep):
|
|
||||||
def disassembled_report(rep):
|
|
||||||
reprtraceback = rep.longrepr.reprtraceback.__dict__.copy()
|
|
||||||
reprcrash = rep.longrepr.reprcrash.__dict__.copy()
|
|
||||||
|
|
||||||
new_entries = []
|
|
||||||
for entry in reprtraceback["reprentries"]:
|
|
||||||
entry_data = {"type": type(entry).__name__, "data": entry.__dict__.copy()}
|
|
||||||
for key, value in entry_data["data"].items():
|
|
||||||
if hasattr(value, "__dict__"):
|
|
||||||
entry_data["data"][key] = value.__dict__.copy()
|
|
||||||
new_entries.append(entry_data)
|
|
||||||
|
|
||||||
reprtraceback["reprentries"] = new_entries
|
|
||||||
|
|
||||||
return {
|
|
||||||
"reprcrash": reprcrash,
|
|
||||||
"reprtraceback": reprtraceback,
|
|
||||||
"sections": rep.longrepr.sections,
|
|
||||||
}
|
|
||||||
|
|
||||||
import py
|
|
||||||
|
|
||||||
d = rep.__dict__.copy()
|
|
||||||
if hasattr(rep.longrepr, "toterminal"):
|
|
||||||
if hasattr(rep.longrepr, "reprtraceback") and hasattr(
|
|
||||||
rep.longrepr, "reprcrash"
|
|
||||||
):
|
|
||||||
d["longrepr"] = disassembled_report(rep)
|
|
||||||
else:
|
|
||||||
d["longrepr"] = str(rep.longrepr)
|
|
||||||
else:
|
|
||||||
d["longrepr"] = rep.longrepr
|
|
||||||
for name in d:
|
|
||||||
if isinstance(d[name], py.path.local):
|
|
||||||
d[name] = str(d[name])
|
|
||||||
elif name == "result":
|
|
||||||
d[name] = None # for now
|
|
||||||
return d
|
|
||||||
|
|
||||||
|
|
||||||
def serialize_warning_message(warning_message):
|
def serialize_warning_message(warning_message):
|
||||||
if isinstance(warning_message.message, Warning):
|
if isinstance(warning_message.message, Warning):
|
||||||
message_module = type(warning_message.message).__module__
|
message_module = type(warning_message.message).__module__
|
||||||
|
|||||||
@@ -10,8 +10,6 @@ import execnet
|
|||||||
|
|
||||||
import xdist.remote
|
import xdist.remote
|
||||||
|
|
||||||
from _pytest import runner # XXX load dynamically
|
|
||||||
|
|
||||||
|
|
||||||
def parse_spec_config(config):
|
def parse_spec_config(config):
|
||||||
xspeclist = []
|
xspeclist = []
|
||||||
@@ -322,7 +320,9 @@ class WorkerController(object):
|
|||||||
self.notify_inproc(eventname, node=self, **kwargs)
|
self.notify_inproc(eventname, node=self, **kwargs)
|
||||||
elif eventname in ("testreport", "collectreport", "teardownreport"):
|
elif eventname in ("testreport", "collectreport", "teardownreport"):
|
||||||
item_index = kwargs.pop("item_index", None)
|
item_index = kwargs.pop("item_index", None)
|
||||||
rep = unserialize_report(eventname, kwargs["data"])
|
rep = self.config.hook.pytest_report_from_serializable(
|
||||||
|
config=self.config, data=kwargs["data"]
|
||||||
|
)
|
||||||
if item_index is not None:
|
if item_index is not None:
|
||||||
rep.item_index = item_index
|
rep.item_index = item_index
|
||||||
self.notify_inproc(eventname, node=self, rep=rep)
|
self.notify_inproc(eventname, node=self, rep=rep)
|
||||||
@@ -367,73 +367,6 @@ class WorkerController(object):
|
|||||||
self.notify_inproc("errordown", node=self, error=excinfo)
|
self.notify_inproc("errordown", node=self, error=excinfo)
|
||||||
|
|
||||||
|
|
||||||
def unserialize_report(name, reportdict):
|
|
||||||
def assembled_report(reportdict):
|
|
||||||
from _pytest._code.code import (
|
|
||||||
ReprEntry,
|
|
||||||
ReprEntryNative,
|
|
||||||
ReprExceptionInfo,
|
|
||||||
ReprFileLocation,
|
|
||||||
ReprFuncArgs,
|
|
||||||
ReprLocals,
|
|
||||||
ReprTraceback,
|
|
||||||
)
|
|
||||||
|
|
||||||
if reportdict["longrepr"]:
|
|
||||||
if (
|
|
||||||
"reprcrash" in reportdict["longrepr"]
|
|
||||||
and "reprtraceback" in reportdict["longrepr"]
|
|
||||||
):
|
|
||||||
|
|
||||||
reprtraceback = reportdict["longrepr"]["reprtraceback"]
|
|
||||||
reprcrash = reportdict["longrepr"]["reprcrash"]
|
|
||||||
|
|
||||||
unserialized_entries = []
|
|
||||||
reprentry = None
|
|
||||||
for entry_data in reprtraceback["reprentries"]:
|
|
||||||
data = entry_data["data"]
|
|
||||||
entry_type = entry_data["type"]
|
|
||||||
if entry_type == "ReprEntry":
|
|
||||||
reprfuncargs = None
|
|
||||||
reprfileloc = None
|
|
||||||
reprlocals = None
|
|
||||||
if data["reprfuncargs"]:
|
|
||||||
reprfuncargs = ReprFuncArgs(**data["reprfuncargs"])
|
|
||||||
if data["reprfileloc"]:
|
|
||||||
reprfileloc = ReprFileLocation(**data["reprfileloc"])
|
|
||||||
if data["reprlocals"]:
|
|
||||||
reprlocals = ReprLocals(data["reprlocals"]["lines"])
|
|
||||||
|
|
||||||
reprentry = ReprEntry(
|
|
||||||
lines=data["lines"],
|
|
||||||
reprfuncargs=reprfuncargs,
|
|
||||||
reprlocals=reprlocals,
|
|
||||||
filelocrepr=reprfileloc,
|
|
||||||
style=data["style"],
|
|
||||||
)
|
|
||||||
elif entry_type == "ReprEntryNative":
|
|
||||||
reprentry = ReprEntryNative(data["lines"])
|
|
||||||
else:
|
|
||||||
report_unserialization_failure(entry_type, name, reportdict)
|
|
||||||
unserialized_entries.append(reprentry)
|
|
||||||
reprtraceback["reprentries"] = unserialized_entries
|
|
||||||
|
|
||||||
exception_info = ReprExceptionInfo(
|
|
||||||
reprtraceback=ReprTraceback(**reprtraceback),
|
|
||||||
reprcrash=ReprFileLocation(**reprcrash),
|
|
||||||
)
|
|
||||||
|
|
||||||
for section in reportdict["longrepr"]["sections"]:
|
|
||||||
exception_info.addsection(*section)
|
|
||||||
reportdict["longrepr"] = exception_info
|
|
||||||
return reportdict
|
|
||||||
|
|
||||||
if name == "testreport":
|
|
||||||
return runner.TestReport(**assembled_report(reportdict))
|
|
||||||
elif name == "collectreport":
|
|
||||||
return runner.CollectReport(**assembled_report(reportdict))
|
|
||||||
|
|
||||||
|
|
||||||
def unserialize_warning_message(data):
|
def unserialize_warning_message(data):
|
||||||
import warnings
|
import warnings
|
||||||
import importlib
|
import importlib
|
||||||
@@ -474,17 +407,3 @@ def unserialize_warning_message(data):
|
|||||||
kwargs[attr_name] = data[attr_name]
|
kwargs[attr_name] = data[attr_name]
|
||||||
|
|
||||||
return warnings.WarningMessage(**kwargs)
|
return warnings.WarningMessage(**kwargs)
|
||||||
|
|
||||||
|
|
||||||
def report_unserialization_failure(type_name, report_name, reportdict):
|
|
||||||
from pprint import pprint
|
|
||||||
|
|
||||||
url = "https://github.com/pytest-dev/pytest-xdist/issues"
|
|
||||||
stream = py.io.TextIO()
|
|
||||||
pprint("-" * 100, stream=stream)
|
|
||||||
pprint("INTERNALERROR: Unknown entry type returned: %s" % type_name, stream=stream)
|
|
||||||
pprint("report_name: %s" % report_name, stream=stream)
|
|
||||||
pprint(reportdict, stream=stream)
|
|
||||||
pprint("Please report this bug at %s" % url, stream=stream)
|
|
||||||
pprint("-" * 100, stream=stream)
|
|
||||||
assert 0, stream.getvalue()
|
|
||||||
|
|||||||
Reference in New Issue
Block a user