Difference between revisions of "CSC111 Lab 9 2018"

From dftwiki3
Jump to: navigation, search
(Challenge #4: Reading the Cat information from a CSV file)
Line 4: Line 4:
 
<bluebox>
 
<bluebox>
 
This lab deals with exceptions and creating classes.   
 
This lab deals with exceptions and creating classes.   
The deadline for this lab is Friday 04/6/18 at 11:55 p.m.
+
The deadline for this lab is <strike>Friday 04/6/18</strike> Sunday 4/8/18, at 11:55 p.m.
 
</bluebox>
 
</bluebox>
 
   
 
   

Revision as of 05:44, 6 April 2018

D. Thiebaut (talk) 09:54, 1 April 2018 (EDT)


This lab deals with exceptions and creating classes. The deadline for this lab is Friday 04/6/18 Sunday 4/8/18, at 11:55 p.m.





Exceptions


Part 1: Preparation


  • Create a new program called lab9_1.py, and copy this code to the new Idle window.


# lab9_1.py
# Your name here

# getInput: returns an integer larger
# than 0.  Expected to be robust
def getInput():
   
   while  True:
      x = eval( input( "Enter an integer greater than 0: " ) )
      if x <= 0:
         print( "Invalid entry.  Try again!" )
      else:   
         return x

def main():
   num = getInput()
   print( "You have entered", num )

main()
  • Test it with numbers such as -3, -10, 0, 5. Verify that the input function works well when you enter numbers.
  • Test your program again, and this time enter expressions such as "as", "if", or "hello" (without the quotes).
  • Make a note of the Error reported by Python:


Lab9Exception1.png


  • Modify your function and add the highlighted code below by hand. This code will catch the ValueError exception.


# getInput: returns an integer larger
# than 0.  Catches Value errors
def getInput():
    
   # repeat forever...
   while  True:

      # try to get an int
      try:
          x = eval( input( "Enter an integer greater than 0: " ) )
      except ValueError:
          # the user must have entered something other than an int
          print( "Invalid entry.  Not an integer.  Try again!" )
          continue

      # No errors caught.  See if the number is negative
      if x <= 0:
         print( "You entered a negative number.  Try again!" )
      else:   
         # finally, we can return x as it is an int that is >0
         return x


  • Run your program and try more different invalid inputs. You can also try just pressing the Return key, indicating that you are not providing anything to the input function. Verify that your program catches all these invalid entries and does not crash.


Review Class Example


  • Below is an example we saw in class, and that is taken from Zelle. It prompts the user for 3 integers, separated by comas, and then it outputs the root of the equation a x^2 + b x + c = 0.


from math import sqrt
def ZelleExample():
    print( "solution to quadratic equation" )
    a, b, c = eval( input( "enter 3 coefficients (a,b,c) " ) )
    disc = sqrt( b*b - 4*a*c )
    root1 = (-b + disc )/ (2*a)
    root2 = (+b + disc )/ (2*a)
    print( "solutions: ", root1, root2 )

ZelleExample()


  • Run this program a few times and first give it numbers that will correspond to valid roots of the equation. For example 2, 3, -4.
  • Now try making the program crash entering values that will make the part in the square root negative: 2, 1, 4.
  • Notice the error you get: ValueError: math domain error.
  • Add a try/except statement to protect the whole block:
def ZelleExample():
    from math import sqrt
    print( "solution to quadratic equation" )
    try:
        a, b, c = eval( input( "enter 3 coefficients (a,b,c) " ) )
        disc = sqrt( b*b - 4*a*c )
        root1 = (-b + disc )/ (2*a)
        root2 = (+b + disc )/ (2*a)
        print( "solutions: ", root1, root2 )
    except ValueError:
        print( "No real roots, negative discriminant" )


ZelleExample()


  • Run your program again with 2, 1, 4 as input and verify that you now catch the ValueError exception.
  • Continue testing your program with different inputs (try fewer than 3 number, forgetting a coma, inputing a string with the number, or providing 0 as the first number.
  • Every time your program crashes, figure out the name of the exception and add it in a new except clause.
  • Your code should looks something like this at some point...


def ZelleExample():
    from math import sqrt
    print( "solution to quadratic equation" )
    try:
        a, b, c = eval( input( "enter 3 coefficients (a,b,c) " ) )
        disc = sqrt( b*b - 4*a*c )
        root1 = (-b + disc )/ (2*a)
        root2 = (+b + disc )/ (2*a)
        print( "solutions: ", root1, root2 )
    except xxx:
        print( "You didn't enter 3 numbers" )
    except xxx:
        print( "Your inputs were not all numbers" )
    except xxx:
        print( "Forgot commas between the numbers?" )
    except xxx:
        print( "No real roots, negative discriminant" )


  • If you really want to be thorough and catch all kinds of exceptions, you could add a final except statement at the end of the list of except lines:


    except:
        print( "Something went wrong" )


  • By not specifying any error in this except clause, you indicate that *ALL* exceptions that do not trigger one of the exceptions above should be caught, and greeted with a "Something went wrong" message.
  • Run your program, and when it prompts you for 3 numbers, type Control-C, which normally would stop a program by making it crash. See what this last except does with Control-C?


Classes and Objects


Cats

Cats.jpg


Below is the program we saw in class, where we create a Cat class, where each cat is defined by a name, a breed, whether it is vaccinated or not, and and age.

# lab9_3.py
# D. Thiebaut
# Program for Week #9
# Define a Cat class, and
# use it to create a collection of
# cats.


class Cat:
    """a class that implements a cat and its
    information.  Name, breed, vaccinated,
    tattooed, and age."""

    def __init__( self, na, brd, vacc, ag ):
        """constructor.  Builds a cat with all its information"""
        self.name       = na
        self.breed      = brd
        self.vaccinated = vacc
        self.age        = ag

    def isVaccinated( self ):
        """returns True if cat is vaccinated, False otherwise"""
        return self.vaccinated

    def getAge( self ):
        """returns cat's age"""
        return self.age

    def getName( self ):
        """returns name of cat"""
        return self.name

    def __str__( self ):
        """default string representation of cat"""
        vacc = "vaccinated"
        if not self.vaccinated:
            vacc = "not vaccinated"
        
        return "{0:20}:==> {1:1}, {2:1}, {3:1} yrs old".format(
            self.name, self.breed, vacc, self.age )
    
def main():
    """ main program.  Creates a list of cats and displays
    groups sharing the same property.
        Minou, 3, vac, stray
        Max, 1, not-vac, Burmese
        Gizmo, 2, vac, Bengal
        Garfield, 4, not-vac, Orange Tabby
    """
    cats = []
    cat = Cat( "Minou", "stray", True, 3 )
    cats.append( cat )
    
    cats.append( Cat( "Max", "Burmese", False, 1 ) )
    cats.append( Cat( "Gizmo", "Bengal", True, 2 ) )
    cats.append( Cat( "Garfield", "Orange Tabby", False, 4 ) )

    # print the list of all the cats
    print( "\nComplete List:" )
    for cat in cats:
        print( cat )

   


main()


  • Recreate this code in a program called Lab9_3.py
  • Run it.
  • Add a loop to your main program that outputs only the cats that are not vaccinated, and only those.
  • Example of what your output should look like:


Complete List:
Minou               :==> stray, vaccinated, 3 yrs old
Max                 :==> Burmese, not vaccinated, 1 yrs old
Gizmo               :==> Bengal, vaccinated, 2 yrs old
Garfield            :==> Orange Tabby, not vaccinated, 4 yrs old

Non-vaccinated cats:
Max                 :==> Burmese, not vaccinated, 1 yrs old
Garfield            :==> Orange Tabby, not vaccinated, 4 yrs old


Note: We will not worry about plural or singular form for "yrs old" in this lab.



Challenge #0: getBreed() method

QuestionMark3.jpg


  • Add a new method to your Cat class that returns the breed of a cat. You may want to call it getBreed(). Add a new loop to your main program, such that it uses the new method on each cat and prints only the stray cats.
  • Example of what your output should look like:


Complete List:
Minou               :==> stray, vaccinated, 3 yrs old
Max                 :==> Burmese, not vaccinated, 1 yrs old
Gizmo               :==> Bengal, vaccinated, 2 yrs old
Garfield            :==> Orange Tabby, not vaccinated, 4 yrs old

Non-vaccinated cats:
Max                 :==> Burmese, not vaccinated, 1 yrs old
Garfield            :==> Orange Tabby, not vaccinated, 4 yrs old

Stray cats:
Minou               :==> stray, vaccinated, 3 yrs old


  • Add another loop to your main function, once more, and make it output the Non-vaccinated cats that are 2 or older.
  • Example of what your output should look like:


Complete List:
Minou               :==> stray, vaccinated, tattooed, 3 yrs old
Max                 :==> Burmese, not vaccinated, tattooed, 1 yrs old
Gizmo               :==> Bengal, vaccinated, tattooed, 2 yrs old
Garfield            :==> Orange Tabby, not vaccinated, not tattooed, 4 yrs old

Non-vaccinated cats:
Max                 :==> Burmese, not vaccinated, tattooed, 1 yrs old
Garfield            :==> Orange Tabby, not vaccinated, not tattooed, 4 yrs old

Stray cats:
Minou               :==> stray, vaccinated, tattooed, 3 yrs old

Non-vaccinated cats 2 or older:
Garfield            :==> Orange Tabby, not vaccinated, not tattooed, 4 yrs old



Challenge #1: Tattooed Cats

QuestionMark5.jpg


  • Assume that we now want to keep track of whether cats are tattooed or not. A tattoo is a good way to mark cats so that they can be easily identified if lost.
  • Add a new boolean field to the class for the tattooed status. True will mean tattooed, False, not tattooed.
  • Modify the constructor so that we can pass the tattooed status along with all the other information
  • Add a method to Cat, called isTattooed(), that will allow us to test if a cat is tattooed or not.
  • Modify your main program so that the tattoo status is included when each cat object is created. You may want to use this new list of cats:
Minou, 3, vaccinated, tattooed, stray
Max, 1, not vaccinated, tattooed, Burmese
Gizmo, 2, vaccinated, tattooed, Bengal
Garfield, 4, not vaccinated, not tattooed, Orange Tabby


  • Modify the __str__() method so that it includes the tattoo information in the returned string.
  • Example of what __str__() will print:


Minou               :==> stray, vaccinated, tattooed, 3 yrs old


  • Run your main program again. It should output the same information as before, but this time the tattoo information will also appear when a cat is listed.
  • Add a new Non-tattooed cat loop to your main program that will output all the cats that are not tattooed.
  • Example of output:


Complete List:
Minou               :==> stray, vaccinated, tattooed, 3 yrs old
Max                 :==> Burmese, not vaccinated, tattooed, 1 yrs old
Gizmo               :==> Bengal, vaccinated, tattooed, 2 yrs old
Garfield            :==> Orange Tabby, not vaccinated, not tattooed, 4 yrs old

Non-vaccinated cats:
Max                 :==> Burmese, not vaccinated, tattooed, 1 yrs old
Garfield            :==> Orange Tabby, not vaccinated, not tattooed, 4 yrs old

Stray cats:
Minou               :==> stray, vaccinated, tattooed, 3 yrs old

Non-vaccinated cats 2 or older:
Garfield            :==> Orange Tabby, not vaccinated, not tattooed, 4 yrs old

Non-tattooed cats:
Garfield            :==> Orange Tabby, not vaccinated, not tattooed, 4 yrs old





Challenge #2: Vaccinated and Tattooed Cats

QuestionMark6.jpg


  • Make the main program display all the cats that are vaccinated and tattooed.
  • Example of output:


omplete List:
Minou               :==> stray, vaccinated, tattooed, 3 yrs old
Max                 :==> Burmese, not vaccinated, tattooed, 1 yrs old
Gizmo               :==> Bengal, vaccinated, tattooed, 2 yrs old
Garfield            :==> Orange Tabby, not vaccinated, not tattooed, 4 yrs old

Non-vaccinated cats:
Max                 :==> Burmese, not vaccinated, tattooed, 1 yrs old
Garfield            :==> Orange Tabby, not vaccinated, not tattooed, 4 yrs old

Stray cats:
Minou               :==> stray, vaccinated, tattooed, 3 yrs old

Non-vaccinated cats 2 or older:
Garfield            :==> Orange Tabby, not vaccinated, not tattooed, 4 yrs old

Non-tattooed cats:
Garfield            :==> Orange Tabby, not vaccinated, not tattooed, 4 yrs old

Vaccinated and tattooed cats:
Minou               :==> stray, vaccinated, tattooed, 3 yrs old
Gizmo               :==> Bengal, vaccinated, tattooed, 2 yrs old




Challenge #3: Reading the Cat information from a CSV file

QuestionMark7.jpg


  • Create a new file with Idle, and copy/paste the following text in it. Call it cats.csv.
Minou, 3, vaccinated, tattooed, stray
Max, 1, not vaccinated, tattooed, Burmese
Gizmo, 2, vaccinated, tattooed, Bengal
Garfield, 4, not vaccinated, not tattooed, Orange Tabby
Silky, 3, vaccinated, tattooed, Siamese
Winston, 1, not vaccinated, not tattooed, stray


  • Now, play with the program below:


# Lab9_4.py
# D. Thiebaut
# Seed for a program that reads cat data from
# a CSV file.


def main():
    # set the name of the csv file containing the list of cats
    fileName = input( "File name? " ) # user enters "cats.csv"

    # open a csv file
    file = open( fileName, "r" )

    # process each line of the file
    for line in file:

        # split the line at the commas
        words = line.strip().split( ", " )
        
        # skip lines that do not have 5 fields
        if len( words ) != 5:
            continue

        # print the fields
        for i in range( len( words ) ):
            print( "words[",i,"]=", words[i].strip(), end=", " )
        
        # if words[2].find( "not" ) != -1:
        #     print( "might want to vaccinate this guy!" )
        print()

main()


  • It reads a file containing several lines where information is separated by commas, and breaks each line into words.
  • It is all you need to make your "cat" program read the cat information from a file, rather than from the same old string.
  • Merge this program (by putting it into a function, for example), with the one you wrote for Challenge #2, and make your program read the cats from a CSV file.
  • This means that your program must
  1. extract each cat from a line of the file,
  2. transform the string "vaccinated" in True, and "not vaccinated" in False (You may want to uncomment the if statement in the program above, and run it to see how to detected vaccination!)
  3. transform the string "tattooed" in True, and "not tattooed" in False (same comment as above),
  4. transform the string containing the age into an int,
  5. and store all this information into a Cat object. All the cats should be added to a list.
  • Verify that your program outputs the correct lists of cats (vaccinated, 2 and older, vaccinated and tattooed, etc.)
  • Example of output:


Complete List:
Minou               :==> stray, vaccinated, tattooed, 3 yrs old
Max                 :==> Burmese, not vaccinated, tattooed, 1 yrs old
Gizmo               :==> Bengal, vaccinated, tattooed, 2 yrs old
Garfield            :==> Orange Tabby, not vaccinated, not tattooed, 4 yrs old
Silky               :==> Siamese, vaccinated, tattooed, 3 yrs old
Winston             :==> stray, not vaccinated, not tattooed, 1 yrs old

Non-vaccinated cats:
Max                 :==> Burmese, not vaccinated, tattooed, 1 yrs old
Garfield            :==> Orange Tabby, not vaccinated, not tattooed, 4 yrs old
Winston             :==> stray, not vaccinated, not tattooed, 1 yrs old

Stray cats:
Minou               :==> stray, vaccinated, tattooed, 3 yrs old
Winston             :==> stray, not vaccinated, not tattooed, 1 yrs old

Non-vaccinated cats 2 or older:
Garfield            :==> Orange Tabby, not vaccinated, not tattooed, 4 yrs old

Non-tattooed cats:
Garfield            :==> Orange Tabby, not vaccinated, not tattooed, 4 yrs old
Winston             :==> stray, not vaccinated, not tattooed, 1 yrs old

Vaccinated and tattooed cats:
Minou               :==> stray, vaccinated, tattooed, 3 yrs old
Gizmo               :==> Bengal, vaccinated, tattooed, 2 yrs old
Silky               :==> Siamese, vaccinated, tattooed, 3 yrs old



Challenge #4: Reading the Cat information from a CSV file

QuestionMark8.jpg


Make your program output the cat information formatted as shown below. This will be the program you'll be submitting to Moodle in the next section.

Example CSV file
Max, 21, vaccinated, not tattooed, stray
Toto, 3, not vaccinated, tattooed, stray
Garfield, 1, not vaccinated, not tattooed, Burmese
Bob, 4, not vaccinated, tattooed, Orange Tabby
Minou, 10, not vaccinated, not tattooed, stray


Program output


Complete List:
Max                 :==> stray, vaccinated, not tattooed, 21 yrs old
Toto                :==> stray, not vaccinated, tattooed, 3 yrs old
Garfield            :==> Burmese, not vaccinated, not tattooed, 1 yrs old
Bob                 :==> Orange Tabby, not vaccinated, tattooed, 4 yrs old
Minou               :==> stray, not vaccinated, not tattooed, 10 yrs old

Non-vaccinated cats:
Toto                :==> stray, not vaccinated, tattooed, 3 yrs old
Garfield            :==> Burmese, not vaccinated, not tattooed, 1 yrs old
Bob                 :==> Orange Tabby, not vaccinated, tattooed, 4 yrs old
Minou               :==> stray, not vaccinated, not tattooed, 10 yrs old

Stray cats:
Max                 :==> stray, vaccinated, not tattooed, 21 yrs old
Toto                :==> stray, not vaccinated, tattooed, 3 yrs old
Minou               :==> stray, not vaccinated, not tattooed, 10 yrs old

Non-vaccinated cats 2 or older:
Toto                :==> stray, not vaccinated, tattooed, 3 yrs old
Bob                 :==> Orange Tabby, not vaccinated, tattooed, 4 yrs old
Minou               :==> stray, not vaccinated, not tattooed, 10 yrs old

Non-tattooed cats:
Max                 :==> stray, vaccinated, not tattooed, 21 yrs old
Garfield            :==> Burmese, not vaccinated, not tattooed, 1 yrs old
Minou               :==> stray, not vaccinated, not tattooed, 10 yrs old

Not vaccinated and tattooed cats:
Toto                :==> stray, not vaccinated, tattooed, 3 yrs old
Bob                 :==> Orange Tabby, not vaccinated, tattooed, 4 yrs old




Moodle Submission


Submit your final lab9_3.py program to Moodle. Your program should prompt the user for the name of a CSV file that will contain a list of cats.

Make sure your program prints a blank line after getting the name of the file from the user! This blank line is used by the autograder to figure out where the output of your program starts.


Example


  • If the file cats2.csv contains the following information:


Max, 1, vaccinated, not tattooed, stray
Black, 3, not vaccinated, tattooed, stray
Gizmo, 2, vaccinated, not tattooed, Bengal
Winston, 2, vaccinated, tattooed, Bengal
Garfield, 3, vaccinated, not tattooed, Burmese
Bob, 4, not vaccinated, tattooed, Orange Tabby
Minou, 1, vaccinated, tattooed, stray
Silky, 3, not vaccinated, tattooed, Siamese


  • Then your program should behave as follows:


File name? cats2.csv

Complete list:
Max                 :==> stray, vaccinated, not tattooed, 1 yrs old
Black               :==> stray, not vaccinated, tattooed, 3 yrs old
etc...







<showafterdate after="20180407 12:00" before="20180601 00:00">

Solution Programs

Part 1


# lab9 programs
# D. Thiebaut

# getInput: returns an integer larger
# than 0.  Expected to be robust
def getInput():
   
   while  True:
      x = int( input( "Enter an integer greater than 0: " ) )
      if x <= 0:
         print( "Invalid entry.  Try again!" )
      else:   
         return x

# betterGetInput: returns an integer larger
# than 0.  Expected to be robust
def betterGetInput():
    
   # repeat forever...
   while  True:

      # try to get an int
      try:
          x = int( input( "Enter an integer greater than 0: " ) )
      except ValueError:
          # the user must have entered something other than an int
          print( "Invalid entry.  Not an integer.  Try again!" )
          continue

      # There was no errors.  See if the number is negative
      if x <= 0:
         print( "You entered a negative number.  Try again!" )
      else:   
         return x

def main1():
   num = betterGetInput()
   print( "You have entered", num )

# =======================================================================

def example1():
    print( "You will need to enter 3 pairs of ints..." )
    while True:
       try:
            x = int( input( "enter a number: " ) )
            y = int( input( "enter another number: " ) )
            print( x, '/', y, '=', x/y )
            break
       except ZeroDivisionError:
            print( "Can't divide by 0!" )
       except ValueError:
            print( "That doesn't look like a number!" )
       except:
            print( "something unexpected happend!" )

def example2( L ):
    print( "\n\nExample 2" )
    sum = 0
    for i in range( len( L ) ):
        try:
            sum +=  L[i]
        except TypeError:
            continue

    print( "sum of items in ", L, "=", sum )


def printUpperFile( fileName ):
    try:
       file = open( fileName, "r" )
    except FileNotFoundError:
       print( "***Error*** File", fileName, "not found!" )
       return

    # if we're here, the file is found and open
    for line in file:
       print( line.upper() )
    file.close()

def createTextFile( fileName ):
   file = open( fileName, "w" )
   file.write( "Welcome\nto\nCSC111\nIntroduction\nto\nComp.\nSci.\n" )
   file.close()

def main2():
    createTextFile( "csc111.txt" )

    example1()

    L = [ 10, 3, 5, 6, 9, 3 ]
    example2( L )
    #example2( [ 10, 3, 5, 6, "NA", 3 ] )

    printUpperFile( "csc111.txt" )
    #printUpperFile( "csc1111.txt" )

main2()


Part 2


# cats1.py
# D. Thiebaut
# Program for Week #9
# Define a Cat class, and
# use it to create a collection of
# cats.


class Cat:
    """a class that implements a cat and its
    information.  Name, breed, vaccinated,
    tattooed, and age."""

    def __init__( self, na, brd, vacc, ag, tat ):
        """constructor.  Builds a cat with all its information"""
        self.name       = na
        self.breed      = brd
        self.vaccinated = vacc
        self.age        = ag
        self.tattooed   = tat

    def isTattooed( self ):
        """returns True if cat is tattooed, False otherwise"""
        return self.tattooed

    def isVaccinated( self ):
        """returns True if cat is vaccinated, False otherwise"""
        return self.vaccinated

    def getAge( self ):
        """returns cat's age"""
        return self.age

    def getName( self ):
        """returns name of cat"""
        return self.name

    def getBreed( self ):
        return self.breed
    
    def __str__( self ):
        """default string representation of cat"""
        vacc = "vaccinated"
        if not self.vaccinated:
            vacc = "not vaccinated"

        tatt = "tattooed"
        if not self.tattooed:
            tatt = "not tattooed"
        
        return "{0:20}:==> {1:1}, {2:1}, {3:1}, {4:1} yrs old".format(
            self.name, self.breed, vacc, tatt, self.age )

def readCatCSV( fileName ):
    """ reads the CSV file and puts all the cats
    in a list of Cat objects"""

    # get the lines from the CSV file
    file = open( fileName, "r" )
    lines = file.readlines()
    file.close()

    # create an empty list of cats
    cats = []
    
    # get one line at a time
    for line in lines:
        # split a line in words
        fields = line.split( ", " )

        # skip lines that do not have 5 fields
        if len( fields ) != 5:
            continue

        # get 5 fields into 5 different variables
        name, age, vac, tat, breed = fields
        breed = breed.strip()
        
        # transform "vaccinated" or "not vaccinated" in True or False
        if vac.lower().find( "not " )==-1:
            vac = True
        else:
            vac = False
            
        # transform "tattooed" or "not tattooed" in True or False
        if tat.lower().find( "not " )==-1:
            tat = True
        else:
            tat = False

        # add a new cat to the list
        cats.append( Cat( name, breed, vac, int(age), tat ) )

    # done with the lines.  Return the cat list
    return cats

def main():
    """ main program.  Creates a list of cats and displays
    groups sharing the same property.
        Minou, 3, vac, stray, tat
        Max, 1, not-vac, Burmese, tat
        Gizmo, 2, vac, Bengal, tat
        Garfield, 4, not-vac, Orange Tabby
    """
    cats = readCatCSV( input( "File name? " ) )
    """
    cat = Cat( "Minou", "stray", True, 3, True)
    cats.append( cat )
    
    cats.append( Cat( "Max", "Burmese", False, 1, True ) )
    cats.append( Cat( "Gizmo", "Bengal", True, 2, True ) )
    cats.append( Cat( "Garfield", "Orange Tabby", False, 4, False ) )
    """
    
    # print the list of all the cats
    print( "\nComplete List:" )
    for cat in cats:
        print( cat )

    print( "\nNon-vaccinated cats:" )
    for cat in cats:
        if cat.isVaccinated()==False:
            print( cat )

    print( "\nStray cats:" )
    for cat in cats:
        if cat.getBreed().lower() == "stray":
            print( cat )

    print( "\nNon-vaccinated cats 2 or older:" )
    for cat in cats:
        if cat.isVaccinated()==False and cat.getAge() >= 2:
            print( cat )

    print( "\nNon-tattooed cats:" )
    for cat in cats:
        if cat.isTattooed()==False:
            print( cat )
            
    print( "\nVaccinated and tattooed cats:" )
    for cat in cats:
        if cat.isVaccinated() and cat.isTattooed():
            print( cat )

def lab9Solution():
    """prompts user for file name, and outputs
    cats that are not vaccinated, and 2 years or older"""
    
    cats = readCatCSV( input( "File name? " ) )
    print()

    for cat in cats:
        if cat.isVaccinated()==False and cat.getAge() >= 2:
            print( cat )
            
#main()
lab9Solution()


</showafterdate>