We removed our free Sandbox April 25th.
You can read more on our blog.

Python

Note

CLI Command examples on this page are always provided without the --application (shorthand -A) argument, assuming you’re running these commands in a connected folder (at creation or using the dotcloud connect command). For more details on connected folders, see Migrating to the CLI 0.9.

The Python service can host any Python web application compatible with the WSGI standard.

That includes all modern Python web frameworks: Django, Pyramid, web.py, web2py, etc.

Note

For the impatient...

Your WSGI callable should be named “application”, be located in a “wsgi.py” file, itself located at the top directory of the service.

Your dependencies should be specified in a PIP-style “requirements.txt” file.

But read on for a guided tour of the service!

Basic Use

Let’s assume that you are building a dotCloud application called “ramen”. For the sake of simplicity, we will also assume that everything related to this application is located in a directory called “ramen-on-dotcloud”.

Let’s setup our environment:

mkdir ramen-on-dotcloud
cd ramen-on-dotcloud
dotcloud create ramen

A dotCloud application is described by a Build File (dotcloud.yml), which is a simple YAML file named “dotcloud.yml” located in our “ramen-on-dotcloud” directory. To add a new service to our app, we just add the following lines to “ramen-on-dotcloud/dotcloud.yml”:

www:
  type: python
  approot: hellopython

This Build File instructs the platform to use the code in the directory “hellopython” for our service. Let’s create it:

mkdir ramen-on-dotcloud/hellopython

As said above, the python service expects you to provide it with a WSGI app. So let’s write a very minimal one. Create the file “ramen-on-dotcloud/hellopython/wsgi.py” with the following content:

def application(environ, start_response):
    status = '200 OK'
    response_headers = [('Content-type', 'text/plain')]
    start_response(status, response_headers)
    return ['Hello world!\n'] + ['{0}={1}\n'.format(k,environ[k])
                                 for k in sorted(environ)]

This will not only display a “Hello world!” message, but also dump the whole WSGI environment for informative purposes.

We can now push our application to dotCloud:

dotcloud push

URLs will be generated for each web service in our application. Open your browser to see your new service in action!

If you want to attach a better URL to your application, read the Custom Domains documentation.

Internals

dotCloud python runs with Nginx as the HTTP frontend. All URLs referring to directories you defined as location aliases in your nginx.conf file will be served as static files from subdirectories in your application. Everything else will be handed to your WSGI app through uWSGI. The uWSGI workers are managed by Supervisor.

Your code dependencies are automatically handled with pip if your app ships an optional “requirements.txt” file.

Warning

The default Nginx configuration for python changed on August 22, 2012. We removed the default location definition of /static/ and so now you must define the location of static content for your application in your own nginx.conf file.

Adapting your application

dotCloud relies on well-established tools and conventions to build your app. It should be trivial to adapt any application to run on dotCloud.

Expose a WSGI application

If you wrote a WSGI application from scratch, all you have to do is to make sure that the callable is named “application” and in the “wsgi.py” file.

If you are using a framework like Django, Pylons, Web2py, and lots of others, you will want to use the WSGI handler provided by the framework.

Here are a few examples of wsgi.py files for some common frameworks:

Django

import os
os.environ['DJANGO_SETTINGS_MODULE'] = '.'
import django.core.handlers.wsgi
application = django.core.handlers.wsgi.WSGIHandler()

Tornado

import tornado.wsgi
import wsgiref.handlers
# Assuming that you defined a MainHandler class somewhere...
from mycode import MainHandler
application = tornado.wsgi.WSGIApplication([(r"/",MainHandler)])

web2py

For web2py, you should just copy or symlink wsgihandler.py to wsgi.py.

Pyramid

import os.path
from pyramid.scripts.pserve import cherrypy_server_runner
from pyramid.paster import get_app
application = get_app(os.path.join(os.path.dirname(__file__), 'production.ini'))

A more detailed WSGI file is available in the Pyramid Cookbook.

Static files

Nginx will serve your static files (e.g. images, css, javascript...) directly, bypassing the Python interpreter. To achieve this, you must move all your static files together and you must provide an nginx.conf file to tell Nginx the location(s) of the static files.

If you are using a framework like Django then you should also update your application settings so that links to static assets will point to the directory you have defined.

For example, if your static assets are in the “media” subdirectory of your application, and your code expects them to be found on the “/media” URI, you can create the following “nginx.conf” file in your approot:

location /media { root /home/dotcloud/current; }

Note

The “root” should be /home/dotcloud/current, not /home/dotcloud/current/media, because the location (/media) will be appended when looking for files.

Code dependencies

You can specify external requirements in a file called requirements.txt. A typical requirements file looks like this:

Django==1.4.3
Pil
http://jsonschema.googlecode.com/files/jsonschema-0.2a.tar.gz

This is not specific to dotCloud at all: more and more Python projects are using this style of files for their dependencies. If you want to install those dependencies in your local environment, just run “pip install -r requirements.txt”. You might also want to check “pip freeze”, which can output a requirements.txt file for you, containing the exact version numbers of all Python packages currently installed. This is very convenient to make sure that you will get the very same set of packages on different servers (e.g. dotCloud and your local development environment).

