SVN: r25399 - in trunk/quixote: . demo server
Neil Schemenauer <nascheme-fVcApmY9cLvQ3/1i3zOLAti2O/[email protected]> Wed, 20 Oct 2004 16:51:21 -0400
| Newsgroups | gmane.comp.web.quixote.cvs |
|---|---|
| Message-ID | <[email protected]> |
Author: nascheme
Date: 2004-10-20 16:50:34 -0400 (Wed, 20 Oct 2004)
New Revision: 25399
Added:
trunk/quixote/logger.py
Removed:
trunk/quixote/demo/demo.conf
Modified:
trunk/quixote/config.py
trunk/quixote/demo/demo.cgi
trunk/quixote/demo/demo_scgi.py
trunk/quixote/demo/session_demo.cgi
trunk/quixote/demo/upload.cgi
trunk/quixote/mod_python_handler.py
trunk/quixote/publish.py
trunk/quixote/server/medusa_http.py
trunk/quixote/server/twisted_http.py
Log:
Split error log and access log functionality into a separate class.
Try to simplify site configuration. Configuration options can now
be passed as keyword args to the Publisher class. The setup_logs()
and shutdown_logs() methods are gone. Logs are now opened when the
publisher is initialized.
Modified: trunk/quixote/config.py
===================================================================
--- trunk/quixote/config.py 2004-10-20 18:37:21 UTC (rev 25398)
+++ trunk/quixote/config.py 2004-10-20 20:50:34 UTC (rev 25399)
@@ -12,19 +12,17 @@
care what happens in the future.
"""
-__revision__ = "$Id$"
-
# Note that the default values here are geared towards a production
# environment, preferring security and performance over verbosity and
# debug-ability. If you just want to get a Quixote application
# up-and-running in a production environment, these settings are mostly
# right; all you really need to customize are ERROR_EMAIL, and ERROR_LOG.
# If you need to test/debug/develop a Quixote application, though, you'll
-# probably want to also change DISPLAY_EXCEPTIONS, SECURE_ERRORS, and
-# maybe RUN_ONCE. Again, you shouldn't edit this file unless you don't
-# care what happens in the future (in particular, an upgrade to Quixote
-# would clobber your edits).
+# probably want to also change DISPLAY_EXCEPTIONS and maybe RUN_ONCE.
+# Again, you shouldn't edit this file unless you don't care what happens
+# in the future (in particular, an upgrade to Quixote would clobber your
+# edits).
# E-mail address to send application errors to; None to send no mail at
@@ -49,31 +47,21 @@
# the local variables and a few lines of context for each level of the
# traceback. If set to None, a generic error display, containing no
# information about the traceback, will be used.
-#
-# It is convenient to enable this on development servers. On publicly
-# accessible servers it should be disabled for security reasons.
-#
-# (For backward compatibility reasons, 0 and 1 are also legal values
-# for this setting.)
DISPLAY_EXCEPTIONS = None
-# If true, then any "resource not found" errors will result in a
-# consistent, terse, mostly-useless message. If false, then the
-# exact cause of failure will be returned.
-SECURE_ERRORS = True
-
# If true, Quixote will service exactly one request at a time, and
# then exit. This makes no difference when you're running as a
# straight CGI script, but it makes it easier to debug while running
# as a FastCGI script.
RUN_ONCE = False
-# Automatically redirect paths referencing non-callable objects to a path
-# with a trailing slash. This is convienent for external users of the
-# site but should be disabled for development. Internal links on the
-# site should not require redirects. They are costly, especially on high
-# latency links like dialup lines.
-FIX_TRAILING_SLASH = True
+# Automatically redirect paths referencing non-callable objects to a
+# path with a trailing slash. This should be disabled for development
+# sites. Internal links on the site should not require redirects. They
+# are costly, especially on high latency links like dialup lines. For
+# the convenience of users, you probably want to set this to True on
+# public sites.
+FIX_TRAILING_SLASH = False
# Compress large pages using gzip if the client accepts that encoding.
COMPRESS_PAGES = False
@@ -140,28 +128,6 @@
# -- End config variables ----------------------------------------------
# (no user serviceable parts after this point)
-# Note that this module is designed to not export any names apart from
-# the above config variables and the following Config class -- hence,
-# all imports are done in local scopes. This allows application config
-# modules to safely say "from quixote.config import *".
-
-class ConfigError(Exception):
-
- def __init__(self, msg, source=None, var=None):
- self.msg = msg
- self.source = source
- self.var = var
-
- def __str__(self):
- chunks = []
- if self.source:
- chunks.append(self.source)
- if self.var:
- chunks.append(self.var)
- chunks.append(self.msg)
- return ": ".join(chunks)
-
-
class Config:
"""Holds all Quixote configuration variables -- see above for
documentation of them. The naming convention is simple:
@@ -188,19 +154,13 @@
'mail_debug_addr',
]
+ def __init__(self, **kwargs):
+ self.set_from_dict(globals()) # set defaults
+ for name, value in kwargs.items():
+ if name not in self.config_vars:
+ raise ValueError('unknown config variable %r' % name)
+ setattr(self, name, value)
- def __init__(self, read_defaults=True):
- for var in self.config_vars:
- setattr(self, var, None)
- if read_defaults:
- self.read_defaults()
-
- def __setattr__(self, attr, val):
- if not attr in self.config_vars:
- raise AttributeError, "no such configuration variable: %s" % `attr`
- self.__dict__[attr] = val
-
-
def dump(self, file=None):
import sys
if file is None:
@@ -212,39 +172,14 @@
for var in self.config_vars:
file.write(" %s = %s\n" % (var, `getattr(self, var)`))
+ def set_from_dict(self, config_vars):
+ for name, value in config_vars.items():
+ if name.isupper():
+ name = name.lower()
+ if name not in self.config_vars:
+ raise ValueError('unknown config variable %r' % name)
+ setattr(self, name, value)
- def set_from_dict(self, dict, source=None):
- import string, re
- ucstring_re = re.compile(r'^[A-Z_]+$')
-
- for (var, val) in dict.items():
- if ucstring_re.match(var):
- setattr(self, string.lower(var), val)
-
- self.check_values(source)
-
- def check_values(self, source):
- """
- check_values(source : string)
-
- Check the configuration variables to ensure that they
- are all valid. Raise ConfigError with 'source' as the
- second argument if any problems are found.
- """
- # Check value of DISPLAY_EXCEPTIONS. Values that are
- # equivalent to 'false' are set to None; a value of 1
- # is changed to 'plain'.
- if not self.display_exceptions:
- self.display_exceptions = None
- elif self.display_exceptions == 1:
- self.display_exceptions = 'plain'
- if self.display_exceptions not in (None, 'plain', 'html'):
- raise ConfigError("Must be None,"
- " 'plain', or 'html'",
- source,
- "DISPLAY_EXCEPTIONS")
-
-
def read_file(self, filename):
"""Read configuration from a file. Any variables already
defined in this Config instance, but not in the file, are
@@ -259,21 +194,4 @@
if exc.filename is None: # arg! execfile() loses filename
exc.filename = filename
raise exc
-
- self.set_from_dict(config_vars, source=filename)
-
- def read_from_module(self, modname):
- """Read configuration info from a Python module (default
- is the module where the Config class is defined, ie.
- quixote.config). Also accumulates config data, just like
- 'read_file()'.
- """
- import sys
- __import__(modname)
- module = sys.modules[modname]
- self.set_from_dict(vars(module), source=module.__file__)
-
- def read_defaults(self):
- self.read_from_module("quixote.config")
-
-# class Config
+ self.set_from_dict(config_vars)
Modified: trunk/quixote/demo/demo.cgi
===================================================================
--- trunk/quixote/demo/demo.cgi 2004-10-20 18:37:21 UTC (rev 25398)
+++ trunk/quixote/demo/demo.cgi 2004-10-20 20:50:34 UTC (rev 25399)
@@ -9,13 +9,7 @@
enable_ptl()
# Create a Publisher instance
-app = Publisher('quixote.demo')
+app = Publisher('quixote.demo', display_exceptions='plain')
-# (Optional step) Read a configuration file
-app.read_config("demo.conf")
-
-# Open the configured log files
-app.setup_logs()
-
# Enter the publishing main loop
app.publish_cgi()
Deleted: trunk/quixote/demo/demo.conf
===================================================================
--- trunk/quixote/demo/demo.conf 2004-10-20 18:37:21 UTC (rev 25398)
+++ trunk/quixote/demo/demo.conf 2004-10-20 20:50:34 UTC (rev 25399)
@@ -1,9 +0,0 @@
-# Config file for the Quixote demo. This ensures that debug and error
-# messages will be logged, and that you will see full error information
-# in your browser. (The default settings shipped in Quixote's config.py
-# module are for security rather than ease of testing/development.)
-
-ERROR_LOG = "/tmp/quixote-demo-error.log"
-DISPLAY_EXCEPTIONS = "plain"
-SECURE_ERRORS = 0
-FIX_TRAILING_SLASH = 0
Modified: trunk/quixote/demo/demo_scgi.py
===================================================================
--- trunk/quixote/demo/demo_scgi.py 2004-10-20 18:37:21 UTC (rev 25398)
+++ trunk/quixote/demo/demo_scgi.py 2004-10-20 20:50:34 UTC (rev 25399)
@@ -14,16 +14,10 @@
from quixote import enable_ptl, Publisher
class DemoPublisher(Publisher):
- def __init__(self, *args, **kwargs):
- Publisher.__init__(self, *args, **kwargs)
+ def __init__(self, *args):
+ Publisher.__init__(self, *args, display_exceptions='plain')
- # (Optional step) Read a configuration file
- self.read_config("demo.conf")
- # Open the configured log files
- self.setup_logs()
-
-
class DemoHandler(QuixoteHandler):
publisher_class = DemoPublisher
root_namespace = "quixote.demo"
Modified: trunk/quixote/demo/session_demo.cgi
===================================================================
--- trunk/quixote/demo/session_demo.cgi 2004-10-20 18:37:21 UTC (rev 25398)
+++ trunk/quixote/demo/session_demo.cgi 2004-10-20 20:50:34 UTC (rev 25399)
@@ -155,8 +155,7 @@
# This is mostly the same as the standard boilerplate for any Quixote
# driver script. The main difference is that we have to instantiate a
# session manager, and use SessionPublisher instead of the normal
-# Publisher class. Just like demo.cgi, we use demo.conf to setup log
-# files and ensure that error messages are more informative than secure.
+# Publisher class.
# You can use the 'shelve' module to create an alternative persistent
# mapping to the DirMapping class above.
@@ -167,7 +166,6 @@
sessions = DirMapping(save_dir="/tmp/quixote-session-demo")
session_mgr = SessionManager(session_class=DemoSession,
session_mapping=sessions)
-app = SessionPublisher('quixote.demo.session', session_mgr=session_mgr)
-app.read_config("demo.conf")
-app.setup_logs()
+app = SessionPublisher('quixote.demo.session', session_mgr=session_mgr,
+ display_exceptions='plain')
app.publish_cgi()
Modified: trunk/quixote/demo/upload.cgi
===================================================================
--- trunk/quixote/demo/upload.cgi 2004-10-20 18:37:21 UTC (rev 25398)
+++ trunk/quixote/demo/upload.cgi 2004-10-20 20:50:34 UTC (rev 25399)
@@ -55,10 +55,7 @@
return header(title) + "\n".join(result) + footer()
def main ():
- pub = Publisher('__main__')
- pub.read_config("demo.conf")
- pub.configure(UPLOAD_DIR="/tmp/quixote-upload-demo")
- pub.setup_logs()
+ pub = Publisher('__main__', display_exceptions='plain')
pub.publish_cgi()
main()
Added: trunk/quixote/logger.py
===================================================================
--- trunk/quixote/logger.py 2004-10-20 18:37:21 UTC (rev 25398)
+++ trunk/quixote/logger.py 2004-10-20 20:50:34 UTC (rev 25399)
@@ -0,0 +1,91 @@
+"""$URL$
+$Id$
+"""
+import sys
+import os
+import time
+import socket
+from quixote.sendmail import sendmail
+
+class DefaultLogger:
+ """
+ This is the default logger object used by the Quixote publisher. You may
+ provide your own object if you wish to have different behavior.
+
+ Instance attributes:
+
+ access_log : file | None
+ file to which every access will be logged. If None then access
+ is not logged.
+ error_log : file
+ file to which application errors (exceptions caught by Quixote,
+ as well as anything printed to stderr by application code) will
+ be logged. Set to sys.stderr by default.
+ error_email : string | None
+ if set then internal server errors will cause messages to be sent to
+ this address
+ """
+ def __init__(self, access_log=None, error_log=None, error_email=None):
+ if access_log:
+ self.access_log = open(access_log, 'a', 1)
+ else:
+ self.access_log = None
+ if error_log is None:
+ self.error_log = sys.stdout
+ else:
+ self.error_log = open(error_log, 'a', 1)
+ self.error_email = error_email
+ sys.stdout = self.error_log # print is handy for debugging
+
+ def log(self, msg):
+ """
+ Write an message to the error log with a time stamp.
+ """
+ timestamp = time.strftime("%Y-%m-%d %H:%M:%S",
+ time.localtime(time.time()))
+ self.error_log.write("[%s] %s\n" % (timestamp, msg))
+
+ def log_internal_error(self, error_summary, error_msg):
+ """(error_summary: str, error_msg: str)
+
+ error_summary is a single line summary of the internal error, suitable
+ for an email subject. error_msg is a multi-line plaintext message
+ describing the error in detail.
+ """
+ self.log("exception caught")
+ self.error_log.write(error_msg)
+ if self.error_email:
+ sendmail('Quixote Traceback (%s)' % error_summary,
+ error_msg, [self.error_email],
+ from_addr=(self.error_email, socket.gethostname()))
+
+ def log_request(self, request, start_time):
+ """Log a request in the access_log file.
+ """
+ if self.access_log is None:
+ return
+ if request.session:
+ user = request.session.user or "-"
+ else:
+ user = "-"
+ now = time.time()
+ seconds = now - start_time
+ timestamp = time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(now))
+
+ request_uri = request.get_path()
+ query = request.get_query()
+ if query:
+ request_uri += "?" + query
+ proto = request.get_environ('SERVER_PROTOCOL')
+ self.access_log.write('%s %s %s %d "%s %s %s" %s %r %0.2fsec\n' %
+ (request.get_environ('REMOTE_ADDR'),
+ user,
+ timestamp,
+ os.getpid(),
+ request.get_method(),
+ request_uri,
+ proto,
+ request.response.status_code,
+ request.get_environ('HTTP_USER_AGENT', ''),
+ seconds
+ ))
Property changes on: trunk/quixote/logger.py
___________________________________________________________________
Name: svn:keywords
+ HeadURL Id
Modified: trunk/quixote/mod_python_handler.py
===================================================================
--- trunk/quixote/mod_python_handler.py 2004-10-20 18:37:21 UTC (rev 25398)
+++ trunk/quixote/mod_python_handler.py 2004-10-20 20:50:34 UTC (rev 25399)
@@ -22,14 +22,14 @@
pass
class ModPythonPublisher(Publisher):
- def __init__(self, package, config=None):
- Publisher.__init__(self, package, config)
- self.error_log = self.__error_log = ErrorLog(self) # may be overwritten
- self.setup_logs()
+ def __init__(self, package, **kwargs):
+ Publisher.__init__(self, package, **kwargs)
+ # may be overwritten
+ self.logger.error_log = self.__error_log = ErrorLog(self)
self.__apache_request = None
def log(self, msg):
- if self.error_log is self.__error_log:
+ if self.logger.error_log is self.__error_log:
try:
self.__apache_request.log_error(msg)
except AttributeError:
@@ -76,6 +76,6 @@
pub = name2publisher.get(package)
if pub is None:
- pub = ModPythonPublisher(package, config)
+ pub = ModPythonPublisher(package, config=config)
name2publisher[package] = pub
return pub.publish_modpython(req)
Modified: trunk/quixote/publish.py
===================================================================
--- trunk/quixote/publish.py 2004-10-20 18:37:21 UTC (rev 25398)
+++ trunk/quixote/publish.py 2004-10-20 20:50:34 UTC (rev 25399)
@@ -8,7 +8,7 @@
__revision__ = "$Id$"
import sys, os, traceback, cStringIO
-import time, types, socket, re, warnings
+import time, types, re, warnings
import struct
import urlparse
try:
@@ -19,9 +19,10 @@
from quixote import errors
from quixote.html import htmltext
from quixote import util
+from quixote.config import Config
from quixote.http_request import HTTPRequest
from quixote.http_response import HTTPResponse, Stream
-from quixote.sendmail import sendmail
+from quixote.logger import DefaultLogger
try:
import cgitb # Only available in Python 2.2
@@ -76,29 +77,34 @@
root_namespace : module | instance | class
the Python namespace that will be searched for objects to
fulfill each HTTP request
+ logger : DefaultLogger
exit_now : boolean
used for internal state management. If true, the loop in
publish_cgi() will terminate at the end of the current request.
- access_log : file
- file to which every access will be logged; set by
- setup_logs() (None if no access log)
- error_log : file
- file to which application errors (exceptions caught by Quixote,
- as well as anything printed to stderr by application code) will
- be logged; set by setup_logs(). Set to sys.stderr if no
- ERROR_LOG setting in the application config file.
config : Config
holds all configuration info for this application. If the
- application doesn't have a config file, uses the default values
- from the quixote.config module.
+ application doesn't provide values then default values
+ from the quixote.config module are used.
_request : HTTPRequest
the HTTP request currently being processed.
namespace_stack : [ module | instance | class ]
"""
- def __init__(self, root_namespace, config=None):
- from quixote.config import Config
+ def __init__(self, root_namespace, logger=None, config=None, **kwargs):
global _publisher
+ if config is None:
+ self.config = Config(**kwargs)
+ else:
+ if kwargs:
+ raise ValueError("cannot provide both 'config' object and"
+ " config arguments")
+ self.config = config
+ if logger is None:
+ self.logger = DefaultLogger(error_log=self.config.error_log,
+ access_log=self.config.access_log,
+ error_email=self.config.error_email)
+ else:
+ self.logger = logger
if _publisher is not None:
raise RuntimeError, "only one instance of Publisher allowed"
@@ -118,82 +124,10 @@
self.namespace_stack = [self.root_namespace]
self.exit_now = False
- self.access_log = None
- self.error_log = sys.stderr # possibly overridden in setup_logs()
- sys.stdout = self.error_log # print is handy for debugging
-
- # Initialize default config object with all the default values from
- # the config variables at the top of the config module, ie. if
- # ERROR_LOG is set to "/var/log/quxiote-error.log", then
- # config.ERROR_LOG will also be "/var/log/quixote-error.log". If
- # application FCGI/CGI scripts need to override any of these
- # defaults, they can do so by direct manipulation of the config
- # object, or by reading a config file:
- # app.read_config("myapp.conf")
- if config is None:
- self.config = Config()
- else:
- self.set_config(config)
-
self._request = None
- def configure(self, **kwargs):
- self.config.set_from_dict(kwargs)
-
- def read_config(self, filename):
- self.config.read_file(filename)
-
- def set_config(self, config):
- from quixote.config import Config
- if not isinstance(config, Config):
- raise TypeError, "'config' must be a Config instance"
- self.config = config
-
- def setup_logs(self):
- """
- Open all log files specified in the config file. Reassign
- sys.stderr to go to the error log, and sys.stdout to go to
- the debug log.
- """
-
- sys.stdout = sys.stderr
-
- if self.config.access_log is not None:
- try:
- self.access_log = open(self.config.access_log, 'a', 1)
- except IOError, exc:
- sys.stderr.write("error opening access log %s: %s\n"
- % (`self.config.access_log`, exc.strerror))
-
- if self.config.error_log is not None:
- try:
- self.error_log = open(self.config.error_log, 'a', 1)
- sys.stdout = sys.stderr = self.error_log
- except IOError, exc:
- # leave self.error_log as it was, most likely sys.stderr
- sys.stderr.write("error opening error log %s: %s\n"
- % (`self.config.error_log`, exc.strerror))
-
- def shutdown_logs(self):
- """
- Close log files and restore sys.stdout and sys.stderr to their
- original values.
- """
- if sys.stdout is sys.__stdout__:
- raise RuntimeError, "'setup_logs()' never called"
- sys.stdout = sys.__stdout__
- self.access_log.close()
- if self.error_log is not sys.__stderr__:
- self.error_log.close()
- sys.stderr = sys.__stderr__
-
def log(self, msg):
- """
- Write an message to the error log with a time stamp.
- """
- timestamp = time.strftime("%Y-%m-%d %H:%M:%S",
- time.localtime(time.time()))
- self.error_log.write("[%s] %s\n" % (timestamp, msg))
+ self.logger.log(msg)
def parse_request(self, request):
"""Parse the request information waiting in 'request'.
@@ -221,38 +155,6 @@
"""
return self._request
- def log_request(self, request, start_time):
- """Log a request in the access_log file.
- """
- if self.access_log is not None:
- if request.session:
- user = request.session.user or "-"
- else:
- user = "-"
- now = time.time()
- seconds = now - start_time
- timestamp = time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(now))
-
- request_uri = request.get_path()
- query = request.get_query()
- if query:
- request_uri += "?" + query
- proto = request.get_environ('SERVER_PROTOCOL')
-
- self.access_log.write('%s %s %s %d "%s %s %s" %s %r %0.2fsec\n' %
- (request.get_environ('REMOTE_ADDR'),
- user,
- timestamp,
- os.getpid(),
- request.get_method(),
- request_uri,
- proto,
- request.response.status_code,
- request.get_environ('HTTP_USER_AGENT', ''),
- seconds
- ))
-
-
def finish_successful_request(self):
"""Called at the end of a successful request. Overridden by
SessionPublisher to handle session details."""
@@ -283,7 +185,7 @@
# set response status code so every custom doesn't have to do it
request.response.set_status(exc.status_code)
- if self.config.secure_errors and exc.private_msg:
+ if not self.config.display_exceptions and exc.private_msg:
exc.private_msg = None # hide it
# walk up stack and find handler for the exception
@@ -345,12 +247,8 @@
request.response.set_header("Content-Type", "text/plain")
user_error_msg = plain_error_msg
- self.log("exception caught")
- self.error_log.write(plain_error_msg)
+ self.logger.log_internal_error(error_summary, plain_error_msg)
- if self.config.error_email:
- self.mail_error(plain_error_msg, error_summary)
-
request.response.set_status(500)
return user_error_msg
@@ -389,12 +287,6 @@
return error_file.getvalue()
- def mail_error(self, msg, error_summary):
- """Send an email notifying someone of a traceback."""
- sendmail('Quixote Traceback (%s)' % error_summary,
- msg, [self.config.error_email],
- from_addr=(self.config.error_email, socket.gethostname()))
-
def get_namespace_stack(self):
"""get_namespace_stack() -> [ module | instance | class ]
"""
@@ -505,7 +397,7 @@
# Some other exception, generate error messages to the logs, etc.
output = self.finish_failed_request()
output = self.filter_output(request, output)
- self.log_request(request, start_time)
+ self.logger.log_request(request, start_time)
return output
def publish(self, stdin, stdout, stderr, env):
@@ -562,9 +454,9 @@
class SessionPublisher(Publisher):
- def __init__(self, root_namespace, config=None, session_mgr=None):
+ def __init__(self, root_namespace, session_mgr=None, **kwargs):
from quixote.session import SessionManager
- Publisher.__init__(self, root_namespace, config)
+ Publisher.__init__(self, root_namespace, **kwargs)
if session_mgr is None:
self.session_mgr = SessionManager()
else:
Modified: trunk/quixote/server/medusa_http.py
===================================================================
--- trunk/quixote/server/medusa_http.py 2004-10-20 18:37:21 UTC (rev 25398)
+++ trunk/quixote/server/medusa_http.py 2004-10-20 20:50:34 UTC (rev 25399)
@@ -133,12 +133,7 @@
port = 8080
print 'Now serving the Quixote demo on port %d' % port
server = http_server.http_server('', port)
- publisher = Publisher('quixote.demo')
-
- # When initializing the Publisher in your own driver script,
- # you'll want to parse a configuration file.
- ##publisher.read_config("/full/path/to/demo.conf")
- publisher.setup_logs()
+ publisher = Publisher('quixote.demo', display_exceptions='plain')
dh = QuixoteHandler(publisher, 'Quixote/demo', server)
server.install_handler(dh)
asyncore.loop()
Modified: trunk/quixote/server/twisted_http.py
===================================================================
--- trunk/quixote/server/twisted_http.py 2004-10-20 18:37:21 UTC (rev 25398)
+++ trunk/quixote/server/twisted_http.py 2004-10-20 20:50:34 UTC (rev 25399)
@@ -239,7 +239,7 @@
return p
-def Server(namespace, http_port):
+def Server(namespace, http_port, **kwargs):
from twisted.internet import reactor
from quixote.publish import Publisher
@@ -255,8 +255,7 @@
## ctx.use_privatekey_file('/path/to/pem/encoded/ssl_key_file')
## return ctx
- publisher = Publisher(namespace)
- ##publisher.setup_logs()
+ publisher = Publisher(namespace, **kwargs)
qf = QuixoteFactory(publisher)
reactor.listenTCP(http_port, qf)
@@ -265,12 +264,12 @@
return reactor
-def run(namespace, port):
- app = Server(namespace, port)
+def run(namespace, port, **kwargs):
+ app = Server(namespace, port, **kwargs)
app.run()
if __name__ == '__main__':
from quixote import enable_ptl
enable_ptl()
- run('quixote.demo', 8080)
+ run('quixote.demo', 8080, display_exceptions='plain')