summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRobert Brewer <fumanchu@aminus.org>2006-08-25 21:25:56 +0000
committerRobert Brewer <fumanchu@aminus.org>2006-08-25 21:25:56 +0000
commita4b0f89d3adff5ce7931d81dc259fed0e9f091f5 (patch)
treefda90c2e4664674aa3d0724beed3b543a824c8ff
parent31bfe036ad8ee2d7222c67deb7b2019a878c239c (diff)
downloadcherrypy-git-a4b0f89d3adff5ce7931d81dc259fed0e9f091f5.tar.gz
More (final?) config overhaul work:
1. Removed cherrypy.config.get! Instead, you should directly inspect cherrypy.request, response, server, etc. Note that request.config.get still works fine. 2. a) cherrypy.log is now an instance of LogManager. It's still callable, but now is the object you inspect instead of calling config.get("log*"). b) cherrypy.log_access is now cherrypy.log.access. 3. All threads should now have access to default Request and Response objects, not just the main thread. 4. deadlock.timeout is now request.timeout. 5. Renamed config.py to _cpconfig.py; cherrypy.config is now an instance of _cpconfig.Config. I still need to decide what to do about log_config (removed for now).
-rw-r--r--cherrypy/__init__.py138
-rw-r--r--cherrypy/_cpconfig.py (renamed from cherrypy/config.py)167
-rw-r--r--cherrypy/_cpengine.py17
-rw-r--r--cherrypy/_cperror.py2
-rw-r--r--cherrypy/_cprequest.py22
-rw-r--r--cherrypy/_cpserver.py33
-rw-r--r--cherrypy/_cptree.py17
-rw-r--r--cherrypy/_cpwsgi.py23
-rw-r--r--cherrypy/lib/caching.py4
-rw-r--r--cherrypy/lib/sessions.py5
-rw-r--r--cherrypy/test/benchmark.py10
-rw-r--r--cherrypy/test/helper.py2
-rw-r--r--cherrypy/test/test.py2
-rw-r--r--cherrypy/test/test_caching.py8
-rw-r--r--cherrypy/test/test_config.py34
-rw-r--r--cherrypy/test/test_conn.py12
-rw-r--r--cherrypy/test/test_core.py18
-rw-r--r--cherrypy/test/test_objectmapping.py2
-rw-r--r--cherrypy/test/test_states.py8
-rw-r--r--cherrypy/test/test_tools.py2
-rw-r--r--cherrypy/test/test_tutorials.py2
-rw-r--r--cherrypy/tutorial/tut10_http_errors.py4
22 files changed, 273 insertions, 259 deletions
diff --git a/cherrypy/__init__.py b/cherrypy/__init__.py
index 40b60e64..63ba4fc1 100644
--- a/cherrypy/__init__.py
+++ b/cherrypy/__init__.py
@@ -3,10 +3,12 @@
__version__ = '3.0.0alpha'
import logging as _logging
+import os as _os
+_localdir = _os.path.dirname(__file__)
from cherrypy._cperror import HTTPError, HTTPRedirect, InternalRedirect, NotFound
from cherrypy._cperror import WrongConfigValue, TimeoutError
-from cherrypy import config
+error_page = {}
from cherrypy import _cptools
tools = _cptools.default_toolbox
@@ -36,55 +38,56 @@ except ImportError:
# in a thread-safe way.
serving = _local()
-# Bind dummy instances of default request/response
-# (in the main thread only!) to help introspection.
-serving.request = _cprequest.Request("localhost", "11111", "localhost")
-serving.response = _cprequest.Response()
-
class _ThreadLocalProxy(object):
- __slots__ = ['__attrname__', '__dict__']
+ __slots__ = ['__attrname__', '_default_child', '__dict__']
- def __init__(self, attrname):
+ def __init__(self, attrname, default):
self.__attrname__ = attrname
+ self._default_child = default
+
+ def _get_child(self):
+ try:
+ return getattr(serving, self.__attrname__)
+ except AttributeError:
+ # Bind dummy instances of default objects to help introspection.
+ return self._default_child
def __getattr__(self, name):
- childobject = getattr(serving, self.__attrname__)
- return getattr(childobject, name)
+ return getattr(self._get_child(), name)
def __setattr__(self, name, value):
- if name == "__attrname__":
- object.__setattr__(self, "__attrname__", value)
+ if name in ("__attrname__", "_default_child"):
+ object.__setattr__(self, name, value)
else:
- childobject = getattr(serving, self.__attrname__)
- setattr(childobject, name, value)
+ setattr(self._get_child(), name, value)
def __delattr__(self, name):
- childobject = getattr(serving, self.__attrname__)
- delattr(childobject, name)
+ delattr(self._get_child(), name)
def _get_dict(self):
- childobject = getattr(serving, self.__attrname__)
+ childobject = self._get_child()
d = childobject.__class__.__dict__.copy()
d.update(childobject.__dict__)
return d
__dict__ = property(_get_dict)
def __getitem__(self, key):
- childobject = getattr(serving, self.__attrname__)
- return childobject[key]
+ return self._get_child()[key]
def __setitem__(self, key, value):
- childobject = getattr(serving, self.__attrname__)
- childobject[key] = value
+ self._get_child()[key] = value
# Create request and response object (the same objects will be used
# throughout the entire life of the webserver, but will redirect
# to the "serving" object)
-request = _ThreadLocalProxy('request')
-response = _ThreadLocalProxy('response')
+from cherrypy.lib import http as _http
+request = _ThreadLocalProxy('request',
+ _cprequest.Request(_http.Host("localhost", 80),
+ _http.Host("localhost", 1111)))
+response = _ThreadLocalProxy('response', _cprequest.Response())
# Create thread_data object as a thread-specific all-purpose storage
thread_data = _local()
@@ -102,56 +105,59 @@ def logtime():
return '%02d/%s/%04d:%02d:%02d:%02d' % (
now.day, month, now.year, now.hour, now.minute, now.second)
-def log_access():
- """Default method for logging access"""
- tmpl = '%(h)s %(l)s %(u)s [%(t)s] "%(r)s" %(s)s %(b)s "%(f)s" "%(a)s"'
- s = tmpl % {'h': request.remote.name or request.remote.ip,
- 'l': '-',
- 'u': getattr(request, "login", None) or "-",
- 't': logtime(),
- 'r': request.request_line,
- 's': response.status.split(" ", 1)[0],
- 'b': response.headers.get('Content-Length', '') or "-",
- 'f': request.headers.get('referer', ''),
- 'a': request.headers.get('user-agent', ''),
- }
- try:
- request.app.access_log.log(_logging.INFO, s)
- except:
- log(traceback=True)
-
_error_log = _logging.getLogger("cherrypy.error")
_error_log.setLevel(_logging.DEBUG)
-
_access_log = _logging.getLogger("cherrypy.access")
_access_log.setLevel(_logging.INFO)
-def _log_message(msg, context = '', severity = _logging.DEBUG):
- """Default method for logging messages (error log).
+
+class LogManager(object):
- This is not just for errors! Applications may call this at any time to
- log application-specific information.
- """
+ screen = True
+ error_file = _os.path.join(_os.getcwd(), _localdir, "error.log")
+ # Using an access file makes CP about 10% slower.
+ access_file = ''
- try:
- log = request.app.error_log
- except AttributeError:
- log = _error_log
- log.log(severity, ' '.join((logtime(), context, msg)))
-
-def log(msg='', context='', severity=_logging.DEBUG, traceback=False):
- """Syntactic sugar for writing to the (error) log.
+ def error(self, msg='', context='', severity=_logging.DEBUG, traceback=False):
+ """Write to the 'error' log.
+
+ This is not just for errors! Applications may call this at any time
+ to log application-specific information.
+ """
+ if traceback:
+ from cherrypy import _cperror
+ msg += _cperror.format_exc()
+
+ try:
+ elog = request.app.error_log
+ except AttributeError:
+ elog = _error_log
+ elog.log(severity, ' '.join((logtime(), context, msg)))
- This is not just for errors! Applications may call this at any time to
- log application-specific information.
- """
- if traceback:
- from cherrypy import _cperror
- msg += _cperror.format_exc()
- logfunc = config.get('log.error.function', _log_message)
- logfunc(msg, context, severity)
-
+ def __call__(self, *args, **kwargs):
+ return self.error(*args, **kwargs)
+
+ def access(self):
+ """Default method for logging access"""
+ tmpl = '%(h)s %(l)s %(u)s [%(t)s] "%(r)s" %(s)s %(b)s "%(f)s" "%(a)s"'
+ s = tmpl % {'h': request.remote.name or request.remote.ip,
+ 'l': '-',
+ 'u': getattr(request, "login", None) or "-",
+ 't': logtime(),
+ 'r': request.request_line,
+ 's': response.status.split(" ", 1)[0],
+ 'b': response.headers.get('Content-Length', '') or "-",
+ 'f': request.headers.get('referer', ''),
+ 'a': request.headers.get('user-agent', ''),
+ }
+ try:
+ request.app.access_log.log(_logging.INFO, s)
+ except:
+ self.error(traceback=True)
+
+
+log = LogManager()
# Helper functions for CP apps #
@@ -229,3 +235,7 @@ def expose(func=None, alias=None):
alias = func
return expose_
+
+# Set up config last so it can wrap other top-level objects
+from cherrypy import _cpconfig
+config = _cpconfig.Config()
diff --git a/cherrypy/config.py b/cherrypy/_cpconfig.py
index 01eb21a8..a317c85f 100644
--- a/cherrypy/config.py
+++ b/cherrypy/_cpconfig.py
@@ -28,8 +28,8 @@ and configuration data may apply to any of those three scopes:
page handler (see next).
-Usage
------
+Declaration
+-----------
Configuration data may be supplied as a Python dictionary, as a filename,
or as an open file object. When you supply a filename or file, CherryPy
@@ -60,12 +60,11 @@ Namespaces
Configuration keys are separated into namespaces by the first "." in the key.
Current namespaces:
- autoreload: Controls the autoreload mechanism in cherrypy.engine.
- These can only be declared in the global config.
- deadlock: Controls the deadlock monitoring system in cherrypy.engine.
+ engine: Controls the 'application engine', including autoreload.
These can only be declared in the global config.
hooks: Declares additional request-processing functions.
log: Configures the logging for each application.
+ These can only be declared in the global or / config.
request: Adds attributes to each Request during the tool_up phase.
response: Adds attributes to each Response during the tool_up phase.
server: Controls the default HTTP server via cherrypy.server.
@@ -82,7 +81,7 @@ import ConfigParser
import logging as _logging
_logfmt = _logging.Formatter("%(message)s")
import os as _os
-_localdir = _os.path.dirname(__file__)
+import types
import cherrypy
@@ -122,70 +121,70 @@ def merge(base, other):
default_conf = {
- # Server config
- 'server.socket_port': 8080,
- 'server.socket_host': '',
- 'server.socket_file': '',
- 'server.socket_queue_size': 5,
- 'server.socket_timeout': 10,
- 'server.protocol_version': 'HTTP/1.1',
- 'server.reverse_dns': False,
- 'server.thread_pool': 10,
- 'server.max_request_header_size': 500 * 1024,
- 'server.instance': None,
-
- # Log config
- 'log.to_screen': True,
-## 'log.error.function': cherrypy._log_message,
- 'log.error.file': _os.path.join(_os.getcwd(), _localdir, "error.log"),
- # Using an access file makes CP about 10% slower.
-## 'log.access.function': cherrypy.log_access,
-## 'log.access.file': _os.path.join(_os.getcwd(), _localdir, "access.log"),
-
- # Process management
- 'autoreload.on': True,
- 'autoreload.frequency': 1,
- 'deadlock.timeout': 300,
- 'deadlock.poll_freq': 60,
-
- 'error_page.404': '',
-
'tools.log_tracebacks.on': True,
'tools.log_headers.on': True,
}
-globalconf = default_conf.copy()
-
-def reset():
- globalconf.clear()
- update(default_conf)
-
-def update(conf):
- """Update globalconf from a dict, file or filename."""
- if isinstance(conf, basestring):
- if conf not in cherrypy.engine.reload_files:
- cherrypy.engine.reload_files.append(conf)
- conf = _Parser().dict_from_file(conf)
- elif hasattr(conf, 'read'):
- conf = _Parser().dict_from_file(conf)
-
- if isinstance(conf.get("global", None), dict):
- conf = conf["global"]
+class Config(object):
- if 'environment' in conf:
- env = environments[conf['environment']]
- for k in env:
- if k not in conf:
- conf[k] = env[k]
+ globalconf = default_conf.copy()
- if 'tools.staticdir.dir' in conf:
- conf['tools.staticdir.section'] = "global"
+ def reset(self):
+ """Reset self.globalconf to default values."""
+ self.globalconf.clear()
+ self.update(default_conf)
- globalconf.update(conf)
+ def update(self, conf):
+ """Update self.globalconf from a dict, file or filename."""
+ if isinstance(conf, basestring):
+ if conf not in cherrypy.engine.reload_files:
+ cherrypy.engine.reload_files.append(conf)
+ conf = _Parser().dict_from_file(conf)
+ elif hasattr(conf, 'read'):
+ conf = _Parser().dict_from_file(conf)
+
+ if isinstance(conf.get("global", None), dict):
+ conf = conf["global"]
+
+ if 'environment' in conf:
+ env = environments[conf['environment']]
+ for k in env:
+ if k not in conf:
+ conf[k] = env[k]
+
+ if 'tools.staticdir.dir' in conf:
+ conf['tools.staticdir.section'] = "global"
+
+ self.globalconf.update(conf)
+
+ _configure_builtin_logging(self.globalconf, cherrypy._error_log)
+ _configure_builtin_logging(self.globalconf, cherrypy._access_log, "log.access_file")
+
+ # Override properties specified in config.
+ gconf = self.globalconf
+ for k in gconf:
+ atoms = k.split(".", 1)
+ namespace = atoms[0]
+ if namespace == "server":
+ setattr(cherrypy.server, atoms[1], gconf[k])
+ elif namespace == "engine":
+ setattr(cherrypy.engine, atoms[1], gconf[k])
+ elif namespace == "log":
+ setattr(cherrypy.log, atoms[1], gconf[k])
+ elif namespace == "error_page":
+ cherrypy.error_page[int(atoms[1])] = gconf[k]
- _configure_builtin_logging(globalconf, cherrypy._error_log)
- _configure_builtin_logging(globalconf, cherrypy._access_log, "log.access.file")
+ def wrap(**kwargs):
+ """Decorator to set _cp_config on a handler using the given kwargs."""
+ def wrapper(f):
+ if not hasattr(f, "_cp_config"):
+ f._cp_config = {}
+ f._cp_config.update(kwargs)
+ return f
+ return wrapper
+ wrap = staticmethod(wrap)
+
def _add_builtin_screen_handler(log):
import sys
@@ -202,7 +201,7 @@ def _add_builtin_file_handler(log, fname):
h._cpbuiltin = "file"
log.addHandler(h)
-def _configure_builtin_logging(conf, log, filekey="log.error.file"):
+def _configure_builtin_logging(conf, log, filekey="log.error_file"):
"""Create/destroy builtin log handlers as needed from conf."""
existing = dict([(getattr(x, "_cpbuiltin", None), x)
@@ -230,28 +229,6 @@ def _configure_builtin_logging(conf, log, filekey="log.error.file"):
h.close()
log.handlers.remove(h)
-def get(key, default=None):
- """Return the config value corresponding to key, or default."""
- try:
- conf = cherrypy.request.config
- if conf is None:
- conf = globalconf
- except AttributeError:
- # There's no request, so just use globalconf.
- conf = globalconf
-
- return conf.get(key, default)
-
-
-def wrap(**kwargs):
- """Decorator to set _cp_config on a handler using the given kwargs."""
- def wrapper(f):
- if not hasattr(f, "_cp_config"):
- f._cp_config = {}
- f._cp_config.update(kwargs)
- return f
- return wrapper
-
class _Parser(ConfigParser.ConfigParser):
"""Sub-class of ConfigParser that keeps the case of options and that raises
@@ -303,26 +280,4 @@ class _Parser(ConfigParser.ConfigParser):
self.read(file)
return self.as_dict()
-
-def log_config():
- """Log engine configuration parameters."""
- cherrypy.log("Server parameters:", 'CONFIG')
-
- server_vars = [
- 'environment',
- 'log.screen',
- 'log.error.file',
- 'server.protocol_version',
- 'server.socket_host',
- 'server.socket_port',
- 'server.socket_file',
- 'server.reverse_dns',
- 'server.socket_queue_size',
- 'server.thread_pool',
- ]
-
- for var in server_vars:
- cherrypy.log(" %s: %s" % (var, get(var)), 'CONFIG')
-
-
del ConfigParser
diff --git a/cherrypy/_cpengine.py b/cherrypy/_cpengine.py
index 764199c7..eb91310d 100644
--- a/cherrypy/_cpengine.py
+++ b/cherrypy/_cpengine.py
@@ -42,8 +42,12 @@ except ValueError, _signal_exc:
class Engine(object):
"""The application engine, which exposes a request interface to (HTTP) servers."""
+ # Configurable attributes
request_class = _cprequest.Request
response_class = _cprequest.Response
+ deadlock_poll_freq = 60
+ autoreload_on = False
+ autoreload_frequency = 1
def __init__(self):
self.state = STOPPED
@@ -66,14 +70,12 @@ class Engine(object):
"""Start the application engine."""
self.state = STARTING
- conf = cherrypy.config.get
-
for func in self.on_start_engine_list:
func()
self.state = STARTED
- freq = float(conf('deadlock.poll_freq', 60))
+ freq = self.deadlock_poll_freq
if freq > 0:
self.monitor_thread = threading.Timer(freq, self.monitor)
self.monitor_thread.start()
@@ -84,16 +86,15 @@ class Engine(object):
def block(self):
"""Block forever (wait for stop(), KeyboardInterrupt or SystemExit)."""
try:
- autoreload = cherrypy.config.get('autoreload.on', False)
- if autoreload:
+ if self.autoreload_on:
i = 0
- freq = cherrypy.config.get('autoreload.frequency', 1)
+ freq = self.autoreload_frequency
while self.state != STOPPED:
time.sleep(.1)
# Autoreload
- if autoreload:
+ if self.autoreload_on:
i += .1
if i > freq:
i = 0
@@ -218,7 +219,7 @@ class Engine(object):
if self.state == STARTED:
for req, resp in self.servings:
resp.check_timeout()
- freq = float(cherrypy.config.get('deadlock.poll_freq', 60))
+ freq = self.deadlock_poll_freq
self.monitor_thread = threading.Timer(freq, self.monitor)
self.monitor_thread.start()
diff --git a/cherrypy/_cperror.py b/cherrypy/_cperror.py
index c3418434..bde44974 100644
--- a/cherrypy/_cperror.py
+++ b/cherrypy/_cperror.py
@@ -266,7 +266,7 @@ def get_error_page(status, **kwargs):
kwargs[k] = _escape(kwargs[k])
template = _HTTPErrorTemplate
- error_page_file = cherrypy.config.get('error_page.%s' % code, '')
+ error_page_file = cherrypy.request.error_page.get(code, '')
if error_page_file:
try:
template = file(error_page_file, 'rb').read()
diff --git a/cherrypy/_cprequest.py b/cherrypy/_cprequest.py
index 0db28064..d4ed2752 100644
--- a/cherrypy/_cprequest.py
+++ b/cherrypy/_cprequest.py
@@ -281,7 +281,6 @@ class Request(object):
methods_with_bodies = ("POST", "PUT")
body = None
body_read = False
- max_body_size = 100 * 1024 * 1024
# Dispatch attributes
dispatch = Dispatcher()
@@ -300,6 +299,7 @@ class Request(object):
hooks = HookMap(hookpoints)
error_response = cherrypy.HTTPError(500).set_response
+ error_page = {}
show_tracebacks = True
throw_errors = False
@@ -420,7 +420,7 @@ class Request(object):
# HEAD requests MUST NOT return a message-body in the response.
cherrypy.response.body = []
- log_access = cherrypy.config.get("log.access.function", cherrypy.log_access)
+ log_access = cherrypy.log.access
if log_access:
log_access()
@@ -448,7 +448,7 @@ class Request(object):
if self.process_request_body:
# Prepare the SizeCheckWrapper for the request body
- mbs = self.max_body_size
+ mbs = cherrypy.server.max_request_body_size
if mbs > 0:
self.rfile = http.SizeCheckWrapper(self.rfile, mbs)
@@ -531,16 +531,18 @@ class Request(object):
def tool_up(self):
"""Process self.config, populate self.toolmap and set up each tool."""
+ self.error_page = cherrypy.error_page.copy()
+
# Get all 'tools.*' config entries as a {toolname: {k: v}} dict.
self.toolmap = tm = {}
reqconf = self.config
for k in reqconf:
- atoms = k.split(".", 2)
+ atoms = k.split(".", 1)
namespace = atoms[0]
if namespace == "tools":
- toolname = atoms[1]
+ toolname, arg = atoms[1].split(".", 1)
bucket = tm.setdefault(toolname, {})
- bucket[atoms[2]] = reqconf[k]
+ bucket[arg] = reqconf[k]
elif namespace == "hooks":
# Attach bare hooks declared in config.
hookpoint = atoms[1]
@@ -554,6 +556,8 @@ class Request(object):
elif namespace == "response":
# Override properties of the current response object.
setattr(cherrypy.response, atoms[1], reqconf[k])
+ elif namespace == "error_page":
+ self.error_page[int(atoms[1])] = reqconf[k]
# Run tool._setup(conf) for each tool in the new toolmap.
tools = cherrypy.tools
@@ -687,6 +691,7 @@ class Response(object):
simple_cookie = Cookie.SimpleCookie()
body = Body()
time = None
+ timeout = 300
timed_out = False
stream = False
@@ -744,12 +749,11 @@ class Response(object):
h.append((name, value))
def check_timeout(self):
- """If now > self.time + deadlock_timeout, set self.timed_out.
+ """If now > self.time + self.timeout, set self.timed_out.
This purposefully sets a flag, rather than raising an error,
so that a monitor thread can interrupt the Response thread.
"""
- timeout = float(cherrypy.config.get('deadlock.timeout', 300))
- if time.time() > self.time + timeout:
+ if time.time() > self.time + self.timeout:
self.timed_out = True
diff --git a/cherrypy/_cpserver.py b/cherrypy/_cpserver.py
index 1e069d52..21fa82a3 100644
--- a/cherrypy/_cpserver.py
+++ b/cherrypy/_cpserver.py
@@ -11,6 +11,18 @@ from cherrypy.lib import attributes
class Server(object):
"""Manager for a set of HTTP servers."""
+ socket_port = 8080
+ socket_host = ''
+ socket_file = ''
+ socket_queue_size = 5
+ socket_timeout = 10
+ protocol_version = 'HTTP/1.1'
+ reverse_dns = False
+ thread_pool = 10
+ max_request_header_size = 500 * 1024
+ max_request_body_size = 100 * 1024 * 1024
+ instance = None
+
def __init__(self):
self.httpservers = {}
self.interrupt = None
@@ -19,32 +31,31 @@ class Server(object):
"""Main function for quick starts. MUST be called from the main thread.
This function works like CherryPy 2's server.start(). It loads and
- starts an httpserver based on the given server object, if any, and
- config entries.
+ starts an httpserver based on the given server object (if provided)
+ and attributes of self.
"""
- httpserver, bind_addr = self.httpserver_from_config(server)
+ httpserver, bind_addr = self.httpserver_from_self(server)
self.httpservers[httpserver] = bind_addr
self.start()
- def httpserver_from_config(self, httpserver=None):
- """Return a (httpserver, bind_addr) pair based on config settings."""
- conf = cherrypy.config.get
+ def httpserver_from_self(self, httpserver=None):
+ """Return a (httpserver, bind_addr) pair based on self attributes."""
if httpserver is None:
- httpserver = conf('server.instance', None)
+ httpserver = self.instance
if httpserver is None:
from cherrypy import _cpwsgi
httpserver = _cpwsgi.WSGIServer()
if isinstance(httpserver, basestring):
httpserver = attributes(httpserver)()
- if conf('server.socket_port'):
- host = conf('server.socket_host')
- port = conf('server.socket_port')
+ if self.socket_port:
+ host = self.socket_host
+ port = self.socket_port
if not host:
host = 'localhost'
return httpserver, (host, port)
else:
- return httpserver, conf('server.socket_file')
+ return httpserver, self.socket_file
def start(self):
"""Start all registered HTTP servers."""
diff --git a/cherrypy/_cptree.py b/cherrypy/_cptree.py
index ac719b57..f8402e2a 100644
--- a/cherrypy/_cptree.py
+++ b/cherrypy/_cptree.py
@@ -1,6 +1,6 @@
import logging
-from cherrypy import config, _cpwsgi
+from cherrypy import _cpconfig, _cpwsgi
class Application(object):
@@ -45,12 +45,12 @@ class Application(object):
def merge(self, conf):
"""Merge the given config into self.config."""
- config.merge(self.conf, conf)
+ _cpconfig.merge(self.conf, conf)
# Create log handlers as specified in config.
rootconf = self.conf.get("/", {})
- config._configure_builtin_logging(rootconf, self.access_log, "log.access.file")
- config._configure_builtin_logging(rootconf, self.error_log)
+ _cpconfig._configure_builtin_logging(rootconf, self.access_log, "log.access_file")
+ _cpconfig._configure_builtin_logging(rootconf, self.error_log)
def guess_abs_path(self):
"""Guess the absolute URL from server.socket_host and script_name.
@@ -61,12 +61,12 @@ class Application(object):
However, outside of the request we must guess, hoping the deployer
set socket_host and socket_port correctly.
"""
- port = int(config.get('server.socket_port', 80))
+ port = cherrypy.server.socket_port
if port in (443, 8443):
scheme = "https://"
else:
scheme = "http://"
- host = config.get('server.socket_host', '')
+ host = cherrypy.server.socket_host
if port != 80:
host += ":%s" % port
return scheme + host + self.script_name
@@ -81,6 +81,11 @@ class Tree:
An instance of this class may also be used as a WSGI callable
(WSGI application object), in which case it dispatches to all
mounted apps.
+
+ apps: a dict of the form {script name: application}, where "script name"
+ is a string declaring the URL mount point (no trailing slash),
+ and "application" is an instance of cherrypy.Application (or an
+ arbitrary WSGI callable if you happen to be using a WSGI server).
"""
def __init__(self):
diff --git a/cherrypy/_cpwsgi.py b/cherrypy/_cpwsgi.py
index cbb4f677..71a46476 100644
--- a/cherrypy/_cpwsgi.py
+++ b/cherrypy/_cpwsgi.py
@@ -120,8 +120,7 @@ def _wsgi_callable(environ, start_response, app):
class CPHTTPRequest(_cpwsgiserver.HTTPRequest):
def parse_request(self):
- mhs = int(cherrypy.config.get('server.max_request_header_size',
- 500 * 1024))
+ mhs = cherrypy.server.max_request_header_size
if mhs > 0:
self.rfile = http.SizeCheckWrapper(self.rfile, mhs)
@@ -135,7 +134,7 @@ class CPHTTPRequest(_cpwsgiserver.HTTPRequest):
"""Decode the 'chunked' transfer coding."""
if isinstance(self.rfile, http.SizeCheckWrapper):
self.rfile = self.rfile.rfile
- mbs = int(cherrypy.config.get('request.max_body_size', 100 * 1024 * 1024))
+ mbs = cherrypy.server.max_request_body_size
if mbs > 0:
self.rfile = http.SizeCheckWrapper(self.rfile, mbs)
try:
@@ -164,23 +163,21 @@ class WSGIServer(_cpwsgiserver.CherryPyWSGIServer):
ConnectionClass = CPHTTPConnection
def __init__(self):
- conf = cherrypy.config.get
-
- sockFile = conf('server.socket_file')
+ server = cherrypy.server
+ sockFile = server.socket_file
if sockFile:
bind_addr = sockFile
else:
- bind_addr = (conf('server.socket_host'),
- conf('server.socket_port'))
+ bind_addr = (server.socket_host, server.socket_port)
s = _cpwsgiserver.CherryPyWSGIServer
# We could just pass cherrypy.tree, but by passing tree.apps,
# we get correct SCRIPT_NAMEs as early as possible.
s.__init__(self, bind_addr, cherrypy.tree.apps.items(),
- conf('server.thread_pool'),
- conf('server.socket_host'),
- request_queue_size = conf('server.socket_queue_size'),
- timeout = conf('server.socket_timeout'),
+ server.thread_pool,
+ server.socket_host,
+ request_queue_size = server.socket_queue_size,
+ timeout = server.socket_timeout,
)
- s.protocol = conf('server.protocol_version', 'HTTP/1.1')
+ s.protocol = server.protocol_version
diff --git a/cherrypy/lib/caching.py b/cherrypy/lib/caching.py
index 778976f4..10e0b4d5 100644
--- a/cherrypy/lib/caching.py
+++ b/cherrypy/lib/caching.py
@@ -91,8 +91,8 @@ def init(cache_class=None):
def get():
# Ignore POST, PUT, DELETE.
# See http://www.w3.org/Protocols/rfc2616/rfc2616-sec13.html#sec13.10.
- invalid = cherrypy.config.get("tools.caching.invalid_methods",
- ("POST", "PUT", "DELETE"))
+ invalid = cherrypy.request.config.get("tools.caching.invalid_methods",
+ ("POST", "PUT", "DELETE"))
if cherrypy.request.method in invalid:
cherrypy.request.cached = c = False
else:
diff --git a/cherrypy/lib/sessions.py b/cherrypy/lib/sessions.py
index 30bbc74c..43b450a8 100644
--- a/cherrypy/lib/sessions.py
+++ b/cherrypy/lib/sessions.py
@@ -353,6 +353,9 @@ def close():
sess.release_lock()
close.failsafe = True
+
+_def_session = RamSession()
+
def init(storage_type='ram', path=None, path_header=None, name='session_id',
timeout=60, domain=None, secure=False, locking='implicit',
clean_freq=5, **kwargs):
@@ -369,7 +372,7 @@ def init(storage_type='ram', path=None, path_header=None, name='session_id',
id = request.simple_cookie[name].value
if not hasattr(cherrypy, "session"):
- cherrypy.session = cherrypy._ThreadLocalProxy('session')
+ cherrypy.session = cherrypy._ThreadLocalProxy('session', _def_session)
# Create and attach a new Session instance to cherrypy.request.
# It will possess a reference to (and lock, and lazily load)
diff --git a/cherrypy/test/benchmark.py b/cherrypy/test/benchmark.py
index a8186651..b12bfc5d 100644
--- a/cherrypy/test/benchmark.py
+++ b/cherrypy/test/benchmark.py
@@ -65,7 +65,7 @@ cherrypy.config.update({
'server.socket_host': 'localhost',
'server.socket_port': 8080,
'server.max_request_header_size': 0,
- 'request.max_body_size': 0,
+ 'server.max_request_body_size': 0,
})
appconf = {
@@ -180,7 +180,7 @@ Finished 1000 requests
self.concurrency = concurrency
def args(self):
- port = cherrypy.config.get('server.socket_port')
+ port = cherrypy.server.socket_port
assert self.concurrency > 0
assert self.requests > 0
return ("-k -n %s -c %s http://localhost:%s%s" %
@@ -240,17 +240,17 @@ def print_report(rows):
def run_standard_benchmarks():
print
print ("Client Thread Report (1000 requests, 14 byte response body, "
- "%s server threads):" % cherrypy.config.get('server.thread_pool'))
+ "%s server threads):" % cherrypy.server.thread_pool)
print_report(thread_report())
print
print ("Client Thread Report (1000 requests, 14 bytes via staticdir, "
- "%s server threads):" % cherrypy.config.get('server.thread_pool'))
+ "%s server threads):" % cherrypy.server.thread_pool)
print_report(thread_report("%s/static/index.html" % SCRIPT_NAME))
print
print ("Size Report (1000 requests, 50 client threads, "
- "%s server threads):" % cherrypy.config.get('server.thread_pool'))
+ "%s server threads):" % cherrypy.server.thread_pool)
print_report(size_report())
diff --git a/cherrypy/test/helper.py b/cherrypy/test/helper.py
index 009249ec..1b67af70 100644
--- a/cherrypy/test/helper.py
+++ b/cherrypy/test/helper.py
@@ -154,7 +154,7 @@ def testmain(conf=None):
def _test_main_thread():
try:
- webtest.WebCase.PORT = cherrypy.config.get('server.socket_port')
+ webtest.WebCase.PORT = cherrypy.server.socket_port
webtest.main()
finally:
thread.interrupt_main()
diff --git a/cherrypy/test/test.py b/cherrypy/test/test.py
index 54225cbd..f7461746 100644
--- a/cherrypy/test/test.py
+++ b/cherrypy/test/test.py
@@ -39,7 +39,7 @@ class TestHarness(object):
print
if isinstance(conf, basestring):
- conf = cherrypy.config.dict_from_config_file(conf)
+ conf = cherrypy.config._Parser().dict_from_file(conf)
baseconf = {'server.socket_host': '127.0.0.1',
'server.socket_port': self.port,
'server.thread_pool': 10,
diff --git a/cherrypy/test/test_caching.py b/cherrypy/test/test_caching.py
index 54665914..7b2405d3 100644
--- a/cherrypy/test/test_caching.py
+++ b/cherrypy/test/test_caching.py
@@ -120,7 +120,7 @@ class CacheTest(helper.CPWebCase):
self.assertStatus("200 OK")
# This also gives us a chance to test 0 expiry with no other headers
self.assertHeader("Pragma", "no-cache")
- if cherrypy.config.get('server.protocol_version') == "HTTP/1.1":
+ if cherrypy.server.protocol_version == "HTTP/1.1":
self.assertHeader("Cache-Control", "no-cache")
d = self.assertHeader("Date")
self.assertHeader("Expires", d)
@@ -129,7 +129,7 @@ class CacheTest(helper.CPWebCase):
self.getPage("/expires/index.html")
self.assertStatus("200 OK")
self.assertHeader("Pragma", "no-cache")
- if cherrypy.config.get('server.protocol_version') == "HTTP/1.1":
+ if cherrypy.server.protocol_version == "HTTP/1.1":
self.assertHeader("Cache-Control", "no-cache")
d = self.assertHeader("Date")
self.assertHeader("Expires", d)
@@ -138,7 +138,7 @@ class CacheTest(helper.CPWebCase):
self.getPage("/expires/cacheable")
self.assertStatus("200 OK")
self.assertHeader("Pragma", "no-cache")
- if cherrypy.config.get('server.protocol_version') == "HTTP/1.1":
+ if cherrypy.server.protocol_version == "HTTP/1.1":
self.assertHeader("Cache-Control", "no-cache")
d = self.assertHeader("Date")
self.assertHeader("Expires", d)
@@ -148,7 +148,7 @@ class CacheTest(helper.CPWebCase):
# dynamic sets Cache-Control to private but it should be
# overwritten here ...
self.assertHeader("Pragma", "no-cache")
- if cherrypy.config.get('server.protocol_version') == "HTTP/1.1":
+ if cherrypy.server.protocol_version == "HTTP/1.1":
self.assertHeader("Cache-Control", "no-cache")
d = self.assertHeader("Date")
self.assertHeader("Expires", d)
diff --git a/cherrypy/test/test_config.py b/cherrypy/test/test_config.py
index b7fe3cc7..d6fab72f 100644
--- a/cherrypy/test/test_config.py
+++ b/cherrypy/test/test_config.py
@@ -1,4 +1,5 @@
"""Tests for the CherryPy configuration system."""
+
from cherrypy.test import test
test.prefer_parent_path()
@@ -14,7 +15,7 @@ def setup_server():
'bar': 'that'}
def index(self, key):
- return cherrypy.config.get(key, "None")
+ return cherrypy.request.config.get(key, "None")
index.exposed = True
global_ = index
xyz = index
@@ -25,19 +26,19 @@ def setup_server():
'baz': 'that2'}
def index(self, key):
- return cherrypy.config.get(key, "None")
+ return cherrypy.request.config.get(key, "None")
index.exposed = True
nex = index
def bar(self, key):
- return cherrypy.config.get(key, "None")
+ return cherrypy.request.config.get(key, "None")
bar.exposed = True
bar._cp_config = {'foo': 'this3', 'bax': 'this4'}
class Another:
def index(self, key):
- return str(cherrypy.config.get(key, "None"))
+ return str(cherrypy.request.config.get(key, "None"))
index.exposed = True
root = Root()
@@ -73,6 +74,31 @@ class ConfigTests(helper.CPWebCase):
for path, key, expected in tests:
self.getPage(path + "?key=" + key)
self.assertBody(expected)
+
+ def testExternalDispatch(self):
+ # 'cherrypy.request' should reference a default instance
+ cherrypy.request.app = cherrypy.tree.apps[""]
+ cherrypy.request.dispatch("/foo/bar")
+ expectedconf = {
+ # From CP defaults
+ 'tools.log_headers.on': False,
+ 'tools.log_tracebacks.on': True,
+ 'request.show_tracebacks': True,
+ 'log.screen': False,
+ 'environment': 'test_suite',
+ 'autoreload.on': False,
+ # From globalconf
+ 'luxuryyacht': 'throatwobblermangrove',
+ # From Root._cp_config
+ 'bar': 'that',
+ # From Foo._cp_config
+ 'baz': 'that2',
+ # From Foo.bar._cp_config
+ 'foo': 'this3',
+ 'bax': 'this4',
+ }
+ for k, v in expectedconf.iteritems():
+ self.assertEqual(cherrypy.request.config[k], v)
if __name__ == '__main__':
diff --git a/cherrypy/test/test_conn.py b/cherrypy/test/test_conn.py
index 75120324..af744b3a 100644
--- a/cherrypy/test/test_conn.py
+++ b/cherrypy/test/test_conn.py
@@ -38,7 +38,7 @@ def setup_server():
cherrypy.tree.mount(Root())
cherrypy.config.update({
- 'request.max_body_size': 100,
+ 'server.max_request_body_size': 100,
'environment': 'test_suite',
})
@@ -48,7 +48,7 @@ from cherrypy.test import helper
class ConnectionTests(helper.CPWebCase):
def test_HTTP11(self):
- if cherrypy.config.get('server.protocol_version') != "HTTP/1.1":
+ if cherrypy.server.protocol_version != "HTTP/1.1":
print "skipped ",
return
@@ -103,7 +103,7 @@ class ConnectionTests(helper.CPWebCase):
self.assertRaises(httplib.NotConnected, self.getPage, "/")
def test_HTTP11_pipelining(self):
- if cherrypy.config.get('server.protocol_version') != "HTTP/1.1":
+ if cherrypy.server.protocol_version != "HTTP/1.1":
print "skipped ",
return
@@ -141,7 +141,7 @@ class ConnectionTests(helper.CPWebCase):
conn.close()
def test_100_Continue(self):
- if cherrypy.config.get('server.protocol_version') != "HTTP/1.1":
+ if cherrypy.server.protocol_version != "HTTP/1.1":
print "skipped ",
return
@@ -193,7 +193,7 @@ class ConnectionTests(helper.CPWebCase):
self.assertBody("thanks for 'I am a small file' (text/plain)")
def test_Chunked_Encoding(self):
- if cherrypy.config.get('server.protocol_version') != "HTTP/1.1":
+ if cherrypy.server.protocol_version != "HTTP/1.1":
print "skipped ",
return
@@ -220,7 +220,7 @@ class ConnectionTests(helper.CPWebCase):
self.assertStatus('200 OK')
self.assertBody("thanks for 'xx\r\nxxxxyyyyy' (application/x-json)")
- # Try a chunked request that exceeds request.max_body_size.
+ # Try a chunked request that exceeds server.max_request_body_size.
# Note that the delimiters and trailer are included.
body = "5f\r\n" + ("x" * 95) + "\r\n0\r\n\r\n"
conn.putrequest("POST", "/upload", skip_host=True)
diff --git a/cherrypy/test/test_core.py b/cherrypy/test/test_core.py
index ff11bfed..2b27e21e 100644
--- a/cherrypy/test/test_core.py
+++ b/cherrypy/test/test_core.py
@@ -219,7 +219,8 @@ def setup_server():
raise ValueError()
# We support Python 2.3, but the @-deco syntax would look like this:
- # @cherrypy.config.wrap(**{"response.stream": True})
+ # @cherrypy.config.response.stream(True)
+ # @cherrypy.config.tools.static.on(True)
def page_streamed(self):
yield "word up"
raise ValueError()
@@ -370,13 +371,13 @@ def setup_server():
return u'Wrong login/password'
cherrypy.config.update({
- 'log.error.file': log_file,
+ 'log.error_file': log_file,
'environment': 'test_suite',
- 'request.max_body_size': 200,
+ 'server.max_request_body_size': 200,
'server.max_request_header_size': 500,
})
appconf = {
- '/': {'log.access.file': log_access_file},
+ '/': {'log.access_file': log_access_file},
'/method': {'request.methods_with_bodies': ("POST", "PUT", "PROPFIND")},
}
cherrypy.tree.mount(root, conf=appconf)
@@ -584,7 +585,7 @@ class CoreRequestHandlingTest(helper.CPWebCase):
self.getPage("/redirect/stringify", protocol="HTTP/1.0")
self.assertStatus(200)
self.assertBody("(['http://127.0.0.1:%s/'], 302)" % self.PORT)
- if cherrypy.config.get('server.protocol_version') == "HTTP/1.1":
+ if cherrypy.server.protocol_version == "HTTP/1.1":
self.getPage("/redirect/stringify", protocol="HTTP/1.1")
self.assertStatus(200)
self.assertBody("(['http://127.0.0.1:%s/'], 303)" % self.PORT)
@@ -627,7 +628,6 @@ class CoreRequestHandlingTest(helper.CPWebCase):
# Test custom error page.
self.getPage("/error/custom")
self.assertStatus(404)
- self.assertEqual(len(self.body), 513)
self.assertBody("Hello, world\r\n" + (" " * 499))
# Test error in custom error page (ticket #305).
@@ -652,7 +652,7 @@ class CoreRequestHandlingTest(helper.CPWebCase):
self.assertBody("[(2, 5), (7, 8)]")
# Get a partial file.
- if cherrypy.config.get('server.protocol_version') == "HTTP/1.1":
+ if cherrypy.server.protocol_version == "HTTP/1.1":
self.getPage("/ranges/slice_file", [('Range', 'bytes=2-5')])
self.assertStatus(206)
self.assertHeader("Content-Type", "text/html")
@@ -688,7 +688,7 @@ llo,
self.getPage("/ranges/slice_file", [('Range', 'bytes=2300-2900')])
self.assertStatus(416)
self.assertHeader("Content-Range", "bytes */14")
- elif cherrypy.config.get('server.protocol_version') == "HTTP/1.0":
+ elif cherrypy.server.protocol_version == "HTTP/1.0":
# Test Range behavior with HTTP/1.0 request
self.getPage("/ranges/slice_file", [('Range', 'bytes=2-5')])
self.assertStatus(200)
@@ -759,7 +759,7 @@ llo,
'Expires', 'Location', 'Server']:
self.assertEqual(hnames.count(key), 1)
- if cherrypy.config.get('server.protocol_version') == "HTTP/1.1":
+ if cherrypy.server.protocol_version == "HTTP/1.1":
# Test RFC-2047-encoded request and response header values
self.getPage("/headers/ifmatch",
[('If-Match', '=?utf-8?q?=E2=84=ABngstr=C3=B6m?=')])
diff --git a/cherrypy/test/test_objectmapping.py b/cherrypy/test/test_objectmapping.py
index 33ad1468..666196ed 100644
--- a/cherrypy/test/test_objectmapping.py
+++ b/cherrypy/test/test_objectmapping.py
@@ -32,7 +32,7 @@ def setup_server():
return "not exposed"
def confvalue(self):
- return cherrypy.config.get("user")
+ return cherrypy.request.config.get("user")
confvalue.exposed = True
def mapped_func(self, ID=None):
diff --git a/cherrypy/test/test_states.py b/cherrypy/test/test_states.py
index dfb530a6..06491642 100644
--- a/cherrypy/test/test_states.py
+++ b/cherrypy/test/test_states.py
@@ -86,8 +86,8 @@ class ServerStateTests(helper.CPWebCase):
self.assertEqual(cherrypy.engine.state, 1)
if self.server_class:
- host = cherrypy.config.get('server.socket_host')
- port = cherrypy.config.get('server.socket_port')
+ host = cherrypy.server.socket_host
+ port = cherrypy.server.socket_port
self.assertRaises(IOError, cherrypy._cpserver.check_port, host, port)
# The db_connection should be running now
@@ -231,8 +231,8 @@ class ServerStateTests(helper.CPWebCase):
"test_states_demo.py")
# Start the demo script in a new process
- host = cherrypy.config.get("server.socket_host")
- port = cherrypy.config.get("server.socket_port")
+ host = cherrypy.server.socket_host
+ port = cherrypy.server.socket_port
cherrypy._cpserver.wait_for_free_port(host, port)
os.spawnl(os.P_NOWAIT, sys.executable, sys.executable,
demoscript, host, str(port))
diff --git a/cherrypy/test/test_tools.py b/cherrypy/test/test_tools.py
index fdbf5159..3f80e1d2 100644
--- a/cherrypy/test/test_tools.py
+++ b/cherrypy/test/test_tools.py
@@ -94,7 +94,9 @@ def setup_server():
pipe._cp_config = {'hooks.before_request_body': pipe_body}
# Multiple decorators; include kwargs just for fun.
+ # XXX Note that encode must run before gzip.
def decorated_euro(self):
+ print cherrypy.request.hooks.callbacks
yield u"Hello,"
yield u"world"
yield europoundUnicode
diff --git a/cherrypy/test/test_tutorials.py b/cherrypy/test/test_tutorials.py
index a15e43a1..c3d7c552 100644
--- a/cherrypy/test/test_tutorials.py
+++ b/cherrypy/test/test_tutorials.py
@@ -36,7 +36,7 @@ def setup_server():
sessions.exposed = True
def traceback_setting():
- return repr(cherrypy.config.get('request.show_tracebacks'))
+ return repr(cherrypy.request.show_tracebacks)
traceback_setting.exposed = True
class Dummy:
diff --git a/cherrypy/tutorial/tut10_http_errors.py b/cherrypy/tutorial/tut10_http_errors.py
index f6d29cf2..0ae31b89 100644
--- a/cherrypy/tutorial/tut10_http_errors.py
+++ b/cherrypy/tutorial/tut10_http_errors.py
@@ -22,7 +22,7 @@ class HTTPErrorDemo(object):
def index(self):
# display some links that will result in errors
- tracebacks = cherrypy.config.get('request.show_tracebacks')
+ tracebacks = cherrypy.request.show_tracebacks
if tracebacks:
trace = 'off'
else:
@@ -48,7 +48,7 @@ class HTTPErrorDemo(object):
def toggleTracebacks(self):
# simple function to toggle tracebacks on and off
- tracebacks = cherrypy.config.get('request.show_tracebacks')
+ tracebacks = cherrypy.request.show_tracebacks
cherrypy.config.update({'request.show_tracebacks': not tracebacks})
# redirect back to the index