Producing ordinal numbers
def ordinal(self, num):
    """
      Returns ordinal number string from int, e.g. 1, 2, 3 becomes 1st, 2nd, 3rd, etc.
    """


Its suspicious that this seems to be a method rather than a free standing function. 

    self.num = num


Why are you storing the input here? Given the purpose of this function that seems odd.

    n = int(self.num)


Its doubtful that this is a good idea. What are you converting from? Converting to int should be really be done closer to whether this number came from.

    if 4 &lt;= n &lt;= 20:


You've made this case larger than necessary, many of those would be correct even with out this test, and its not clear what so special about the range 4-20.

      suffix = 'th'
    elif n == 1 or (n % 10) == 1:


You don't need the or. If n == 1, then that the second condition will be true anyways.

      suffix = 'st'
    elif n == 2 or (n % 10) == 2:
      suffix = 'nd'
    elif n == 3 or (n % 10) == 3:
      suffix = 'rd'
    elif n &lt; 100:
      suffix = 'th'


What happens if suffix is >= 100? You'll get an error.

    ord_num = str(n) + suffix
    return ord_num


You don't need to split this across two lines.

Here is my version:

# much code can be improved by using a datastructe.
SUFFIXES = {1: 'st', 2: 'nd', 3: 'rd'}
def ordinal(num):
    # I'm checking for 10-20 because those are the digits that
    # don't follow the normal counting scheme. 
    if 10 &lt;= num % 100 &lt;= 20:
        suffix = 'th'
    else:
        # the second parameter is a default.
        suffix = SUFFIXES.get(num % 10, 'th')
    return str(num) + suffix