Блог экспериментатора инженера-разработчика: Infanty.
Я пишу how-to статьи на редкие темы или статьи обзоры - для себя и тех кто со мной работает.
Блог существует при поддержке: "Оккупационных сил Марса".

CherryPy — объектно-ориентированный веб-фреймворк, написанный на языке программирования Python. Спроектирован для быстрой разработки веб-приложений для сети Интернет. Представляет собой надстройку над HTTP-протоколом, но остаётся на низком уровне и не выходит за рамки требований RFC 2616. Может выступать в качестве самостоятельного веб-сервера или работать под управлением другого серверного приложения, поддерживающего протокол WSGI.

Но мало кто знает как запустить этот маленький и быстрый фреймворк используя uWSGI, без использования встроенного WSGI сервера.

Вариант 1: менее правильный

Для начала создадим файл cherrypy_uwsgi.py содержащий:

  • два (для примера) приложения CherryPy;
  • функцию именованную по спецификации PEP-3333;
  • в функции зарегистрируем пути (URL) для приложений CherryPy;
  • после чего передадим управление CherryPy для обработки запросов к зарегистрированным URL.
import cherrypy

# CherryPy applications.
class One:
  @cherrypy.expose
  def index(self):
    r = cherrypy.response
    r.headers['Content-Type'] = 'text/plain'
    return "Hello World" 

# CherryPy applications.
class Two:
  @cherrypy.expose
  def default(self, *args, **kwargs):
    r = cherrypy.response
    r.headers['Content-Type'] = 'text/plain'
    content = "Positional arguments\n\n"
    for k in args:
      content += k + "\n"
    content += "\nKeyword arguments\n\n"
    for k in kwargs:
      content += k + ": " + kwargs[k] + "\n"
    return content

# Defined function named as specified in the PEP-3333.
def application(environ, start_response):
  # Application "One" at mount point: "/".
  cherrypy.tree.mount(One(), '/', None)
  # Application "Two" at mount point: "/cherrypy-two".
  cherrypy.tree.mount(Two(), '/cherrypy-two', None)
  # Is transfers control to CherryPy.
  # "cherrypy.tree" is a WSGI compatible application.
  return cherrypy.tree(environ, start_response) 

После чего исправляем конфиг uWSGI описанный в статье: Веб-интерфейс для Python в Ubuntu используя Nginx и uWSGI. В файле "uwsgiapp.ini" расположенном в папке "/home/example.com" удаляем строки:

mount = /testuwsgiapp=wsgi.py
manage-script-name = true 

и добавляем строку с именем файла содержащего приложения CherryPy:

wsgi-file = cherrypy_uwsgi.py 

После чего перезапустим uWSGI:

sudo stop uwsgiapp
sudo start uwsgiapp 

И проверим работу приложения, набрав в браузере URL: "http://example.com/" и "http://example.com/cherrypy-two".

Вариант 2.1: более правильный

В этом варианте также создадим файл cherrypy_uwsgi.py следующего содержания:

import cherrypy

class Root(object):
    @cherrypy.expose
    def index(self):
        return "hello world"
		
# Disable monitor which re-executes the process when files change.
cherrypy.config.update({'engine.autoreload.on': False})
# Disable the built-in HTTP server since it will not be used.
cherrypy.server.unsubscribe()
# Start the CherryPy’s engine.
cherrypy.engine.start()

# Create WSGI app from the CherryPy application.
wsgiapp = cherrypy.tree.mount(Root()) 

После чего исправляем конфиг uWSGI как в варианте 1. Кроме того при редактировании файла "uwsgiapp.ini" добавим дополнительные строки для запуска приложения:

# WSGI app from the CherryPy application to 
# receive requests from uWSGI.
callable = wsgiapp 

Вариант 2.2: дополнительный

Рассмотрим другой возможный вариант содержимого файла cherrypy_uwsgi.py реализующего урок из документации CherryPy: "Tutorial 5 - Track my end-user’s activity". В нём не только показана регистрацая нескольких путей (URL) на сайте, но и работа с формой, сессией (папка: "/home/session" должна существавать с правами на запись) и конфигурацией CherryPy:

import random
import string

import cherrypy

class StringGenerator(object):
    @cherrypy.expose
    def index(self):
        return """<html>
          <head></head>
          <body>
            <form method="get" action="generate">
              <input type="text" value="8" name="length" />
              <button type="submit">Give it now!</button>
            </form>
          </body>
        </html>"""

    @cherrypy.expose
    def generate(self, length=8):
        some_string = ''.join(random.sample(string.hexdigits, int(length)))
        cherrypy.session['mystring'] = some_string
        return some_string
        
    @cherrypy.expose
    def display(self):
        return cherrypy.session['mystring']
         
# Disable monitor which re-executes the process when files change.
cherrypy.config.update({'engine.autoreload.on': False})
# Disable the built-in HTTP server since it will not be used.
cherrypy.server.unsubscribe()
# Start the CherryPy’s engine.
cherrypy.engine.start()

conf = {
    '/': {
        'tools.sessions.on': True,
        'tools.sessions.storage_type': "file",
        'tools.sessions.storage_path': "/home/session"
    }
}

# Create WSGI app from the CherryPy application.
wsgiapp = cherrypy.tree.mount(StringGenerator(), '/', conf)