# Virus Health Check: a validation tool for HETDEX/VIRUS data
# Copyright (C) 2016, 2017 "The HETDEX collaboration"
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.
"""Interface for the html renderer
The relevant parts are imported into html/__init__.py
"""
from __future__ import (absolute_import, division, print_function,
unicode_literals)
import contextlib
from libvhc.html import fplane
from libvhc.html import queue
HTML_RECAP = "{{recipe}}_recap_{}.html"
"""Template name for the html recap files"""
# _manager = multiprocessing.Manager()
# Private container for the fplane object
# key: recipe; value: fplane.FPlane instance
_listeners = dict()
_queues = dict()
[docs]class HtmlRecipeError(KeyError):
"""The html render for the recipe has not been initialised"""
pass
[docs]def get_listener(name):
"""Return the queue listener
Parameters
----------
name : string
name of the logger
Returns
-------
:class:`libvhc.html.queue.SetupQueueListener`
can be used once in a :keyword:`with`
Raises
------
KeyError
if the ``name`` listener is not found
"""
return _listeners[name]
[docs]def get_queue(name):
"""Returns the queue saved under the ``name``.
If it does not exist, create it first
Parameters
----------
path : string
path of the two above files
Returns
-------
:class:`libvhc.html.queue.HTMLQueue`
"""
try:
return _queues[name]
except KeyError:
q = queue.HTMLQueue()
_queues[name] = q
return q
[docs]@contextlib.contextmanager
def html_context(name):
"""Yield the listener and the queue associated with ``name`` from within a
:keyword:`with` statement
Parameters
----------
name : string
name of the listener and the queue
Yields
------
queue-like instance
:class:`~pyhetdex.tools.logging_helper.SetupQueueListener`
"""
try:
with get_queue(name) as q, get_listener(name) as l:
yield q, l
finally:
clear_html(name)
[docs]def clear_html(name):
"""Remove the queue and the listener
Parameters
----------
name : string
name of the queue and logger
"""
_queues.pop(name, None)
_listeners.pop(name, None)
[docs]def init_renderer(recipe, fplane_file, use_process=True):
"""Initialize the renderer for the HTML file and the
:class:`fplane.FPlane`
Parameters
----------
recipe : string
name of the recipe
fplane_file : string
name of the file describing the focal plane.
use_process : bool, optional
run the listener in a process or in a thread
"""
q = get_queue(recipe)
listener = queue.SetupQueueListener(q, fplane.FPlane, recipe, fplane_file,
use_process=use_process)
_listeners[recipe] = listener
[docs]def _mkmessage(vcheck, message):
"""Prepend the string from ``vcheck`` to the ``message``
Parameters
----------
vcheck : instance of :class:`~libvhc.VCheck`
store the recipe name and the check currently executing
message : string
message of the test
Returns
-------
string
"""
return str(vcheck) + "; " + message
[docs]def add_fplane_test(vcheck, message, success):
"""Append a new :class:`TestResults` to the focal plane tests
The name of the recipe and driver are prepended to the message.
Parameters
----------
vcheck : instance of :class:`~libvhc.VCheck`
store the recipe name and the check currently executing
message : string
message of the test
success : string or bool
success status of the test; must be one of the accepted values of
:class:`TestResults`
Raises
------
HtmlRecipeError
if the ``recipe`` renderer has not been initialized
"""
get_queue(vcheck.recipe).put(['add_test', (_mkmessage(vcheck, message),
success)])
[docs]def add_ifu_test(vcheck, ifuslot, message, success):
"""Append a new :class:`TestResults` to the ifu tests
The name of the recipe and driver are prepended to the message.
Parameters
----------
vcheck : instance of :class:`~libvhc.VCheck`
store the recipe name and the check currently executing
ifuslot : string
id of the ifu slot, if the IFU does not exists, add the message to the
global messages marking it as a failure. Use a non existing ``ifuslot``
(e.g. ``None``) to add it to the orphaned tests
message : string
message of the test
success : string or bool
success status of the test; must be one of the accepted values of
:class:`TestResults`
Raises
------
HtmlRecipeError
if the ``recipe`` renderer has not been initialized
"""
get_queue(vcheck.recipe).put(['add_ifu_test', (ifuslot,
_mkmessage(vcheck, message),
success)])
[docs]def add_ntests(vcheck, new_tests):
"""Add ``new_tests`` to the number of tests
Parameters
----------
vcheck : instance of :class:`~libvhc.VCheck`
store the recipe name and the check currently executing
new_tests : int
number on tests to add
Raises
------
HtmlRecipeError
if the ``recipe`` renderer has not been initialized
"""
get_queue(vcheck.recipe).put(['add_ntests', (new_tests,)])
[docs]def render_html(recipe, fnames, path, xmin=-450, ymin=-550, xscale=1, yscale=1,
open_html=False):
"""Render the html and save it into ``outpath``.
The name of the output html is ``recipe_recap.html``. If it already exists,
a counter is added: ``recipe_recap_n.html``
Parameters
----------
recipe : string
name of the recipe
fnames : :class:`libvhc.utils.FileNameRotator`
object containing the file names. It expects the html file on
:attr:`fnames.html_recap`, the log file on :attr:`fnames.logfile` and
the result file on :attr:`fnames.result_file`. The html recap file
name is expected to contain a placeholder ``{recipe}``
path : string
path given to vhc
xmin, ymin : float
minimum ``x`` and ``y`` coordinate to rescale the ifu positions
scale : float
divide the ``x`` and ``y`` by this value after subtracting the
minima. See :func:`fplane.IFU.rescale` for further details
open_html : bool
open the new html in the default browser
"""
q = get_queue(recipe)
# rescale the IFU to fit them into the html frame
q.put(['ifu_rescale', (xmin, ymin, xscale, yscale)])
# post process the ifus to get the ifu statuses in place
q.put('postprocess_ifus')
# set the template into the fplane object
q.put('load_template')
# render the template
q.put(['render', (path, fnames.logfile, fnames.result_file,
fnames.driver_file)])
# build the output file name and save the rendered template
fname = fnames.html_recap.format(recipe=recipe)
write_html(recipe, fname, open_html=open_html)
[docs]def write_html(recipe, fname, open_html=False):
'''Send the command to write the html recap file.
Parameters
----------
recipe : string
name of the recipe
fname : string
name of the file
open_html : bool
open the new html in the default browser
'''
q = get_queue(recipe)
q.put(['write_recap', (fname, ), {'auto_open': open_html}])