For more information on pip and the format of requirements.txt, see pip’s documentation (http://pip.openplans.org/).

Custom Nginx Configuration

You can specify custom rewrite rules (and actually almost any Nginx setting) by creating a file named nginx.conf at the top of your app.

This file will be included by Nginx.

Note

You should not include a whole Nginx configuration: just the snippets that you need!

A typical example would be:

rewrite ^/search/(.*) /engine/?q=$1 ;

Check out the Nginx wiki to see all available options.

Note

Already have some Apache mod_rewrite RewriteRule statements? All of them can be converted to Nginx configuration.

Python Versions

The Python service supports four different branches of Python (2.6, 2.7, 3.1, 3.2), it will default to Python 2.6 unless you specify otherwise. The current versions of each Python branch are listed in the table below. Pick the branch that works best for you.

branch version variable
2.6* 2.6.5 v2.6
2.7 2.7.2 v2.7
3.1 3.1.2 v3.1
3.2 3.2.2 v3.2

* Python 2.6 is the default

To configure your service to use a version of Python other than 2.6, you will set the python_version config option in your dotcloud.yml.

For example, this is what you would have if you wanted Python 2.7.x:

www:
  type: python
  config:
    python_version: v2.7

Custom uWSGI Configuration

uWSGI has a bazillion ways to configure it. The main ways are:

  1. Some special parameters can only be set in the dotcloud.yml config section
  2. via environment variables, which you can set either by:
    • dotcloud env set or
    • in the dotcloud.yml file
  3. via Nginx using ~/current/uwsgi.conf (it gets pulled into /etc/nginx/sites-enabled/default)

uWSGI config via a config section

You can modify the following uWSGI options in the config section of "dotcloud.yml":

  • uwsgi_processes: integer, the number of workers to spawn (the default is 4);
  • uwsgi_memory_report: if set to true, this will log each request with information about the memory usage (the default is false);
  • uwsgi_buffer_size: set (in bytes) the size of the buffer used to parse uwsgi packets. The default value is 4096 but you will need to increase it if you have requests with large headers;
  • uwsgi_harakiri: every request that takes longer than the seconds specified in the harakiri timeout will be dropped and the corresponding worker recycled;
  • uwsgi_enable_threads: (default false) Enable threads, this will allow you to spawn threads in your app;
  • uwsgi_single_interpreter: (default false) Python has the concept of “multiple interpreters”. This allows it to isolate apps living in the same process. If you do not want this kind of feature use this option.

Here is an example:

www:
  type: python
  config:
    uwsgi_memory_report: true
    uwsgi_buffer_size: 8192
    uwsgi_harakiri: 75
    uwsgi_enable_threads: true
    uwsgi_single_interpreter: true

Warning

The config dictionary of a service is applied when your service is launched for the first time. If you change it, you will need to destroy the concerned service and push your application again to apply the changes.

uWSGI Config via Environment Variables

Remember when you use environement variables that you must start them with UWSGI_ and change any hyphens (“-”) into underscores (“_”) (uWSGI docs). There are two ways to set environment variables:

  1. the dotcloud.yml environment section,
  2. using dotcloud env set

Using the dotcloud.yml environment section lets you set the parameters on a per-service basis. If you set the environment variables via dotcloud env then they will apply to all your services (so all your Python/uWSGI services would be affected).

uWSGI Config via Nginx

You can define additional uWSGI parameters in a uwsgi.conf file at the root of your application. The Nginx wiki mentions it briefly For example:

uwsgi_param   ENVIRONMENT  prod;

New Relic

If you want to use New Relic to monitor your Python service, then you need to complete the following steps.

Config

To enable New Relic support in your Python application, set enable_newrelic to true in your dotcloud.yml config. Setting enable_newrelic to True will automatically configure uWSGI to work properly with New Relic.

Note

The New Relic client doesn’t work with Python 3 yet. If you try to use it with Python 3, your deploy will fail.

Environment Variables

The New Relic client requires some configuration information in order to work correctly. You will do this by adding some environmental variables.

  • NEW_RELIC_LICENSE_KEY: (required) Your license key as found in ‘Help Center’ of your account when you log into New Relic;
  • NEW_RELIC_APP_NAME: The name of the application you wish to report data against in the New Relic UI. If not defined the default is “Python Application”;
  • NEW_RELIC_LOG: The path to a file to be used for the agent log. If not defined then no logging will occur. Can also be set to “stdout” or “stderr” to have logging go to standard output or standard error;
  • NEW_RELIC_LOG_LEVEL: The level at which logging will be output by the agent. If not defined then defaults to “info”. Possible values, in increasing order of detail, are: “critical”, “error”, “warning”, “info” and “debug”;
  • NEW_RELIC_CONFIG_FILE: if they want a full config file, use this variable with the full path to the newrelic.ini file.

See dotCloud environment variables guide for more information about environmental variables.

Here is an example dotcloud.yml for using New Relic with all of the environment variables. It is important to note that you don’t need all of these environment variables. They are all listed here just to show you an example of them being used:

www:
  type: python
  environment:
     NEW_RELIC_LICENSE_KEY: zbc1234sjnfnsdnFAKE0KEYk3232kjnknfksdnfkw23
     NEW_RELIC_APP_NAME: dotCloud Python App
     NEW_RELIC_LOG: /var/log/supervisor/newrelic.log
     NEW_RELIC_LOG_LEVEL: info
     NEW_RELIC_CONFIG_FILE: /home/dotcloud/current/newrelic.ini
  config:
     enable_newrelic: true

Warning

The config dictionary of a service is applied when your service is launched for the first time. If you change it, you will need to destroy the concerned service and push your application again to apply the changes.

Other documentations

You might be interested by the following dotCloud tutorials:

Or third-party documentation: