Note
See Heroku Buildpack for an alternative way to deploy Python (and PyPy) applications.
All Python applications deployed to Stackato are, by default, run with WSGI. Applications are started from a top-level script called wsgi.py defining a global application variable containing the WSGI application object. For a minimal sample application, see wsgi-helloworld.
By default, Python applications are served through uWSGI. You may add additional arguments to uWSGI in your stackato.yml, eg:
processes:
web: $STACKATO_UWSGI --mount foo=app.py --import module
It is possible to serve static files with uWSGI.
Some applications require the user to specify the APP_URL. Below is an example on how to obtain the correct urls:
import json
vcap_app = json.loads(os.environ['VCAP_APPLICATION'])
APP_URL = 'http://' + vcap_app['uris'][0]
Some minor edits are required to make your application work with a database. Python database configurations are located inside settings.py.
Authentication details for your configured database services can be found in the os.environ variable, under DATABASE_URL. Here is an example of getting the correct credentials.
import urlparse
DATABASES = {}
if 'DATABASE_URL' in os.environ:
url = urlparse.urlparse(os.environ['DATABASE_URL'])
DATABASES['default'] = {
'NAME': url.path[1:],
'USER': url.username,
'PASSWORD': url.password,
'HOST': url.hostname,
'PORT': url.port,
}
if url.scheme == 'postgres':
DATABASES['default']['ENGINE'] = 'django.db.backends.postgresql_psycopg2'
elif url.scheme == 'mysql':
DATABASES['default']['ENGINE'] = 'django.db.backends.mysql'
else:
DATABASES['default'] = {
'ENGINE': 'django.db.backends.sqlite3', # Add 'postgresql_psycopg2', 'postgresql', 'mysql', 'sqlite3' or 'oracle'.
'NAME': 'dev.db', # Or path to database file if using sqlite3.
'USER': '', # Not used with sqlite3.
'PASSWORD': '', # Not used with sqlite3.
'HOST': '', # Set to empty string for localhost. Not used with sqlite3.
'PORT': '', # Set to empty string for default. Not used with sqlite3.
}
import json
vcap_services = json.loads(os.environ['VCAP_SERVICES'])
srv = vcap_services['mysql'][0]
cred = srv['credentials']
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'NAME': cred['name'],
'USER': cred['user'],
'PASSWORD': cred['password'],
'HOST': cred['hostname'],
'PORT': cred['port'],
}
}
Non-HTTP apps that run as a Stackato application under the control of the Health Manager.
To deploy worker applications, you need to use the command key and set the proceses: web key to Null ("~").
name: python-app
framework:
type: python
runtime: python27
command: python worker.py
processes:
web: ~
It is possible to serve static files with uWSGI using processes: web: in the stackato.yml file to specify folders that will be served statically and not by the app.
To make a single folder serve statically, use --check-static:
processes:
web: $STACKATO_UWSGI --check-static $HOME/<folder>
To specify multiple folders with static files that do not share a common root, use --static-map:
processes:
web: $STACKATO_UWSGI --static-map /foo=$HOME/static --static-map /bar=$HOME/sub
In this case /foo/index.html would serve $HOME/static/index.html, and /bar/index.html would serve $HOME/sub/index.html. If the file doesn't exist, then uWSGI will forward the request to the app.
Note
Serving static files via uWSGI is only available for Perl and Python frameworks.
To use a different web server, instead of uWSGI, specify its startup command in stackato.yml. Here's a sample stackato.yml used to deploy a Django 1.4 application named "dj14" using gunicorn:
name: dj14
framework:
type: python
processes:
web: gunicorn -b 0.0.0.0:$PORT dj14.wsgi
requirements:
pypm: [gunicorn]
pip: ["http://www.djangoproject.com/download/1.4-beta-1/tarball/#egg=django-1.4b1"]
The custom web server must bind to IP address 0.0.0.0 and port $PORT. The same trick can be used to serve non-WSGI applications (such as Tornado). See the bottle-py3 example sample for an example.
Note
To install packages from custom repository/mirror. Use the PIP_OPTS or PYPM_OPTS environment variables.
Application dependencies such as web frameworks or modules from PyPI can be installed using PyPM and/or pip.
Definition PyPM
To install packages during application deployment with PyPM, add the requirements to stackato.yml:
requirements:
pypm:
- tornado
- pymongo
See the stackato.yml of tornado-chat-mongo sample app for an example.
Alternatively, you can list the modules in a top-level requirements-pypm.txt file. The format is similar, if not same, as pip requirements files and accepts version specification. The name of this file can be overriden by setting the PYPM_REQUIREMENTS_FILE environment variable.
Definition pip
In addition - or as alternative - to PyPM, your application can also make use of pip to install certain dependencies. The above tornado-chat-mongo sample installs "pycurl" using pip:
requirements:
pypm:
- tornado
- pymongo
pip:
- pycurl
If your application already contains a requirements.txt file, that will be automatically used to install dependencies; no need to specify them manually in stackato.yml. The name of this file can be overriden by setting the PIP_REQUIREMENTS_FILE environment variable.
Note
A bug in pip may prevent the log file from being accessed by stackato logs.
To speed up deployment, utilize Asset Caching to store resources downloaded by PyPM and pip. See Caching Staging Assets for more details.
Here is an example of pushing an app using PyPy.
First, clone the https://github.com/Stackato-Apps/werkzeug-debugger repository.
Then add the following BUILDPACK_URL to the stackato.yml file:
env:
BUILDPACK_URL: git://github.com/ActiveState/heroku-buildpack-pypy.git
Finally, push the app to Stackato:
$ stackato push -n
Examples of deploying other frameworks are included in the GitHub samples repo: