Difference between revisions of "CSC111 Lab 9 2015"

From dftwiki3
Jump to: navigation, search
 
(37 intermediate revisions by the same user not shown)
Line 1: Line 1:
 
--[[User:Thiebaut|D. Thiebaut]] ([[User talk:Thiebaut|talk]]) 07:14, 29 March 2015 (EDT)
 
--[[User:Thiebaut|D. Thiebaut]] ([[User talk:Thiebaut|talk]]) 07:14, 29 March 2015 (EDT)
 
----
 
----
 
+
 +
<tanbox>
 +
The submission link for this lab is [http://tinyurl.com/lab9submit http://tinyurl.com/lab9submit].
 +
</tanbox>
 +
 +
<br />
 +
<br />
 +
__TOC__
 +
<br />
 
<!--showafterdate after="20150401 12:00" before="20150601 00:00"-->
 
<!--showafterdate after="20150401 12:00" before="20150601 00:00"-->
 +
<br />
 +
=Pair Programming=
 +
<br />
 +
[[Image:PairProgrammingMuppets.jpg|right|150px]]
 +
For this lab you will be working in pairs.  Find a partner in the class with whom you will work today, and attempt to follow these directions:
 +
# Close 1 computer, and work on only one computer. 
 +
# Only one driver!  One person holds the keyboard, the other person watches and suggests code, corrections, or spots bugs.
 +
# Every so often (20 minutes, maybe?) switch roles.
 +
# Every so often (40 minutes, maybe?) take a break.  Relax.
 +
# When you are done with one section and you have a working program, exchange it with your partner, so that both members of the pair will have a copy of the code that was developed together.
 +
# When you are done with all the problems for the lab, get the submission URL from the lab instructor or from the TA, and '''both members of the pair''' should submit the program. 
 
<br />
 
<br />
 
=Exceptions=
 
=Exceptions=
Line 69: Line 88:
 
<br />
 
<br />
  
==Part 2: Exercise==
+
==Review Class Example==
 
<br />
 
<br />
* Create a new program called lab9_2.py with the code below:
+
* Below is an example we saw in class, and that is taken from Zelle. It illustrates how we can guard some code against several types of errors.  Review it.  You will need to follow this example for the next set of exercises.
 
<br />
 
<br />
 
::<source lang="python">
 
::<source lang="python">
==Code==
+
def ZelleExample():
 +
    import math
 +
    print( "solution to quadratic equation" )
 +
    try:
 +
        a, b, c = eval( input( "enter 3 coefficients (a,b,c) " ) )
 +
        disc = math.sqrt( b*b - 4*a*c )
 +
        root1 = (-b + disc )/ (2*a)
 +
        root2 = (+b + disc )/ (2*a)
 +
        print( "solutions: ", root1, root2 )
 +
    except NameError:
 +
        print( "You didn't enter 3 numbers" )
 +
    except TypeError:
 +
        print( "Your inputs were not all numbers" )
 +
    except SyntaxError:
 +
        print( "Forgot commas between the numbers?" )
 +
    except ValueError:
 +
        print( "No real roots, negative discriminant" )
 +
    except:
 +
        print( "Something went wrong..." )
 +
 
 +
</source>
 
<br />
 
<br />
  
 +
==Part 2: Exercise==
 +
<br />
 +
* Create a new program called lab9_2.py with the code below:
 
<br />
 
<br />
<source lang="python">
+
::<source lang="python">
 
def example1():
 
def example1():
 
     for i in range( 3 ):
 
     for i in range( 3 ):
Line 106: Line 148:
  
 
def main():
 
def main():
 +
    # create a text file for use later...
 +
    createTextFile( "csc111.txt" )
 +
 +
    # test first function
 
     example1()
 
     example1()
 +
 +
    # test second function
 
     L = [ 10, 3, 5, 6, 9, 3 ]
 
     L = [ 10, 3, 5, 6, 9, 3 ]
 
     example2( L )
 
     example2( L )
     example2( [ 10, 3, 5, 6, "NA", 3 ] )
+
     #example2( [ 10, 3, 5, 6, "NA", 3 ] )
    example3( [ 10, 3, 5, 6 ] )
 
  
     printUpperFile( "doesNotExist.txt" )
+
     # test third function
     printUpperFile( "./Dessssktop/misspelled.txt" )
+
    fileName = input( "Enter name of file to display (type csc111.txt): " )
 +
     printUpperFile( fileName )
  
 
main()
 
main()
Line 121: Line 169:
  
  
* The program below is not very robust.  We can easily make it crash.
+
* The program above has many flaws;  it is not very robust.  We can easily make it crash.
* Observe each function and see how to make it fail, or see why it will fail the way it is called
+
* Observe each function.  Run your program a few times.
* Make the program crash.  Register the '''XXXXError''' that is generated.  For example, if the output of the crash looks like this:
+
* Figure out how to make each function crash
<tt><font color="red">
+
* Go ahead and start forcing the first function to crash.  Register the <font color="red">'''XXXXError'''</font> that is generated.  For example, if the output of the crash looks like this:
Traceback (most recent call last):
+
<blockquote><tt><font color="red">
  File "/Users/thiebaut/Desktop/except0.py", line 29, in <module>
+
Traceback (most recent call last):<br />
    main()
+
File "/Users/thiebaut/Desktop/except0.py", line 29, in <module><br />
  File "/Users/thiebaut/Desktop/except0.py", line 27, in main
+
main()<br />
    example3( [ 10, 3, 5, 6 ] )
+
File "/Users/thiebaut/Desktop/except0.py", line 27, in main<br />
  File "/Users/thiebaut/Desktop/except0.py", line 18, in example3
+
example3( [ 10, 3, 5, 6 ] )<br />
    sum = sum + L[i]
+
File "/Users/thiebaut/Desktop/except0.py", line 18, in example3<br />
'''IndexError''': list index out of range
+
sum = sum + L[i]<br />
</font></tt>
+
'''IndexError''': list index out of range<br />
 +
</font></tt></blockquote>
  
 
:what you are interested in is '''IndexError'''.  This is the ''exception'' you want to guard your code against.
 
:what you are interested in is '''IndexError'''.  This is the ''exception'' you want to guard your code against.
 
+
<br />
<code><pre>
+
::<source lang="python">
  
 
   try:
 
   try:
Line 145: Line 194:
 
       .........
 
       .........
  
</pre></code>
+
</source>
* Verify that you have made your functions more robust to erroneous input/data.
 
 
<br />
 
<br />
 +
* Add the try/except statement inside the function, and verify that your function is now more robust and does not crash on the same input that made it crash before.
 +
<br />
 +
* Repeat the same process for the other functions.
 +
<br />
 +
=Classes and Objects=
 +
<br />
 +
==Cats==
 +
[[File:Cats.jpg|150px|right]]
 +
<br />
 +
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'''.
 +
<br />
 +
::<source lang="python">
 +
# 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 ):
==Solution==
+
        """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 )
 +
 
 +
 
 +
 
 +
 
 +
if __name__=="__main__":
 +
    main()
 +
 
 +
</source>
 +
<br />
 +
* Recreate this code in a program called Lab9_2.py
 +
* Run it.
 +
* Add a loop to your main program that outputs only the cats that are '''not vaccinated''', and only those.
 +
<br /><br />
 +
{| style="width:100%; background:silver"
 +
|-
 +
|
 +
==Challenge  #0: getBreed() method==
 +
|}
 +
[[Image:QuestionMark3.jpg|right|120px]]
 +
<br />
 +
*  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.
 +
* Add another loop to your main function, once more, and make it output the '''non-vaccinated cats that are 2 or older'''.
 +
<br /><br />
 +
{| style="width:100%; background:silver"
 +
|-
 +
|
 +
==Challenge  #1: Tattooed Cats==
 +
|}
 +
[[Image:QuestionMark5.jpg|right|120px]]
 +
<br />
 +
* 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 one 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:
 +
::::<source lang="text">
 +
Minou, 3, vaccinated, tattooed, stray
 +
Max, 1, not vaccinated, tattooed, Burmese
 +
Gizmo, 2, vaccinated, tattooed, Bengal
 +
Garfield, 4, not vaccinated, not tattooed, Orange Tabby
 +
</source>
 +
<br />
 +
::* Modify the '''__str__()''' method so that it includes the tattoo information in the returned string.
 +
::* 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 section to your main program that will output all the cats that are '''not tattooed'''.
 +
<br />
 +
<br /><br />
 +
{| style="width:100%; background:silver"
 +
|-
 +
|
 +
==Challenge  #2: Vaccinated and Tattooed Cats==
 +
|}
 +
[[Image:QuestionMark6.jpg|right|120px]]
 +
<br />
 +
* Make the main program display all the cats that are vaccinated '''and''' tattooed.
 +
<br />
 +
<br /><br />
 +
{| style="width:100%; background:silver"
 +
|-
 +
|
 +
==Challenge  #3: Reading the Cat information from a CSV file==
 +
|}
 +
[[Image:QuestionMark7.jpg|right|120px]]
 +
<br />
 +
* Create the short program below and name it '''createCatCSV.py'''.
 +
<br />
 +
::<source lang="python">
 +
# createCatCSV.py
 +
# D. Thiebaut
 +
# save several cat definitions into a CSV file.
 +
 
 +
def createCatCSV( fileName ):
 +
    file = open( fileName, "w" )
 +
    file.write( """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\n""" )
 +
    file.close()
 +
 
 +
 
 +
def main():
 +
    createCatCSV( "cats.csv" )
 +
 
 +
main()
 +
</source>
 +
<br />
 +
* Run the program once.  Verify that it will have created a new file in the same folder/directory where your program resides.  Verify (using Notepad or TextEdit) that it contains a collection of lines, each representing a cat.
 +
<br />
 +
* Now, play with the program below:
 +
<br />
 +
::<source lang="python">
 +
# Lab9CatsCSV.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=", " )
 +
        print()
 +
 
 +
if __name__=="__main__":
 +
    main()
 +
</source>
 +
<br />
 +
* Merge this program and the one you wrote for Challenge #2, and make your program read the cats from a CSV file.  It means your program must
 +
::# extract each cat from a line of the file,
 +
::# transform the string "vaccinated" in True, and "not vaccinated" in False (it's simpler than you think!)
 +
::# transform the string "tattooed" in True, and "not tattooed" in False (same comment),
 +
::# transform the string containing the age into an int,
 +
::# and store all this information into a Cat object.  All the cats should be added to a list. 
 +
 
 +
* Verify that the program outputs the correct lists of cats (vaccinated, 2 and older, vaccinated and tattooed, etc.)
 +
<br />
 +
<!--
 +
==Wheel==
 +
<br />
 +
<tanbox>
 +
[[Image:fileicon-pdf.png | right | 35px|link=http://cs.smith.edu/dftwiki/images/1/17/ZelleGraphicsDescription.pdf]]You may find the following [[media:ZelleGraphicsDescription.pdf|document]] describing the different graphic objects introduce in the Zelle's textbook useful.
 +
</tanbox>
 +
<br />
 +
 
 +
 
 +
 
 +
 
 +
 
 +
 
 +
 
 +
 
 +
===Classes for a wheel and a Car===
 +
 
 +
Below is the code we wrote in class this week:
 +
 
 +
<source lang="python">
 +
# carNew.py
 +
# D. Thiebaut
 +
# first program using a class to define                                                                             
 +
# a new graphic object: a wheel, which                                                               
 +
# is made of 2 concentric circles.  The class
 +
# Wheel supports methods to initialize the
 +
# graphics object, draw it on the window,
 +
# and move it.
 +
 
 +
from graphics import *
 +
W = 400    # width of the graphics window
 +
H = 400    # height of the graphics window
 +
 
 +
#----------------------------------------------------------------
 +
class Wheel:
 +
    """A class with two concentric circles"""
 +
 
 +
    def __init__( self, center, r1, r2 ):
 +
        """constructor"""
 +
        self.radius1 = min( r1, r2 )
 +
        self.radius2 = max( r1, r2 )
 +
        self.circ1 = Circle( center, self.radius1 )
 +
        self.circ2 = Circle( center, self.radius2 )
 +
       
 +
    def draw( self, win ):
 +
        """draws the wheel on the graphics window win"""
 +
        self.circ2.draw( win )
 +
        self.circ1.draw( win )
 +
 
 +
    def move( self, dx, dy ):
 +
        self.circ1.move( dx, dy )
 +
        self.circ2.move( dx, dy )
 +
 
 +
    def setFill( self, color1, color2 ):
 +
        self.circ1.setFill( color1 )
 +
        self.circ2.setFill( color2 )
 +
 
 +
    def getRadius1( self ):
 +
        """returns the smallest radius"""
 +
        return self.radius1
 +
 
 +
    def getRadius2( self ):
 +
        """returns the largest radius"""
 +
        return self.radius2
 +
 
 +
class Car:
 +
    def __init__( self, P1, P2 ):
 +
        self.body = Rectangle( P1, P2 )
 +
        w =abs( P2.getX()-P1.getX() )
 +
        h =abs( P2.getY()-P1.getY() )
 +
        center1 = Point( w/4+P1.getX(), P2.getY() )
 +
        center2 = Point( P2.getX()-w/4, P2.getY() )
 +
        r2      = w/8
 +
        r1      = r2/2
 +
        self.w1 = Wheel( center1, r1, r2 )
 +
        self.w2 = Wheel( center2, r1, r2 )
 +
 
 +
    def setFill( self, bodyc, tirec, insidec ):
 +
        self.body.setFill( bodyc )
 +
        self.w1.setFill( tirec, insidec )
 +
        self.w2.setFill( tirec, insidec )
 +
 
 +
    def draw( self, win ):
 +
        self.body.draw( win )
 +
        self.w1.draw( win )
 +
        self.w2.draw( win )
 +
 
 +
    def move( self, dx, dy):
 +
        self.body.move( dx, dy )
 +
        self.w1.move( dx, dy )
 +
        self.w2.move( dx, dy )
 +
 
 +
#----------------------------------------------------------------
 +
def waitForClick( win, message ):
 +
    """ waitForClick: stops the GUI and displays a message. 
 +
    Returns when the user clicks the window. The message is erased."""
 +
 
 +
    # wait for user to click mouse to start
 +
    startMsg = Text( Point( win.getWidth()/2, win.getHeight()/2 ), message )
 +
    startMsg.draw( win )    # display message
 +
    win.getMouse()          # wait
 +
    startMsg.undraw()      # erase
 +
 
 +
 
 +
def main():
 +
    """demo program for wheel: draws wheel on screen"""
 +
    global W, H
 +
    win = GraphWin( "wheel demo", W, H )
 +
    waitForClick( win, "click to start" )
 +
 
 +
    #--- create new wheel object ---
 +
    #w = Wheel( Point( W/2, H/2 ), 20, 40 )
 +
    #w.setFill( "black", "yellow" )
 +
    #w.draw( win )
 +
 
 +
    #--- create a car object ---
 +
    car = Car( Point( 20, 20 ), Point( 120, 60 ) )
 +
    car.setFill( "red", "yellow", "black" )
 +
    car.draw( win )
 +
    waitForClick( win, "click to move" )
 +
 
 +
 
 +
    #--- move the car ---
 +
    for i in range( 100 ):
 +
        car.move( 3, 0 )
 +
 
 +
    waitForClick( win, "click to end" )
 +
 
 +
main()
 +
 
 +
 
 +
</source>
 +
 
 +
 
 +
* Run the program a few times to make sure you understand how it works.
 +
 
 +
* Assume that the programmer writing the main program (we always assume that the programmer writing the main program is different from the programmer writing the classes, as is most often the case in real life) forgot the rule that when building a car, the first point passed to the constructor is the top left point of the rectangle defining the body, and that the second point is the bottom right point of the body.
 +
 
 +
:Instead the programmer creates the object '''car''' as follows:
 +
 
 +
    car = Car( Point( 120, 60 ), Point( 20, 20 ) )
 +
 
 +
 
 +
:Make this modification and run your program.  What happens?
 +
 
 +
* Fix the '''class''' ''Car'' so that the user can specify any point in any order (top-left, bottom-right), or (top-right, bottom-left), or (bottom-left, top-right), and the constructor will correctly define the body and the wheels to fit the shape defined by the two points.
 +
 
 +
* Oh, by the way, the car is a two-door convertible.  Add a door to the car.  The door should be a simple rectangle in the middle of the body of the car, between the two wheels.  (You may want to sketch the shape of the car on paper and figure out what proportions to use to position the door.)
 +
 
 +
* Add a windshield to the car as well.  You are free to define its shape, and the '''Polygon''' class will provide a nice solution for you.  '''Polygons''' are defined in Section 3.6 of [http://cs.smith.edu/dftwiki/images/1/17/ZelleGraphicsDescription.pdf Zelle's 4-page document on his graphics library].
 +
 
 +
==Random cars going in random directions==
 +
 
 +
* Make your program create a list of 5 cars.
 +
 
 +
* Each car has a random horizontal velocity (dx != 0, dy=0), making it go left, or right.  Make dx and dy part of the class, i.e. make these variables '''member variables''' of the class '''Car'''.
 +
 
 +
* Make your program move all 5 cars at the same time, until all the cars have exited the window.  As soon as the cars all disappear your program will stop.  Think of an efficient way to do this...  This is a bit tricky... (But we are at a time in the semester where you can deal with tricky questions... :-)
 +
 
 +
-->
 +
 
 +
<!-- /showafterdate -->
 +
 
 +
<!-- ============================================================= -->
 +
<!-- ============================================================= -->
 +
<!-- ============================================================= -->
 +
<!-- ============================================================= -->
 +
 
 +
<showafterdate after="20150403 11:00" before="20150601 00:00">
 +
=Solution Programs=
 +
==Part 1 ==
 
<br />
 
<br />
 
<source lang="python">
 
<source lang="python">
 +
# 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():
 
def example1():
 +
    print( "You will need to enter 3 pairs of ints..." )
 
     while True:
 
     while True:
 
       try:
 
       try:
Line 168: Line 631:
 
       except:
 
       except:
 
             print( "something unexpected happend!" )
 
             print( "something unexpected happend!" )
           
+
 
           
 
 
def example2( L ):
 
def example2( L ):
 
     print( "\n\nExample 2" )
 
     print( "\n\nExample 2" )
    print( "L          = ", L )
 
 
     sum = 0
 
     sum = 0
    sumOfPairs = []
 
 
     for i in range( len( L ) ):
 
     for i in range( len( L ) ):
            try:
+
        try:
                sumOfPairs.append( L[i]+L[i+1] )
+
            sum +L[i]
            except IndexError:
+
        except TypeError:
                continue
+
             continue
             except TypeError:
+
 
                continue
+
     print( "sum of items in ", L, "=", sum )
   
+
 
     print( "sumOfPairs = ", sumOfPairs )
 
  
 
def printUpperFile( fileName ):
 
def printUpperFile( fileName ):
Line 190: Line 649:
 
     except FileNotFoundError:
 
     except FileNotFoundError:
 
       print( "***Error*** File", fileName, "not found!" )
 
       print( "***Error*** File", fileName, "not found!" )
       return False
+
       return
      
+
 
 +
     # if we're here, the file is found and open
 
     for line in file:
 
     for line in file:
        print( line.upper() )
+
      print( line.upper() )
 
     file.close()
 
     file.close()
    return True
+
 
   
+
def createTextFile( fileName ):
def main():
+
  file = open( fileName, "w" )
 +
  file.write( "Welcome\nto\nCSC111\nIntroduction\nto\nComp.\nSci.\n" )
 +
  file.close()
 +
 
 +
def main2():
 +
    createTextFile( "csc111.txt" )
 +
 
 
     example1()
 
     example1()
   
+
 
 
     L = [ 10, 3, 5, 6, 9, 3 ]
 
     L = [ 10, 3, 5, 6, 9, 3 ]
 
     example2( L )
 
     example2( L )
 +
    #example2( [ 10, 3, 5, 6, "NA", 3 ] )
 +
 +
    printUpperFile( "csc111.txt" )
 +
    #printUpperFile( "csc1111.txt" )
 +
 +
main2()
 +
 +
 +
 +
</source>
 +
<br />
 +
==Part 2==
 +
<br />
 +
<source lang="python">
 +
# lab9_2sol.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, tat, ag ):
 +
        """constructor.  Builds a cat with all its information"""
 +
        self.name      = na
 +
        self.breed      = brd
 +
        self.vaccinated = vacc
 +
        self.tattooed  = tat
 +
        self.age        = ag
 +
 +
    def isTattooed( self ):
 +
        """returns whether the cat is tattooed or not"""
 +
        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 ):
 +
        """returns breed of cat"""
 +
        return self.breed
 +
 +
    def __str__( self ):
 +
        """default string representation of cat"""
 +
        vacc = "vaccinated"
 +
        if not self.vaccinated:
 +
            vacc = "not vaccinated"
 +
        tat = "tattooed"
 +
        if not self.tattooed:
 +
            tat = "not tattooed"
 +
       
 +
        return "{0:20}:==> {1:1}, {2:1}, {3:1}, {4:1} yrs old".format(
 +
            self.name, self.breed, vacc, tat, self.age )
  
     L = [ 10, 3, "NA", 6, 9, 3 ]
+
def createCatCSV( fileName ):
     example2( L )
+
     file = open( fileName, "w" )
 +
    file.write( """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
 +
Bob, 2, not vaccinated, not tattooed, Burmese\n""" )
 +
   
 +
    file.close()
 +
 
 +
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 = []
 
      
 
      
     open( "doesNotExistYest.txt", "w" ).close()
+
     # get one line at a time
 +
    for line in lines:
 +
        # split a line in words
 +
        fields = line.split( "," )
  
    printUpperFile( "doesNotExistYest.txt" ):
+
        # 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()
 
          
 
          
    printUpperFile( "./Dessssktop/misspelled.txt" )
+
        # 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, tat, int(age) ) )
 +
 +
    # 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.
 +
    """
 +
 +
    createCatCSV( "cats.csv" )
 +
   
 +
    cats = readCatCSV( "cats.csv" )
 +
 +
    # print the list of all the cats
 +
    print( "\nComplete List:" )
 +
    for cat in cats:
 +
        print( cat )
 +
 +
    # print the stray cats
 +
    print( "\nStray Cats:" )
 +
    for cat in cats:
 +
        if cat.getBreed().lower().strip()=="stray":
 +
            print( cat )
 +
   
 +
 +
    # print the non-vaccinated cats 2 and older
 +
    print( "\nNon-vaccinated cats 2 or older:" )
 +
    for cat in cats:
 +
        if cat.getAge() >= 2 and cat.isVaccinated()==False:
 +
            print( cat )
 +
 +
    # print the non-tattooed cats 
 +
    print( "\nNon-tattooed cats" )
 +
    for cat in cats:
 +
        if cat.isTattooed()==False:
 +
            print( cat )
 +
   
 +
if __name__=="__main__":
 +
    main()
 +
 +
</source>
 +
 +
<br />
 +
</showafterdate>
 +
<br />
 +
<!-- ========================================================== -->
 +
<!-- ========================================================== -->
 +
<!-- ========================================================== -->
 +
<br />
 +
<onlydft>
 +
=VPL Module=
 +
<br />
 +
==vpl_run.sh==
 +
<br />
 +
<source lang="bash">
 +
#! /bin/bash
 +
 +
cat > vpl_execution <<EOF
 +
#! /bin/bash
 +
 +
# --- Python ----
 +
if [[ `hostname -s` = "beowulf2" ]]; then
 +
  python=/usr/bin/python3.3
 +
else
 +
  python=/usr/local/bin/python3.4
 +
fi
 +
 +
prog=lab9_2.py
 +
 +
\$python createCatCSV.py
 +
 +
echo "CSV file:"
 +
cat cats.csv
 +
 +
echo ""
 +
echo "Your program output"
 +
\$python \$prog
 +
 +
EOF
 +
chmod +x vpl_execution
 +
</source>
 +
<br />
 +
==vpl_debug.sh==
 +
<br />
 +
<source lang="bash">
 +
</source>
 +
<br />
 +
==vpl_evaluate.sh==
 +
<br />
 +
<source lang="bash">
 +
#! /bin/bash
 +
 +
cat  > vpl_execution <<EOF
 +
#! /bin/bash
 +
 +
# --- Python ----
 +
if [[ `hostname -s` = "beowulf2" ]]; then
 +
  python=/usr/bin/python3.3
 +
else
 +
  python=/usr/local/bin/python3.4
 +
fi
 +
 +
 +
 +
\$python evaluate.py
 +
 +
EOF
 +
 +
chmod +x vpl_execution
 +
</source>
 +
<br />
 +
==vpl_evaluate.cases==
 +
<br />
 +
<source lang="text">
 +
</source>
 +
<br />
 +
==createCatCSV.py==
 +
<br />
 +
<source lang="python">
 +
import random
 +
 +
def createCatCSV( fileName ):
 +
    names = ["Minou", "Max",  "Gizmo",  "Garfield", "Silky", "Winston",    "Bob",  "Black" ]
 +
    breeds= ["stay",  "stray", "Siamese", "Burmese", "Bengal", "Orange Tabby","stray", "Bengal" ]
 +
    N = len( names )
 +
    file = open( fileName, "w" )
 +
    for i in range( N ):
 +
        name = random.choice( names )
 +
        names.remove( name )
 +
        vac  = random.choice( [ "vaccinated", "not vaccinated" ] )
 +
        tat  = random.choice( [ "tattooed", "not tattooed" ] )
 +
        breed = random.choice( breeds )
 +
        breeds.remove( breed )
 +
        age = random.choice( [1, 1, 2, 3, 4, 1] )
 +
        file.write( "%s, %d, %s, %s, %s\n" % ( name, age, vac, tat, breed ) )
 +
    file.close()
 +
 +
def main():
 +
    createCatCSV( "cats.csv" )
  
 
main()
 
main()
 
</source>
 
</source>
 +
<br />
 +
==evaluate.py==
 +
<br />
 +
<source lang="python">
 +
# evaluate.py
 +
# D. Thiebaut
 +
# This program is used to test a student's python program on Moodle.
  
<!-- /showafterdate -->
+
import sys
 +
import random
 +
import subprocess
 +
 
 +
#--- GLOBALS ---
 +
#--- define what the student program is called, and what the solution
 +
#--- program name is.
 +
 
 +
 
 +
module = "lab9_2"
 +
solutionModule = module + "sol"
 +
userOutSplitPattern = ""      # pattern used to start recording the user
 +
                              # output.  Useful when program does several
 +
                              # input() statements, and user output starts
 +
                              # after that.
 +
stripOutputsBeforeCompare = True
 +
                              # set to True if extra spaces at beginning or
 +
                              # end of user output is ok
 +
stripDoubleSpaceBeforeCompare = True
 +
                              # set to True if double spaces must be removed in
 +
                              # outputs
 +
interpreter = sys.executable
 +
 
 +
def commentLong( line ):
 +
    print( "<|--\n" + line  + "\n --|>" )
 +
 
 +
def commentShort( text ):
 +
    print( "Comment :=>> " + text )
 +
 
 +
def printGrade( grade ):
 +
    print( "Grade :=>> ", grade )
 +
 
 +
# generateInputFileWithRandomInputs
 +
# generate a file with name "inputFileName" with some random input
 +
# for the program.
 +
# MAKE SURE TO EDIT THIS TO MATCH THE PROGRAM BEING TESTED
 +
def generateInputFileWithRandomInputs( inputFileName ):
 +
    #--- we don't need an input file for stdin, but we'll generate a
 +
    #--- dummy one nonetheless
 +
    #--- generate random inputs ---
 +
    import createCatCSV
 +
    text = open( "cats.csv", "r" ).read()
 +
    #print( text )
 +
    return text
 +
 
 +
# removeIf__name__: re
 +
def removeIf__name__( moduleName  ):
 +
 
 +
    file = open( moduleName + ".py", "r" )
 +
    lines = file.readlines()
 +
    file.close()
 +
 
 +
    newLines = []
 +
    for line in lines:
 +
        if line.find( "if __name__" ) != -1:
 +
            line = "if True:\n"
 +
        newLines.append( line.rstrip() )
 +
 
 +
    file = open( moduleName + ".py", "w" )
 +
    file.write( "\n".join( newLines ) )
 +
    file.close()
 +
 
 +
# checkForFunctionPresence
 +
# checks that "functionName" is defined and called in the program.
 +
# MAKE SURE TO EDIT TO MATCH PROGRAM BEING TESTED
 +
def checkForFunctionPresence( module, functionName ):
 +
    foundDef = False
 +
    foundCall = False
 +
 
 +
    for line in open( module+".py", "r" ).readlines():
 +
        # remove comments
 +
        idx = line.find( "#" )
 +
        if ( idx >=0 ): line = line[0:idx]
 +
 
 +
        if line.startswith( "def " + functionName + "(" ):
 +
            foundDef = True
 +
            continue
 +
        if line.startswith( "def " + functionName + " (" ):
 +
            foundDef = True
 +
            continue
 +
        if line.find( functionName+"(" ) != -1:
 +
            foundCall = True
 +
            continue
 +
 
 +
    return (foundDef, foundCall)
 +
 
 +
 
 +
 
 +
# ==================================================================
 +
# NO EDITS NEEDED BELOW!
 +
# ==================================================================
 +
 
 +
def clearLog():
 +
    open( "log.txt", "w" ).write( "" )
 +
 
 +
def log( message ):
 +
    file = open( "log.txt", "a" )
 +
    file.write( message + "\n" )
 +
    file.flush()
 +
    file.close()
 +
 
 +
 
 +
# checkModuleRunsOK: runs the module as a shell subprocess and
 +
# look for errors in the output.  This is required, because otherwise
 +
# importing the module in this program will make this program crash.
 +
# It's not possible (as far as I can tell0 to catch exceptions from
 +
# the import or __module__ statements.
 +
# returns True, none if no errors, otherwise False, string if there's
 +
# an exception, and the error message (string) is in the returned 2nd
 +
# arg.
 +
# The module name is assumed to not include ".py"
 +
def checkModuleRunsOk( module, inputFileName ):
 +
    global interpreter
 +
    p = subprocess.Popen( [ interpreter, module+".py" ],
 +
                          stdout=subprocess.PIPE,
 +
                          stderr=subprocess.PIPE,
 +
                          stdin=subprocess.PIPE)
 +
 
 +
    #print( "inputFileName = ", inputFileName )
 +
    #print( "open( inputFileName, r).read() = ", open( inputFileName, "r" ).read() )
 +
 
 +
    p.stdin.write( bytes( open( inputFileName, "r" ).read(), 'UTF-8' ) )
 +
    data = p.communicate( )
 +
    p.stdin.close()
 +
 
 +
    error = data[1].decode( 'UTF-8' )
 +
    if len( error ) > 1:
 +
        return False, error
 +
    return True, None
 +
 
 +
 
 +
# extractTextFromErrorMessage( sys_exc_info ):
 +
def extractTextFromErrorMessage( sys_exc_info ):
 +
    print( "sys_exec_info = ", sys_exc_info )
 +
    text = ""
 +
    for field in sys_exc_info:
 +
        if type( field )==type( " " ):
 +
            text += field + "\n"
 +
    return text
 +
 
 +
# runModule:
 +
# runs the module, passes it data from the input file on its stdin
 +
# and get its output on stdout captured in outputFileName.
 +
# We assume the module will not crash, because we already tested
 +
# it with checkModuleRunsOk().
 +
def runModule( module, inputFileName, outputFileName ):
 +
    global userOutSplitPattern
 +
 
 +
    # remove the if __name__=="__main__": statement
 +
    removeIf__name__( module )
 +
 
 +
    error = False
 +
 
 +
    #--- make stdin read information from the text file
 +
    #sys.stdin = open( inputFileName, "r" )
 +
 
 +
    #--- capture the stdout of the program to test into a file
 +
    saveStdOut = sys.stdout
 +
    saveStdErr = sys.stderr
 +
 
 +
    sys.stdout = open( outputFileName, "w" )
 +
    sys.stderr = open( "errorOut", "w" )
 +
 
 +
    #--- run the student program ---
 +
    try:
 +
        _module = __import__(  module  )
 +
    except:
 +
        error = True
 +
        sys.stderr.close()
 +
        sys.stderr = saveStdErr
 +
        sys.stdout.close()
 +
        sys.stdout = saveStdOut
 +
        text = sys.exc_info()[0]
 +
        text = extractTextFromErrorMessage( text )
 +
        print( "*** sys.exc_info() = ", text )
 +
        text = open( outputFileName, "r" ).read() + "\n" + text
 +
        return text
 +
 
 +
    #--- filter out junk from output of program ---
 +
    sys.stdout.close()
 +
    sys.stdout = saveStdOut
 +
    sys.stderr.close()
 +
    sys.stderr = saveStdErr
 +
 
 +
    file = open( outputFileName, "r" )
 +
    text = file.read()
 +
    #print( "output = ", text )
 +
    file.close()
 +
    return text
 +
 
 +
def removeBlankLines( lines ):
 +
    newLines = []
 +
    log( "removeBlankLines: lines = " + str( lines ) )
 +
    for line in lines.split( "\n" ):
 +
        if len( line )==0:
 +
            continue
 +
        newLines.append( line )
 +
 
 +
    return ( "\n".join( newLines ) ) + "\n"
 +
 
 +
def compareUserExpected( inputLines, userOutText, expectedOutText ):
 +
    import re
 +
    global stripOutputsBeforeCompare
 +
 
 +
 
 +
    userOutText = removeBlankLines( userOutText )
 +
    expectedOutText = removeBlankLines( expectedOutText )
 +
    misMatchLineNumbers = []
 +
    userTextOutLines = userOutText.split( "\n" )
 +
    expectedOutTextLines = expectedOutText.split( "\n" )
 +
 
 +
 
 +
    for i in range( len( userTextOutLines ) ):
 +
        lineNo = i+1
 +
        userLine = userTextOutLines[i]
 +
        if i >= len( expectedOutTextLines ):
 +
            misMatchLineNumbers.append( lineNo )
 +
            break
 +
        expectedLine = expectedOutTextLines[i]
 +
        log( "comparing:\n  "+userLine+"\n  "+expectedLine )
 +
 
 +
        if stripOutputsBeforeCompare:
 +
            userLine = userLine.strip()
 +
            expectedLine = expectedLine.strip()
 +
 
 +
        if stripDoubleSpaceBeforeCompare:
 +
            userLine = re.sub(' +',' ', userLine )
 +
            expectedLine = re.sub( ' +', ' ', expectedLine )
 +
 
 +
        if userLine != expectedLine:
 +
            log( "\ndifference: user    >" + userTextOutLines[i] + "<" )
 +
            log( "expected >" + expectedOutTextLines[i] + "<" )
 +
            misMatchLineNumbers.append( lineNo )
 +
 
 +
    return misMatchLineNumbers
 +
 
 +
 
 +
 
 +
def main():
 +
    global module
 +
    global solutionModule
 +
 
 +
    #--- clear debug log ---
 +
    clearLog()
 +
 
 +
    #--- check that the main module uses a main() function
 +
    """
 +
    foundDef, foundCall = checkForFunctionPresence( module, "main" )
 +
 
 +
    if (not foundDef) or (not foundCall):
 +
        commentShort( "-Missing main() program" )
 +
        commentShort( "Your program must use a main() function." )
 +
        commentShort( "(make sure you spell it exactly \"main()\"!" )
 +
        printGrade( 40 )
 +
        return
 +
    """
 +
    inputFileName = "cats.csv"
 +
 
 +
    #--- generate input file with random data ---
 +
    inputLines = generateInputFileWithRandomInputs( inputFileName )
 +
 
 +
 
 +
    Ok, errorMessage = checkModuleRunsOk( module, inputFileName )
 +
    if not Ok:
 +
        commentLong( "- Your program crashed...\n"
 +
                    + "Error message:\n"
 +
                    + errorMessage + "\n" )
 +
        printGrade( 50 )
 +
        return
 +
 
 +
    expectedOutText = runModule( solutionModule, inputFileName, "expectedOut" )
 +
    userOutText = runModule( module, inputFileName, "userOut" )
 +
 
 +
    #print( "expectedOutText = ", expectedOutText )
 +
    #print( "userOutText = ", userOutText )
 +
 
 +
    missMatches = compareUserExpected( inputLines, userOutText, expectedOutText )
 +
 
 +
    if len( missMatches ) != 0:
 +
        commentLong( "- Incorrect output...\n"
 +
                    +"Expected output:\n"
 +
                    +expectedOutText + "\n"
 +
                    +"Your output:\n"
 +
                    +userOutText + "\n" )
 +
        printGrade( 75 )
 +
    else:
 +
        commentLong( "- Your program passes the test\n" )
 +
        printGrade( 100 )
 +
 
 +
 
 +
main()
 +
 
 +
 
 +
 
 +
</source>
 +
<br />
 +
==lab9_2sol.py==
 +
<br />
 +
<source lang="python">
 +
# lab9_2sol.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, tat, ag ):
 +
        """constructor.  Builds a cat with all its information"""
 +
        self.name      = na
 +
        self.breed      = brd
 +
        self.vaccinated = vacc
 +
        self.tattooed  = tat
 +
        self.age        = ag
 +
 
 +
    def isTattooed( self ):
 +
        """returns whether the cat is tattooed or not"""
 +
        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 ):
 +
        """returns breed of cat"""
 +
        return self.breed
 +
 
 +
    def __str__( self ):
 +
        """default string representation of cat"""
 +
        vacc = "vaccinated"
 +
        if not self.vaccinated:
 +
            vacc = "not vaccinated"
 +
        tat = "tattooed"
 +
        if not self.tattooed:
 +
            tat = "not tattooed"
 +
 
 +
        return "{0:1}, {1:1}, {2:1}, {3:1}, {4:1} yrs old".format(
 +
            self.name, self.breed, vacc, tat, 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, tat, int(age) ) )
 +
 
 +
    # done with the lines.  Return the cat list
 +
    return cats
 +
 
 +
def main():
 +
    """ main program.
 +
    Reads a CSV file containing cats.
 +
    Display the cats matching different criteria.
 +
    """
 +
    cats = readCatCSV( "cats.csv" )
 +
 
 +
    # print the list of all the cats
 +
    #print( "\nComplete List:" )
 +
    #for cat in cats:
 +
    #    print( cat )
 +
 
 +
    # print the stray cats
 +
    #print( "\nStray Cats:" )
 +
    #for cat in cats:
 +
    #    if cat.getBreed().lower().strip()=="stray":
 +
    #        print( cat )
 +
 
 +
 
 +
    # print the non-vaccinated cats 2 and older
 +
    #print( "\nNon-vaccinated cats 2 or older:" )
 +
    for cat in cats:
 +
        if cat.getAge() >= 2 and cat.isVaccinated()==False:
 +
            print( cat )
 +
 
 +
    # print the non-tattooed cats
 +
    #print( "\nNon-tattooed cats" )
 +
    #for cat in cats:
 +
    #    if cat.isTattooed()==False:
 +
    #        print( cat )
 +
 
 +
if __name__=="__main__":
 +
    main()
 +
 
 +
</source>
 +
<br />
 +
 
 +
</onlydft>
 +
<br />
 +
<br />
 +
<br />
 +
<br />
 +
<br />
 +
<br />
 +
<br />
 +
<br />
 +
[[Category:CSC111]][[Category:Labs]][[Category:Python]]

Latest revision as of 13:29, 17 June 2015

--D. Thiebaut (talk) 07:14, 29 March 2015 (EDT)


The submission link for this lab is http://tinyurl.com/lab9submit.





Pair Programming


PairProgrammingMuppets.jpg

For this lab you will be working in pairs. Find a partner in the class with whom you will work today, and attempt to follow these directions:

  1. Close 1 computer, and work on only one computer.
  2. Only one driver! One person holds the keyboard, the other person watches and suggests code, corrections, or spots bugs.
  3. Every so often (20 minutes, maybe?) switch roles.
  4. Every so often (40 minutes, maybe?) take a break. Relax.
  5. When you are done with one section and you have a working program, exchange it with your partner, so that both members of the pair will have a copy of the code that was developed together.
  6. When you are done with all the problems for the lab, get the submission URL from the lab instructor or from the TA, and both members of the pair should submit the program.


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 = int( 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 "6.3", 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 = 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

      # 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 different invalid inputs, such as strings or floats. 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 illustrates how we can guard some code against several types of errors. Review it. You will need to follow this example for the next set of exercises.


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


Part 2: Exercise


  • Create a new program called lab9_2.py with the code below:


def example1():
    for i in range( 3 ):
        x = int( input( "enter an integer: " ) )
        y = int( input( "enter another integer: " ) )
        print( x, '/', y, '=', x/y )

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

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


def printUpperFile( fileName ):
   file = open( fileName, "r" )
   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 main():
    # create a text file for use later...
    createTextFile( "csc111.txt" )

    # test first function
    example1()

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

    # test third function 
    fileName = input( "Enter name of file to display (type csc111.txt): " )
    printUpperFile( fileName )

main()



  • The program above has many flaws; it is not very robust. We can easily make it crash.
  • Observe each function. Run your program a few times.
  • Figure out how to make each function crash
  • Go ahead and start forcing the first function to crash. Register the XXXXError that is generated. For example, if the output of the crash looks like this:

Traceback (most recent call last):
File "/Users/thiebaut/Desktop/except0.py", line 29, in <module>
main()
File "/Users/thiebaut/Desktop/except0.py", line 27, in main
example3( [ 10, 3, 5, 6 ] )
File "/Users/thiebaut/Desktop/except0.py", line 18, in example3
sum = sum + L[i]
IndexError: list index out of range

what you are interested in is IndexError. This is the exception you want to guard your code against.


  try:
      ........
      ........
  except IndexError:
      .........


  • Add the try/except statement inside the function, and verify that your function is now more robust and does not crash on the same input that made it crash before.


  • Repeat the same process for the other functions.


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.

# 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 ):
        """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 )

   


if __name__=="__main__":
    main()


  • Recreate this code in a program called Lab9_2.py
  • Run it.
  • Add a loop to your main program that outputs only the cats that are not vaccinated, and only those.



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.
  • Add another loop to your main function, once more, and make it output the non-vaccinated cats that are 2 or older.



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 one 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.
  • 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 section to your main program that will output all the cats that are not tattooed.




Challenge #2: Vaccinated and Tattooed Cats

QuestionMark6.jpg


  • Make the main program display all the cats that are vaccinated and tattooed.




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

QuestionMark7.jpg


  • Create the short program below and name it createCatCSV.py.


# createCatCSV.py
# D. Thiebaut
# save several cat definitions into a CSV file.

def createCatCSV( fileName ):
    file = open( fileName, "w" )
    file.write( """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\n""" )
    file.close()


def main():
    createCatCSV( "cats.csv" )

main()


  • Run the program once. Verify that it will have created a new file in the same folder/directory where your program resides. Verify (using Notepad or TextEdit) that it contains a collection of lines, each representing a cat.


  • Now, play with the program below:


# Lab9CatsCSV.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=", " )
        print()

if __name__=="__main__":
    main()


  • Merge this program and the one you wrote for Challenge #2, and make your program read the cats from a CSV file. It means 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 (it's simpler than you think!)
  3. transform the string "tattooed" in True, and "not tattooed" in False (same comment),
  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 the program outputs the correct lists of cats (vaccinated, 2 and older, vaccinated and tattooed, etc.)



<showafterdate after="20150403 11:00" before="20150601 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


# lab9_2sol.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, tat, ag ):
        """constructor.  Builds a cat with all its information"""
        self.name       = na
        self.breed      = brd
        self.vaccinated = vacc
        self.tattooed   = tat
        self.age        = ag

    def isTattooed( self ):
        """returns whether the cat is tattooed or not"""
        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 ):
        """returns breed of cat"""
        return self.breed

    def __str__( self ):
        """default string representation of cat"""
        vacc = "vaccinated"
        if not self.vaccinated:
            vacc = "not vaccinated"
        tat = "tattooed"
        if not self.tattooed:
            tat = "not tattooed"
        
        return "{0:20}:==> {1:1}, {2:1}, {3:1}, {4:1} yrs old".format(
            self.name, self.breed, vacc, tat, self.age )

def createCatCSV( fileName ):
    file = open( fileName, "w" )
    file.write( """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
Bob, 2, not vaccinated, not tattooed, Burmese\n""" )
    
    file.close()

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, tat, int(age) ) )

    # 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.
    """

    createCatCSV( "cats.csv" )
    
    cats = readCatCSV( "cats.csv" )

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

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

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

    # print the non-tattooed cats  
    print( "\nNon-tattooed cats" )
    for cat in cats:
        if cat.isTattooed()==False:
            print( cat )
    
if __name__=="__main__":
    main()


</showafterdate>


...