Browse Source

Merge pull request #1583 from TechEmpower/python-webware

Python: Add webware
Hamilton Turner 10 years ago
parent
commit
8bc36c9411
27 changed files with 546 additions and 0 deletions
  1. 1 0
      .travis.yml
  2. 0 0
      frameworks/Python/historical/README.md
  3. 27 0
      frameworks/Python/historical/benchmark_config.json
  4. 18 0
      frameworks/Python/historical/install.sh
  5. 1 0
      frameworks/Python/historical/webware/.gitignore
  6. 6 0
      frameworks/Python/historical/webware/app/.cvsignore
  7. 27 0
      frameworks/Python/historical/webware/app/AppServer
  8. 27 0
      frameworks/Python/historical/webware/app/Configs/AppServer.config
  9. 6 0
      frameworks/Python/historical/webware/app/Configs/Application.config
  10. 2 0
      frameworks/Python/historical/webware/app/Context/.cvsignore
  11. 15 0
      frameworks/Python/historical/webware/app/Context/DbSession.py
  12. 14 0
      frameworks/Python/historical/webware/app/Context/Fortune.py
  13. 10 0
      frameworks/Python/historical/webware/app/Context/UrlHelper.py
  14. 13 0
      frameworks/Python/historical/webware/app/Context/World.py
  15. 16 0
      frameworks/Python/historical/webware/app/Context/db.py
  16. 23 0
      frameworks/Python/historical/webware/app/Context/fortune.py
  17. 11 0
      frameworks/Python/historical/webware/app/Context/json2.py
  18. 10 0
      frameworks/Python/historical/webware/app/Context/plaintext.py
  19. 20 0
      frameworks/Python/historical/webware/app/Context/queries.py
  20. 26 0
      frameworks/Python/historical/webware/app/Context/updates.py
  21. 33 0
      frameworks/Python/historical/webware/app/Launch.py
  22. 55 0
      frameworks/Python/historical/webware/app/WebKit.cgi
  23. 1 0
      frameworks/Python/historical/webware/app/adapter.address
  24. 1 0
      frameworks/Python/historical/webware/app/http.address
  25. 171 0
      frameworks/Python/historical/webware/app/webkit
  26. 3 0
      frameworks/Python/historical/webware/requirements.txt
  27. 9 0
      frameworks/Python/historical/webware/setup.sh

+ 1 - 0
.travis.yml

@@ -126,6 +126,7 @@ env:
     - "TESTDIR=Python/django"
     - "TESTDIR=Python/falcon"
     - "TESTDIR=Python/flask"
+    - "TESTDIR=Python/historical"
     - "TESTDIR=Python/klein"
     - "TESTDIR=Python/pyramid"
     - "TESTDIR=Python/tornado"

+ 0 - 0
frameworks/Python/historical/README.md


+ 27 - 0
frameworks/Python/historical/benchmark_config.json

@@ -0,0 +1,27 @@
+{
+  "framework": "historical",
+  "tests": [{
+    "webware": {
+      "setup_file": "webware/setup",
+      "json_url": "/json2",
+      "plaintext_url": "/plaintext",
+      "db_url": "/db",
+      "query_url": "/queries?queries=",
+      "update_url": "/updates?queries=",
+      "fortune_url": "/fortune",
+      "port": 8080,
+      "approach": "Realistic",
+      "classification": "Micro",
+      "database": "MySQL",
+      "framework": "Webware",
+      "language": "Python",
+      "orm": "Full",
+      "platform": "Apache",
+      "webserver": "None",
+      "os": "Linux",
+      "database_os": "Linux",
+      "display_name": "Webware",
+      "notes": "CPython 2.7"
+    }
+  }]
+}

+ 18 - 0
frameworks/Python/historical/install.sh

