KirbyBase : replacing string exceptions

Brendan brendandetracey at yahoo.com
Mon Nov 23 16:22:25 CET 2009


In KirbyBase there is a method that uses string exceptions for
control, even though it has a defined exception. Is there any reason
the string exceptions below could not be replaced?
i.e. in code below replace:
raise "No Match"
with:
raise KBError()
and
except 'No Match':
with:
except KBError:

I have pasted the relevant method and the class definition of KBError
below

 
#----------------------------------------------------------------------
    # _getMatches
 
#----------------------------------------------------------------------
    def _getMatches(self, fptr, fields, patterns, useRegExp):
        # Initialize a list to hold all records that match the search
        # criteria.
        match_list = []

        # If one of the fields to search on is 'recno', which is the
        # table's primary key, then search just on that field and
return
        # at most one record.
        if 'recno' in fields:
            return self._getMatchByRecno(fptr,patterns)
        # Otherwise, search table, using all search fields and
patterns
        # specified in arguments lists.
        else:
            new_patterns = []
            fieldNrs = [self.field_names.index(x) for x in fields]
            for fieldPos, pattern in zip(fieldNrs, patterns):
                if self.field_types[fieldPos] == str:
                    # If useRegExp is True, compile the pattern to a
                    # regular expression object and add it to the
                    # new_patterns list.  Otherwise,  just add it to
                    # the new_patterns list.  This will be used below
                    # when matching table records against the
patterns.
                    if useRegExp:
                        new_patterns.append(re.compile(pattern))
                        # the pattern can be a tuple with re flags
like re.I
                    else:
                        new_patterns.append(pattern)
                elif self.field_types[fieldPos] == bool:
                    # If type is boolean, I am going to coerce it to
be
                    # either True or False by applying bool to it.
This
                    # is because it could be '' or [].  Next, I am
going
                    # to convert it to the string representation:
either
                    # 'True' or 'False'.  The reason I do this is
because
                    # that is how it is stored in each record of the
table
                    # and it is a lot faster to change this one value
from
                    # boolean to string than to change possibly
thousands
                    # of table values from string to boolean.  And, if
they
                    # both are either 'True' or 'False' I can still
                    # compare them using the equality test and get the
same
                    # result as if they were both booleans.
                    new_patterns.append(str(bool(pattern)))
                else:
                    # If type is int, float, date, or datetime, this
next
                    # bit of code will split the the comparison string
                    # into the string representing the comparison
                    # operator (i.e. ">=" and the actual value we are
going
                    # to compare the table records against from the
input
                    # pattern, (i.e. "5").  So, for example, ">5"
would be
                    # split into ">" and "5".
                    r = re.search('[\s]*[\+-]?\d', pattern)
                    if self.field_types[fieldPos] == int:
                        patternValue = int(pattern[r.start():])
                    elif self.field_types[fieldPos] == float:
                        patternValue = float(pattern[r.start():])
                    else:
                        patternValue = pattern[r.start():]
                    new_patterns.append(
                     [self.cmpFuncs[pattern[:r.start()]],
patternValue]
                    )

            fieldPos_new_patterns = zip(fieldNrs, new_patterns)
            maxfield = max(fieldNrs)+1

            # Record current position in table. Then read first detail
            # record.
            fpos = fptr.tell()
            line = fptr.readline()

            # Loop through entire table.
            while line:
                # Strip off newline character and any trailing spaces.
                line = line[:-1].strip()
                try:
                    # If blank line, skip this record.
                    if line == "": raise 'No Match'
                    # Split the line up into fields.
                    record = line.split("|", maxfield)

                    # Foreach correspond field and pattern, check to
see
                    # if the table record's field matches
successfully.
                    for fieldPos, pattern in fieldPos_new_patterns:
                        # If the field type is string, it
                        # must be an exact match or a regular
expression,
                        # so we will compare the table record's field
to it
                        # using either '==' or the regular expression
                        # engine.  Since it is a string field, we will
need
                        # to run it through the unencodeString
function to
                        # change any special characters back to their
                        # original values.
                        if self.field_types[fieldPos] == str:
                            try:
                                if useRegExp:
                                    if not pattern.search(
                                     self._unencodeString(record
[fieldPos])
                                     ):
                                        raise 'No Match'
                                else:
                                    if record[fieldPos] != pattern:
                                        raise 'No Match'
                            except Exception:
                                raise KBError(
                                 'Invalid match expression for %s'
                                 % self.field_names[fieldPos])
                        # If the field type is boolean, then I will
simply
                        # do an equality comparison.  See comments
above
                        # about why I am actually doing a string
compare
                        # here rather than a boolean compare.
                        elif self.field_types[fieldPos] == bool:
                            if record[fieldPos] != pattern:
                                raise 'No Match'
                        # If it is not a string or a boolean, then it
must
                        # be a number or a date.
                        else:
                            # Convert the table's field value, which
is a
                            # string, back into it's native type so
that
                            # we can do the comparison.
                            if record[fieldPos] == '':
                                tableValue = None
                            elif self.field_types[fieldPos] == int:
                                tableValue = int(record[fieldPos])
                            elif self.field_types[fieldPos] == float:
                                tableValue = float(record[fieldPos])
                            # I don't convert datetime values from
strings
                            # back into their native types because it
is
                            # faster to just leave them as strings
and
                            # convert the comparison value that the
user
                            # supplied into a string.  Comparing the
two
                            # strings works out the same as comparing
two
                            # datetime values anyway.
                            elif self.field_types[fieldPos] in (
                             datetime.date, datetime.datetime):
                                tableValue = record[fieldPos]
                            else:
                                # If it falls through to here, then,
                                # somehow, a bad field type got put
into
                                # the table and we show an error.
                                raise KBError('Invalid field type for
%s'
                                 % self.field_names[fieldPos])
                            # Now we do the actual comparison.  I used
to
                            # just do an eval against the pattern
string
                            # here, but I found that eval's are VERY
slow.
                            # So, now I determine what type of
comparison
                            # they are trying to do and I do it
directly.
                            # This sped up queries by 40%.
                            if not pattern[0](tableValue, pattern[1]):
                                raise 'No Match'
                # If a 'No Match' exception was raised, then go to the
                # next record, otherwise, add it to the list of
matches.
                except 'No Match':
                    pass
                else:
                    match_list.append([line, fpos])
                # Save the file position BEFORE we read the next
record,
                # because after a read it is pointing at the END of
the
                # current record, which, of course, is also the
BEGINNING
                # of the next record.  That's why we have to save the
                # position BEFORE we read the next record.
                fpos = fptr.tell()
                line = fptr.readline()

        # After searching, return the list of matched records.
        return match_list

 
#----------------------------------------------------------------------

#--------------------------------------------------------------------------
# KBError Class
#--------------------------------------------------------------------------
class KBError(Exception):
    """Exception class for Database Management System.

    Public Methods:
        __init__ - Create an instance of exception.
    """
 
#----------------------------------------------------------------------
    # init
 
#----------------------------------------------------------------------
    def __init__(self, value):
        self.value = value

    def __str__(self):
        return `self.value`

    # I overrode repr so I could pass error objects from the server to
the
    # client across the network.
    def __repr__(self):
        format = """KBError("%s")"""
        return format % (self.value)



More information about the Python-list mailing list