These notes are available (in colour) online at: http://goo.gl/Cr7Ev

App Engine

Introduction

App Engine (http://code.google.com/appengine/) is a service provided by Google that enables anyone to upload and run web applications on Google’s servers. You can build your App Engine app with Python, and the SDK (or "Software Development Kit") comes with a nifty little webserver that you can use to test your applications on your home computer!

Today we're going to use the data from the xkcd colour name survey (http://blog.xkcd.com/2010/05/03/color-survey-results/) to build a fun search engine for colours.

Getting Started

  1. Download and install the App Engine SDK: http://code.google.com/appengine/downloads.html#Google_App_Engine_SDK_for_Python

NOTE: Due to permission restrictions, you will need to install the SDK somewhere else (try C:\Documents and Settings\demo00\google_appengine or similar).

  1. Run the Google App Engine Launcher, and select Create New Application from the File menu. Give your application a name, and specify a location for it in your home directory (this location must already exist).


  1. If you click the green Run button, the launcher will start the local webserver for you. Do that now and leave it running. If you go to the address http://localhost:8000 in your browser, you should see a friendly message from your app.

     If http://localhost:8000 isn’t working, try 127.0.0.1:8000.

Task 1:

Set up app engine and have a working “Hello world!” app before you move on.


Behind the Scenes

The App Engine launcher has created three files for you: app.yaml, index.yaml and main.py. The first two are configuration files (we won’t deal with them much today) main.py will contain our application code.

Open main.py in your favourite text editor (I suggest Notepad++ if you're using Windows.) You should see something like this: 


from google.appengine.ext import webapp
from google.appengine.ext.webapp import util

class MainHandler(webapp.RequestHandler):
        def get(self):
          
 self.response.out.write('Hello world!')

application = webapp.WSGIApplication([('/', MainHandler)],
                                             debug=True)

def main():
        util.run_wsgi_app(application)

if __name__ == '__main__':
        main()


For the moment, we are interested in only two sections, highlighted above.

The Python list highlighted in blue is a list of tuples, mapping urls to Python classes. When a user of your webapp tries to access the root URL (e.g. http://localhost:8000/), the app engine webserver will respond by calling the get method of the MainHandler class.

In the example above, the get method writes "Hello world!", and this is what is eventually returned to the browser.

Usually a web server returns html rather than just plain text, and for that we need these:


<!DOCTYPE html>

<html>

     <body>

          <p> Hello World! </p>

     </body>

</html>


Task 2:

Change the app so that it writes html and make “Hello world!” bold instead of plain text.


Hello, name!

It's a nice start, but our webapp seems a little unfriendly and impersonal, kind of like a computer. Let's add some HTML code for a form so that we can greet our users by name. This will give them the impression we care, and encourage them to keep coming back to our site.

Here is what the modified get method should look like, more or less:


        def get(self):
            username = self.request.get('username')


            html = """<html>

<body>

<form action="/" method="get">
        What is your name?

<input type="text" name="username">

<input type="submit">
</form> """


            html += "<p>Hello, " + username + "</p>"
            html += "</body></html>"
            self.response.out.write(html)


It uses self.request.get('username') to retrieve whatever was typed by the user into the text box. If the user did not type anything, then App Engine will automatically set the username variable to be an empty string.

This code looks a little weird because there’s a long string in the middle, and the stuff inside the string doesn’t have to be indented. As you can see it gets a bit messy trying to have chunks of html inside a python file.

Task 3:

Make your app say Hello to the name entered in the text box.


Using Templates

As you can see from your Hello, name app, having html code and python in the same file can get very mess. App Engine lets us write our websites in HTML, and leave special place holders to be filled in using values from a dictionary.  

Copy the following template into a new file (call it template.html).


<html>
 <body>
   <form action="/" method="get">

      What is your name?

      <input type="text" name="username">
     <input type="submit">
   </form>
   <p>Hello,
{{ username }}</p>
 </body>
</html>


When we render the template, all of the parts in double squiggly brackets {{ }} (highlighted yellow) will be replaced with values from the dictionary python program. This means that we need a dictionary in the python which is something like this: {“username”: “georgina”}

So now we have to fill in the value in the Python program:

You’ll need to import the template module: (at the top with the other imports)

from google.appengine.ext.webapp import template

Replace the contents of the get method of the MainHandler class with the following code:


def get(self):
            username = self.request.get('username')
            template_values = {"username" : username}
            self.response.out.write(

template.render("template.html",template_values))


See! Now that’s much cleaner, and easier to work with. :)

Task 4:

Once you’ve set up the templates, refresh your page and make sure it works like before.


Loading the colour data

Although most web browsers recognise a small number of colour names (e.g. "blue", "red", "black", "magenta"), most web designers specify the colours they want their website to use using hexadecimal colour codes: http://en.wikipedia.org/wiki/Web_colors E.g., white is #FFFFFF, black is #000000, and #e2ca76 is a kind of sandy colour. You might not be surprised to hear that if you try and tell a web browser you want "something sandy, light, but not too light", it's probably not going to know what you mean. This is where our search engine comes in. We're going to take thisx list of colour names and hex values: http://xkcd.com/color/rgb.txt, which looks like this: 


cloudy blue #acc2d9

dark pastel green #56ae57

dust #b2996e 

electric lime #a8ff04

...


(but much much longer, there's 974 of them), and let users search by name for a colour, displaying any that match.

Reading the colour file

First, we need to load the text file into Python. What Python data structure is perfect for storing the mapping from colour name to hex value for each line of the file?

  1. Save the file rgb.txt into the same folder as your webapp.
  2. Copy the following function into the top of your main.py file (after the import statements, before the MainHandler class.

def get_colours():
        colours = {}
        for line in open('rgb.txt','rU'):
            name, hexvalue = line.strip().split('\t')
            colours[name] = hexvalue
        return colours


  1. Add a line to the MainHandler get function that calls this function, e.g.:

colours = get_colours()

Task 5:

Add {{ colours }} to your template (anywhere) and add the colours list to your template dictionary. See the (huge!) list of colours it prints out when you look at your page.


A table of colours!

At the moment, the information is there but it’s difficult to read, and there are no pretty colours! Now we are going to see another advantage of templates -- they can have loops!

In your template.html file, add the following code snippet somewhere in the <body>:



<table align="center" width="60%”

<tr>

<th>Name</th>

<th width="70%">Colour</th>

<th>Hex value</th>

</tr>

{% for colour in colours.items %}

<tr>

<td><a href="./?hexcode={{ colour.1 }}">

{{ colour.0 }}</a>

</td>

<td style="background:{{ colour.1 }}"></td>

<td>{{ colour.1 }}</td>

</tr>

{% endfor %}

</table>


Back in main.py, add "results" to the dictionary we pass to the template renderer:


template_values = {"username": username, "colours” : colours}


Task 6:

Use the template html to create a whole table of pretty (and not-so-pretty) colours!


And the final step

This is where you must combine all the skills from the previous tasks.

E.g. I could search for “blue” and it would find all of the colours with ‘blue’ in the name and show only them in the table we created before.

Task 7:

Add a search form with the ability to search for colours by name.

Extensions: