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

Link images of comparison plots in DokuReport using hookwrapper. #590

Merged
merged 11 commits into from
Jun 21, 2016
20 changes: 20 additions & 0 deletions tardis/tests/tests_slow/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
from astropy import units as u

from tardis.tests.tests_slow.report import DokuReport
from tardis.tests.tests_slow.plot_helpers import PlotUploader


def pytest_configure(config):
Expand Down Expand Up @@ -39,6 +40,25 @@ def pytest_unconfigure(config):
shutil.rmtree(config.option.tempdir)


@pytest.mark.hookwrapper
def pytest_runtest_makereport(item, call):
# execute all other hooks to obtain the report object
outcome = yield
report = outcome.get_result()
if report.when == "call":
if "plot_object" in item.fixturenames:
plot_obj = item.funcargs["plot_object"]
plot_obj.upload(report)
report.extra = plot_obj.get_extras()


@pytest.fixture(scope="function")
def plot_object(request):
plot_obj = PlotUploader(request)
setattr(request.node, "plot_obj", plot_obj)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wo don't need this line anymore.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@yeganer I'm further simplifying to:

@pytest.fixture(scope="function")
def plot_object(request):
    return PlotUploader(request)

... in the next commit

return plot_obj


@pytest.fixture(scope="session")
def integration_tests_config(request):
return request.config.option.integration_tests_config
Expand Down
54 changes: 54 additions & 0 deletions tardis/tests/tests_slow/plot_helpers.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import tempfile

from pytest_html import extras
import tardis


class PlotUploader(object):
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd add an add method for adding plots and call upload() in pytest_runtest_makereport. Then we can give the report object to upload() and upload adds stuff like the passed/failed text depending on the report

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  • Done.

def __init__(self, request):
self.request = request
self._plots = list()
self.plot_html = list()
self.dokuwiki_url = self.request.config.dokureport.dokuwiki_url

def add(self, plot, name):
"""
Accept a `matplotlib.pyplot.figure` and add it to self._plots.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can you please do numpydoc style documentation. for all functions that have documentation.

"""
self._plots.append((plot, name))

def upload(self, report):
"""
Upload the content in self._plots to dokuwiki.
"""
for plot, name in self._plots:
plot_file = tempfile.NamedTemporaryFile(suffix=".png")
axes = plot.axes[0]

if report.passed:
axes.text(0.8, 0.8, 'passed', transform=axes.transAxes,
bbox={'facecolor': 'green', 'alpha': 0.5, 'pad': 10})
else:
axes.text(0.8, 0.8, 'failed', transform=axes.transAxes,
bbox={'facecolor': 'red', 'alpha': 0.5, 'pad': 10})

plot.savefig(plot_file.name)

self.request.config.dokureport.doku_conn.medias.add(
"plots:{0}_{1}.png".format(tardis.__githash__[0:7], name),
plot_file.name
)

thumbnail_html = """
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you define this HTML snippet as a constant at the top?

Copy link
Author

@kdexd kdexd Jun 21, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ Done.

<div class="image" style="float: left">
<a href="#">
<img src= "{0}lib/exe/fetch.php?media=plots:{1}_{2}.png" />
</a>
</div>
""".format(self.dokuwiki_url, tardis.__githash__[0:7], name)

self.plot_html.append(extras.html(thumbnail_html))
plot_file.close()

def get_extras(self):
return self.plot_html
6 changes: 5 additions & 1 deletion tardis/tests/tests_slow/report.py
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,11 @@ def _generate_report(self, session):
)
)
report_content += doc.unicode(indent=2)

# Quick hack for preventing log to be placed in narrow left out space
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As this line only affects the result part of the whole log I'd move it so it only works on result just after result = ...

report_content = report_content.replace(
u'class="log"', u'class="log" style="clear: both"'
)
return report_content

def _save_report(self, report_content):
Expand Down Expand Up @@ -186,7 +191,6 @@ def pytest_terminal_summary(self, terminalreporter):
self.dokuwiki_url, tardis.__githash__[0:7]
)
)

else:
terminalreporter.write_sep(
"-", "Connection not established, upload failed.")
98 changes: 56 additions & 42 deletions tardis/tests/tests_slow/test_w7.py
Original file line number Diff line number Diff line change
Expand Up @@ -111,57 +111,44 @@ def test_luminosity_inner(self):
self.reference['luminosity_inner'],
self.result.luminosity_inner)

def test_spectrum(self):
try:
assert_quantity_allclose(
self.reference['luminosity_density_nu'],
self.result.runner.spectrum.luminosity_density_nu)

assert_quantity_allclose(
self.reference['delta_frequency'],
self.result.runner.spectrum.delta_frequency)

assert_quantity_allclose(
self.reference['wavelength'],
self.result.runner.spectrum.wavelength)

assert_quantity_allclose(
self.reference['luminosity_density_lambda'],
self.result.runner.spectrum.luminosity_density_lambda)

self.plot_spectrum(has_passed=True)
except Exception as e:
self.plot_spectrum(has_passed=False)
raise e

def plot_spectrum(self, has_passed):
def test_spectrum(self, plot_object):
plot_object.add(self.plot_spectrum(), "spectrum")

assert_quantity_allclose(
self.reference['luminosity_density_nu'],
self.result.runner.spectrum.luminosity_density_nu)

assert_quantity_allclose(
self.reference['delta_frequency'],
self.result.runner.spectrum.delta_frequency)

assert_quantity_allclose(
self.reference['wavelength'],
self.result.runner.spectrum.wavelength)

assert_quantity_allclose(
self.reference['luminosity_density_lambda'],
self.result.runner.spectrum.luminosity_density_lambda)

def plot_spectrum(self):
plt.suptitle("Deviation in spectrum_quantities", fontweight="bold")
figure = plt.figure()

# `ldl_` prefixed variables associated with `luminosity_density_lambda`.
# Axes of subplot are extracted, if we wish to make multiple plots
# for different spectrum quantities all in one figure.
ldl_ax = plt.subplot(111)
ldl_ax = figure.add_subplot(111)
ldl_ax.set_title("Deviation in luminosity_density_lambda")
ldl_ax.set_xlabel("Wavelength")
ldl_ax.set_ylabel("Relative error (1 - result / reference)")
deviation = 1 - (
self.result.runner.spectrum.luminosity_density_lambda.value /
self.reference['luminosity_density_lambda'].value)

if has_passed:
ldl_ax.text(0.8, 0.8, 'passed', transform=ldl_ax.transAxes,
bbox={'facecolor': 'green', 'alpha': 0.5, 'pad': 10})
ldl_ax.plot(self.reference['wavelength'], deviation,
color="green", marker=".")
else:
ldl_ax.text(0.8, 0.8, 'failed', transform=ldl_ax.transAxes,
bbox={'facecolor': 'red', 'alpha': 0.5, 'pad': 10})
ldl_ax.plot(self.reference['wavelength'], deviation,
color="red", marker=".")

# Figure is saved in `tmp` directory right now, till a suitable way of
# saving them is decided.
plt.savefig(os.path.join(self.base_plot_dir, "spectrum.png"))
ldl_ax.plot(self.reference['wavelength'], deviation,
color="blue", marker=".")

return figure

def test_montecarlo_properties(self):
assert_quantity_allclose(
Expand All @@ -176,7 +163,34 @@ def test_montecarlo_properties(self):
self.reference['montecarlo_nu'],
self.result.montecarlo_nu)

def test_shell_temperature(self):
def test_shell_temperature(self, plot_object):
plot_object.add(self.plot_t_rads(), "t_rads")

assert_quantity_allclose(
self.reference['t_rads'],
self.result.t_rads)
self.reference['t_rads'],
self.result.t_rads)

def plot_t_rads(self):
plt.suptitle("Shell temperature for packets", fontweight="bold")
figure = plt.figure()

ax = figure.add_subplot(111)
ax.set_xlabel("Shell id")
ax.set_ylabel("t_rads")

result_line = ax.plot(self.result.t_rads, color="blue",
marker=".", label="Result")
reference_line = ax.plot(self.reference['t_rads'], color="green",
marker=".", label="Reference")
ax.axis([0, 28, 5000, 10000])

error_ax = ax.twinx()
error_line = error_ax.plot((1 - self.result.t_rads / self.reference['t_rads']),
color="red", marker=".", label="Rel. Error")
error_ax.set_ylabel("Relative error (1 - result / reference)")

lines = result_line + reference_line + error_line
labels = [l.get_label() for l in lines]

ax.legend(lines, labels, loc="lower left")
return figure