On Nov 23, 7:22 am, Brendan <brendandetra...@yahoo.com> wrote: > 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: >
It looks like in some cases KBError() should fall through and only 'No Match' was intended to be silently caught. I would consider either leaving it alone if it works, or doing more serious surgery on the code to simplify the control flow. The method is awfully long and nested. > 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) -- http://mail.python.org/mailman/listinfo/python-list