@@ -0,0 +1,18 @@
+
+export PY2_ROOT=$IROOT/py2
+export PY2=$PY2_ROOT/bin/python
+export PY2_PIP=$PY2_ROOT/bin/pip
+
+mkdir -p $IROOT/.pip_cache
+export PIP_DOWNLOAD_CACHE=$IROOT/.pip_cache
+
+fw_depends python2 apache
+
+$PY2_PIP install --install-option="--prefix=${PY2_ROOT}" -r $TROOT/webware/requirements.txt
+
+cd $TROOT/webware 
+rm -fr Webware Webware-1.1.1
+rm Webware-1.1.1.tar.gz
+wget downloads.sourceforge.net/webware/Webware-1.1.1.tar.gz
+tar -xf Webware-1.1.1.tar.gz
+cp -r app/ Webware-1.1.1/

+ 1 - 0
frameworks/Python/historical/webware/.gitignore

@@ -0,0 +1 @@
+Webware*

+ 6 - 0
frameworks/Python/historical/webware/app/.cvsignore

@@ -0,0 +1,6 @@
+*.pyc
+*.pyo
+address.*
+httpd.*
+appserverpid.*
+profile.pstats

+ 27 - 0
frameworks/Python/historical/webware/app/AppServer

@@ -0,0 +1,27 @@
+#!/bin/sh
+
+# WebKit application server launch script for Unix.
+# This wrapper script is needed for the AutoReload mechanism.
+
+# You may want to use a specific Python executable:
+PYTHON=python
+
+# You may give the following Python parameters in advance,
+# followed by the parameters passed on to ThreadedAppServer:
+#   -O with optimization (.pyo instead of .pyc)
+#   -u unbuffered output (useful for debugging)
+unset PY_OPTS
+while [ "$1" = "-O" -o "$1" = "-u" ]; do
+    PY_OPTS="$PY_OPTS $1"
+    shift
+done
+
+# Make the directory where this script lives the current directory:
+cd `dirname $0`
+
+# As long as the app server returns a 3, it wants to be restarted:
+errorlevel=3
+while [ $errorlevel -eq 3 ]; do
+    $PYTHON$PY_OPTS Launch.py ThreadedAppServer $*
+    errorlevel=$?
+done

+ 27 - 0
frameworks/Python/historical/webware/app/Configs/AppServer.config

@@ -0,0 +1,27 @@
+# AppServer.config file for Webware for Python
+
+PrintConfigAtStartUp = False
+Verbose = False # verbose output
+
+PlugInDirs = [WebwarePath] # load all Webware plug-ins
+PlugIns = [] # use this if you want to load specific plug-ins only
+
+# This is the IP address at which the application server will listen:
+Host = 'localhost' # use '' for listening on all network interfaces
+
+EnableAdapter = True # enable WebKit adapter
+AdapterPort = 8086
+
+EnableHTTP = True # enable built-in Webserver
+HTTPPort = 8080
+
+# The initial, minimum and maxium number of worker threads:
+StartServerThreads = 10
+MinServerThreads = 5
+MaxServerThreads = 20
+
+# The maximum execution time for AppServer requests:
+MaxRequestTime = 300 # specified in seconds
+
+# You can activate auto reloading on source changes here:
+AutoReload = True

+ 6 - 0
frameworks/Python/historical/webware/app/Configs/Application.config

@@ -0,0 +1,6 @@
+Contexts = {}
+Contexts['default'] = 'Context'
+
+PrintConfigAtStartUp = False
+LogActivity = False
+Verbose = False

+ 2 - 0
frameworks/Python/historical/webware/app/Context/.cvsignore

@@ -0,0 +1,2 @@
+*.pyc
+*.pyo

+ 15 - 0
frameworks/Python/historical/webware/app/Context/DbSession.py

@@ -0,0 +1,15 @@
+import os
+
+from sqlalchemy.ext.declarative import declarative_base
+from sqlalchemy import create_engine
+from sqlalchemy.orm import sessionmaker
+
+DBDRIVER = 'mysql'
+DBHOSTNAME = os.environ.get('DBHOST', 'localhost')
+DATABASE_URI = '%s://benchmarkdbuser:benchmarkdbpass@%s:3306/hello_world?charset=utf8' % (DBDRIVER, DBHOSTNAME)
+
+class Database():
+	Base = declarative_base()
+	db_engine = create_engine(DATABASE_URI)
+	Session = sessionmaker(bind=db_engine)
+	DbSession = Session()

+ 14 - 0
frameworks/Python/historical/webware/app/Context/Fortune.py

