T-Th 9:05 or 11:15
in Kimball B11

CS 1110: Introduction to Computing Using Python

Spring 2013

Assignment 1:
Currency

First submission due on CMS by Monday, February 18th at 11:59 pm.
These instructions last updated on February 24 2013 14:55.
Any changes from the handout marked in orange.
Feb 14 04:42am: Clarification on iscurrency spec (see Piazza @42 followup)
Feb 17 10:49pm: Removed stray cut-and-paste error from specification of exchange (see Piazza @68)
Feb 18 10:26pm: Explained that after partners group on CMS, only one partner submits the code.
Feb 19 11:04pm: Explained in Section 10.1 where your feedback can be found.
Feb 24 2:46pm: Explained in Section 10.1 how to contact your grader.
Feb 24 2:46pm: Added more info about picking test cases in Section 6.

Authors: W. White, Q. Jia, L. Lee, S. Marschner; image credit: AFP (originating page)

Preliminaries

Thinking about that trip overseas? Best to go when the exchange rate is in your favor, if you can swing it: when your dollars buy more in the foreign currency, you can do more on your vacation. Hence, it would be nice to have a function that, given your current amount of cash in US dollars, tells you how much your money is worth in another currency.

However, there isn't a set mathematical formula to compute this conversion; rather, the value of one currency with respect to another is constantly changing. In fact, in the time that it takes you to read this paragraph, the exchange rate between the dollar and the Euro has probably changed several times. How on Earth do we write a program to handle something like that?

Our answer is to make use of a web service. A web service is an program that, when you send it web requests, automatically generates a web page with the information that you asked for. In our case, we'll employ a web service that tells us the current exchange rate for most major international currencies. Your job will be to use (surprise!) string methods to get and read the web page and extract the exact information we need.

Learning Objectives

This assignment is designed to give you (more) practice with the following skills:

  • How to write a self-contained module in Python
  • How to use string and object 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 you will write should be relatively short and straightforward. The emphasis in A1 is testing and “good practices”, as introduced in lecture and lab, rather than complicated computation.

Start Early: 300 students trying to contact a web service at once could slow everybody down

Connecting to, and reading from, a web page is not instantaneous. It will take several seconds for some of the functions you will write to complete. Furthermore, if you wait until the last minute to test this assignment, you will be connecting to the same web page as everyone else in the class, so things could slow down even more.

Academic Integrity and Previous Versions of This Assignment

This assignment is a slightly modified version of an assignment given the previous semester. Please do this assignment without consulting (or seeking) previous solutions. First, you are allowed to revise and resubmit, with help from us, until you have mastered the skills you'll need in subsequent assignments, so there's no reason to not do this assignment on your own (or with your partner). Second, to consult any prior solutions is a violation of CS1110's academic integrity policies.

Table of Contents

  1. Before You Get Started
  2. The Currency Exchange Web Service
  3. How To Proceed Through A1: Iterative Development
  4. Part A: Breaking up Strings
  5. Part B: Processing a JSON String
  6. Part C: Currency Query
  7. Part D: Currency Exchange
  8. Finishing the Assignment
  9. Appendix: Connecting to Google

Before You Get Started

Read Carefully

These instructions may seem long, but that's because we have aimed to give you all the information you need in one document. Your chances of completing the assignment quickly and correctly will be increased by reading carefully and following all instructions. Many requests for resubmission and regrades are caused not by issues with programming but simply by not following directions.

Pay particular attention to the section on Iterative Development, because it contains important instructions for the remaining sections, and we will not repeat these instructions for each section.

Grading Policy (Revise-and-Resubmit Cycle)

To ensure that everyone masters the material in this assignment, we use an iterative feedback process. If your code doesn't meet one or more of the three criteria below, we will give you feedback, and assign you a new “grade” indicating the number of (re-)submissions so far, so we can keep track of your progress. You should then revise and resubmit your code. This process will be repeated until your code meets all the criteria, at which point we will give you full marks (a score of 10). The achievement of mastery should be recorded by Monday, February 25th. In order for this to happen, you should check CMS for a grade update, and revise if you're asked to, at least once a day from the deadline for your first submission, Monday, February 18th. In our experience, almost everyone is able to achieve a perfect score within two revisions. Again, do not be alarmed if you see a grade of "1" for the assignment at first, because that's just our notation for saying that you submitted your first try!

