Use Bottle Python framework with Google App Engine

26 Feb

Hi fellas, hope you’re already flying high with GAE and have your own Amazon product store set up after reading my previous post series on how to Set up an Amazon Book Store on Google App Engine! GAE supports a number of Python web frameworks. See what the Google App Engine site says:

” Google App Engine supports any framework written in pure Python that speaks CGI (and any WSGI-compliant framework using a CGI adaptor) ”

One such framework is ‘Bottle’. Its lightweight (literally, 72 KB only and one file has it all !). This is what ‘Bottle’ s website says:

Bottle is a fast, simple and lightweight WSGI micro web-framework for Python. It is distributed as a single file module and has no dependencies other than the Python Standard Library.

  • Routing: Requests to function-call mapping with support for clean and dynamic URLs.
  • Templates: Fast and pythonic built-in template engine and support for mako, jinja2 and cheetah templates.
  • Utilities: Convenient access to form data, file uploads, cookies, headers and other HTTP related metadata.
  • Server: Built-in HTTP development server and support for paste, fapws3, bjoern, Google App Engine, cherrypy or any other WSGI capable HTTP server.

Bottle might not be a full fledged framework like Django, Pylons etc. but I may say it is ideal for small to medium applications.

In this small article I’ll explain how to use Bottle with Google App Engine.

Lets start with the prerequisites:

  • Google App Engine and Python 2.5: Download and install Python 2.5 from here. and the GAE sdk for Python from here. It’ll be an advantage if you complete atleast the ‘Hello World’ tutorial from the docs.
  • Bottle: Get a copy of Bottle from here. You can also use ‘easy_install’ to install it in your Python installation. All we need is the ‘bottle.py’ file. Get the documentation from here: Bottle docs. It has a very good tutorial for getting started with Bottle. Though it’s not mandatory that you complete the tutorial, I’ll explain as much as possible.

Make a new folder in a location of your choice, name it ‘bottleapp’ (you can name it whatever you want, as far as you remember the path and the folder name while running the app). Put the following folders in the ‘bottleapp’ folder:
>bottleapp
>>>framework
>>>templates
>>>styles

Extract the downloaded Bottle tar archive, copy the file ‘bottle.py’ to ‘framework’. If you chose ‘easy_install’ then ‘bottle.py’ can be found in the following location:
C:\Python25\Lib\site-packages\bottle-0.8.5-py2.5.egg\
(I’m on Windows, your path depends on your OS, but it’s the same from ‘Python25’ onwards. Bottle version might differ.) Create an empty Python file and save it as ‘__init__.py’ in the ‘framework’ folder. This file allows us to import the framework as a module from the ‘framework’ folder.

Now create a config file, that is ‘app.yaml’ and save it in the root folder, i.e. bottleapp. Put the following in it:

application: my-bottle-app
version: 1
runtime: python
api_version: 1

handlers:
- url: /styles
  static_dir: styles

- url: /.*
  script: main.py

We’re naming our app as ‘my-bottle-app’. It’s version 1 of our app, uses the python runtime and GAE api_version is 1. ‘handlers’ specifies that whenever ‘styles’ is appended to the url, load the ‘styles’ folder that holds the stylesheets for our app. All the urls will be handled by ‘main.py’.

Now make a new Python file and put the following code into it:

from framework import bottle
from framework.bottle import route, template, request, error, debug
from google.appengine.ext.webapp.util import run_wsgi_app

@route('/')
def DisplayForm():
    message = 'Hello World'
    output = template('templates/home', data = message)
    return output

def main():
    debug(True)
    run_wsgi_app(bottle.default_app())

@error(403)
def Error403(code):
    return 'Get your codes right dude, you caused some error!'

@error(404)
def Error404(code):
    return 'Stop cowboy, what are you trying to find?'

if __name__=="__main__":
    main()

Save it as ‘main.py’ in the root folder i. e. bottleapp folder.
This is a very simple ‘Hello World’ example to check if everything is in place and running. Here’s what the code does:
Import the ‘Bottle’ framework from the ‘framework’ folder. Import the decorators ‘route’ and ‘error’. ‘route’ maps the urls to handlers and ‘error’ is used to handle errors like 404, 403 etc. (More on decorators, route and error). Import the modules ‘template’ – the Simple Template Engine packed along with Bottle, ‘request’ – used to handle the types of requests GET, POST, DELETE etc., ‘debug’ – used to trace and print errors so that you know where to look and correct. ‘debug’ is used only while developing the application, not on a production server.

We use the ‘route’ decorator to map the root (‘/’) url to the handler ‘DisplayForm’. So when the root url is accessed, the ‘DisplayForm’ function is called. ‘DisplayForm’ displays a simple message on the page using the ‘template’ function to render the template ‘home’ which is stored in the ‘templates’ folder. 2 ‘error’ decorators are mapped to 2 functions, one for 404 error and the other for 403. The main function runs the app.

Let’s make the ‘home’ template now. Make a new file and put the following code in it:

<html>
<body>
<h2>{{ data }}</h2>
</body>
</html>

Save this file as ‘home.tpl’ in the templates folder. ‘data’ corresponds to ‘data = message’ that we passed in template(‘templates/home’, data=message). You can pass any Python object type, string, list, dictionary, tuple etc. If you name your template as ‘page.tpl’ then you pass it without the extension as template(‘page’).

Its time to see the app in action. Run the app using ‘dev_appserver.py ‘. Visit the url http://localhost:8080/ in your browser. If you didn’t mess anything, then you should see the homepage with ‘Hello World’ written. Congrats! You have successfully used Bottle framework with GAE.

Next, we see how to use requests for form processing with Bottle.
Modify the main.py file, and add the following code to the DisplayForm function:

output = template('templates/home')
return output

Notice we don’t pass a data variable to the template function, because we just want to display a page with a form when the root url is visited. Now modify the ‘home’ template and replace everything with the following:

<html>
<head>
	<link type='text/css' rel='stylesheet' href='/styles/styles.css' /> 
</head>
<body>
<div id='wrap'>
<form action='/save' method='POST'>
	Name:<br /> <input type='text' name='name' /> <br />
	Gender:<br /> <select name='gender'>
					<option value='male'>Male</option>
					<option value='female'>Female</option>
				</select>
			<br />
	Age:<br /> <input type='text' name='age' > <br />
	Address:<br /> <textarea name='add'></textarea> <br />

	<input type='submit' value='Save' />
</form>
</div>
</body>
</html>

Save the file, and try visiting the root url now. You should see a form displayed. We’ve set the form method to ‘POST’. The action is set to ‘/save’. That means ‘save’ will be appended to the root url when the form is submitted with some data. Don’t submit it yet, we need to handle this new url with a ‘route’ mapping.

Add a new function to ‘main.py’ :

 
@route('/save', method='POST')
def ProcessForm():
    name = request.POST.get('name', '').strip()
    gender = request.POST.get('gender', '').strip()
    age = request.POST.get('age', '').strip()
    address = request.POST.get('add', '').strip()

    values = {'name':name, 'gender':gender, 'age':age, 'address':address}

    return template('templates/data', data = values)

We’re mapping ‘/save’ to the ‘ProcessForm’ handler. The method is set to ‘POST’. You can change it to ‘GET’ if you’ve set the form method to GET. Inside this handler, we’re getting the values of the form fields. name = request.POST.get(‘name’, ”).strip(), gets the value of the text field which has the name ‘name’, similarly for the select ‘gender’, fields ‘age’ and ‘address’.
We combine these values in a Python dictionary object ‘values’ and pass it to the template function for rendering on the template. This time we use a new template, ‘data’.

Here’s the ‘data’ template:

<html>
<head>
	<link type='text/css' rel='stylesheet' href='/styles/styles.css' /> 
</head>
<body>
<div id='wrap'>
<p>Hello {{ data['name'] }}</p>
<p> Your Data: </p>
%if data['gender']=='male':
	<p>Mr. {{data['name']}}</p>
%elif data['gender'] == 'female':
	<p>Ms./Mrs. {{data['name']}}</p>
%end
<p>{{ data['age'] }}</p>
<p>{{ data['address'] }}</p>
</div>
</body>
</html>

Save this as ‘data.tpl’ in the ‘templates’ folder. There’s a lot’s of template specific code in this. {{ data[‘name’] }} outputs the variable name directly. Python code is written with a preceding ‘%’ sign. Every block should have a corresponding ‘%end’ tag. No need to worry about indentation, it’s taken care of internally by Bottle.

Run the application again, and visit the root url http://localhost:8080/, fill in the details, and click ‘Save’. You should see the data page with the data values you entered in the form.

Here’s the last thing we need, a stylesheet to make our application look good ! Make a new file and add the following styles to it:

body{ background-color: beige; }
#wrap{ border:1px solid green; height: 230px; width:300px; padding: 20px;}

Save this as ‘styles.css’ in the ‘styles’ folder. Reload the browser and now you have a styled application !
Congrats again for your new Google App Engine application using ‘Bottle’ Python framework! Jump to the Bottle documentation for learning the framework more neatly. Any doubts, queries or improvements, contact me: mail@rutwick.com, @tweetrut.

36 Responses to “Use Bottle Python framework with Google App Engine”