Deploying a Pyramid App on AppFog

August 28, 2012

Last July, AppFog revealed it's official plans, which include a free plan that comes with 2GB of RAM. I then decided to give it a try and move a Pyramid app that I had running on a VPS for about a year. The app uses Python 2.7, PostgreSQL, Pyramid 1.3.2 and SQLAlchemy 0.7.8.

On the VPS, the app was running using Waitress behind nginx.

I had to make some minor modifications to the code to make it run on AppFog, which were not really documented anywhere. I decided to post it here, in the hope someone finds it when needed.

Configuration File

First of all, I created a new configuration file. I named it appfog.ini, but name it whatever you like. I removed the key sqlalchemy.url, since it is set in environment variables by AppFog. Also, for the app to know that it has to retreive the environment variables instead of using sqlalchemy.url, I added the key/value appfog = true.

SQLAlchemy Connection

In main function of __init__.py, I replaced the line where the engine is created from the configuration file to take into account that the connection information could come from environment variables. So I replaced:

engine = engine_from_config(settings, 'sqlalchemy.')

with:

if settings.get('appfog') == 'true':
engine = appfog_engine(settings)
else:
from sqlalchemy import engine_from_config
engine = engine_from_config(settings, 'sqlalchemy.')

And I defined appfog_engine later in the same file:

def appfog_engine(settings):
from sqlalchemy import create_engine
import os, json
all_config = json.loads(os.getenv("VCAP_SERVICES"))
config = all_config['postgresql-9.1'][0]['credentials']
connection_string = ('postgresql+psycopg2://%(username)s:%(password)s'
'@%(host)s:%(port)d/%(name)s')
engine = create_engine(connection_string % config)
return engine

Requirements

Like when you deploy on Heroku, you have to provide a requirements.txt file, that you generate by running:

$ pip freeze > requirements.txt

WSGI App

You then have to create a wsgi.py file that you place at the root of your project, beside setup.py and appfog.ini. In wsgi.py, you put:

import os
from paste.deploy import loadapp

os.system("python setup.py develop")
path = os.getcwd()
application = loadapp('config:appfog.ini', relative_to=path)

That's It

Your app is ready to upload using the regular instructions, using the af commmand line tool provided by AppFog.

Useful Stuff

Since my app was already in production for about a year, I had data in my PostgreSQL database that I had to migrate from my server to AppFog. One nice feature they provide is the ability to make a tunnel to your services. You can find the doc here. With the help of the tunnel, it was easy to use pg_dump and psql to migrate the database.

Generating Country List For HTML Select

December 13, 2011

During a client project using Paypal DirectPayment API, I had to make a <select> with all the countries with their country codes as the value. For example:

<option value="US">United States</option>
<option value="CA">Canada</option>

Paypal already gives this list.

Problem is that it's only in English and all in caps. What I needed is a French version and an English version, not in caps.

Geonames.org just happens to have what I needed. This Python script is what I coded to generate what I needed:

import urllib, json, unicodedata

def get_list(username='demo', lang='en'):
"""Fetches the json of all countries from geonames.org."""
params = urllib.urlencode({'lang': lang, 'username': username})
url = 'http://api.geonames.org/countryInfoJSON?%s' % params
f = urllib.urlopen(url)
response_text = f.read()
return json.loads(response_text)["geonames"]

def country_list_generator(country_list, func):
"""Returns a generator of countries.
They are sorted alphabetically,
and the func passed as argument is applied to each of them."""
ordered = sorted(country_list,
key=lambda k: strip_accents(k['countryName']))
return (func(country) for country in ordered)

def country_to_option(country):
"""Transforms a country dict to an html option tag,
The country code is used for the value."""
return ('<option value="%s">%s</option>\n' % \
(country['countryCode'], country['countryName'])).encode('utf-8')

def country_to_csharp_dict_pair(country):
"""Transforms a country dict to a C# Dictionary pair."""
return ('{"%s", "%s"},\n' % \
(country['countryCode'], country['countryName'])).encode('utf-8')

def strip_accents(s):
"""Removes the accents from a unicode string.
This function is used for sorting."""
return ''.join((c for c in unicodedata.normalize('NFD', s) \
if unicodedata.category(c) != 'Mn'))

if __name__ == '__main__':
country_list = get_list('demo', lang='en')
with open('output.txt', 'w') as f:
gen = country_list_generator(country_list, country_to_option)
f.writelines(gen)

Hope it's useful to someone else.

The code is on Github.

Styling Google Maps

August 29, 2011

It seems to be a little known fact that you can add custom styles to Google Maps using the Javascript API.

It's really not that complex and we use it often for client sites.

First thing to do is create the JSON to use for the style. You can use this wizard, it's a great tool for that.

Then you use the JSON in your Javascript like so:

// your JSON
var mapStyle = [
{
featureType: "landscape",
elementType: "all",
stylers: [
{ hue: "#ff4d00" },
{ lightness: -72 },
{ saturation: -74 }
]
}
];

// usual Google Maps code, plus styling
var map;

$(function () {
var mapOptions = {
zoom: 12,
mapTypeId: 'MapStyle',
mapTypeControlOptions: {
mapTypeIds: ['MapStyle', google.maps.MapTypeId.SATELLITE]
}
};

var styledMapOptions = { name: "Map" };

map = new google.maps.Map(document.getElementById("styled-maps-example-1"), mapOptions);
map.setCenter(new google.maps.LatLng(46.8,-71.25));
var mapType = new google.maps.StyledMapType(mapStyle, styledMapOptions);
map.mapTypes.set('MapStyle', mapType);
map.setMapTypeId('MapStyle');
});

It's even in the docs. I don't see any reason why there's so little use of this feature.