Alexandre
Alexandre

Reputation: 641

Manage exceptions handling

I have class named ExcelFile, his job is to manage excel files (read, extract data, and differents things for the stack).

I want to implement a system for managing errors/exceptions.

For example, ExcelFile as a method load(), like a "setup"

def load(self):
        """
            Setup for excel file
            Load workbook, worksheet and others characteristics (data lines, header...)
            :return: Setup successfully or not
            :rtype: bool

            Current usage
            :Example:

            > excefile = ExcelFile('test.xls')
            > excefile.load()
                True
            > excefile.nb_rows()
                4
        """
        self.workbook = xlrd.open_workbook(self.url)
        self.sheet = self.workbook.sheet_by_index(0)
        self.header_row_index = self.get_header_row_index()

        if self.header_row_index == None:  # If file doesn't have header (or not valid)
            return False

        self.header_fields = self.sheet.row_values(self.header_row_index)
        self.header_fields_col_ids = self.get_col_ids(self.header_fields)  # Mapping between header fields and col ids
        self.nb_rows = self.count_rows()
        self.row_start_data = self.header_row_index + self.HEADER_ROWS
        return True

As you can see, I can encounter 2 differents errors:

  1. The file is not an excel file (raise xlrd.XLRDError)
  2. The file has an invalid header (so I return False)

I want to implement a good management system of ExcelFile errors, because this class is used a lot in the stack.

This is my first idea for processing that :

Implement a standard exception

class ExcelFileException(Exception):

    def __init__(self, message, type=None):
        self.message = message
        self.type = type

    def __str__(self):
        return "{} : {} ({})".format(self.__class__.__name__, self.message, self.type)

Rewrite load method

def load(self):
    """
        Setup for excel file
        Load workbook, worksheet and others characteristics (data lines, header...)
        :return: Setup successfully or not
        :rtype: bool

        Current usage
        :Example:

        > excefile = ExcelFile('test.xls')
        > excefile.load()
            True
        > excefile.nb_rows()
            4
    """
    try:
        self.workbook = xlrd.open_workbook(self.url)
    except xlrd.XLRDError as e:
        raise ExcelFileException("Unsupported file type", e.__class__.__name__)

    self.sheet = self.workbook.sheet_by_index(0)
    self.header_row_index = self.get_header_row_index()

    if self.header_row_index == None:  # If file doesn't have header (or not valid)
        raise ExcelFileException("Invalid or empty header")

    self.header_fields = self.sheet.row_values(self.header_row_index)
    self.header_fields_col_ids = self.get_col_ids(self.header_fields)  # Mapping between header fields and col ids
    self.nb_rows = self.count_rows()
    self.row_start_data = self.header_row_index + self.HEADER_ROWS
    return True

And this an example in a calling method, a big problem is I have to manage a dict named "report" with errors in french, for customers success and other.

    ...
def foo():
    ...
    file = ExcelFile(location)

    try:
        file.load()
    except ExcelFileException as e:
        log.warn(e.__str__())
        if e.type == 'XLRDError'
            self.report['errors'] = 'Long description of the error, in french (error is about invalid file type)'
        else:
            self.report['errors'] = 'Long description of the error, in french (error is about invalid header)'
...

What do you think about that ? Do you have a better way ? Thank you

Upvotes: 0

Views: 90

Answers (2)

Arduino_Sentinel
Arduino_Sentinel

Reputation: 819

Also the error can be fixed by installing missing a optional dependence Xlrd

pip install Xlrd

More available python packages when working with excel

Upvotes: 1

User2342342351
User2342342351

Reputation: 2174

You could change your exception to log the errors in your dict:

class ExcelFileException(Exception):

    def __init__(self, message, report, type=None):
        report['errors'].append(message)
        self.message = message
        self.type = type

    def __str__(self):
        return "{} : {} ({})".format(self.__class__.__name__, self.message, self.type)

When you will raise an exception:

raise ExcelFileException("Invalid or empty header", report)

The errors will be present in self.dictionnary['errors']

Upvotes: 1

Related Questions