@@ -0,0 +1,14 @@
+from DbSession import Database
+from sqlalchemy import Column
+from sqlalchemy.types import Integer, String
+
+class Fortune(Database.Base):
+    __tablename__ = "Fortune"
+    id = Column(Integer, primary_key=True)
+    message = Column(String)
+
+    def serialize(self):
+        return {
+            'id': self.id,
+            'randomNumber': self.randomNumber,
+        }

+ 10 - 0
frameworks/Python/historical/webware/app/Context/UrlHelper.py

@@ -0,0 +1,10 @@
+def getQueryNum(queryString):
+    try:
+        num_queries = int(queryString)
+        if num_queries < 1:
+            return 1
+        if num_queries > 500:
+            return 500
+        return num_queries
+    except ValueError:
+        return 1

+ 13 - 0
frameworks/Python/historical/webware/app/Context/World.py

@@ -0,0 +1,13 @@
+from DbSession import Database
+from sqlalchemy import Column
+from sqlalchemy.types import Integer
+
+class World(Database.Base):
+    __tablename__ = "World"
+    id = Column(Integer, primary_key=True)
+    randomNumber = Column(Integer)
+    def serialize(self):
+        return {
+            'id': self.id,
+            'randomNumber': self.randomNumber,
+        }

+ 16 - 0
frameworks/Python/historical/webware/app/Context/db.py

@@ -0,0 +1,16 @@
+
+from WebKit.HTTPContent import HTTPContent
+from DbSession import Database
+from World import World
+import json
+from random import randint
+
+class db(HTTPContent):
+    def defaultAction(self):
+        self.response().clearHeaders()
+        self.response()._headers["Content-Type"] = "application/json"
+        wid = randint(1, 10000)
+        world = Database.DbSession.query(World).get(wid).serialize()
+        output = json.dumps(world)
+        self.response()._headers["Content-Length"] = len(output)
+        self.write(output)

+ 23 - 0
frameworks/Python/historical/webware/app/Context/fortune.py

@@ -0,0 +1,23 @@
+import json
+import bleach
+from random import randint
+from operator import attrgetter
+
+from WebKit.Page import Page
+from DbSession import Database
+from Fortune import Fortune
+
+class fortune(Page):
+	def writeHTML(self):
+		output = "<!DOCTYPE html><html><head><title>Fortunes</title></head><body><table><tr><th>id</th><th>message</th></tr>"
+		self.response().clearHeaders()
+		self.response()._headers["Content-Type"] = "text/html; charset=UTF-8"
+		fortunes = Database.DbSession.query(Fortune).all()
+		fortunes.append(Fortune(id=0, message="Additional fortune added at request time."))
+		fortunes.sort(key=attrgetter("message"))
+		for fortune in fortunes:
+			message = bleach.clean(fortune.message)
+			output += "<tr><td>%s</td><td>%s</td></tr>" % (fortune.id , message.encode("utf-8"))
+		output += "</table></body></html>"
+		self.response()._headers["Content-Length"] = len(output)
+		self.writeln(output)

+ 11 - 0
frameworks/Python/historical/webware/app/Context/json2.py

@@ -0,0 +1,11 @@
+
+from WebKit.HTTPContent import HTTPContent
+import json
+
+class json2(HTTPContent):
+    def defaultAction(self):
+        self.response().clearHeaders()
+        self.response()._headers["Content-Type"] = "application/json"
+        output = json.dumps({"message": "Hello, World!"})		
+        self.response()._headers["Content-Length"] = len(output)		
+        self.write(output)

+ 10 - 0
frameworks/Python/historical/webware/app/Context/plaintext.py

@@ -0,0 +1,10 @@
+
+from WebKit.HTTPContent import HTTPContent
+
+class plaintext(HTTPContent):
+    def defaultAction(self):
+    	self.response().clearHeaders()
+        self.response()._headers["Content-Type"] = "text/plain"
+        output = "Hello, World!"
+        self.response()._headers["Content-Length"] = len(output)
+        self.write(output)

+ 20 - 0
frameworks/Python/historical/webware/app/Context/queries.py

@@ -0,0 +1,20 @@
+import json
+from random import randint
+from functools import partial
+
+from WebKit.HTTPContent import HTTPContent
+from DbSession import Database
+from World import World
+import UrlHelper 
+
+class queries(HTTPContent):
+    def defaultAction(self):
+        self.response().clearHeaders()
+        self.response()._headers["Content-Type"] = "application/json"
+        num_queries = UrlHelper.getQueryNum(self.request().field("queries"))
+        rp = partial(randint, 1, 10000)
+        get = Database.DbSession.query(World).get
+        worlds = [get(rp()).serialize() for _ in xrange(num_queries)]
+        output = json.dumps(worlds)
+        self.response()._headers["Content-Length"] = len(output)
+        self.write(output)

+ 26 - 0
frameworks/Python/historical/webware/app/Context/updates.py

@@ -0,0 +1,26 @@
+import json
+from random import randint
+from functools import partial
+
+from WebKit.HTTPContent import HTTPContent
+from DbSession import Database
+from World import World
+import UrlHelper 
+
+class updates(HTTPContent):
+    def defaultAction(self):
+        self.response().clearHeaders()
+        self.response()._headers["Content-Type"] = "application/json"
+        num_queries = UrlHelper.getQueryNum(self.request().field("queries"))
+        worlds = []
+        rp = partial(randint, 1, 10000)
+        ids = [rp() for _ in xrange(num_queries)]
+        ids.sort()
+        for id in ids:
+            world = Database.DbSession.query(World).get(id)
+            world.randomNumber = rp()
+            worlds.append(world.serialize())
+        Database.DbSession.commit()
+        output = json.dumps(worlds)
+        self.response()._headers["Content-Length"] = len(output)
+        self.write(output)

+ 33 - 0
frameworks/Python/historical/webware/app/Launch.py

@@ -0,0 +1,33 @@
+#!/usr/bin/python
+
+# You can pass several parameters on the command line
+# (more info by running this with option --help)
+# or you can modify the default values here
+# (more info in WebKit.Launch):
+import os
+
+workDir = None
+webwareDir = os.path.dirname(os.path.normpath(os.getcwd()))
+libraryDirs = ['Lib']
+runProfile = False
+logFile = None
+pidFile = None
+user = None
+group = None
+
+import sys
+sys.path.insert(0, webwareDir)
+
+from WebKit import Launch
+
+Launch.workDir = workDir
+Launch.webwareDir = webwareDir
+Launch.libraryDirs = libraryDirs
+Launch.runProfile = runProfile
+Launch.logFile = logFile
+Launch.pidFile = pidFile
+Launch.user = user
+Launch.group = group
+
+if __name__ == '__main__':
+    Launch.main()

+ 55 - 0
frameworks/Python/historical/webware/app/WebKit.cgi

@@ -0,0 +1,55 @@
+#!/usr/bin/python
+
+# If the Webware installation is located somewhere else,
+# then set the webwareDir variable to point to it here:
+webwareDir = '/home/knewman/Development/tfb-benchmark/webware/Webware'
+
+# If you used the MakeAppWorkDir.py script to make a separate
+# application working directory, specify it here:
+workDir = '/home/knewman/Development/tfb-benchmark/webware/Webware/WebwareTest'
+
+try:
+    import os, sys
+    if not webwareDir:
+        webwareDir = os.path.dirname(os.path.dirname(os.getcwd()))
+    sys.path.insert(1, webwareDir)
+    webKitDir = os.path.join(webwareDir, 'WebKit')
+    if workDir is None:
+        workDir = webKitDir
+    else:
+        sys.path.insert(1, workDir)
+    try:
+        import WebKit.Adapters.CGIAdapter
+    except ImportError:
+        if os.path.exists(webwareDir) and os.path.exists(webKitDir):
+            cgiAdapter = os.path.join(webKitDir, 'Adapters', 'CGIAdapter.py')
+            if os.path.exists(cgiAdapter):
+                raise
+            msg = "CGIAdapter module at <code>%s</code> cannot be loaded" % cgiAdapter
+        else:
+            msg = "Webware installation not found at <code>%s</code>" % webwareDir
+        sys.stdout.write('''Content-Type: text/html\n
+<html><head><title>WebKit CGI Error</title><body>
+<h3>WebKit CGI Error</h3>
+<p>%s.</p>
+<p>You may need to edit the WebKit.cgi script so that <code>webwareDir</code>
+points to the actual Webware installation directory.</p>
+<p>You may also need to modify permissions of the Webware installation
+with <code>chmod</code> so that the CGIAdapter module can be imported.</p>
+</body></html>\n''' % msg)
+    else:
+        WebKit.Adapters.CGIAdapter.main(workDir)
+except:
+    import sys, traceback
+    from time import asctime, localtime, time
+    sys.stderr.write('[%s] [error] WebKit: Error in adapter\n' % asctime(localtime(time())))
+    sys.stderr.write('Error while executing script\n')
+    traceback.print_exc(file=sys.stderr)
+    output = ''.join(traceback.format_exception(*sys.exc_info()))
+    output = output.replace('&', '&amp;').replace(
+        '<', '&lt;').replace('>', '&gt;').replace('"', '&quot;')
+    sys.stdout.write('''Content-Type: text/html\n
+<html><head><title>WebKit CGI Error</title><body>
+<h3>WebKit CGI Error</h3>
+<pre>%s</pre>
+</body></html>\n''' % output)

+ 1 - 0
frameworks/Python/historical/webware/app/adapter.address

@@ -0,0 +1 @@
+127.0.0.1:8086

+ 1 - 0
frameworks/Python/historical/webware/app/http.address

@@ -0,0 +1 @@
+127.0.0.1:8080

+ 171 - 0
frameworks/Python/historical/webware/app/webkit

@@ -0,0 +1,171 @@
+#!/bin/sh
+#
+# WebKit application server
+# part of Webware for Python
+# www.webwareforpython.org
+#
+# /etc/init.d/webkit
+#
+# init.d script for Debian GNU/Linux
+#
+
+### START LOCAL CONFIGURATION
+
+# If you store this script in your Webware working directory
+# and create a symlink to it as /etc/init.d/webkit_appname,
+# it will try to guess your configuration parameters. You can
+# make changes either directly here or you can also override
+# the configuration in the Launch.py script.
+
+# The name of your Webware application:
+APP_NAME=`basename "$0"`
+
+# Description of your Webware application:
+DESC="Webware"
+
+# The location of the start sript:
+if [ -h "$0" ]; then
+    # Get the target file if start script is given as a link:
+    START_SCRIPT=`readlink -f "$0"`
+else
+    START_SCRIPT="$0"
+fi
+
+# The working directory or path to WebKit:
+WORK_DIR=`dirname "$START_SCRIPT"`
+# Make sure to have the absolute path:
+test -d "$WORK_DIR" || exit 0
+WORK_DIR=`cd "$WORK_DIR" 2>/dev/null && pwd`
+
+# The app server launch script:
+APP_SERVER="$WORK_DIR/AppServer"
+test -x "$APP_SERVER" || exit 0
+
+# The app server configuration:
+APP_SERVER_CONFIG="$WORK_DIR/Configs/AppServer.config"
+test -f "$APP_SERVER_CONFIG" || exit 0
+
+# The WebKit app server log file
+# (you can set this in Launch.py as well):
+#LOG_FILE="/var/log/$APP_NAME.log"
+LOG_FILE="$WORK_DIR/Logs/webkit.log"
+# Use this extension if you want to move the last log away
+# (also consider using logrotate or something similar):
+LOG_OLD=".old"
+
+# The app server process id file
+# (you can set this in Launch.py as well):
+#PID_FILE="/var/run/$APP_NAME.pid"
+PID_FILE="$WORK_DIR/webkit.pid"
+
+# The user and group to run the app server
+# (you can set this in Launch.py as well).
+# If undefined, it will be the user and group
+# running the start script (usually root).
+# You should use a low-privilege account,
+# like the work dir owner, wwwrun or nobody.
+# This will use the owner of the AppServer script:
+WEBWARE_USER=`stat -c "%U" "$APP_SERVER"`
+WEBWARE_GROUP=`stat -c "%G" "$APP_SERVER"`
+
+# Unset the following variable if you want to store the
+# pid and log files as the user running the start script
+# (usually root) or set it if you want these files to be
+# written after switching to WEBWARE_USER:WEBWARE_GROUP.
+LAUNCH_AS_WEBWARE="yes"
+
+# Additional options -u or -O to be passed on to Python:
+PYTHONOPTS=
+# Additional libraries to be included in the Python path:
+PYTHONPATH=
+export PYTHONPATH
+
+### END LOCAL CONFIGURATION
+
+set -e
+
+PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
+
+d_start() {
+    # Keep backup of last log file:
+    if [ "$LOG_OLD" -a -f "$LOG_FILE" ]; then
+        if [ -s "$LOG_FILE" ]; then
+            mv "$LOG_FILE" "$LOG_FILE$LOG_OLD"
+        else
+            rm "$LOG_FILE"
+        fi
+    fi
+    # Prepare option to set group
+    if [ "$WEBWARE_GROUP" ]; then
+        WEBWARE_GROUP="-g $WEBWARE_GROUP"
+    fi
+    # Note that the pid file does not record the pid of the
+    # wrapper script, but the pid of the Python app server:
+    if [ "$LAUNCH_AS_WEBWARE" ]; then
+        # Prepare option to set user
+        if [ "$WEBWARE_USER" ]; then
+            WEBWARE_USER="-c $WEBWARE_USER"
+        fi
+        # Switch user first, then create pid and log files:
+        start-stop-daemon -S -b -q -p "$PID_FILE" \
+            $WEBWARE_USER $WEBWARE_GROUP -a "$APP_SERVER" \
+            -- $PYTHONOPTS -d "$WORK_DIR" -o "$LOG_FILE" \
+            -i "$PID_FILE" > /dev/null
+
+    else
+        # Prepare option to set user
+        if [ "$WEBWARE_USER" ]; then
+            WEBWARE_USER="-u $WEBWARE_USER"
+        fi
+        # Create pid and log files first, then switch user:
+        start-stop-daemon -S -q -p "$PID_FILE" -a "$APP_SERVER" \
+            -- $PYTHONOPTS -d "$WORK_DIR" -i "$PID_FILE" \
+            $WEBWARE_USER $WEBWARE_GROUP >> "$LOG_FILE" 2>&1 &
+    fi
+}
+
+d_stop() {
+    # Note that we are terminating the Python app server here;
+    # the app server wrapper script will follow automatically:
+    [ -f "$PID_FILE" ] && \
+    start-stop-daemon -K -q -p $PID_FILE \
+        $WEBWARE_USER -n python
+    rm -f "$PID_FILE"
+}
+
+d_reload() {
+    [ -f "$PID_FILE" ] && \
+    start-stop-daemon -K -q -p $PID_FILE \
+        $WEBWARE_USER -n python -s HUP
+}
+
+case "$1" in
+    start)
+        echo -n "Starting $DESC: $APP_NAME"
+        d_start
+        echo "."
+        ;;
+    stop)
+        echo -n "Stopping $DESC: $APP_NAME"
+        d_stop
+        echo "."
+        ;;
+    reload|force-reload)
+        echo -n "Reloading $DESC configuration..."
+        d_reload
+        echo "done."
+        ;;
+    restart)
+        echo -n "Restarting $DESC: $NAME"
+        d_stop
+        sleep 1
+        d_start
+        echo "."
+        ;;
+    *)
+        echo "Usage: $SCRIPTNAME {start|stop|restart|reload|force-reload}" >&2
+        exit 1
+        ;;
+esac
+
+exit 0

+ 3 - 0
frameworks/Python/historical/webware/requirements.txt

@@ -0,0 +1,3 @@
+bleach==1.4.1
+mysqlclient==1.3.6
+SQLAlchemy==0.9.9

+ 9 - 0
frameworks/Python/historical/webware/setup.sh

@@ -0,0 +1,9 @@
+#!/bin/bash
+
+export PY2_ROOT=$IROOT/py2
+export PY2=$PY2_ROOT/bin/python
+
+cd $TROOT/webware/Webware-1.1.1
+$PY2 install.py --no-password-prompt 
+cd $TROOT/webware/Webware-1.1.1/app
+$PY2 Launch.py &