support.report – Reporting Manager

This module defines functions and classes which implement a flexible reporting manager for applications and libraries.

Public Classes

This module is built around two main parts: the first one is the reporting manager; the second one is a collection of handlers which manages the way by which the report is going to be published.

The reporting manager has only on public class.

Report

To date, the module includes a number of handlers listed below in alphabetical order. A handler is a derived class from the BaseHandler class.

FileHandler

StreamHandler

MailHandler

Using the module

The first step is to create a report and at least a handler, then you fill the report with some sections and then publish it. The creating step may done either in programmatic way or using a configuration file.

Using the module with its API

Creating a report needs at least the following steps.

  1. Create a Report class instance.

  2. Set the template report with the Report.set_template method.

  3. Create at least a handler class instance (see FileHandler for a file handler).

  4. Set the handler options (see FileHandler.set_filename for the file handler).

  5. Add the created handler to the report with the Report.add_handler method.

A report mainly consist in four parts: a header, a table of contents, a list of sections and a tail. The header and the tail may have some optional variables which has set with the Report.set_attributes method. The table of contents is automatically generated from the list of sections. Theses are added to the report with the Report.add_section method.

Then, the report is ready to be published by calling the Report.publish which is going to use the registered handlers.

Examples
content_attributes = {
    "name": "Dummy Product",
    "editor": "Dummy Company, SA",
    "description": "Dummy product is a amazing tool to do nothing",
    "version": "0.1.0+dummy",
    "url": "http://dummy.exemple.com/installer.exe",
    "installer": "./store/installer_0.1.0+dummy.exe",
    "release_note": "http://dummy.exemple.com/release_note.html",
    "published": "2016-02-18",
    "file_size": 12345689
}

a_report = report.Report()
a_report.set_template()
a_report.set_attributes(report_attributes)

a_handler = report.FileHandler()
a_handler.set_filename("report.html")
a_report.add_handler(a_handler)

a_report.add_section(content_attributes)
a_report.publish()

Using the module with a configuration file

The creation step may be described in a configuration file (see Example of configuration file for an example) which is going to load by the Report.load_config method.

a_report = report.Report()
filename = os.path.join(os.path.dirname(__file__), "report.example.ini")
a_report.load_config(_load_config(filename), False)
a_report.set_attributes(report_attributes)
a_report.add_section(content_attributes)
a_report.publish()

Objects reference

This section details the objects defined in this module.

class support.report.Report

Bases: object

Make and publish report with the registered handlers.

The report is based on a template using named keyword argument and composed of named sections. The module use the HTML Default template by default. The use of the named keyword argument is based on the Format String Syntax of the string module.

Each section starts with a HTML comment and it ends with the start of next section or with the end of the file. The comment must have the following format and must be on one line:

<!-- $lau:<name>$ -->

where name MUST comprise only ASCII alphanumerics and hyphen [0-9A-Za-z-] and MUST NOT be empty.

If a named section is not declared in Report.names, its contents is added to the current section (i.e. no section is created).

names

The well-known named sections in a report template.

Type

list

Configuration

Example of configuration file details the configuration options the Report.

Public Methods

This class has a number of public methods listed below in alphabetical order.

add_handler

publish

add_section

set_attributes

load_config

set_template

Using Report…

The section “Using the module” provides a simple use case of the class.

_clear_template()

Clear the template.

_load_default()

Configure the report module with its default value.

_parse_template(template)

Parse the template to extract the report sections.

Parameters

template (str) – The full path name of the template file.

add_handler(handler)

Add a handler to publish the report.

Parameters

handler (BaseHandler) – The handler to add, It’s a class instance derived from the BaseHandler base class.

add_section(attributes)

Add a section to the report.

Parameters

attributes (dict) – The product attributes (typically the one returned by the cots.core.BaseProduct.dump method).

load_config(config, append=True)

Configure the report module from a dictionary.

Parameters
  • config (dict) – The configuration as described in the report.example.ini.

  • append (bool) – (optional) False to indicate if the configuration specified by the config parameter will overwrite the current configuration. True to indicate if the configuration specified by the config parameter will append to the current configuration.

publish()

Publish the report with the registered handler

set_attributes(attributes=None)

Set the attributes of the report.

Theses attributes are used in the header and tail sections of the report (see Title, BodyStart, BodyEnd, Tail sections in the template)

Parameters

attributes (dict) – The attributes.

set_template(template='/home/docs/checkouts/readthedocs.org/user_builds/lapptrack/checkouts/develop/lapptrack/support/report_template.html', separator='')

Set the report template.

Parameters
  • template (str) – (optional) is the full path name of the template file. The format of the template file is described in the Report class introduction. The HTML Default template is used by default.

  • separator (str) – (optional) The separator added at the end of each added section in the report.

class support.report.BaseHandler

Bases: object

Base class for all publishing handlers.

Public Methods

This class has a number of public methods listed below in alphabetical order.

load_config

publish

Methods to Override

This class is a abstract class, so all the methods must be overridden. They are listed below in alphabetical order.

_load_default

load_config

publish

Using BaseHandler…

This class is the abstract class for publishing handler used by Report and this one only use the public methods.

_load_default()

Configure the handler with its default value.

load_config(config)

Configure the handler from a dictionary.

Parameters

config (dict) – The configuration as described in the report.example.ini.

publish(report, subtype, charset=None)

Publish the report

Parameters
  • report (str) – The report.

  • subtype (str) – The subtype of the content report as defined by the IANA.

  • charset (str) – The charset used in the report. If a “charset” parameter is specified in the report, this parameter should not used according to the RFC 6838.

class support.report.MailHandler

Bases: support.report.BaseHandler

Mail publishing handler.

This concrete class implements the publishing mechanism by sending the report by mail. So most of information are in the BaseHandler class documentation. The information below focuses on the added value of this class.

Public Methods

This class has a number of public methods listed below in alphabetical order.

load_config

set_sent_mail_folder

publish

set_pending_mail_folder

set_credentials

set_subject

set_from_address

set_to_addresses

set_host

Overridden Methods

This class is a concrete class, so the overridden methods are listed below in alphabetical order.

_load_default

load_config

publish

Using MailHandler…

The “Using the module” section provides a simple use case of a publishing handler concrete class (a file handler in the example). The handler classes differ by the options to set.

For this handler, only the mail host and the mail recipient must be set with the set_host and set_to_addresses methods as shown in the following example. All other options have default values.

Examples
a_handler = report.MailHandler()
a_handler.set_host("smtp.example.com")
a_handler.set_to_addresses("sysadmin@example.com")

The above steps, except the first one, may be described in a dictionary which is going to load by the MailHandler.load_config method. The Report.load_config method use this one to set options for each declared handler (see “Configuration file” section).

_load_default()

Configure the handler with its default value.

For the mail handler, there is no default value

_subject2filename()

Convert a mail subject in a file name.

The method replace special characters in string using the %xx escape using the urllib.parse.quote function.

The method use only the first 20 characters of the subject to avoid long file name. The file name has a suffix based on current date time to guarantee to have a unique value.

Returns

unique string for the filename.

Return type

str

load_config(config)

Configure the handler from a dictionary.

Parameters

config (dict) – The configuration as described in the report.example.ini.

publish(report, subtype, charset=None)

Publish the report

Parameters
  • report (str) – The report.

  • subtype (str) – The subtype of the content report as defined by the IANA.

  • charset (str) – The charset used in the report. If a “charset” parameter is specified in the report, this parameter should not used according to the RFC 6838.

set_credentials(credentials)

Set the recipients mail addresses.

Parameters

credentials (list) – The username and the password to connect to the SMTP server.

set_from_address(address='')

Set the sender mail address.

Parameters

address (str) – (optional) The mail addresses of the sender. If not specified, the address is set to the local hostname. (see smtplib.SMTP)

set_host(hostname, port_number=25)

Set the SMTP host.

Parameters
  • hostname (str) – The full qualified name of the SMTP server host.

  • port_number (int) – (optional): The port number to use. By default, the standard SMTP port number is used.

set_pending_mail_folder(path='')

Set the pending mail special folder.

Parameters

path (str) – (optional) The full path name of the folder where a copy of the mail will be written until it is sent. It avoid to lost mail if the mail server configuration is erroneous or if the mail server doesn’t answer. An empty string does nothing.

set_sent_mail_folder(path)

Set the mail sent special folder.

Parameters

path (str) – The full path name of the folder where a copy of the mail will be written. If the folder doesn’t exit, it will be create. An empty string does nothing.

set_subject(subject='')

Set the subject mail.

Parameters

subject (str) – The subject mail. An empty string does nothing.

set_to_addresses(addresses)

Set the recipients mail addresses.

Parameters

addresses (str or list) – The mail addresses of the recipient. An empty item of the list, an empty list or an empty string (or only composed of space) raised a ValueError exception.

class support.report.FileHandler

Bases: support.report.BaseHandler

File publishing handler.

This concrete class implements the publishing mechanism by writing the report in a regular file. So most of information are in the BaseHandler class documentation. The information below focuses on the added value of this class.

Public Methods

This class has a number of public methods listed below in alphabetical order.

load_config

set_filename

publish

set_mode

Overridden Methods

This class is a concrete class, so the overridden methods are listed below in alphabetical order.

_load_default

load_config

publish

Using MailHandler…

The “Using the module” section provides a simple use case of a publishing handler concrete class (precisely a file handler in the example). The handler classes differ by the options to set.

For this handler, only filename must be set with the set_filename as shown in the following example. All other options have default values.

With the default settings, the file is open in overwriting mode (i.e (“w” open mode). The set_mode sets the opening mode of the file (practically the “w” or “a” mode, the others mode aren’t useful in this context).

Examples
a_handler = report.FileHandler()
a_handler.set_filename("report.html")

The above steps, except the first one, may be described in a dictionary which is going to load by the FileHandler.load_config method. The Report.load_config method use this one to set options for each declared handler (see “Configuration file” section).

_load_default()

Configure the handler with its default value.

For the file handler, there is no default value

load_config(config)

Configure the handler from a dictionary.

Parameters

config (dict) – The configuration as described in report.ini.

publish(report, subtype, charset=None)

Publish the report

Parameters
  • report (str) – The report.

  • subtype (str) – The subtype of the content report as defined by the IANA.

  • charset (str) – The charset used in the report. If a “charset” parameter is specified in the report, this parameter should not used according to the RFC 6838.

set_filename(filename)

Set the full path name of the destination file.

Parameters

filename (str) – The full path name of the destination file.

set_mode(mode='w')

Set the mode in which the file is opened.

Parameters

mode (str) – The mode in which the file is opened.(see open)

class support.report.StreamHandler

Bases: support.report.BaseHandler

Stream publishing handler.

This concrete class implements the publishing mechanism by writing the report in a stream. So most of information are in the BaseHandler class documentation. The information below focuses on the added value of this class.

Public Methods

This class has a number of public methods listed below in alphabetical order.

load_config

set_stream

publish

Overridden Methods

This class is a concrete class, so the overridden methods are listed below in alphabetical order.

_load_default

load_config

publish

Using MailHandler…

The “Using the module” section provides a simple use case of a publishing handler concrete class (a file handler in the example). The handler classes differ by the options to set.

For this handler, there is no mandatory option to set, the only option is the stream, and its default value is the standard output (see sys.stdout).

Examples
a_handler = report.StreamHandler()

The above steps, except the first one, may be described in a dictionary which is going to load by the StreamHandler.load_config method. The Report.load_config method use this one to set options for each declared handler (see “Configuration file” section).

_load_default()

Configure the handler with its default value.

For the file handler, there is no default value

load_config(config)

Configure the handler from a dictionary.

Parameters

config (dict) – The configuration as described in the report.example.ini.

publish(report, subtype, charset=None)

Publish the report

Parameters
  • report (str) – The report.

  • subtype (str) – The subtype of the content report as defined by the IANA.

  • charset (str) – The charset used in the report. If a “charset” parameter is specified in the report, this parameter should not used according to the RFC 6838.

set_stream(stream=<_io.TextIOWrapper name='<stdout>' mode='w' encoding='UTF-8'>)

Set the stream in which the report will be written.

Parameters

stream (io.TextIOWrapper) – The standard stream on which report will be written. If it is not present, sys.stdout is going to be used.

Configuration file

Example of configuration file
# -----------------------------------------------------------------------------
# This ini file contains the configuration details of the report module.
# Only one report and its ways of publication have to define in this file. If
# you need of several report, you must define several configurations file and
# call `Report.load_config()` method for each of them.
# -----------------------------------------------------------------------------
#
# Core section contains configuration items for the report processor.
# handlers (mandatory): is the list of handlers to publish the report. Each
# handler has to have a corresponding section for its own configuration.
# template (optional): is the full path name of the template file. The Report
# class introduction described the format of the template file. The default
# value is 'summary_tmpl.html'.
[core]
handlers = mailhandler,filehandler
;template = summary_tmpl.html

# Attributes section contains named keyword used in the template report (see
# `template` item in the above section. Theses attributes are used in the header
# and tail sections of the report (see `Title`, `BodyStart`, `BodyEnd`, `Tail`
# sections in the template). The 'summary_tmpl.html' doesn't use any additional
# attribute, so this section is empty if you use the default template.
;[attributes]
;about = "Short text to summarize the report content"

# Handlers section contains configuration details for handlers declared in the
# `core`section (see `handlers`item).
# The following sections give an example for each handler supported by the
# `report` module (send a mail, write in a file, write in a stream). Each
# handler section has to define a `class` item.
# Warning: name section must be lowercase, since the section name is a key in
# core section.
#
# Mail handler.
# class: indicates the handler’s class (as determined in the report module).
# By default, the name of the section is used as the class name.
# host (mandatory): is a string containing the full qualified name of the SMTP
# server host, or a 2-tuple containing the full qualified name of the SMTP
# server and the port number to use.
# credentials (optional): is a 2-tuple containing the username and the password
# to connect to the SMTP server.
# from_address(optional): is a string containing the mail addresses of the
# sender. If not specified, the address is set to the local hostname. (see
# smtplib.SMTP())
# mail_sent (optional): is the full path name of the folder where a copy of the
# mail will be written. An empty string does nothing.
# pending_mail (optional): is the full path name of the folder where a copy of
# the mail will be written until it is sent. It avoid to lost mail if the mail
# server configuration is erroneous or if the mail server doesn't answer. An
# empty string does nothing.
# to_addresses (mandatory): is a string or a list containing the mail addresses
# of the recipient.
# subject (optional): is a string containing the mail subject. An empty string
# does nothing.
[mailhandler]
class = MailHandler
host = smtp.example.com
;host = smtp.example.com, 25
;credentials= username, password
;from_address = lappupdate@example.com
;mail_sent = ./mailstore/sent
;pending_mail = ./mailstore/pending
to_addresses = sysadmin@example.com
;to_addresses = sysadmin@example.com, helpdesk@example.com
;subject = lAppUpdate: New Update(s) Alert

# File handler.
# class: indicates the handler’s class (as determined in the report module).
# By default, the name of the section is used as the class name.
# filename (mandatory): is a string containing the full path name of the
# destination file.
# mode (optional): is a string specifying the mode in which the file is opened.
# (see [`open()`](https://docs.python.org/3/library/functions.html#open)
[filehandler]
class = FileHandler
filename = ./tempstore/report.html
;mode = w

# Stream handler.
# class: indicates the handler’s class (as determined in the report module).
# By default, the name of the section is used as the class name.
# stream (optional): is a string specifying the [standard stream](https://docs.
# python.org/3/library/sys.html#sys.stdout) on which report will be written. By 
# default, sys.stdout will be used.
[streamhandler]
class = StreamHandler
;stream = sys.stderr

Report Templates

HTML Default template
<html lang=en-GB>
<!-- $lau:HeaderStart$ -->
<head>
    <meta http-equiv=Content-Type content="text/html; charset=UTF-8">
    <style>
        <!--
        /* Font Definitions */
        @font-face
            {font-family:Wingdings;
            panose-1:5 0 0 0 0 0 0 0 0 0;}
        @font-face
            {font-family:Wingdings;
            panose-1:5 0 0 0 0 0 0 0 0 0;}
        @font-face
            {font-family:Calibri;
            panose-1:2 15 5 2 2 2 4 3 2 4;}
         /* Style Definitions */
        p.body, li.body, div.body
            {margin-top:10.0pt;
            margin-right:0cm;
            margin-bottom:10.0pt;
            margin-left:0cm;
            line-height:115%;
            font-size:11.0pt;
            font-family:"Calibri","sans-serif";}
        h1
            {margin-top:10.0pt;
            margin-right:0cm;
            margin-bottom:0cm;
            margin-left:0cm;
            margin-bottom:.0001pt;
            line-height:115%;
            background:#4F81BD;
            border:none;
            padding:0cm;
            font-size:12.0pt;
            font-family:"Calibri","sans-serif";
            color:white;
            text-transform:uppercase;
            letter-spacing:.75pt;
            font-weight:bold;}
        h2
            {margin-top:10.0pt;
            margin-right:0cm;
            margin-bottom:0cm;
            margin-left:0cm;
            margin-bottom:.0001pt;
            line-height:115%;
            background:#DBE5F1;
            border:none;
            padding:0cm;
            font-size:10.0pt;
            font-family:"Calibri","sans-serif";
            text-transform:uppercase;
            letter-spacing:.75pt;
            font-weight:normal;}
        a:link, span.link
            {color:blue;
            text-decoration:underline;}
        a:visited, span.visited
            {color:purple;
            text-decoration:underline;}
        em
            {color:#243F60;
            text-transform:uppercase;
            letter-spacing:.25pt;
            font-style:normal;}
        p
            {margin-right:0cm;
            margin-left:0cm;
            font-size:12.0pt;
            font-family:"Times New Roman","serif";}
        p.list_body, li.list_body, div.list_body
            {margin-top:3.0pt;
            margin-right:0cm;
            margin-bottom:3.0pt;
            margin-left:0cm;
            line-height:100%;
            font-size:11.0pt;
            font-family:"Calibri","sans-serif";}
        @page WordSection1
            {size:595.3pt 841.9pt;
            margin:70.85pt 70.85pt 70.85pt 70.85pt;}
        div.WordSection1
            {page:WordSection1;}
        /* List Definitions */
        ol
            {margin-bottom:0cm;}
        ul
            {margin-bottom:0cm;}
        -->
    </style>
<!-- $lau:Title$ -->
    <!-- reserved for <title></title> tag in a HTML document published on a web server -->
<!-- $lau:HeaderEnd$ -->
</head>
<!-- $lau:BodyStart$ -->
<body link=blue vlink=purple>
<div class=WordSection1>
    <p class=body>On {date}, the following products have available updates.</p>
<!-- $lau:TOCStart$ -->
    <ul>
<!-- $lau:TOCEntry$ -->
        <li class=list_body><a href="#{id}">{name} ({version})</a></li>
<!-- $lau:TOCEnd$ -->
    </ul>
    <p class=body></p>
<!-- $lau:SummaryStart$ -->
<!-- $lau:SummaryEntry$ -->
    <div style='border:solid #4F81BD 3.0pt;padding:0cm 0cm 0cm 0cm;background:#4F81BD'>
        <h1 style='margin-top:0cm;line-height:normal;background:#4F81BD'>
            <a name="{id}">{name}</a></h1>
    </div>
    <p class=body>
        <a href="{location}">{name} ({version})</a> has been released on {published}. It will be
        fetched on the next step.
    </p>
    <p class=body>
        file size: {file_size}<br>
        hash: {secure_hash}
    </p>
    <div style='border:solid #DBE5F1 3.0pt;padding:0cm 0cm 0cm 0cm;background:#DBE5F1'>
        <h2 style='margin-top:0cm;line-height:normal;background:#DBE5F1'>
            Release note
        </h2>
    </div>
    <p class=body>See the <a href="{release_note}">detailed change history</a>.</p>
    <div style='border:solid #DBE5F1 3.0pt;padding:0cm 0cm 0cm 0cm;background:#DBE5F1'>
        <h2 style='margin-top:0cm;line-height:normal;background:#DBE5F1'>
            Product information
        </h2>
    </div>
    <p class=body style='margin-bottom:0cm;margin-bottom:.0001pt;line-height:normal'>
        Published by {editor}, {description}
    </p>
    <p class=body style='margin-bottom:0cm;margin-bottom:.0001pt;line-height:normal'>
    </p>
<!-- $lau:SummaryEnd$ -->
<!-- $lau:BodyEnd$ -->
</div>
</body>
<!-- $lau:Tail$ -->
</html>
Example of a text template
<!-- $lau:BodyStart$ -->
On {date}, products below have available updates.
--------------------------------------------------------------------------------
<!-- $lau:SummaryStart$ -->
<!-- $lau:SummaryEntry$ -->
{name} {version} released on {published}
================================================================================
location: {location}
installer: {installer}
file size: {file_size}

Release note since ...
------------------------
See the detailed change history at {release_note}

{release_note}

Product information
------------------------
Published by {editor}, {description}
<!-- $lau:SummaryEnd$ -->
<!-- $lau:BodyEnd$ -->