Introduction to Python

davidbpython.com




Projects, Session 9



PLEASE REMEMBER:

  1. re-read the assignment before submitting
  2. go through the checklist including the tests
  3. make sure your notations are as specified in the homework instructions

All requirements are detailed in the homework instructions document.

Careless omissions will result in reductions to your solution grade.

 
9.1 Notes typing assignment. Please write out this week's transcription notes. The notes are displayed as a .png image named transcription in each week's project files folder.

This does not need to be in a Python program - you can use a simple text file.

 
9.2 Function get_input_as_int. Read the docstring and write a function that behaves accordingly. Make note of argument(s) and return value(s). Test the program as shown below.
def get_input_as_int():       # please complete the args list on this line

    """
    Given a string argument,
    checks to see if the value is all digits,
    converts to integer and returns it

    Argument:      a string

    Return value:  integer based on string argument

    Raises:        ValueError if arg is not all digits
    """

    # your function code here


# Test your function with this additional code
x = get_input_as_int('5')
print(x)                       # 5
print(type(x))                 # <class 'int'>

# uncomment this code to test for error
# x = get_input_as_int('hello')     # should raise ValueError

  • The function will not print anything! Some students print from the function and think they've returned from the function. The function must return an integer.
  • The function will not use input(). It simply expects the string argument, then converts that argument to int().
  • The function will not exit(). To signal an error, use the raise statement, e.g. raise ValueError('arg must be an int')
  • The function will not use try:. To signal an error we use raise by itself.
  • Make sure your function variable names do not match those outside the function!
  • If you see None printed, remember that any function without a return statement will return None. Does your function return the integer, or just print it?

 
9.3 Function file_count (based on the "word count" or "wc" program from Session 4). Read the docstring and write a function that behaves accordingly. Make note of argument(s) and return value(s). Test the program as shown below.

You are encouraged to develop a solution that does not loop and does not open the file more than once. See the project discussion for details.

def file_count():                    # please complete the args list on this line

    """
    Given the name of a file and an optional
    'l', 'w' or 'c', return the number of
    lines, words or letters in the file.

    Arguments:          name of a file  (str)
                        items= 'l', 'w' or 'c' (str) (optional, default None)

    Return value:  count of lines, words or characters;
                   if no items= argument is passed, returns all 3

    Raises:        ValueError if 2nd argument is not
                   'l', 'w' or 'c' (or None)
    """

    # your function code here


# Test your function with this additional code

# items='l':  returns count of lines
lines = file_count('FF_tiny.txt', items='l')
print(lines)           # 9


# items='w':  returns count of words
words = file_count('FF_tiny.txt', items='w')
print(words)           # 45


# items='c':  returns count of characters
chars = file_count('FF_tiny.txt', items='c')
print(chars)           # 368


# with no items= argument:  returns count of all 3
lines, words, chars = file_count('FF_tiny.txt')

print(lines)           # 9
print(words)           # 45
print(chars)           # 368


# make sure the function can work with other files as well
lines, words, chars = file_count('pyku.txt')
print(lines)          # 3
print(words)          # 15
print(chars)          # 80


# uncomment the below code line to test for error
# with filename and invalid items= argument:  raises ValueError
# x = file_count('FF_tiny.txt', items='s')
    # ValueError:  'items=' must be 'l', 'w' or 'c' only

Notes:

  • You should open the file only once in the program. Use .read() to get the text of the file as a single string - both the lines (with .splitlines()) and words (with .split()) can be obtained from this string.
  • The function will not print anything! Some students print from the function and think they've returned from the function. The function must return 3 integers.
  • The function will not use input(). It simply expects the string filename argument, then reads the file and calculates the counts.
  • The function will not exit(). To signal an error, use the raise statement, e.g. raise ValueError("'items=' must be 'l', 'w' or 'c' only")
  • The function will not use try:. To signal an error we use raise by itself.
  • Make sure your function variable names do not match those outside the function!
  • You must test the function using the test code, and you must see the output shown.
  • if you see None printed, or TypeError: cannot unpack non-iterable NoneType object then you did not return any values from the function - the function returns 1 int or 3 ints.
  • if you see ValueError: not enough values to unpack (expected 3, got y) then you returned the wrong number of values from the function - with no 'items=' argument, the function returns 3 ints.
  • if you see TypeError: cannot unpack non-iterable int object then you only returned one value from the function - with no 'items=' argument, the function returns 3 ints.

 
9.4 Function get_lookup_dict (based on project solution 5.4). Read the docstring and write a function that behaves accordingly. Make note of argument(s) and return value(s). Test the program as shown below.
def get_lookup_dict():      # please complete the args list on this line

    """
    Given the name of a CSV file, return a dict of
    key/value pairs where the 1st column is the key
    and the 2nd column is the value.

    Argument:      name of a file

    Return value:  dict pairing 1st column value
                   with 2nd column value

    Raises:        FileNotFoundError if file not found
                   (Python will do this automatically)
    """

    # your function code here


# Test your function with this additional code:
ret = get_lookup_dict('pac_man_ghosts.csv')

print(ret)     # {'Shadow': 'Blinky', 'Speedy': 'Pinky',
               #  'Bashful': 'Inky', 'Pokey': 'Clyde'}


ret = get_lookup_dict('huh')      # raises FileNotFoundError



# 2nd test: <U>in the same program</U>, the program should work as follows:
ret2 = get_lookup_dict('boropop2020.csv')

print(ret2)   #  {'Bronx': '1472654',
              #   'Brooklyn': '2736074'
              #   'Manhattan': '1694251',
              #   'Queens': '2405464',
              #   'Richmond': '495747'}

  • The function will not print anything! Some students print from the function and think they've returned from the function. The function must return a dict.
  • The function will not use input(). It simply expects the string filename argument, then reads the file and builds the dict.
  • The function will not exit(). To signal an error, use the raise statement, e.g. raise ValueError('arg must be an int') (though you may not need to raise an error from this function since Python raises a FileNotFound error)
  • You must test the function using the test code, and you must see the output shown.
  • Make sure your function variable names do not match those outside the function!
 
9.5 Place the code for all 3 of your functions in a module named funclib.py and run a test program to test it.

YOU MUST INCLUDE THE OUTPUT OF YOUR TEST RUN SHOWING '3 passed' IN YOUR SUBMISSION TO RECEIVE CREDIT. Please copy all of your functions to a file named funclib.py, saved in the main session directory. The functions should be pasted, one after another, inside the file without any additional code -- just 3 functions. The test program, test_funclib.py, is also located in the session directory. You should now see funclib.py and test_funclib.py in the same directory before proceeding. RUN test_funclib.py by issuing the following command at the command line (Anaconda prompt (Windows) or Terminal (Mac) (remember that terminal prompts may vary -- on Mac may be a % or $, on PC it's a >:

$ pytest

IF YOU ARE ON WINDOWS you may need to run pytest this way:

> python -m pytest

PLEASE INDICATE IN YOUR SOLUTION WHETHER OR NOT YOU SEE THE BELOW (or similar) OUTPUT (or an error of some sort)

Running pytest, you should see (AND PASTE INTO YOUR SUBMISSION) output reflecting the passing of 3 tests - at the least, you should see:
(base) davidg@Davids-MacBook-Pro session_09_funcs_modules % pytest
  ===================================== test session starts =====================================
  platform darwin -- Python 3.9.13, pytest-7.1.2, pluggy-1.0.0
  rootdir: /Users/thurmanlong/Downloads/python_data_ipy (2)/session_09_funcs_modules
  plugins: anyio-3.5.0
  collected 3 items

  test_funclib.py ...
  ============================== 3 passed in 0.02s ===============================

Please disregard any warnings referring to code that is not in your module -- a DeprecationWarning has been reported with recent versions of Anaconda, and it does not affect our efforts here, nor does it need to be addressed. ("Deprecation" in this context means a feature that has been slated for removal but is still being used -- the warning says "we're going to remove this soon, so stop using it in future". But because this refers not to our program but to another module involved in testing, we can rely on an anaconda update (at some point in the future) to manage this issue.) Submit the contents of funclib.py, i.e. the three functions. (Please DO NOT TURN IN the calling code below - turn in your module of three functions). PLEASE INDICATE IN YOUR SOLUTION WHETHER OR NOT YOU SEE THE ABOVE OUTPUT (or an error of some sort). If you see an error, it is because one of the tests failed. Looking at the error carefully, you will see that an AssertionError occurred, and the test program should display what it was trying to assert and

For example, if get_input_as_int() when given '5' returned 6, you would see the following in red on your PyCharm output:
test_funclib.py:3 (test_get_input_as_int)
6 != 5

Expected :5
Actual   :6

The testing program is indicating that the assertion expected the return value should be 5, but was actually 6. In the case where a test fails, you should look at your function code to see why it returned the incorrect value that it did.

Here are the contents of test_funclib.py:
import funclib            # funclib.py must be in same directory as this test script


def test_get_input_as_int():
    x = funclib.get_input_as_int('5')

    assert x == 5

    try:
        funclib.get_input_as_int('what?')
    except ValueError:
        pass
    else:
        raise AssertionError("get_input_as_int('what') does not raise a ValueError")


def test_file_count():
    lines, words, chars = funclib.file_count('FF_tiny.txt')

    assert lines == 9

    assert words == 45

    assert chars == 368

    lines = funclib.file_count('FF_tiny.txt', items='l')
    assert lines == 9

    words = funclib.file_count('FF_tiny.txt', items='w')
    assert words == 45

    chars = funclib.file_count('FF_tiny.txt', items='c')
    assert chars == 368

    lines, words, chars = funclib.file_count('pyku.txt')

    assert lines == 3
    assert words == 15
    assert chars == 80


    try:
        funclib.file_count('FF_tiny.txt', items='xxx')
    except ValueError:
        pass
    else:
        exit('file_count(items=\'xxx\') did NOT raise ValueError')


def test_get_lookup_dict():
    ret = funclib.get_lookup_dict('pac_man_ghosts.csv')
    assert ret == {'Shadow': 'Blinky', 'Speedy': 'Pinky', 'Bashful': 'Inky', 'Pokey': 'Clyde'}

  • You must test your module using the test code, and you must see the output shown above. If you see an error, then one of the functions did not test successfully.

 
9.6 Please write out a sentence or two describing how you'd like to use Python in the future. This can be anything, so have fun with it if you can. If you're not sure and never had a specific object in mind, you can just pick something based on what you can imagine or have heard Python can do. No wrong answers!
 
[pr]