Source code for reports.report

# coding=utf-8
# -*- python -*-
#
#  This file is part of report software
#
#  Copyright (c) 2016
#  All rights reserved
#
#  File author(s): Thomas Cokelaer <cokelaer@gmail.com>
#
#  Distributed under the BSD 3-Clause License.
#  See accompanying file LICENSE.txt distributed with this software
#
##############################################################################
"""Base classes to create HTML reports easily"""
import os
import shutil
import glob

import easydev
import pandas as pd
from jinja2.environment import Environment
from jinja2 import FileSystemLoader

from .htmltable import HTMLTable

__all__ = ['Report']


def _get_report_version():
    # cannot use from report import version since it imports the module (not the
    # package) due to identical name. Hopefully, easydev does help:        
    deps = easydev.get_dependencies('reports')
    index = [x.project_name for x in deps].index('reports')
    return deps[index].version


[docs]class Report(object): """A base class to create HTML pages The :class:`Report` is used to #. fetch Jinja templates and css from a user directory (by default a generic set of files is provided as an example #. fetch the CSS and images #. hold variables and contents within a dictionary (:attr:`jinja`) #. Create the HTML document in a local directory. :: from report import Report r = Report() r.create_report(onweb=True) The next step is for you to copy the templates in a new directory, edit them and fill the :attr:`jinja` attribute to fulfil your needs:: from report import Report r = Report("myreport_templates") r.jinja["section1"] = "<h1></h1>" r.create_report() """ def __init__(self, template_path="generic", filename='index.html', directory='report', overwrite=True, verbose=True, template_filename='index.html', css_path="generic"): """.. rubric:: Constructor :param template_path: where to find the templates. If not provided, uses the generic version :param filename: default to **index.html** :param directory: defaults to **report** :param overwrite: default to True :param verbose: default to True :param dependencies: add the dependencies table at the end of the document if True. :param template_filename: entry point of the jinja code :param template_path: where to find the templates. If not provided, uses the generic version a template directory should contain a set of jinja files including *template_filename*. """ self.verbose = verbose self._directory = directory self._filename = filename # This contains the sections and their names when # method add_section is used self.sections = [] self.section_names = [] #: flag to add dependencies self.add_dependencies = False self.title = 'Title undefined' # For jinja2 inheritance, we need to use the environment # to indicate where are the parents' templates if template_path == "generic": share_path = easydev.get_shared_directory_path('reports') self.template_path = os.sep.join([share_path, 'data', 'templates', "generic"]) else: self.template_path = template_path self.env = Environment() self.env.loader = FileSystemLoader(self.template_path) # use template provided inside gdsctools self.template = self.env.get_template(template_filename) self.jinja = { 'time_now': self.get_time_now(), "title": self.title, 'dependencies': self.get_table_dependencies().to_html(), "report_version": _get_report_version() } self._to_create = ['images', 'css', 'js',] self._init_report() def _get_filename(self): return self._filename def _set_filename(self, filename): self._filename = filename filename = property(_get_filename, _set_filename, doc="The filename of the HTML document") def _get_directory(self): return self._directory def _set_directory(self, directory): self._directory = directory directory = property(_get_directory, _set_directory, doc="The directory where to save the HTML document") def _get_abspath(self): return self.directory + os.sep + self.filename abspath = property(_get_abspath, doc="The absolute path of the document (read only)") def _init_report(self): """create the report directory and return the directory name""" self.sections = [] self.section_names = [] # if the directory already exists, print a warning try: if os.path.isdir(self.directory) is False: if self.verbose: print("Created directory {}".format(self.directory)) os.mkdir(self.directory) # list of directories created in the constructor for this in self._to_create: try: os.mkdir(self.directory + os.sep + this) except: pass # already created ? except Exception: pass finally: temp_path = easydev.get_shared_directory_path("reports") filenames = glob.glob(self.template_path + os.sep + "*css") filenames += glob.glob(os.sep.join([temp_path, "data", "css", "*css"])) for filename in filenames: target = os.sep.join([self.directory, 'css' ]) if os.path.isfile(target) is False: shutil.copy(filename, target) for filename in ['sorttable.js', 'highlight.pack.js']: target = os.sep.join([self.directory, 'js', filename ]) if os.path.isfile(target) is False: filename = easydev.get_share_file("reports", "data", filename) shutil.copy(filename, target)
[docs] def to_html(self): self.jinja['time_now'] = self.get_time_now() return self.template.render(self.jinja)
[docs] def write(self): with open(self.abspath, "w") as fh: data = self.to_html() fh.write(data)
[docs] def onweb(self): """Open the HTML document in a browser""" from easydev import onweb onweb(self.abspath)
[docs] def create_report(self, onweb=True): self.write() if onweb is True: self.onweb()
[docs] def get_time_now(self): """Returns a time stamp""" import datetime import getpass username = getpass.getuser() # this is not working on some systems: os.environ["USERNAME"] timenow = str(datetime.datetime.now()) timenow = timenow.split('.')[0] msg = '<div class="date">Created on ' + timenow msg += " by " + username +'</div>' return msg
[docs] def get_table_dependencies(self): """Returns dependencies of the pipeline as an HTML/XML table The dependencies are the python dependencies as returned by pkg_resource module. """ dependencies = easydev.get_dependencies("reports") # TODO: Could re-use new method in HTMLTable for adding href # but needs some extra work in the add_href method. names = [x.project_name for x in dependencies] versions = [x.version for x in dependencies] links = ["""https://pypi.python.org/pypi/%s""" % p for p in names] df = pd.DataFrame({ 'package': ["""<a href="%s">%s</a>""" % (links[i], p) for i, p in enumerate(names)], 'version': versions}) table = HTMLTable(df, name="dependencies", escape=False) table.sort('package') return table