Source code for paramcomparison.writers

# Copyright (c) 2015 Hong Xu <hong@topbug.net>

# This file is part of ParamComparison.

# ParamComparison is free software: you can redistribute it and/or modify it under the terms of the
# GNU Lesser General Public License as published by the Free Software Foundation, either version 3
# of the License, or (at your option) any later version.

# ParamComparison 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 Lesser General Public License for more details.

# You should have received a copy of the GNU Lesser General Public License along with
# ParamComparison. If not, see <http://www.gnu.org/licenses/>.

from __future__ import print_function

import abc
import six

@six.add_metaclass(abc.ABCMeta)
[docs]class Writer(object): """ The base class for all writers, which define how to write output in specific formats. """ @abc.abstractmethod
[docs] def get_file_name(self, name): """ :type name: str :param name: Comparison parameter name. :return: The file name given the comparison parameter name :rtype: str """ raise NotImplementedError
@abc.abstractmethod
[docs] def write_title(self, comparison_param): """ :type comparison_param: str :param comparison_param: Comparison parameter name. :return: The file title given the comparison parameter name :rtype: str """ raise NotImplementedError
@abc.abstractmethod
[docs] def write_table(self, names, params, row_idx, row_values, col_idx, col_values, values): """ :type names: sequence of strings :param names: A sequence of names of fields. :type params: sequence of strings :param params: A sequence of parameters corresponding to the variable name in the same position of names. :type row_idx: int :param row_idx: The index of the row field. :type row_values: sequence of strings :param row_values: A sequence of all possible values of the row fields. :type col_idx: int :param col_idx: The index of the column field. :type col_values: sequence of strings :param col_values: A sequence of all possible values of the column fields. :type values: dict: (str, str) -> str :param values: A dictionary whose key is an element of the Cartesion product of row_values and col_values, and value is the corresponding result in the table entry. :return: The table string :rtype: str """ raise NotImplementedError
@abc.abstractmethod
[docs] def write_separator(self): """ :return: The separator between two sets of tables. :rtype: str """ raise NotImplementedError
import os try: from StringIO import StringIO # python 2 except: from io import StringIO
[docs]class RstWriter(Writer): """ A class to write RST output. """ def __init__(self, indent_size = 4): """ :type indent_size: int :param indent_size: The size of indent used in the rst output. Must be greater than 0. """ self.indent_size = indent_size
[docs] def get_file_name(self, name): """ See :func:`Writer.get_file_name`. """ return '{}.rst'.format(name)
[docs] def write_title(self, comparison_param): """ See :func:`Writer.write_title`. """ return comparison_param + os.linesep + '=' * len(comparison_param) + os.linesep
[docs] def write_table(self, names, params, row_idx, row_values, col_idx, col_values, values): """ See :func:`Writer.write_table`. """ table = StringIO(os.linesep) # table title print ('.. table::', file = table, end = '') if len(names) > 2: print (' ', file = table, end = '') # need an extra space table_title_list = [] for i in range(len(names)): if i == row_idx or i == col_idx: continue if i == len(names) - 1: sep = '' table_title_list.append('{} = {}'.format(names[i], params[i])) table_title_list.sort() print(', '.join(table_title_list), file = table) else: print('', file = table) print('', file = table) # The first cell shows what are the rows and what are the cols first_cell_line_1 = 'Row: ' + names[row_idx] first_cell_line_2 = 'Col: ' + names[col_idx] # max widths of each column max_widths = [0 for i in range(len(col_values) + 1)] # max heights of each row max_heights = [0 for i in range(len(row_values) + 1)] # get the max width and column max_widths[0] = max(map(len, row_values)) # TODO: incorrect if '\t' is contained max_widths[0] = max(max_widths[0], len(first_cell_line_1), len(first_cell_line_2)) max_heights[0] = max(map(lambda x : x.count('\n'), col_values)) if max_heights[0] < 2: # first cell has 2 lines max_heights[0] = 2 for i in range(1, len(col_values) + 1): max_widths[i] = max(map(len, [values[(j, col_values[i - 1])] for j in row_values])) max_widths[i] = max(max_widths[i], len(col_values[i - 1])) for i in range(1, len(row_values) + 1): max_heights[i] = max(map(lambda x : x.count('\n'), [values[(row_values[i - 1], j)] for j in col_values])) # start writing the table for i in range(len(row_values) + 1): print(' ' * self.indent_size + '+', file = table, end = '') for j in max_widths: print('-' * j, file = table, end = '+') print('', file = table) print(' ' * self.indent_size + '|', file = table, end = '') if i == 0: # first row is different: only column titles print(first_cell_line_1, file = table, end = '') print(' ' * (max_widths[0] - len(first_cell_line_1)), file = table, end = '|') for j in range(len(col_values)): print(col_values[j], file = table, end = '') # fill in the rest of space with whitespaces print(' ' * (max_widths[j + 1] - len(col_values[j])), file = table, end = '|') print('', file = table) # line 2 print(' ' * self.indent_size + '|', file = table, end = '') print(first_cell_line_2, file = table, end = '') print(' ' * (max_widths[0] - len(first_cell_line_2)), file = table, end = '|') for j in range(1, len(max_widths)): # line 2 only has spaces print(' ' * max_widths[j], file = table, end = '|') print('', file = table) continue # the rest of the row should print row names first print(row_values[i - 1], file = table, end = '') # fill in the rest of space with whitespaces print(' ' * (max_widths[0] - len(row_values[i - 1])), file = table, end = '|') for j in range(len(col_values)): v = values[(row_values[i - 1], col_values[j])] print(v, file = table, end = '') # fill in the rest of space with whitespaces print(' ' * (max_widths[j + 1] - len(v)), file = table, end = '|') print('', file = table) print(' ' * self.indent_size + '+', file = table, end = '') for j in max_widths: print('-' * j, file = table, end = '+') print('', file = table) print('', file = table) ret = table.getvalue() table.close() return ret
[docs] def write_separator(self): """ See :func:`Writer.write_separator`. """ return os.linesep + '----' + os.linesep + os.linesep