Our evaluation of your code will focus on the following criteria, in order:

  • appropriateness of function specifications and formatting with respect to the course style guidelines, available on the course web page.

  • adequacy of the test cases

  • correctness of the code

Collaboration Policy

You may do this assignment with one other person. If you are going to work together, then form your group on CMS by Monday, February 18th. Both people must do something to form the group: The first person proposes, and then the other accepts. You have to do this early because CMS doesn't allow you to form groups once grades are released. Once you've grouped on CMS, only one person submits the files.

If you do this assignment with another person, you must work together. It is against the rules for one person to do some programming on this assignment without the other person sitting nearby and helping. Take turns "driving"; alternate using the keyboard and mouse.

With the exception of your CMS-registered partner, you may not look at anyone else's code or show your code to anyone else (except a CS1110 staff member) in any form whatsoever.

Warning: If you and your partner use different OS's (e.g., one uses Windows, the other Mac), please be aware that these platforms handle whitespace differently. You may find that when you trade files back and forth, spaces become tabs and vice versa. Follow the guidelines for making whitespace visible in Komodo Edit.

Assignment Scope: no if-statements, loops or recursion

Everything that you need to complete this assignment has been covered by the 6th lecture and 3rd lab. In particular, you may not use if-statements anywhere in this assignment, because they are actually superfluous and heavy-handed for the task. Similarly, students with prior programming experience should not use loops or recursion.

Getting Help

If you do not know where to start, find your progress has stalled, or become lost along the way, please see someone immediately; a little in-person help can do wonders. See the staff page for who you can see when. Piazza is also an excellent resource for getting questions answered quickly (although you are not allowed to post your code there).


The Currency-Exchange Web Service

Before you start, it's useful to play around a little with the currency-exchange web service, just using your web browser.

For this assignment, you will use a simulated currency exchange service that never changes exchange rates. This is important for testing; if the answer is always changing, it is hard to test that you are getting the right answers. (The appendix explains how you can make a few minor changes to hook your program up to Google's currency calculator to get real-time currency-exchange results, if you like, but don't submit such code for your assignment.)

To use the service, you employ special URLs that start with the following prefix:

  http://cs1110.cs.cornell.edu/2013sp/a1/calculator.php?
