Merge pull request #226 from ryanpetrello/next

Make some notable changes to how ``pecan.conf.app`` is passed to a new app.
This commit is contained in:
markmcclain
2013-08-08 16:45:46 -07:00
5 changed files with 42 additions and 85 deletions

View File

@@ -54,17 +54,15 @@ Attaching Hooks
---------------
Hooks can be attached in a project-wide manner by specifying a list of hooks
in your project's ``app.py`` file.
in your project's configuration file.
::
from application.root import RootController
from my_hooks import SimpleHook
app = make_app(
RootController(),
hooks = [SimpleHook()]
)
app = {
'root' : '...'
# ...
'hooks': lambda: [SimpleHook()]
}
Hooks can also be applied selectively to controllers and their sub-controllers
using the :attr:`__hooks__` attribute on one or more controllers.
@@ -125,20 +123,6 @@ By default, both outputs are enabled.
* :ref:`pecan_hooks`
Enabling RequestViewerHook
..........................
This hook can be automatically added to the application itself if a certain
key, ``requestviewer``, exists in the configuration used for the app, e.g.::
app = {}
server = {}
requestviewer = {}
It does not need to contain anything (could be an empty dictionary), and this
is enough to force Pecan to load this hook when the WSGI application is
created.
Configuring RequestViewerHook
.............................
@@ -179,25 +163,16 @@ response::
X-Pecan-params []
X-Pecan-hooks ['RequestViewerHook']
The hook can be configured via a dictionary (or Config object from Pecan) when
adding it to the application or via the ``requestviewer`` key in the actual
configuration being passed to the application.
The configuration dictionary is flexible (none of the keys are required) and
can hold two keys: ``items`` and ``blacklist``.
This is how the hook would look if configured directly when using ``make_app``
(shortened for brevity)::
This is how the hook would look if configured directly (shortened for brevity)::
...
hooks = [
'hooks': lambda: [
RequestViewerHook({'items':['path']})
]
And the same configuration could be set in the config file like::
requestviewer = {'items:['path']}
Modifying Output Format
.......................

View File

@@ -25,8 +25,7 @@ __all__ = [
]
def make_app(root, static_root=None, logging={}, debug=False,
wrap_app=None, **kw):
def make_app(root, **kw):
'''
Utility for creating the Pecan application object. This function should
generally be called from the ``setup_app`` function in your project's
@@ -37,8 +36,6 @@ def make_app(root, static_root=None, logging={}, debug=False,
:param static_root: The relative path to a directory containing static
files. Serving static files is only enabled when
debug mode is set.
:param logging: A dictionary used to configure logging. This uses
``logging.config.dictConfig``.
:param debug: A flag to enable debug mode. This enables the debug
middleware and serving static files.
:param wrap_app: A function or middleware class to wrap the Pecan app.
@@ -49,18 +46,15 @@ def make_app(root, static_root=None, logging={}, debug=False,
This should be used if you want to use middleware to
perform authentication or intercept all requests before
they are routed to the root controller.
:param logging: A dictionary used to configure logging. This uses
``logging.config.dictConfig``.
All other keyword arguments are passed in to the Pecan app constructor.
:returns: a ``Pecan`` object.
'''
# A shortcut for the RequestViewerHook middleware.
if hasattr(conf, 'requestviewer'):
existing_hooks = kw.get('hooks', [])
existing_hooks.append(RequestViewerHook(conf.requestviewer))
kw['hooks'] = existing_hooks
# Pass logging configuration (if it exists) on to the Python logging module
logging = kw.get('logging', {})
if logging:
if isinstance(logging, Config):
logging = logging.to_dict()
@@ -72,17 +66,21 @@ def make_app(root, static_root=None, logging={}, debug=False,
app = Pecan(root, **kw)
# Optionally wrap the app in another WSGI app
wrap_app = kw.get('wrap_app', None)
if wrap_app:
app = wrap_app(app)
# Configuration for serving custom error messages
if hasattr(conf.app, 'errors'):
app = ErrorDocumentMiddleware(app, conf.app.errors)
errors = kw.get('errors', getattr(conf.app, 'errors', {}))
if errors:
app = ErrorDocumentMiddleware(app, errors)
# Included for internal redirect support
app = RecursiveMiddleware(app)
# When in debug mode, load our exception dumping middleware
static_root = kw.get('static_root', None)
debug = kw.get('debug', False)
if debug:
app = DebugMiddleware(app)

View File

@@ -173,11 +173,12 @@ class Pecan(object):
:param root: A string representing a root controller object (e.g.,
"myapp.controller.root.RootController")
:param default_renderer: The default rendering engine to use. Defaults
to mako.
:param template_path: The default relative path to use for templates.
Defaults to 'templates'.
:param hooks: A list of Pecan hook objects to use for this application.
:param default_renderer: The default template rendering engine to use.
Defaults to mako.
:param template_path: A relative file system path (from the project root)
where template files live. Defaults to 'templates'.
:param hooks: A callable which returns a list of
:class:`pecan.hooks.PecanHook`s
:param custom_renderers: Custom renderer objects, as a dictionary keyed
by engine name.
:param extra_template_vars: Any variables to inject into the template
@@ -195,9 +196,9 @@ class Pecan(object):
)
def __init__(self, root, default_renderer='mako',
template_path='templates', hooks=[], custom_renderers={},
extra_template_vars={}, force_canonical=True,
guess_content_type_from_ext=True):
template_path='templates', hooks=lambda: [],
custom_renderers={}, extra_template_vars={},
force_canonical=True, guess_content_type_from_ext=True, **kw):
if isinstance(root, six.string_types):
root = self.__translate_root__(root)
@@ -205,7 +206,11 @@ class Pecan(object):
self.root = root
self.renderers = RendererFactory(custom_renderers, extra_template_vars)
self.default_renderer = default_renderer
# pre-sort these so we don't have to do it per-request
if six.callable(hooks):
hooks = hooks()
self.hooks = list(sorted(
hooks,
key=operator.attrgetter('priority')

View File

@@ -5,16 +5,6 @@ from ${package} import model
def setup_app(config):
model.init_model()
app_conf = dict(config.app)
return make_app(
config.app.root,
static_root=config.app.static_root,
template_path=config.app.template_path,
logging=getattr(config, 'logging', {}),
debug=getattr(config.app, 'debug', False),
force_canonical=getattr(config.app, 'force_canonical', True),
guess_content_type_from_ext=getattr(
config.app,
'guess_content_type_from_ext',
True),
)
return make_app(app_conf.pop('root'), **app_conf)

View File

@@ -1047,21 +1047,6 @@ class TestTransactionHook(PecanTestCase):
class TestRequestViewerHook(PecanTestCase):
def test_hook_from_config(self):
from pecan.configuration import _runtime_conf as conf
conf['requestviewer'] = {
'blacklist': ['/favicon.ico']
}
class RootController(object):
pass
app = make_app(RootController())
while hasattr(app, 'application'):
app = app.application
del conf.__values__['requestviewer']
assert app.hooks
def test_basic_single_default_hook(self):
_stdout = StringIO()
@@ -1073,7 +1058,9 @@ class TestRequestViewerHook(PecanTestCase):
app = TestApp(
make_app(
RootController(), hooks=[RequestViewerHook(writer=_stdout)]
RootController(), hooks=lambda: [
RequestViewerHook(writer=_stdout)
]
)
)
response = app.get('/')
@@ -1104,7 +1091,9 @@ class TestRequestViewerHook(PecanTestCase):
app = TestApp(
make_app(
RootController(), hooks=[RequestViewerHook(writer=_stdout)]
RootController(), hooks=lambda: [
RequestViewerHook(writer=_stdout)
]
)
)
response = app.get('/404', expect_errors=True)
@@ -1134,7 +1123,7 @@ class TestRequestViewerHook(PecanTestCase):
app = TestApp(
make_app(
RootController(),
hooks=[
hooks=lambda: [
RequestViewerHook(
config={'items': ['path']}, writer=_stdout
)
@@ -1169,7 +1158,7 @@ class TestRequestViewerHook(PecanTestCase):
app = TestApp(
make_app(
RootController(),
hooks=[
hooks=lambda: [
RequestViewerHook(
config={'blacklist': ['/']}, writer=_stdout
)
@@ -1196,7 +1185,7 @@ class TestRequestViewerHook(PecanTestCase):
app = TestApp(
make_app(
RootController(),
hooks=[
hooks=lambda: [
RequestViewerHook(
config={'items': ['date']}, writer=_stdout
)