summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRyan Petrello <lists@ryanpetrello.com>2013-08-08 14:16:36 -0400
committerRyan Petrello <lists@ryanpetrello.com>2013-08-08 14:40:57 -0400
commitfb2cf166aaf5b5af461879ec5b7a46806e8aee45 (patch)
tree55e258c72fc496b79d77c6d43e0750c752b89cec
parent38c64ff3518470ff668a06725abb4d2f2d5ab7ba (diff)
downloadpecan-fb2cf166aaf5b5af461879ec5b7a46806e8aee45.tar.gz
Make some notable changes to how ``pecan.conf.app`` is passed to a new app.
* Now pecan.conf.app items are treated as keywords passed directly to Pecan apps. This means no more tinkering with *both* your configuration file *and* your app.py file. * Removed support for the RequestViewerHook config file shortcut (because now you can easily specify hooks via configuration).
-rw-r--r--docs/source/hooks.rst41
-rw-r--r--pecan/__init__.py22
-rw-r--r--pecan/core.py21
-rw-r--r--pecan/scaffolds/base/+package+/app.py_tmpl14
-rw-r--r--pecan/tests/test_hooks.py29
5 files changed, 42 insertions, 85 deletions
diff --git a/docs/source/hooks.rst b/docs/source/hooks.rst
index 9a9d099..3185355 100644
--- a/docs/source/hooks.rst
+++ b/docs/source/hooks.rst
@@ -52,17 +52,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.
@@ -123,20 +121,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
.............................
@@ -177,25 +161,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
.......................
diff --git a/pecan/__init__.py b/pecan/__init__.py
index cf175b8..cf93e05 100644
--- a/pecan/__init__.py
+++ b/pecan/__init__.py
@@ -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)
diff --git a/pecan/core.py b/pecan/core.py
index c09763d..8f6e32f 100644
--- a/pecan/core.py
+++ b/pecan/core.py
@@ -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')
diff --git a/pecan/scaffolds/base/+package+/app.py_tmpl b/pecan/scaffolds/base/+package+/app.py_tmpl
index 191fc11..098deb4 100644
--- a/pecan/scaffolds/base/+package+/app.py_tmpl
+++ b/pecan/scaffolds/base/+package+/app.py_tmpl
@@ -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)
diff --git a/pecan/tests/test_hooks.py b/pecan/tests/test_hooks.py
index 66947ca..9c3192e 100644
--- a/pecan/tests/test_hooks.py
+++ b/pecan/tests/test_hooks.py
@@ -1017,21 +1017,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()
@@ -1043,7 +1028,9 @@ class TestRequestViewerHook(PecanTestCase):
app = TestApp(
make_app(
- RootController(), hooks=[RequestViewerHook(writer=_stdout)]
+ RootController(), hooks=lambda: [
+ RequestViewerHook(writer=_stdout)
+ ]
)
)
response = app.get('/')
@@ -1074,7 +1061,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)
@@ -1104,7 +1093,7 @@ class TestRequestViewerHook(PecanTestCase):
app = TestApp(
make_app(
RootController(),
- hooks=[
+ hooks=lambda: [
RequestViewerHook(
config={'items': ['path']}, writer=_stdout
)
@@ -1139,7 +1128,7 @@ class TestRequestViewerHook(PecanTestCase):
app = TestApp(
make_app(
RootController(),
- hooks=[
+ hooks=lambda: [
RequestViewerHook(
config={'blacklist': ['/']}, writer=_stdout
)
@@ -1166,7 +1155,7 @@ class TestRequestViewerHook(PecanTestCase):
app = TestApp(
make_app(
RootController(),
- hooks=[
+ hooks=lambda: [
RequestViewerHook(
config={'items': ['date']}, writer=_stdout
)