This prefix is followed with a currency query; a currency query has three pieces of information in the following format (without spaces; we've included spaces here solely for readability):
  q=amount source =? target
where amount is a float, source is a three-letter code for the original currency, and target is a three-letter code for the new currency. For example, if you want to know the value of 2.5 dollars (USD) in Euros (EUR), the query is
  q=2.5USD=?EUR
The full URL for this query is
  http://cs1110.cs.cornell.edu/2013sp/a1/calculator.php?q=2.5USD=?EUR
Click on the link to see it in action.

You will note that the “web page” that shows up in your browser is just a single line in the following format:

  {money_in: "2.5 U.S. dollars",money_out: "2.0366598775 Euros",error: "",icc: true}
This is what is known as a JSON representation of the answer; JSON is a way of encoding complex data. You will use your string-processing know-how to pull out the relevant data from JSON strings.

Try a few more currency queries to familiarize yourself with the service. Note that if you enter an invalid query (for example, using a non-existent currency code like "AAA"), you will get the following response, indicating an error:

  {money_in: "",money_out: "",error: "4",icc: false}
This will be important for error handling in this assignment.


Focus of the Assignment

Your primary goal in this assignment is to use the currency-exchange service to write the following function:

def exchange(amount_from, currency_from, currency_to):
    """Returns: amount of currency received in the given exchange.

    In this exchange, the user is changing <amount_from> money in
    currency <currency_from> to the currency <currency_to>.
    The value returned is a float representing the amount in
    currency <currencyTo>.

    Preconditions: <amount_from> is a float. Both <currency_from>
    and <currency_to> are strings that are valid three-letter currency
    codes."""

This function will involve several steps: getting the JSON string from the web service, breaking up the string to pull out the numeric value, and converting that value to a float. As this is the very first assignment, we are going to take you through this process step-by-step.

You will notice that the assignment steps might seem ordered “in reverse”: we have you write the functions to break up the string first, and the functions to interact with the web service last. One reason we've chosen this ordering is to focus on the string-processing aspects of the task.


Currency Exchange Table

In order to make it easier to test your program, we have fixed the exchange rates in our web service. That way you can test the answer in a web browser (using a currency query URL) and then compare the results to your Python program, without worrying about rates fluctuating.

The following currencies are supported by our web service:

Code Name 1 USD = Code Name 1 USD =
AED United Arab Emirates dirham 3.67300014 MAD Moroccan dirham 8.96073406
ANG Netherlands Antilles guilder 1.74999869 MDL Moldovan leu 12.4599723
ARS Argentine peso 4.60600254 MKD Macedonian denar 50
AUD Australian dollar 0.952743902 MUR Mauritian rupee 30.7002732
BGN Bulgarian lev 1.59330049 MXN Mexican peso 13.1385327
BHD Bahrain dinar 0.377009934 MYR Malaysian ringgit 3.12949865
BND Brunei dollar 1.25080051 NAD Namibian dollar 8.26268736
BOB Bolivian boliviano 7.01001731 NGN Nigerian naira 157.05984
BRL Brazil real 2.02269873 NIO Nicaraguan cordoba 23.689946
BWP Botswana pula 7.73395205 NOK Norwegian krone 5.96630232
CAD Canadian dollar 0.988601426 NPR Nepalese rupee 89.3415528
CHF Swiss franc 0.978396994 NZD New Zealand dollar 1.23823675
CLP Chilean peso 482.392668 OMR Omani rial 0.384949995
CNY Chinese yuan 6.36589915 PEN Peruvian nuevo sol 2.61500122
COP Colombian peso 1821.49362 PGK Papua New Guinean kina 2.12404418
CRC Costa Rican colon 499.5005 PHP Philippine peso 42.2904508
CZK Czech koruna 20.2889141 PKR Pakistan rupee 94.3930527
DKK Danish krone 6.06369303 PLN Polish zloty 3.3252972
DOP Dominican peso 39.1251614 PYG Paraguayan guarani 4424.77876
DZD Algerian dinar 82.1962847 QAR Qatar riyal 3.64090484
EEK Estonian kroon 11.7303429 RON Romanian lei 3.65570564
EGP Egyptian pound 6.07651548 RSD Serbian dinar 96.2927299
EUR Euro 0.814663951 RUB Russian ruble 31.8969092
FJD Fiji dollar 1.78253119 SAR Saudi riyal 3.75009375
GBP British pound 0.636861546 SCR Seychelles rupee 13.000013
HKD Hong Kong dollar 7.75662804 SEK Swedish krona 6.70627842
HNL Honduran lempir 19.5000195 SGD Singapore dollar 1.25080051
HRK Croatian kuna 6.06818209 SKK Slovak koruna 24.5428887
HUF Hungarian forint 226.8088 SLL Sierra Leonean leone 4329.00433
IDR Indonesian rupiah 9523.80952 SVC Salvadoran colon 8.74997813
ILS Israeli shekel 4.04799301 THB Thai baht 31.5497224
INR Indian rupee 55.8784086 TND Tunisian dinar 1.62299986
JMD Jamaican dollar 89.1821992 TRY Turkish lira 1.79870026
JOD Jordanian dinar 0.708501307 TTD Trinidad dollar 6.4
JPY Japanese yen 79.1577614 TWD Taiwan dollar 29.987705
KES Kenyan shilling 84.0689365 TZS Tanzanian shilling 1579.77883
KRW South Korean won 1132.50283 UAH Ukrainian grivna 8.0990022
KWD Kuwaiti dinar 0.282719878 UGX Ugandan shilling 2481.38958
KYD Cayman Islands dollar 0.820001476 USD U.S. dollar 1
KZT Kazakh tenge 149.276011 UYU Uruguayan peso 21.1501449
LBP Lebanese pound 1506.0241 UZS Uzbekistani sum 1912.04589
LKR Sri Lankan rupee 132.013201 VND Vietnamese dong 20833.3333
LTL Lithuanian litas 2.8127971 YER Yemeni rial 215.517241
LVL Latvian lats 0.567099174 ZAR South African rand 8.26268736
MAD Moroccan dirham 8.96073406 ZMK Zambia kwacha 4878.04878

Note, however, that you should not use the values in this table in any of the functions that you write in a1.py. The table above is for testing your functions; not for writing them, and there is no reason for you to waste your time hard-coding in each of the approximately zillion currencies listed in this table into your program, since the web service you'll contact already knows them all anyway.


How To Proceed Through A1: Iterative Development

One of the most important outcomes of this assignment is that you understand the importance of testing. This assignment will follow an iterative development cycle. That means you will write a few functions, then fully test them before you write any more. This process makes it easier to find bugs; you know that any bugs must have been part of the work you did since the last test.

In this section we help you get started with this process. We also provide an overview of the rest of the assignment.


Setting up

To do this assignment, Python and the Cornell Extensions must be set up properly on the computer you plan to work on. If you have not already done this, follow the installation instructions to set it up on your computer. Alternatively, you can just work in the ACCEL lab.

It is possible to do this assignment without the command shell, provided that you have added a "run button" to Komodo Edit. However, we suggest that you run your unit test on the command line (type python a1test.py) when you get near the end of the assignment, for reasons given below.

Finally, create a folder on your hard drive that is dedicated to this assignment and this assignment only. Every time that you work on a new assignment, we want you to make a new folder, to keep things organized and avoid problems with naming collisions. Make sure that the command shell and Komodo Edit are both open in the current folder before you start.

Put the file cunittest.py in this directory.


The Module a1

In your newly created directory, you should create the module a1 (with file name a1.py). This will be the main module for this assignment. Following the style guidelines, the first three lines of this file should be single-line comments with (1) the module name, (2) your name and netid, and (3) the date the file was last edited. Immediately after this, add the following docstring:

"""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()."""

This docstring is the module specification. We recommend that you directly cut-and-paste this docstring into a1. For now, we want to expose you to specifications, not have you write them on your own.

The Module a1test

Iterative development hinges on proper unit testing, which was covered in lecture and lab. In the same folder as a1.py, create the module a1test (with file name a1test.py). This will be the unit test for the a1 module.

As with a1.py, the first three lines of this file should be the authoring-info 3-comment header. Immediately after it, add the following Python code:

"""Unit test for module a1

When run as an application, this module invokes several
procedures that test the various functions in the module
a1."""

import cunittest
import a1

Add four procedure stubs to this a1test: testA(), testB(), testC(), testD(), separated from each other by two blank lines. Remember that a procedure stub has a function header and then the keyword pass (indented) after the header, but nothing else. You'll add test cases to these procedures later.

Finally, at the end of a1test.py, add the following application code (see lecture slides for more on application code).

if __name__ == "__main__":
    testA()
    testB()
    testC()
    testD()
    print "Module a1 passed all test cases"

The application code will call your four test procedures, which are (currently) empty. If everything is working, then the module, when run, prints out the message

"Module a1 passed all test cases"
Try it.

Instructions for the Remainder of the Assignment

The rest of the assignment is broken into Parts A, B, C, and D. In each part, do the following:

  1. For each function we ask you to write, write its header in a1. Then, admire the completeness of the specifications we give you for each function, and then copy each one (copy-and-paste is fine) into the corresponding function body, indented.

  2. Add test cases to the appropriate test procedure in a1test for each function — yes, before writing the function bodies, as we talked about in lecture.

  3. Write the function bodies so that the functions satisfy their specifications.

  4. Run the unit test a1test. If errors are found, fix them and re-test; rinse and repeat until no more errors are found.

Unless otherwise instructed, each test case should be a call one of the cunittest assertion procedures. Your tests should be representative, meaning that they should cover the space of possible inputs; we exercised this concept in lab.


If You Choose to Craft Your Own Specifications

The descriptions that we provide in each part below represent the level of completeness and precision we are looking for in your docstring comments. In fact, it is best to copy-and-paste these descriptions to create the first draft of your docstring comments. If you do not copy-and-paste, please adhere to the conventions we use, such as using a single line, followed by a blank and a more descriptive paragraph, using "Returns: ..." for fruitful functions, and so on. Using a consistent set of good conventions in this class will help us all.

One way to check that your specifications are written correctly is to start an interactive Python shell and type

>>> import a1
>>> help(a1)
This should list all the functions with their specifications.


Part A: Breaking Up Strings

Back to extracting currency information from a JSON string. The first step we want you to take is Conceptually, our first goal is to be able to separate the currency amount from the currency name. For example, if we are given the string

"0.814663951 Euros"
then we want to break it up into "0.814663951" and "Euros".

We guarantee that there will be no spaces in the currency amount, and that the first space will be before the currency name (though there may be later spaces in the currency name itself, such as "U.S. Dollar"). Hence we just need the following two functions. To accomplish this task, you are to write two general helper functions, which can apply to more than just strings representing currency amounts, but to any strings containing at least one space.


before_space(s)

Returns: Substring of <s> up to, but not including, the first space

Precondition: <s> has at least one space in it



after_space(s)

Returns: Substring of <s> after the first space

Precondition: <s> has at least one space in it



Implement these functions according to their specifications in the way described in the section “Instructions for the Remainder of the Assignment” above: write header and specification in a1.py; give testA in a1test.py a specification about what functions it's testing and write test cases for your functions in testA; fill in the function body in a1; test by running a1test; correct any errors and re-test until no errors remain. Your function bodies will probably have only one or two lines and use find() or index(). Your test cases should make use of assert_equals in cunittest.py. Our implementation has four test cases for each of the two functions above. When you think about what test cases you want to include, consider: does the specification allow for strings with more than one space? Strings that start with a space? Strings that don't have any spaces?

Part B: Processing a JSON String

All responses to a currency query to our web service, whether valid or invalid, contain the keywords "money_in" and "money_out". In the case of a valid currency query, the answer is in quotes after the keyword "money_out". If it is invalid, then the quotes after money_out are empty. Hence the next step is to extract the information in quotes after these keywords.

First, add the following function to a1.py. Again, do this by following the steps outlined in “Instructions for the Remainder of the Assignment”: put test cases in a1test.testB() before writing function bodies in a1.

Make sure you've appropriately specified testB().

first_inside_quotes(s)

Returns: The first substring of s between two double-quote characters

A quote character is one that is inside a string, not one that delimits it. We can use ' to delimit the string if we want to use " inside it.

Example: If s is 'A "B C" D', this function returns "B C"
Example: If s is 'A "B C" D "E F" G', this function still returns "B C" because it only picks the first such substring.

Precondition: <s> is a string with at least two double-quote characters inside.


 

Next, add the following functions. To create test cases, you will need to try out several JSON responses. To get some JSON responses for testing, enter a query URL into the web service and copy the result into a test case.


get_money_in(query)

Returns: The money_in value in the response to a currency query.

Given a JSON response to a currency query, this returns the string inside quotes (") immediately following the keyword money_in. For example, if the JSON string is

  '{money_in: "2 U.S. dollars",money_out: "1.629327902 Euros",error: "",icc: true}'
then this function returns '2 U.S. dollars' (not '"2 U.S. dollars"'). It returns the empty string if the JSON string is the result of an invalid query.

Precondition: <query> is the response to a currency query



get_money_out(query)

Returns: The money_out value in the response to a currency query.

Given a JSON response to a currency query, this returns the string inside quotes (") immediately following the keyword money_out. For example, if the JSON string is

  '{money_in: "2 U.S. dollars",money_out: "1.629327902 Euros",error: "",icc: true}'
then this function returns '1.629327902 Euros' (not '"1.629327902 Euros"'). It returns the empty string if the JSON string is the result of an invalid query.

Precondition: <query> is the response to a currency query



get_error(query)

Returns: The error value in the response to a currency query.

Given a JSON response to a currency query, this returns the string inside quotes (") immediately following the keyword error. For example, if the JSON string is

  '{money_in: "",money_out: "",error: "4",icc: false}'
then this function returns "4" (not '"4"' or the number 4). The returned string will be non-empty if a currency-conversion error occurred, for example, if invalid currency keywords were supplied in the query. It returns the empty string if the JSON string is the result of a valid query.

Precondition: <query> is the response to a currency query



You should not need a conditional statement to implement these functions; simply find the position of the appropriate keyword and extract the value in quotes immediately after it. Your implementations must use the find or index() string methods, plus the helper function first_inside_quotes() you already wrote (or a function that uses first_inside_quotes).

 


Part C: Currency Query

Now it is time to interact with the web service. In this part, you will implement a single function. The test cases should go in procedure testC() in a1test.py; don't forget to specify testC() properly.


currency_response(amount_from, currency_from, currency_to)

Returns: A JSON string that is a response to a currency query.

A currency query converts <amount_from> money in currency <currency_from> to the currency <currency_to>. The response should be a string of the form

  '{money_in: "<old-amount>",money_out: "<new-amount>",error: "",icc: true}'
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.

Preconditions: <amount_from> is of type float, while <currency_from> and <currency_to> are of type string.



While this function sounds complicated, it is actually the simplest function so far and can be implemented in two lines. You need to use the urlopen function from the module urllib2 that we saw in lab 2. Recall that this function takes a string that represents a URL and returns an object of type “instance” that represents the web page for that url. Such an object has the following methods:

Method Specification
geturl() Returns: The URL address of this web page as a string.
read() Returns: The contents of this web page as a string.

Using one or both of these methods is enough to implement the function above.


Testing

You need to ensure that the function returns exactly the right JSON string for the value given. The best way to test this is to enter a web-service URL, such as http://cs1110.cs.cornell.edu/2013sp/a1/calculator.php?q=2.5USD=?EUR , in your browser to manually get the right JSON answer and copy it into a test case in testC; then check that the function returns the same JSON string. Remember to be thorough with your choice of test cases; one is not enough.

Important:

Fetching a web page takes time, especially if too many people are trying to do so at the simultaneously. You should give each call to this function at least 10-20 seconds to complete before restarting any tests.

There is another issue if you are running the unit test with the "run button" and not from the command shell. It appears that Komodo delays all of the print statements until the unit test is complete. So you will see nothing for a while (almost a minute, if you have a lot of tests) and then you will see everything at once. This can get confusing if there are multiple outputs, for instance, if you have put in many print statements to debug your code. We recommend running this unit test from the command shell, so that you can see each print statement the second it is executed: type python a1test.py at the command prompt (not the Python command prompt).

Part D: Currency Exchange

We are now ready for the final part of the assignment. Implement the following functions according to their specification, again using our test-case-before-function-body methodology. The test cases should go in procedure testD in a1test, which you should properly specify. You may wish to use assert_true as opposed to assert_equals in some of your test cases.


iscurrency(currency)

Returns: True if <currency> is a valid 3-letter code for a currency, False otherwise

Precondition: <currency> is a string.



exchange(amount_from, currency_from, currency_to)

Returns: amount of currency received in the given exchange.

In this exchange, the user is changing <amount_from> money in currency <currency_from> to the currency <currency_to>. The value returned is a float representing the amount in currency <currencyTo>. Preconditions: <amount_from> is a float. Both <currency_from> and <currency_to> are strings that are valid three-letter currency codes.



In implementing iscurrency(currency), you should not use the table of currencies. That would make a very large function with a lot of if-statements. You are not allowed if-statements in this lab. Instead, you must use currency_response and get_error() as helper methods to implement iscurrency.


Testing

In the case of iscurrency, you will find the exchange table useful in determining correct answers for your test cases. While it is not okay to use the table in iscurrency itself, it is okay to use the table to decide on some test cases.

You may also use the table to craft some test cases for the function exchange. However, you will probably find it easier to use a currency query URL to look up the correct answer, and then paste the answer into your test case.

A bigger issue with testing exchange is that problem that we saw in class: real numbers cannot be represented exactly, which can lead to problems when trying to test equality. To solve this problem, cunittest provides a function called assert_floats_equal, which you encountered in lecture and lab. You should use this function to test exchange instead of assert_equals.

Finally, bear in mind that, like currency_response, these functions connect to the web service, and so are not instantaneous. In our solution, with complete test procedures for everything, it can take up to 10 seconds to run the unit test on campus. This will be a bit slower if you are working closer to the deadline. Again, we recommend that you run the unit test from the command shell, and via not the "run button" in Komodo Edit, so that you can see print statements as they are executed.


Finishing the Assignment

Once you have everything working, go back and make sure that your program meets the class coding conventions, including the following:

  1. There are no tabs in the file, only spaces
  2. Functions are each separated by two blank lines.
  3. Lines are short enough that horizontal scrolling is not necessary (about 80 chars is long enough). Note: if you have a long string expression of the form string1 + string2 + ... + stringk, if you put it in parentheses, you can “hit return” within the parentheses (as long as you don't do that within a string); that way your lines of code won't be over the length limit.
  4. The specifications for all of the functions, including the test procedures, are complete.
  5. Function specifications are immediately after the function header and indented.
  6. Your name(s) and netid(s) are in the comments at the top of the modules.

Turning it In

Upload the files a1.py and a1test.py to CMS by the due date: Monday, February 18th at 11:59 pm. Do not submit any files with the extension/suffix .pyc. It will help to set the preferences in your operating system so that extensions always appear.

Check the CMS daily until you get feedback from a grader. Make sure your CMS notifications for CS 1110 are set so that you are sent an email when one of your grades is changed. To find the feedback, click on the Assignment 1 link in CMS; on the page you're brought to, click on the red word “show” in the line “Grading Comments & Requests (show)&rqduo; You can contact your grader if you have questions about their feedback; you can see their netid in the place you can see their feedback.

Within 24 hours of getting feedback, do RRRRR: Read the feedback, Revise your program accordingly, Resubmit, and Request a Regrade using the CMS. If you do not request a regrade, we have no simple way of knowing that you have resubmitted.

This whole process, starting from first submission on Monday, February 18th, continues until you submit a solution that demonstrates complete mastery; in some cases this may require multiple additional resubmits by you. You need to have submitted a final, correct version by Monday, February 25th, which means you'll probably want to have re-submitted at least once before then.


Appendix: Connecting to Google

This section is not part of the assignment. It is optional. Furthermore, do not make the changes suggested in this section to the files that you submit for grading; if you do, they will be sent back to you to fix.

So far you have worked with a simulated currency exchange service. But with a few changes you can use the real thing. In the web service instructions we told you to use the URL prefix

  http://cs1110.cs.cornell.edu/2013sp/a1/calculator.php?
If you change that prefix to
  http://www.google.com/ig/calculator?
you will use Google's calculator instead. And, our server has a slightly different output format: Google uses “lhs” and “rhs” instead of money_in and money_out. You should be able to modify your code to handle the Google calculator's output format. Do so, and you can try it out on converting dollars to Euros (pick small values for now).

Run the exchange function four or five times. See the value change? That is one of the reasons we did not use Google; that is too hard to test against. In fact, even employees at Google would do what we did: write a program against an unchanging exchange service before deploying it against the real thing.

There is another reason why we are not using Google. Run currencyResponse to get the JSON string for 1000 U.S. dollars to IDR (Indonesian rupiahs). Though the numbers may be different, the rhs value of JSON string will look something roughly like this:

  rhs: "9.52380952 million Indonesian rupiahs"
Once a value gets above a million, Google "anglicizes" the number, spelling out the word "million". There is a space before "million", and so your function will give the exchange rate as 9.52380952. This is incorrect, but it is not your fault; Google violated the precondition of your functions.

Solving this second problem is beyond the scope of this assignment. We will revisit it later in the course when we have the right tools. Right now, the best that you can do is implement a new version of exchange with the following specification:

def google_exchange(amount_from, currency_from, currency_to):
    """Returns: description of currency received in exchange.

    This function connects to the Google currency converter to change
    <amount_from> money in currency <currency_from> to
    the currency <currency_to>. The value returned is string with
    the amount and name of the new currency.

    Example: "9.52380952 million Indonesian rupiahs"

    Precondition: <amount_from> is a float. Both <currency_from>
    and <currency_to> are strings with valid three-letter currency
    codes."""

Feel free to implement this function if you wish. We will not grade it, and you will not get credit for it.