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:
@@ -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
|
||||
.......................
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
@@ -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')
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user