Skip to content
Snippets Groups Projects
write_excel.py 5.21 KiB
Newer Older
"""
Contains utility class for writing to xlsx
"""

from openpyxl import Workbook, load_workbook
from openpyxl.utils import get_column_letter
from openpyxl.styles import Font
from openpyxl.styles.fills import PatternFill
from openpyxl.chart import PieChart, Reference

class ExcelWriter:
    """
    Utility class which writes `TestEntry` objects to an excel file.
    Creates file if it does not exist.
    """
    PASS_COL = "00FF00"
    FAIL_COL = "FF0000"
    def __init__(self, output_file):
        self.output_file = output_file
        self.work_book = self.get_workbook()
        self.work_sheet = self.work_book.active

    def get_entry_with_id(self, test_id):
        """
        When inserting an entry, it might be a test being re-run. In that case,
        the row containing that test needs to be updated, as opposed to appending
        the entry to the end of the file.
        This method finds that row, returning the row number,
        or -1 in the case where that test is not in the report yet.
        """
        for cell in self.work_sheet["A"]:
            if cell.value is None:
                return -1
            if cell.value == test_id:
                print("MATCH with id {} at row {}".format(test_id, cell.row))
                return cell.row
        return -1

    def get_last_row(self):
        """
        return index of first empty row
        """
        for cell in self.work_sheet["A"]:
            if cell.value is None:
                return cell.row
        return cell.row + 1

    def write_test_entry(self, test_entry):
        """
        Write a test entry to the work_sheet
        """
        existing_entry_row = self.get_entry_with_id(test_entry.test_id)
        last_row = self.get_last_row()
        # Use the above two values to pick a row
        entry_row = existing_entry_row if existing_entry_row != -1 else last_row

        # Pick a cell color based on test outcome
        cell_col = ExcelWriter.PASS_COL if test_entry.result == "PASS" else ExcelWriter.FAIL_COL

        # Test entry as a list
        entry_vals = test_entry.as_list()

        for col, cell_vale in zip(self.work_sheet.iter_cols(min_row=entry_row,
                                                            max_col=len(entry_vals),
                                                            max_row=entry_row), entry_vals):
            for cell in col:
                cell.value = cell_vale
                cell.fill = PatternFill("solid", fgColor=cell_col)# cellCol

    def get_workbook(self):
        """
        Returns workbook at output_file/.
        Creates and initialises it (adds headers) if it doesn't exist yet.
        """
        try:
            work_book = load_workbook(filename=self.output_file)
            return work_book
        except FileNotFoundError:
            work_book = Workbook()
            init_workbook(work_book)
            return work_book
    
    def get_chart_work_sheet(self):
        """
        Returns work sheet where charts will be drawn to.
        Creates if does not exist
        """
        try:
            chart_work_sheet = self.work_book["charts"]
            return chart_work_sheet
        except KeyError:
            return self.work_book.create_sheet("charts")
    
    def write_pie_chart_data(self):
        """
        Writes pie chart data (the charts sheet) required to construct the pie chart later
        """
        chart_work_sheet = self.get_chart_work_sheet()

        # Get data from main work sheet
        last_row = self.get_last_row()
        data = Reference(self.work_sheet, min_col=3, max_col=3, min_row=2, max_row=last_row)

        # Construct pie chart
        pie = PieChart()
        pie.add_data(data, titles_from_data=True)
        #pie.set_categories(labels)
        pie.title = "PASS/FAIL Distribution"

        chart_work_sheet.add_chart(pie, "A1")
    
    def write_pie_chart(self):
        """
        Writes a pie chart showing PASS/FAIL stats.
        Writes the chart to a separate work sheet.
        """
        chart_work_sheet = self.get_chart_work_sheet()

        # Get data from main work sheet
        last_row = self.get_last_row()
        data = Reference(self.work_sheet, min_col=3, max_col=3, min_row=2, max_row=last_row)

        # Construct pie chart
        pie = PieChart()
        pie.add_data(data, titles_from_data=True)
        #pie.set_categories(labels)
        pie.title = "PASS/FAIL Distribution"

        chart_work_sheet.add_chart(pie, "A1")

    def save(self):
        """
        Save workbook to disk.
        """
        self.work_book.save(filename=self.output_file)

def init_workbook(work_book):
    """
    Writes column headers to ws.
    """
    headers = [("Test ID", 10), ("Test name", 80), ("Result", 6), ("Error Message", 100),
               ("NFV API", 25), ("Robot Test File", 25)]
    header_font = Font(bold=True)
    work_sheet = work_book.active
    for col, header in zip(work_sheet.iter_cols(min_row=1, max_col=len(headers),
                                                max_row=1), headers):
        for cell in col:
            header_name = header[0]
            colsize = header[1]
            work_sheet.column_dimensions[get_column_letter(cell.column)].width = colsize
            cell.value = header_name
            cell.font = header_font