This assignment is designed to give you practice with the following skills:
- How to write a self-contained module in Python
- How to write a script that uses a self-contained module
- How to use string methods in Python
- How to connect Python to a web service
- How to read specifications and understand preconditions
- How to use docstrings appropriately for specifications
- How to follow the coding conventions for this course
- How to thoroughly test a program
The functions we ask you to write in this assignment are relatively short and straightforward. The emphasis is testing and “good practices”, not complicated computations. You will find that the
most recent lab
is very helpful in understanding this assignment.
“””
Test script for module a1
When run as a script, this module invokes several procedures that
test the various functions in the module a1.
Author: Anqi Bai/Hongyi Lu NetId:ab2897/hl2374
Date: 9/22/2019
“””
import introcs
import a1
#Testing function before_space and after_space
def testA():
“””
Test Procedure for Part A
Testing function before_space and after_space
“””
print(‘Testing function before_space’)
#testing strings with one space
result = a1.before_space(‘2 Bitcon’)
introcs.assert_equals(‘2’,result)
#testing strings with only space
result = a1.before_space(‘ ‘)
introcs.assert_equals(”,result)
#testing strings with more than one spaces
result = a1.before_space(‘6 Japanese Yen’)
introcs.assert_equals(‘6’,result)
#testing strings with more than one consective spaces
result = a1.before_space(‘6 CubanPeso’)
introcs.assert_equals(‘6’,result)
print(‘Testing function after_space’)
#testing strings with one space
result = a1.after_space(‘2 Bitcon’)
introcs.assert_equals(‘Bitcon’,result)
#testing strings with only space
result = a1.after_space(‘ ‘)
introcs.assert_equals(”,result)
#testing strings with more than one spaces
result = a1.after_space(‘6 Japanese Yen’)
introcs.assert_equals(‘Japanese Yen’,result)
#testing strings with more than one consective spaces
result = a1.after_space(‘6 CubanPeso’)
introcs.assert_equals(‘ CubanPeso’,result)
#Testing function first_inside_quotes, get_lhs, get_rhs and has_error
def testB():
“””
Test procedure for Part B
Testing function first_inside_quotes, get_lhs, get_rhs and has_error
“””
print(‘Testing function first_inside_quotes’)
#test strings with two quotes
result = a1.first_inside_quotes(‘A “B C” D’)
introcs.assert_equals(‘B C’,result)
#test strings with nothing in quotes
result = a1.first_inside_quotes(‘””‘)
introcs.assert_equals(”,result)
#test strings with all strings in two quotes
result = a1.first_inside_quotes(‘”A B C D E F”‘)
introcs.assert_equals(‘A B C D E F’,result)
#test strings with more than two quotes
result = a1.first_inside_quotes(‘A “B C” “D” “E” F’)
introcs.assert_equals(‘B C’,result)
print(‘Testing function get_lhs’)
#Testing json with valid currency and amount
result = a1.get_lhs(‘{ “ok”:true, “lhs”:”1 Bitcoin’+
‘”, “rhs”:”9916.0137939344 Euros”, “err”:”” }’)
introcs.assert_equals(‘1 Bitcoin’,result)
#Testing json with invalid currency and amount
result = a1.get_lhs(‘{ “ok”:false, “lhs”:””, “rhs”:””,’+
‘ “err”:”Source currency code is invalid.” }’)
introcs.assert_equals(”,result)
print(‘Testing function get_rhs’)
#Testing json with valid currency and amount
result = a1.get_rhs(‘{ “ok”:true, “lhs”:”1 Bitcion”, ‘+
‘”rhs”:”9916.0137 Euros”, “err”:”” }’)
introcs.assert_equals(‘9916.0137 Euros’,result)
#Testing json with valid currency and amount
result = a1.get_rhs(‘{ “ok”:true, “lhs”:”1 Bitcion”,’+
‘ “rhs”:”233 AED”, “err”:”” }’)
introcs.assert_equals(‘233 AED’,result)
#Testing json with invalid currency and amount
result = a1.get_rhs(‘{ “ok”:false, “lhs”:””, “rhs”:””,’+
‘ “err”:”Source currency code is invalid.” }’)
introcs.assert_equals(”,result)
print(‘Testing function has_error’)
#Testing Json that is a response for invalid currency
result = a1.has_error(‘{ “ok”:True, “lhs”:”1 Bitcoin”, ‘+
‘”rhs”:”9916.0137 Euros”, “err”:”” }’)
introcs.assert_equals(False,result)
#Testing Json that is a response for valid currency
result = a1.has_error(‘{ “ok”:false, “lhs”:””, “rhs”:””, ‘+
‘”err”:”Source currency code is invalid.” }’)
introcs.assert_equals(True,result)
#Testing function currency_response
def testC():
“””
Test procedure for Part C
Testing function currency_response
“””
print(‘Testing function currency_response’)
#Testing with proper currency code and amount (same currency)
result = a1.currency_response(‘USD’,’USD’,1.0)
introcs.assert_equals(‘{ “ok”:true, “lhs”:”1 United States ‘+
‘Dollar”, “rhs”:”1 United States Dollar”, “err”:”” }’,result)
#Testing with proper currency code and amount
result = a1.currency_response(‘AUD’,’USD’,2.0)
introcs.assert_equals(‘{ “ok”:true, “lhs”:”2 Australian Dollars”, ‘+
‘”rhs”:”1.4041334881625 United States Dollars”, “err”:”” }’,result)
#Testing with improper currency code and amount with one invalid currency
result = a1.currency_response(‘USD’,’ABC’,3.0)
introcs.assert_equals(‘{ “ok”:false, “lhs”:””, “rhs”:””‘+
‘, “err”:”Exchange currency code is invalid.” }’,result)
#Testing with improper currency code and amount with two invalid currencies
result = a1.currency_response(‘TYU’,’ABC’,3.0)
introcs.assert_equals(‘{ “ok”:false, “lhs”:””, “rhs”:””, ‘+
‘”err”:”Source currency code is invalid.” }’,result)
#Testing function is_currency and exchange
def testD():
“””
Test Procedure for Part D
Testing function is_currency and exchange
“””
print(‘Testing function is_currency’)
#Testing with valid currency code
result = a1.is_currency(‘USD’)
introcs.assert_equals(True,result)
#Testing with valid currency code
result = a1.is_currency(‘CNY’)
introcs.assert_equals(True,result)
#Testing with invalid currency code
result = a1.is_currency(‘ZZZ’)
introcs.assert_equals(False,result)
print(‘Testing function exchange’)
#Testing with valid same currency and amount
result = a1.exchange(‘USD’,’USD’,666.0)
introcs.assert_floats_equal(666.0,result)
#Testing with valid currency and amount with multiple decimals
result = a1.exchange(‘USD’,’JPY’,666.0)
introcs.assert_floats_equal(71871.39,result)
testA()
testB()
testC()
testD()
print(‘Module a1 passed all tests.’)
“””
Module for currency exchange
This module provides several string parsing functions to implement a
simple currency exchange routine using an online currency service.
The primary function in this module is exchange.
Author: Anqi Bai/Hongyi Lu NetId:ab2897/hl2374
Date: 9/22/2019
“””
import introcs
def before_space(s):
“””
Returns a copy of s up to, but not including, the first space
Parameter s: the string to slice
Precondition: s is a string with at least one space
“””
pos = s.index(‘ ‘)
before = s[:pos]
return before
def after_space(s):
“””
Returns a copy of s after the first space
Parameter s: the string to slice
Precondition: s is a string with at least one space
“””
pos = s.index(‘ ‘)
after = s[pos+len(‘ ‘):]
return after
def first_inside_quotes(s):
“””
Returns the first substring of s between two (double) quotes
A quote character is one that is inside a string, not one that
delimits it. We typically use single quotes (‘) to delimit a
string if want to use a double quote character (“) inside of it.
Examples:
first_inside_quotes(‘A “B C” D’) returns ‘B C’
first_inside_quotes(‘A “B C” D “E F” G’) returns ‘B C’,
because it only picks the first such substring
Parameter s: a string to search
Precondition: s is a string containing at least two double quotes
“””
pos1 = s.find(‘”‘)
pos2 = s.find(‘”‘,pos1+1)
return s[pos1+1:pos2]
def get_lhs(json):
“””
Returns the lhs value in the response to a currency query
Given a JSON response to a currency query, this returns the
string inside double quotes (“) immediately following the keyword
“lhs”. For example, if the JSON is
‘{ “ok”:true, “lhs”:”1 Bitcoin”, “rhs”:”9916.0137 Euros”, “err”:”” }’
then this function returns ‘1 Bitcoin’ (not ‘”1 Bitcoin”‘).
This function returns the empty string if the JSON response
contains an error message.
Parameter json: a json string to parse
Precondition: json is the response to a currency query
“””
poslhs = (json).find(‘lhs’)
newjson = json[poslhs+4 :]
return first_inside_quotes(newjson)
def get_rhs(json):
“””
Returns the rhs value in the response to a currency query
Given a JSON response to a currency query, this returns the
string inside double quotes (“) immediately following the keyword
“rhs”. For example, if the JSON is
‘{ “ok”:true, “lhs”:”1 Bitcoin”, “rhs”:”9916.0137 Euros”, “err”:”” }’
then this function returns ‘9916.0137 Euros’ (not
‘”9916.0137 Euros”‘).
This function returns the empty string if the JSON response
contains an error message.
Parameter json: a json string to parse
Precondition: json is the response to a currency query
“””
posrhs = (json).find(‘rhs’)
newjson = json[posrhs+4 :]
return first_inside_quotes(newjson)
def has_error(json):
“””
Returns True if the query has an error; False otherwise.
Given a JSON response to a currency query, this returns the
opposite of the value following the keyword “ok”. For example,
if the JSON is
‘{ “ok”:false, “lhs”:””, “rhs”:””, “err”:”Currency amount is invalid.” }’
then the query is not valid, so this function returns True (It
does NOT return the message ‘Source currency code is invalid’).
Parameter json: a json string to parse
Precondition: json is the response to a currency query
“””
pos1 = (json).find(‘”ok”‘)
pos2 = (json).find(‘,’,pos1+2)
parameter = (json)[pos1+5:pos2]
return bool(parameter ==’false’)
def currency_response(src, dst, amt):
“””
Returns a JSON string that is a response to a currency query.
A currency query converts amt money in currency src to the
currency dst. The response should be a string of the form
‘{ “ok”:true, “lhs”:”
where the values old-amount and new-amount contain the value
and name for the original and new currencies. If the query is
invalid, both old-amount and new-amount will be empty, while
“ok” will be followed by the value false (and “err” will have
an error message).
Parameter src: the currency on hand (the LHS)
Precondition: src is a string with no spaces or non-letters
Parameter dst: the currency to convert to (the RHS)
Precondition: dst is a string with no spaces or non-letters
Parameter amt: amount of currency to convert
Precondition: amt is a float
“””
stramt = str(amt)
website = ‘http://cs1110.cs.cornell.edu/2019fa/a1?’\
+’src=’+src+’&’+’dst=’+dst+’&’+’amt=’+stramt
response = introcs.urlread(website)
return response
def is_currency(code):
“””
Returns: True if code is a valid (3 letter code for a) currency
It returns False otherwise.
Parameter code: the currency code to verify
Precondition: code is a string with no spaces or non-letters.
“””
s1 = currency_response(code,’CNY’, ‘666’)
s2 = has_error(s1)
return bool(s2==False)
def exchange(src, dst, amt):
“””
Returns the amount of currency received in the given exchange.
In this exchange, the user is changing amt money in currency
src to the currency dst. The value returned represents the
amount in currency dst.
The value returned has type float.
Parameter src: the currency on hand (the LHS)
Precondition: src is a string for a valid currency code
Parameter dst: the currency to convert to (the RHS)
Precondition: dst is a string for a valid currency code
Parameter amt: amount of currency to convert
Precondition: amt is a float
“””
s1 = currency_response(src, dst, amt)
s2 = get_rhs(s1)
result = before_space(s2)
result = float(result)
return result
“””
User interface for module currency
When run as a script, this module prompts the user for two currencies and
an amount. It prints out the result of converting the first currency to
the second.
Author: Anqi Bai/Hongyi Lu NetId:ab2897/hl2374
Date: 9/22/2019
“””
import a1
first = input(‘Enter source currency: ‘)
second = input(‘Enter target currency: ‘)
third = float(input(‘Enter original amount: ‘))
result = a1.exchange(first,second,third)
print(‘You can exchange ‘+str(third)+’ ‘+first+’ for ‘+str(result)+’ ‘+second+”.”)
Hi, this is Ellie Cheong, looking at your Assignment A1.
Please revise your A1 solution as we suggest below. Look at each point and revise
according to it before going on to the next. When done, resubmit. THEN SUBMIT A REQUEST
FOR A REGRADE, SAYING SIMPLY THAT YOU RESUBMITTED. This is how we will know to regrade it.
If we don’t get this regrade request, there will be no easy way for us to know that you
resubmitted. Be sure you have set your notifications on the CMS so that you receive an
email when a grade has been changed.
===========
Start grading of hr349/a1.py
Max points for A1 Functions: 45
Max points for Part A (Space breaking functions): 13
Finished Part A (Space breaking functions)
Max points for Part B (JSON extraction utilities): 14
Finished Part B (JSON extraction utilities)
Max points for Part C (Currency query connection): 6
Finished Part C (Currency query connection)
Max points for Part D (Currency functions): 12
Finished Part D (Currency functions)
Finished A1 Functions
Max points for A1 Test Cases: 29
Max points for Tests for Part A: 9
The following test cases have the wrong outputs: 1 point deducted.
assert_equals (line 31): expected ‘ CubanPeso’ but instead got ‘CAD’
You are missing 2 tests for before_space. 2 points deducted.
You are missing 2 tests for after_space. 2 points deducted.
The test on line 22 does not have an explanatory comment: 1 point deducted.
introcs.assert_equals(‘5’, a1.before_space(‘5 USD’))
The test on line 23 does not have an explanatory comment: 1 point deducted.
introcs.assert_equals(”, a1.before_space(‘ ‘))
The test on line 24 does not have an explanatory comment: 1 point deducted.
introcs.assert_equals(’10’, a1.before_space(’10 AED’))
The test on line 25 does not have an explanatory comment: 1 point deducted.
introcs.assert_equals(‘2’, a1.before_space(‘2 CAD’))
The test on line 28 does not have an explanatory comment: Maximum deduction reached.
introcs.assert_equals(‘USD’, a1.after_space(‘5 USD’))
The test on line 29 does not have an explanatory comment: Maximum deduction reached.
introcs.assert_equals(”, a1.after_space(‘ ‘))
The test on line 30 does not have an explanatory comment: Maximum deduction reached.
introcs.assert_equals(‘AED’, a1.after_space(’10 AED’))
The test on line 31 does not have an explanatory comment: Maximum deduction reached.
introcs.assert_equals(‘ CubanPeso’, a1.after_space(‘2 CAD’))
Finished Tests for Part A
Max points for Tests for Part B: 11
You are missing one last test for get_lhs. 1 point deducted.
The test on line 42 does not have an explanatory comment: 1 point deducted.
introcs.assert_equals(‘Y’, a1.first_inside_quotes(‘X “Y”Z’))
The test on line 43 does not have an explanatory comment: 1 point deducted.
introcs.assert_equals(”, a1.first_inside_quotes(‘””‘))
The test on line 44 does not have an explanatory comment: 1 point deducted.
introcs.assert_equals(‘XYZ’, a1.first_inside_quotes(‘”XYZ”‘))
The test on line 45 does not have an explanatory comment: 1 point deducted.
introcs.assert_equals(‘Y’, a1.first_inside_quotes(‘X “Y” “Z”‘))
The test on line 49 does not have an explanatory comment: 1 point deducted.
introcs.assert_equals(‘5 USD’, result)
The test on line 51 does not have an explanatory comment: 1 point deducted.
introcs.assert_equals(”, result)
The test on line 56 does not have an explanatory comment: 1 point deducted.
introcs.assert_equals(‘4.61 Euros’, result)
The test on line 58 does not have an explanatory comment: 1 point deducted.
introcs.assert_equals(‘18.37 AED’, result)
The test on line 60 does not have an explanatory comment: 1 point deducted.
introcs.assert_equals(”, result)
The test on line 64 does not have an explanatory comment: 1 point deducted.
introcs.assert_equals(False, result)
The test on line 66 does not have an explanatory comment: Maximum deduction reached.
introcs.assert_equals(False, result)
The test on line 68 does not have an explanatory comment: Maximum deduction reached.
introcs.assert_equals(True, result)
Finished Tests for Part B
Max points for Tests for Part C: 4
The following test cases have the wrong outputs: 1 point deducted.
assert_equals (line 84): expected ‘{ “ok”:true, “lhs”:”5 United States Dollar”, “rhs”:”18.37 United Arab Emirates Dirham”, “err”:”” }’ but instead got ‘{ “ok”:true, “lhs”:”5 Australian Dollars”, “rhs”:”3.5103337204061 United States Dollars”, “err”:”” }’
The test on line 80 does not have an explanatory comment: 1 point deducted.
introcs.assert_equals(‘{ “ok”:true, “lhs”:”1 United States ‘ + ‘Dollar”, “rhs”:”1 United States Dollar”, “err”:”” }’
The test on line 83 does not have an explanatory comment: 1 point deducted.
introcs.assert_equals(‘{ “ok”:true, “lhs”:”5 United States Dollar”, ‘ + ‘”rhs”:”18.37 United Arab Emirates Dirham”‘
The test on line 86 does not have an explanatory comment: 1 point deducted.
introcs.assert_equals(‘{ “ok”:false, “lhs”:””, “rhs”:””‘ + ‘, “err”:”Exchange currency code is invalid.” }’, result)
The test on line 88 does not have an explanatory comment: Maximum deduction reached.
introcs.assert_equals(‘{ “ok”:false, “lhs”:””, “rhs”:””, ‘ + ‘”err”:”Source currency code is invalid.” }’, result)
Finished Tests for Part C
Max points for Tests for Part D: 5
The procedure ‘testD’ crashed when called. 4 points deducted.
Traceback (most recent call last):
File “a1grade/rubrik.py”, line 890, in grade_test_D
a1test.testD()
File “a1test.py”, line 106, in testD
result = a1.get_rhs(bads)
File “/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/introcs/testcase.py”, line 443, in assert_floats_equal
quit_with_error(message)
File “/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/introcs/testcase.py”, line 304, in quit_with_error
quit()
File “/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/_sitebuiltins.py”, line 26, in __call__
raise SystemExit(code)
SystemExit: None
The test on line 98 does not have an explanatory comment: 1 point deducted.
introcs.assert_equals(True, a1.is_currency(‘USD’))
The test on line 99 does not have an explanatory comment: Maximum deduction reached.
introcs.assert_equals(True, a1.is_currency(‘AED’))
The test on line 100 does not have an explanatory comment: Maximum deduction reached.
introcs.assert_equals(False,a1.is_currency(‘XYZ’))
The test on line 104 does not have an explanatory comment: Maximum deduction reached.
introcs.assert_floats_equal(5, result)
The test on line 106 does not have an explanatory comment: Maximum deduction reached.
introcs.assert_floats_equal(183.66, result)
Finished Tests for Part D
Finished A1 Test Cases
Max points for A1 Application: 11
Max points for User Input: 5
Finished User Input
Max points for Output Formats: 6
Finished Output Formats
Finished A1 Application
Max points for Coding Style: 15
Max points for File a1.py: 5
The docstring for ‘a1.py’ does not include a valid date after Date: 0.5 points deducted.
Line 149 of ‘a1.py’ is too long (113 characters) and must be broken up: 1 point deducted.
url = ‘http://cs1110.cs.cornell.edu/2019fa/a1?’ + ‘src=’ + src + ‘&’ + ‘dst=’ + dst + ‘&’ + ‘amt=’ + str(amt)
Finished File a1.py
Max points for File a1test.py: 5
The docstring for ‘a1test.py’ does not include a valid date after Date: 0.5 points deducted.
The specification for function ‘testA’ is not correct on the first line. 1 point deducted.
Given: Test Procedure for Part A Testing before_space and after_space functions
Want: Test procedure for Part A
The specification for function ‘testD’ is not correct on the first line. 1 point deducted.
Given: Test Procedure for Part D Testing is_currency and exchange function
Want: Test procedure for Part D
Line 59 of ‘a1test.py’ is too long (108 characters) and must be broken up: 1 point deducted.
result = a1.get_rhs(‘{ “ok”:false, “lhs”:””, “rhs”:””,’ + ‘ “err”:”Source currency code is invalid.” }’)
Line 67 of ‘a1test.py’ is too long (110 characters) and must be broken up: 1 point deducted.
result = a1.has_error(‘{ “ok”:false, “lhs”:””, “rhs”:””,’ + ‘ “err”:”Source currency code is invalid.” }’)
Line 80 of ‘a1test.py’ is too long (120 characters) and must be broken up: 0.5 points deducted.
introcs.assert_equals(‘{ “ok”:true, “lhs”:”1 United States ‘ + ‘Dollar”, “rhs”:”1 United States Dollar”, “err”:”” }’
Line 83 of ‘a1test.py’ is too long (119 characters) and must be broken up: Maximum deduction reached.
introcs.assert_equals(‘{ “ok”:true, “lhs”:”5 United States Dollar”, ‘ + ‘”rhs”:”18.37 United Arab Emirates Dirham”‘
Line 84 of ‘a1test.py’ is too long (99 characters) and must be broken up: Maximum deduction reached.
‘, “err”:”” }’, result)
Line 86 of ‘a1test.py’ is too long (120 characters) and must be broken up: Maximum deduction reached.
introcs.assert_equals(‘{ “ok”:false, “lhs”:””, “rhs”:””‘ + ‘, “err”:”Exchange currency code is invalid.” }’, result)
Line 88 of ‘a1test.py’ is too long (118 characters) and must be broken up: Maximum deduction reached.
introcs.assert_equals(‘{ “ok”:false, “lhs”:””, “rhs”:””, ‘ + ‘”err”:”Source currency code is invalid.” }’, result)
Finished File a1test.py
Max points for File a1app.py: 5
The docstring for ‘a1app.py’ does not include a valid date after Date: 0.5 points deducted.
Line 16 of ‘a1app.py’ is too long (118 characters) and must be broken up: 1 point deducted.
print(‘You can exchange ‘ + str(amount) + ‘ ‘ + source_currency + ‘ for ‘ + str(result) + ‘ ‘ + target_currency + “.”)
Finished File a1app.py
Finished Coding Style
1. A1 Functions 45 out of 45
A. Part A (Space breaking functions) (13 )
B. Part B (JSON extraction utilities) (14 )
C. Part C (Currency query connection) ( 6 )
D. Part D (Currency functions) (12 )
2. A1 Test Cases 0 out of 29
A. Tests for Part A ( 0 )
B. Tests for Part B ( 0 )
C. Tests for Part C ( 0 )
D. Tests for Part D ( 0 )
3. A1 Application 11 out of 11
A. User Input ( 5 )
B. Output Formats ( 6 )
4. Coding Style 7.0 out of 15
A. File a1.py ( 3.5)
B. File a1test.py ( 0.0)
C. File a1app.py ( 3.5)
——————————————————-
Total 63.0 out of 100
Deductions:
Total out of 100