CherryPy Project Download

Wikipedia describes Comet as, "a neologism to describe a web application model in which a long-held HTTP request allows a web server to push data to a browser, without the browser explicitly requesting it.". In other words, Comet is that asynchronous Javascript mojo you need to build really fancy AJAX applications.

The following code demonstrates how to write a Comet application using CherryPy and jQuery. It is a web interface into the console ping command. The ping command was chosen for this example because it will run indefinitely if given no arguments. Executing never-ending commands is usually a big no-no when it comes to web application programming but with CherryPy we can handle this quite easily:

#!/usr/bin/env python
# -*- coding: utf-8 -*-
import os, signal
from subprocess import Popen, PIPE
# string.Template requires Python 2.6+
from string import Template

import cherrypy

__author__ = 'Dan McDougall <>'
# Thanks to joshthecoder for the pid-in-session bit

# Trying to cut down on long lines...
jquery_url = ''
jquery_ui_url = ''
jquery_ui_css_url = \

class Comet(object):
    """An example of using CherryPy for Comet-style asynchronous communication"""
    def index(self):
        """Return a basic HTML page with a ping form, a kill form, and an iframe"""
        # Note: Dollar signs in string.Template are escaped by using two ($$)
        html = """\
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "">
<html xmlns="" lang="en">
    <link rel="stylesheet" type="text/css" href="${jquery_ui_css_url}" media="screen" />
    <script type="text/javascript" src="${jquery_url}"></script>
    <script type="text/javascript" src="${jquery_ui_url}"></script>
    .fg-button {
    outline: 0;
    clear: left;
    margin:0 4px 0 0;
    padding: .1em .5em;
    text-decoration:none !important;
    position: relative;
    text-align: center;
    zoom: 1;
    .fg-button .ui-icon {
    position: absolute;
    top: 50%;
    margin-top: -8px;
    left: 50%;
    margin-left: -8px;
    a.fg-button { float:left;  }
    .terminal {
    position: relative;
    top: 0;
    left: 0;
    display: block;
    font-family: monospace;
    white-space: pre;
    width: 100%; height: 30em;
    border: none;
  <script type="text/javascript">
        $$('#kill_ping').click(function() {
                url: "/kill_proc",
                cache: false,
                success: function(html){
            return false;
  <h3>CherryPy Comet Example</h3>
  <form id="ping_form" target="console_iframe" method="post" action="/ping">
  <input type="text" id="host" name="host" size="18" />
  <button id="ping" class="fg-button ui-state-default ui-corner-all" type="submit">
  <form id="kill_form" method="post" action="/kill_proc">
  <button id="kill_ping" class="fg-button ui-state-default ui-corner-all"
  title="Click to stop to the ping (sends SIGINT)" type="submit">
  <div id="result" class="ui-state-highlight">
  <span class="ui-icon ui-icon-check ui-icon-left" style="margin-right: .3em;">
  <iframe name="console_iframe" class="terminal" />  
        t = Template(html)
        page = t.substitute(
        return page

    def ping(self, host, **kw):
        """Execute, 'ping <host>' and stream the output"""
        # Escape the host parameter (prevents things like "; rm -rf *")
        host = "'" + host.replace("'", "'\\''") + "'"
        command = "ping %s" % host
        # This javascript just scrolls the iframe to the bottom
        scroll_to_bottom = '<script type="text/javascript">window.scrollBy(0,50);</script>'
        process = Popen(command, shell=True, stdout=PIPE, stderr=PIPE,
                        close_fds=True, preexec_fn=os.setsid)
        # Save the pid in the user's session (a thread-safe place)
        cherrypy.session['pid'] =
        def run_command():
            # The yeilds here are the key to keeping things streaming
            yield '<style>body {font-family: monospace;}</style>'
            while not process.poll(): # While the process is still running...
                out = # Read it's output a character at a time
                if out == '\n': # Since we're not using text/plain we need line break tags
                    out = "\n<br />%s" % scroll_to_bottom # include the iframe scroll fix
                yield out # Stream it to the browser
            # Now write out anything left in the buffer...
            out = ""
            for char in
                if char == "\n":
                    out += "\n<br />%s" % scroll_to_bottom
                    out += char
            yield out
        return run_command()
    # Enable streaming for the ping method.  Without this it won't work.
    ping._cp_config = {'': True}

    def kill_proc(self, **kw):
        """Kill the process associated with the pid in our session."""
        pid = cherrypy.session.get('pid')
        if not pid:
            return "No active process to kill"
        # Without SIGINT we don't get the final summary from the ping command
        # emulates control-C (SIGKILL or SIGTERM would just end the process with no summary)
        os.killpg(pid, signal.SIGINT)
        return "<strong>Success:</strong> The ping process was killed successfully."

    'tools.sessions.on': True,
cherrypy.tree.mount(Comet(), config=None)

Hosted by WebFaction

Log in as guest/cherrypy to create/edit wiki pages