Question
This Codio project is the workspace for the final course project. While you are welcome to completeproject on your own computer, this project has several
This Codio project is the workspace for the final course project. While you are welcome to completeproject on your own computer, this project has several tools to allow you to check your work along the way.
We have not provided you with any files for this project. You will create the files as directed. When you are done, you will have three files: currency.py, the module with the project functions; testcurrency.py, the unit tests for the currency functions, and exchangeit.py, an interactive script that allows a non-programmer to convert between two currencies.
You should also take a chance to familiarize yourself with this guide. To access the table of contents, click the upper-right button.
You will see several sections, breaking up each step into smaller tasks. In this project, you will work in the top-level directory. You should not make any new folders, and you should not store your files anywhere else.
2. Project Rules
This project is designed for a student who has learned about functions, specifications, and testing but has not yet learned any advanced control structures (if-statements, for-loops, etc.). It is also designed to be used in tandem with the introcs module, which simplifies a lot of advanced Python concepts.
To maintain the spirit of the assignment (and help with the grading process), certain Python commands are restricted in this assignment:
No advanced control structures (conditionals, loops, try-except blocks)
No Python or 3rd party modules other than introcs and the ones you make
No method calls, including string methods
Strings should use the functions in introcs instead of methods.
In addition, this project has the following style requirements:
Every function must have a complete specification.
Every module must start with a docstring with your name and date.
There must be two blank lines between any two function definitions.
Function bodies should be indented with 4 spaces.
No non-docstring line may be longer than 80 characters.
3. Project Workflow
Throughout this project, you will stick to the following workflow, one function at a time.
Add a stub for a function to currency.py.
Add a complete set of test cases for the function to testcurrency.py.
Implement the function in currency.py, using the tests as a guide.
With few exceptions, we will not give you any hints on the functions. The specifications should be sufficient. We also will not tell you the number of test cases that we are looking for (though you will get feedback from the "Check It!" buttons). We expect you to figure these out on your own.
Remember, to run the test script, you just run it as a normal Python script.
codio@mike-panther:~/workspace/exercise1$ python3 testcurrency.py
Testing before_space
Testing after_space
Testing first_inside_quotes
Testing get_src
Testing get_dst
Testing has_error
Testing service_response
Testing iscurrency
Testing exchange
All tests completed successfully
4. A Word of Warning
This Codio project provides a lot of buttons to allow you to test your code for correctness. It might be tempting to rely on these buttons all the time, instead of testing your code on your own. This is a mistake, particularly when you are implementing functions and test cases.
Connecting to the web service takes time. It is not horribly slow, but the time is measured in seconds, not milliseconds (as many programs are). If there are many test cases, the function will have to connect to the web service many times, increasing the time to a minute or even more. Because the grading tools in this project are thorough, they are not fast.
You should use your own test script testcurrency.py to test the function before pressing the Check It button. Your test script will give you better feedback anyway. The "Check It!" button is only for when you believe you have completed the step and should move on. Remember that a new terminal session in Codio can be opened at any time through the top menu via Tools > Terminal.
5. Create the Module
The first file to create is the file currency.py, as this will be the main module for the project. You will not add any function stubs yet. Instead, we want you to add only the following three items right now (in order):
The module docstring with name and date.
A single import statement, importing introcs.
An assignment statement creating the global variable APIKEY.
You should assign APIKEY to the passkey (as a string) that you got from the course Canvas page.
The docstring of this module should be as follows:
"""
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: NAME
Date:TODAY
"""
Replace NAME and TODAY with the correct values.
The next file to create is the file exchangeit.py, which provides the text-driven user interface. You will not return to this file until the end of the project, but it is helpful to set it up now. Right now, this file should only contain two things:
The module docstring with name and date.
A single import statement, importing currency.
The docstring of this script should be as follows:
"""
User interface for module currency
When run as a script, this module prompts the user for two currencies and amount.
It prints out the result of converting the first currency to the second.
Author: NAME
Date:TODAY
"""
Replace NAME and TODAY with the correct values.
Check the Script
You may run this test multiple times.
7. Create the Test Script
The final file to create is the file testcurrency.py, which is the test script for this project. We do not want you to add test procedures yet. Right now, we just want you to create the file with the following four items (in order):
The module docstring with name and date.
An import statement for the module introcs.
An import statement for the module currency.
A print statement displaying "All tests completed successfully."
The docstring of this script should be as follows:
"""
Unit tests for module currency
When run as a script, this module invokes several procedures that test
the various functions in the module currency.
Author: NAME
Date:TODAY
"""
Replace NAME and TODAY with the correct values.
Check the Script
You may run this test multiple times.
8. Expand the Test Script
You should now add a test procedure stub to testcurrency.py for every function that you are going to implement in the project. Each stub will have a specification and a print statement. For example, for the function before_space, you should make a test procedure called test_before_space (which takes no arguments). It should have the docstring:
"""Test procedure for before_space"""
and should print out the message "Testing before_space".
Do the same for every other function in the project. The project functions are as follows: before_space, after_space, first_inside_quotes, get_src, get_dst, has_error, service_response, iscurrency and exchange.
In addition, remember to call the test procedures at the bottom of the script, but above the final print statement. When you are done, the script should display the following:
codio@mike-panther:~/workspace/exercise1$ python3 testcurrency.py
Testing before_space
Testing after_space
Testing first_inside_quotes
Testing get_src
Testing get_dst
Testing has_error
Testing service_response
Testing iscurrency
Testing exchange
All tests completed successfully
Check the Procedures
You may run this script multiple times.
9. Stub the Function before_space
A large part of this project is breaking up a JSON string. Conceptually, you want to separate the currency amount from the currency name. For example, if you are given the string:
"0.863569 Euros"
Then you want to break it up into "0.863569" and "Euros". This is the motivation for the functions in this section.
The function before_space has the following specification:
"""
Returns the substring of s up to, but not including, the first space.
Example: before_space('Hello World') returns 'Hello'
Parameter s: the string to slice
Precondition: s is a string with at least one space in it
"""
Add a stub for this function (including the specification) to the file currency.py.
Check the Stub
You may run this test multiple times
10. Add Test Cases for before_space
Reread the specification for before_space, paying close attention to the precondition. Create test cases for this function and add them to the test procedure test_before_space in testcurrency.py. Remember, to implement a test case:
Call the function on a sample input of your choice.
Store the returned result as a variable.
Compare the result with the expected output using assert_equals in introcs.
See the Unit Test Functions in the IntroCS API for more information.
When designing test cases for before_space, think about how spaces may occur in the string - both position and frequency - and how that can affect the result.
Check the Test Cases
You may call this function multiple times.
11. Implement the Function before_space
Implement the function according to the specification. Use the test script testcurrency.py to aid your development before checking your answer below.
Check the Function
You may run this test multiple times.
12. Stub the Function after_space
The function after_space is the dual to before_space. One will allow us to get the currency amount, and the other will allow us to get the currency name.
The function after_space has the following specification:
"""
Returns the substring of s after the first space
Example: after_space('Hello World') returns 'World'
Parameter s: the string to slice
Precondition: s is a string with at least one space in it
"""
Add a stub for this function (including the specification) to the file currency.py.
Check the Stub
You may run this test multiple times.
13. Add Test Cases for after_space
When designing test cases for after_space, think about how spaces may occur in the string - both position and frequency - and how that can effect the result. Because after_space processes spaces differently than before_space, there are certain tests that are important for after_space that were not necessarily important for before_space (and vice versa).
Check the Test Cases
You may run this test multiple times.
14. Implement the Function after_space
Implement the function according to the specification. Use the test script testcurrency.py to aid your development before checking your answer below.
Check the Function
You may run this test multiple times.
15. Enforce the Preconditions
Both before_space and after_space have the same preconditions. Add assert statements to both of these functions enforcing the preconditions. Error messages are not necessary.
Remember that test scripts are not designed to check assert statements. If you want to check your assert statements, you will need to check them manually:
codio@mike-panther:~/workspace$ python3
Python 3.6.6 (default, Jul 31 2018, 22:09:10)
[GCC 4.8.4] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import currency
>>> currency.before_space(3)
Check the Asserts
You may run this test multiple times.
16. Stub the Function first_inside_quotes
Note that JSON strings have a lot of elements inside quotes:
'{"success": true, "src": "2 United States Dollars", "dst": "1.772814 Euros", "error": ""}'
We need a function that can extract the parts of the string that are inside quotes. That is the purpose of the function first_inside_quotes, which has the following specification:
"""
Returns the first substring of s between two (double) quote characters
Note that the double quotes must be part of the string.So "Hello World" is a
precondition violation, since there are no double quotes inside the string.
Example: first_inside_quotes('A "B C" D') returns 'B C'
Example: 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 with at least two (double) quote characters inside
"""
Add a stub for this function (including the specification) to the file currency.py.
Check the Stub
You may run this test multiple times.
17. Add Test Cases for first_inside_quotes
When designing test cases for first_inside_quotes, think about how quotes may occur in the string - both position and frequency - and how that can affect the result.
Your test cases will have to contain double quotes. Remember that "Hello" is not a valid input. Those double quotes are not part of the string. To ensure that the double quotes are part of the string, you may need to use escape characters.
Check the Test Cases
You may run this test multiple times.
18. Implement the Function first_inside_quotes
Implement the function according to the specification. Use the test script testcurrency.py to aid your development before checking your answer below.
Check the Function
You may run this test multiple times.
19. Enforce the Precondition
Review the precondition for first_inside_quotes. Add assert statements to this function enforcing the precondition. Error messages are not necessary.
Remember that test scripts are not designed to check assert statements. If you want to check your assert statements, you will need to check them manually:
codio@mike-panther:~/workspace$ python3
Python 3.6.6 (default, Jul 31 2018, 22:09:10)
[GCC 4.8.4] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import currency
>>> currency.first_inside_quotes("Hello")
Check the Asserts
You may run this test multiple times.
20. Stub the Function get_src
The function first_inside_quotes will only access the first set of data inside quotes. To process our JSON strings, we need more targeted extraction functions, which is the purpose of the three functions in this section. Most (if not all) of the functions in this section will use first_inside_quotes as a helper.
The function get_src has the following specification:
"""
Returns the src value in the response to a currency query.
Given a JSON string provided by the web service, this function returns the string
inside string quotes (") immediately following the substring '"src"'. For example,
if the json is
'{"success": true, "src": "2 United States Dollars", "dst": "1.772814 Euros", "error": ""}'
then this function returns '2 United States Dollars' (not '"2 United States Dollars"').
On the other hand if the json is
'{"success":false,"src":"","dst":"","error":"Source currency code is invalid."}'
then this function returns the empty string.
The web server does NOT specify the number of spaces after the colons. The JSON
'{"success":true, "src":"2 United States Dollars", "dst":"1.772814 Euros", "error":""}'
is also valid (in addition to the examples above).
Parameter json: a json string to parse
Precondition: json a string provided by the web service (ONLY enforce the type)
"""
Add a stub for this function (including the specification) to the file currency.py.
Check the Stub
You may run this test multiple times.
21. Add Test Cases for get_src
When designing test cases for get_src, look very closely at the precondition. It says that the string must be a valid response from the web service. This is an extremely restrictive precondition, so it limits the possible test cases significantly. However, notice the comment about colons in the specification. That will be important for your test cases.
Check the Test Cases
You may run this test multiple times.
22. Implement the Function get_src
Implement the function according to the specification. An ideal solution will use first_inside_quotes as a helper. Use the test script testcurrency.py to aid your development before checking your answer below.
Check the Function
You may run this test multiple times.
23. Stub the Function get_dst
The function get_dst is very similar to get_src. It has the following specification:
"""
Returns the dst value in the response to a currency query.
Given a JSON string provided by the web service, this function returns the string
inside string quotes (") immediately following the substring '"dst"'. For example,
if the json is
'{"success": true, "src": "2 United States Dollars", "dst": "1.772814 Euros", "error": ""}'
then this function returns '1.772814 Euros' (not '"1.772814 Euros"'). On the other
hand if the json is
'{"success":false,"src":"","dst":"","error":"Source currency code is invalid."}'
then this function returns the empty string.
The web server does NOT specify the number of spaces after the colons. The JSON
'{"success":true, "src":"2 United States Dollars", "dst":"1.772814 Euros", "error":""}'
is also valid (in addition to the examples above).
Parameter json: a json string to parse
Precondition: json a string provided by the web service (ONLY enforce the type)
"""
Add a stub for this function (including the specification) to the file currency.py.
Check the Stub
You may run this test multiple times.
24. Add Test Cases for get_dst
When designing test cases for get_src, look very closely at the precondition. Note that whenever the "src" value is empty, the "dst" value must be as well. This means that the test cases for the two are very similar.
Check the Test Cases
You may run this test multiple times.
25. Implement the Function get_dst
Implement the function according to the specification. The solution will be very similar to get_src. Use the test script testcurrency.py to aid your development before checking your answer below.
Check the Function
You may run this test multiple times.
26. Stub the Function has_error
The function has_error is similar to get_src and get_dst except that it returns a boolean instead of a string. It has the following specification:
"""
Returns True if the response to a currency query encountered an error.
Given a JSON string provided by the web service, this function returns True if the
query failed and there is an error message. For example, if the json is
'{"success":false,"src":"","dst":"","error":"Source currency code is invalid."}'
then this function returns True (It does NOT return the error message
'Source currency code is invalid'). On the other hand if the json is
'{"success": true, "src": "2 United States Dollars", "dst": "1.772814 Euros", "error": ""}'
then this function returns False.
The web server does NOT specify the number of spaces after the colons. The JSON
'{"success":true, "src":"2 United States Dollars", "dst":"1.772814 Euros", "error":""}'
is also valid (in addition to the examples above).
Parameter json: a json string to parse
Precondition: json a string provided by the web service (ONLY enforce the type)
"""
Add a stub for this function (including the specification) to the file currency.py.
Check the Stub
You may run this test multiple times.
27. Add Test Cases for has_error
Once again, the precondition for has_error is very similar to get_src and get_dst. This suggests that the test cases are similar. Because this function returns a boolean, you are free to use assert_true and assert_false instead of assert_equals when creating your test cases.
Check the Test Cases
You may run this test multiple times.
28. Implement the Function has_error
Implement the function according to the specification. Remember that you may not use conditionals (if-statements). Instead, you should use what you know about boolean expressions. Use the test script testcurrency.py to aid your development before checking your answer below.
Check the Function
You may run this test multiple times.
29. Enforce the Preconditions
All of the functions get_src, get_dst, and has_error have the same preconditions. The precondition is quite complex and effectively impossible to enforce (without significantly more knowledge of Python). But that is okay. Enforcing preconditions is a good idea, but it is not mandatory. You are allowed to enforce all, none, or even part of a specification. So reread the specification and only enforce what you are directed to enforce.
Remember that test scripts are not designed to check assert statements. If you want to check your assert statements, you will need to check them manually:
codio@mike-panther:~/workspace$ python3
Python 3.6.6 (default, Jul 31 2018, 22:09:10)
[GCC 4.8.4] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import currency
>>> currency.get_src(3)
Check the Asserts
You may run this test multiple times.
30. Stub the Function service_response
The function service_response is the heart of this project. It is the function that connects to the web service and returns a JSON string. It has the following specification:
"""
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
'{"success": true, "src": "
where the values src-amount and dst-amount contain the value and name for the src
and dst currencies, respectively. If the query is invalid, both src-amount and
dst-amount will be empty, and the error message will not be empty.
There may or may not be spaces after the colon.To test this function, you should
chose specific examples from your web browser.
Parameter src: the currency on hand
Precondition src is a nonempty string with only letters
Parameter dst: the currency to convert to
Precondition dst is a nonempty string with only letters
Parameter amt: amount of currency to convert
Precondition amt is a float or int
"""
Add a stub for this function (including the specification) to the file currency.py.
Check the Stub
You may run this test multiple times.
31. Add Test Cases for service_response
Creating test cases for service_response is a bit of a challenge. A test case requires both an input and an expected output. You need to know what the web service will respond with in order to get the expected output. Fortunately, we have shown you how to play with the web service in your web browser. Look at the following URL:
https://ecpyfac.ecornell.com/python/currency/fixed?src=USD&dst=EUR&amt=2.5&key=a1b2c3d4
a1b2c3d4 is a demonstration passkey that only works on this query. To try other queries, you will need to use your own passkey.
Looking at this link you see that service_response('USD','EUR',2.5) should return
'{"success": true, "src": "2.5 United States Dollars", "dst": "2.2160175 Euros", "error": ""}'
Note that we had to add additional single quotes to turn the answer into a string. Use this process to come up with more test cases for your function.
Warning: The verification process below is potentially slow since it has to connect to the web service.
Check the Test Cases
You may run this test multiple times.
32. Implement the Function service_response
Implement the function according to the specification. To, you will need a function that connects to a web page/service. Fortunately, there is such a function. Look at the Web Access Functions in the IntroCS API and find the function urlread. The purpose of this function is to generate the corresponding URL query string with the provided currency values and return a JSON string as a response to the query.
Try this function out in the interactive shell using the query from the following step:
codio@mike-panther:~/workspace$ python3
Python 3.6.6 (default, Jul 31 2018, 22:09:10)
[GCC 4.8.4] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import introcs
>>> q = 'https://ecpyfac.ecornell.com/python/currency/fixed?src=USD&dst=EUR&amt=2.5&key=a1b2c3d4'
>>> introcs.urlread(q)
'{"success": true, "src": "2.5 United States Dollars", "dst": "2.2160175 Euros", "error": ""}'
See how this works? In this example, the source currency is USD (for US Dollars) and the destination is EUR (for Euros), and the amount of dollars to convert to Euros is the value of amt, 2.5. In the returned JSON string, the value of 2.4 Dollars in Euros is shown as "2.2160175". For other amounts or currencies, you would change the value of src, dst, or amt.
Use this function to implement service_response. Use the test script testcurrency.py to aid your development before checking your answer below.
Warning: The verification process below is potentially slow since it has to connect to the web service.
33. Enforce the Preconditions
The preconditions for service_response are straight-forward. However, notice that there are three parameters. You will need assert statements to cover the preconditions for each parameter. Error messages are not necessary.
Remember that test scripts are not designed to check assert statements. If you want to check your assert statements, you will need to check them manually:
codio@mike-panther:~/workspace$ python3
Python 3.6.6 (default, Jul 31 2018, 22:09:10)
[GCC 4.8.4] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import currency
>>> currency.service_response('A B','C',2)
Check the Asserts
You may run this test multiple times.
34. Stub the Function iscurrency
The last two functions are the goal of the assignment: a function to check if a currency code is valid, and a function to compute the exchange rate given two currency codes. The first of these, iscurrency has the following specification:
"""
Returns True if currency is a valid (3 letter code for a) currency.
It returns False otherwise.
Parameter currency: the currency code to verify
Precondition: currency is a nonempty string with only letters
"""
Add a stub for this function (including the specification) to the file currency.py.
Check the Stub
You may run this test multiple times.
35. Add Test Cases for iscurrency
The test cases for iscurrency are limited by the precondition. Remember, you should never implement a test case that violates the precondition. Because the precondition is so strong, there are really only two significantly different tests here. Can you figure them out?
Warning: The verification process below is potentially slow, since it has to connect to the web service.
Check the Test Cases
You may run this test multiple times.
36. Implement the Function iscurrency
Many students find iscurrency to be the trickiest function in the project. We will give you a hint. The only way to figure out if a currency is valid is to ask the web service. That means this function should use service_response as a helper. But you only have one currency, not two. So think about how you could call this function with only one currency variable.
In addition, you may find some of the other functions that you developed earlier useful as helpers. As always use the test script testcurrency.py to aid your development before checking your answer below.
Warning: The verification process below is potentially slow, since it has to connect to the web service.
Check the Function
You may run this test multiple times.
37. Stub the Function exchange
The function exchange is the end goal of this assignment. It is the function that you will call in the application script exchangeit.py. It has the following specification:
"""
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 currency_to.
The value returned has type float.
Parameter src: the currency on hand
Precondition src is a string for a valid currency code
Parameter dst: the currency to convert to
Precondition dst is a string for a valid currency code
Parameter amt: amount of currency to convert
Precondition amt is a float or int
"""
Add a stub for this function (including the specification) to the file currency.py.
Check the Stub
You may run this test multiple times.
38. Add Test Cases for exchange
Once again, exchange has very strong preconditions that heavily restrict the allowable inputs. Once again, there are really only two significantly different tests here. Can you figure them out?
Warning: The verification process below is potentially slow, since it has to connect to the web service.
Check the Test Cases
You may run this test multiple times.
39. Implement the Function exchange
The implementation of exchange will require many (but not all) of the functions that you have implemented so far as helpers. Think about the functions you have implemented as "building blocks" and how they can help you implement this function.
As always use the test script testcurrency.py to aid your development before checking your answer below.
Warning: The verification process below is potentially slow, since it has to connect to the web service.
Check the Function
You may run this test multiple times.
40. Enforce the Preconditions
The functions iscurrency and exchange have very different preconditions. But at this point you should understand enforcing preconditions enough to add the appropriate assert statements.
The one challenging function is exchange. Note that it requires that the arguments src and dst be valid currency codes. Is there a function that could help you with this?
Check the Asserts
You may run this test multiple times.
41. Implement the Application Script
Now that you have completed the module currency.py, you are ready to work on the script exchangeit.py. This script is just that - a script. It should not contain any function definitions. It should just contain a sequence of Python statements that
Ask the the user for a first currency code
Ask the the user for a second currency code
Ask the the user for an amount (of the first currency)
Prints the conversion to the second currency
The following example shows you what the script should do when you run it.
codio@mike-panther:~/workspace$ python3 exchangeit.py
3-letter code for original currency: USD
3-letter code for the new currency: EUR
Amount of the original currency: 2.5
You can exchange 2.5 USD for 2.216 EUR.
Notice the wording, spacing, and punctuation. In addition, the final print statement rounds the exchange amount to three decimal places. Your implementation must match this.
42. Review the Style Guidelines
Before submitting the project, make sure you have obeyed the style guidelines. Remember
Every function must have a complete specification.
Every module must start with a docstring with your name and date.
There must be two blank lines between any two function definitions.
Function bodies should be indented with 4 spaces.
No non-docstring line may be longer than 80 characters.
Many of the specifications we gave you violate that last rule (because we did not want to break up the JSON strings). But it is okay for a specification to run overlong in some cases.
Check the Style
You may run this test multiple times.
43. Reflect and Submit
Congratulations. You have now completed a real Python application. Of course a lot of the hard-work was done for you. We provided the specifications and you coded to spec. But this is not uncommon for an entry-level developer. Now that you have seen how the application fits together, you may start to see why we made the choices that we did.
If you were to design the specifications yourself, what would you have changed?
Lines inside of a docstring may be longer than 80 characters.
Step by Step Solution
There are 3 Steps involved in it
Step: 1
Get Instant Access to Expert-Tailored Solutions
See step-by-step solutions with expert insights and AI powered tools for academic success
Step: 2
Step: 3
Ace Your Homework with AI
Get the answers you need in no time with our AI-driven, step-by-step assistance
Get Started