make_app() now uses the debugger param in DebugMiddleware()
Setting app.debugger in setup.py now takes proper effect. A warning is issued if the entry point is not callable. Change-Id: I58a860b8ef0e1cb956b4554071275c024a1949d2 Closes-Bug: #1449573
This commit is contained in:
@@ -29,11 +29,24 @@ browser for easy debugging:
|
|||||||
|
|
||||||
To further aid in debugging, the middleware includes the ability to repeat the
|
To further aid in debugging, the middleware includes the ability to repeat the
|
||||||
offending request, automatically inserting a breakpoint, and dropping your
|
offending request, automatically inserting a breakpoint, and dropping your
|
||||||
console into the Python debugger, ``pdb``:
|
console into the Python debugger, ``pdb.post_mortem``:
|
||||||
|
|
||||||
.. figure:: debug-middleware-2.png
|
.. figure:: debug-middleware-2.png
|
||||||
:alt: Pecan debug middleware request debugger.
|
:alt: Pecan debug middleware request debugger.
|
||||||
|
|
||||||
|
You can also use any debugger with a suitable ``post_mortem`` entry point.
|
||||||
|
For example, to use the `PuDB Debugger <http://pypi.python.org/pypi/pudb>`_,
|
||||||
|
set ``debugger`` like so::
|
||||||
|
|
||||||
|
import pudb
|
||||||
|
|
||||||
|
app = {
|
||||||
|
...
|
||||||
|
'debug': True,
|
||||||
|
'debugger': pudb.post_mortem,
|
||||||
|
...
|
||||||
|
}
|
||||||
|
|
||||||
.. seealso::
|
.. seealso::
|
||||||
|
|
||||||
Refer to the `pdb documentation
|
Refer to the `pdb documentation
|
||||||
|
|||||||
@@ -4,19 +4,16 @@ from .core import (
|
|||||||
)
|
)
|
||||||
from .decorators import expose
|
from .decorators import expose
|
||||||
from .hooks import RequestViewerHook
|
from .hooks import RequestViewerHook
|
||||||
from .middleware.debug import DebugMiddleware
|
|
||||||
from .middleware.errordocument import ErrorDocumentMiddleware
|
|
||||||
from .middleware.recursive import RecursiveMiddleware
|
|
||||||
from .middleware.static import StaticFileMiddleware
|
|
||||||
|
|
||||||
from .configuration import set_config, Config
|
from .configuration import set_config, Config
|
||||||
from .configuration import _runtime_conf as conf
|
from .configuration import _runtime_conf as conf
|
||||||
|
from . import middleware
|
||||||
|
|
||||||
try:
|
try:
|
||||||
from logging.config import dictConfig as load_logging_config
|
from logging.config import dictConfig as load_logging_config
|
||||||
except ImportError:
|
except ImportError:
|
||||||
from logutils.dictconfig import dictConfig as load_logging_config # noqa
|
from logutils.dictconfig import dictConfig as load_logging_config # noqa
|
||||||
|
|
||||||
|
import six
|
||||||
import warnings
|
import warnings
|
||||||
|
|
||||||
|
|
||||||
@@ -40,6 +37,8 @@ def make_app(root, **kw):
|
|||||||
debug mode is set.
|
debug mode is set.
|
||||||
:param debug: A flag to enable debug mode. This enables the debug
|
:param debug: A flag to enable debug mode. This enables the debug
|
||||||
middleware and serving static files.
|
middleware and serving static files.
|
||||||
|
:param debugger: A callable to start debugging, defaulting to the Python
|
||||||
|
debugger entry point ``pdb.post_mortem``.
|
||||||
:param wrap_app: A function or middleware class to wrap the Pecan app.
|
:param wrap_app: A function or middleware class to wrap the Pecan app.
|
||||||
This must either be a wsgi middleware class or a
|
This must either be a wsgi middleware class or a
|
||||||
function that returns a wsgi application. This wrapper
|
function that returns a wsgi application. This wrapper
|
||||||
@@ -90,19 +89,28 @@ def make_app(root, **kw):
|
|||||||
# Configuration for serving custom error messages
|
# Configuration for serving custom error messages
|
||||||
errors = kw.get('errors', getattr(conf.app, 'errors', {}))
|
errors = kw.get('errors', getattr(conf.app, 'errors', {}))
|
||||||
if errors:
|
if errors:
|
||||||
app = ErrorDocumentMiddleware(app, errors)
|
app = middleware.errordocument.ErrorDocumentMiddleware(app, errors)
|
||||||
|
|
||||||
# Included for internal redirect support
|
# Included for internal redirect support
|
||||||
app = RecursiveMiddleware(app)
|
app = middleware.recursive.RecursiveMiddleware(app)
|
||||||
|
|
||||||
# When in debug mode, load our exception dumping middleware
|
# When in debug mode, load our exception dumping middleware
|
||||||
static_root = kw.get('static_root', None)
|
static_root = kw.get('static_root', None)
|
||||||
if debug:
|
if debug:
|
||||||
app = DebugMiddleware(app)
|
debugger = kw.get('debugger', None)
|
||||||
|
debugger_kwargs = {}
|
||||||
|
if six.callable(debugger):
|
||||||
|
debugger_kwargs['debugger'] = debugger
|
||||||
|
elif debugger:
|
||||||
|
warnings.warn(
|
||||||
|
"`app.debugger` is not callable, ignoring",
|
||||||
|
RuntimeWarning
|
||||||
|
)
|
||||||
|
app = middleware.debug.DebugMiddleware(app, **debugger_kwargs)
|
||||||
|
|
||||||
# Support for serving static files (for development convenience)
|
# Support for serving static files (for development convenience)
|
||||||
if static_root:
|
if static_root:
|
||||||
app = StaticFileMiddleware(app, static_root)
|
app = middleware.static.StaticFileMiddleware(app, static_root)
|
||||||
|
|
||||||
elif static_root:
|
elif static_root:
|
||||||
warnings.warn(
|
warnings.warn(
|
||||||
|
|||||||
@@ -0,0 +1,4 @@
|
|||||||
|
from . import debug
|
||||||
|
from . import errordocument
|
||||||
|
from . import recursive
|
||||||
|
from . import static
|
||||||
|
|||||||
@@ -253,7 +253,10 @@ class DebugMiddleware(object):
|
|||||||
|
|
||||||
To further aid in debugging, the middleware includes the ability to repeat
|
To further aid in debugging, the middleware includes the ability to repeat
|
||||||
the offending request, automatically inserting a breakpoint, and dropping
|
the offending request, automatically inserting a breakpoint, and dropping
|
||||||
your console into the Python debugger, ``pdb``.
|
your console into the Python debugger, ``pdb.post_mortem``.
|
||||||
|
|
||||||
|
You can also use any debugger with a suitable ``post_mortem`` entry point
|
||||||
|
such as the `PuDB Debugger <http://pypi.python.org/pypi/pudb>`_,
|
||||||
|
|
||||||
For more information, refer to the `documentation for pdb
|
For more information, refer to the `documentation for pdb
|
||||||
<http://docs.python.org/library/pdb.html>`_ available on the Python
|
<http://docs.python.org/library/pdb.html>`_ available on the Python
|
||||||
@@ -261,7 +264,7 @@ class DebugMiddleware(object):
|
|||||||
|
|
||||||
:param app: the application to wrap.
|
:param app: the application to wrap.
|
||||||
:param debugger: a callable to start debugging, defaulting to the Python
|
:param debugger: a callable to start debugging, defaulting to the Python
|
||||||
debugger, ``pdb``.
|
debugger entry point ``pdb.post_mortem``.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, app, debugger=pdb.post_mortem):
|
def __init__(self, app, debugger=pdb.post_mortem):
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import warnings
|
|||||||
|
|
||||||
import webob
|
import webob
|
||||||
from webob.exc import HTTPNotFound
|
from webob.exc import HTTPNotFound
|
||||||
|
import mock
|
||||||
from webtest import TestApp
|
from webtest import TestApp
|
||||||
import six
|
import six
|
||||||
from six import b as b_
|
from six import b as b_
|
||||||
@@ -1616,6 +1617,41 @@ class TestNonCanonical(PecanTestCase):
|
|||||||
assert len(wrapped_apps) == 1
|
assert len(wrapped_apps) == 1
|
||||||
|
|
||||||
|
|
||||||
|
class TestDebugging(PecanTestCase):
|
||||||
|
def test_debugger_setup(self):
|
||||||
|
class RootController(object):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def debugger():
|
||||||
|
pass
|
||||||
|
|
||||||
|
app_conf = dict(
|
||||||
|
debug=True,
|
||||||
|
debugger=debugger
|
||||||
|
)
|
||||||
|
with mock.patch('pecan.middleware.debug.DebugMiddleware') \
|
||||||
|
as patched_debug_middleware:
|
||||||
|
app = make_app(RootController(), **app_conf)
|
||||||
|
args, kwargs = patched_debug_middleware.call_args
|
||||||
|
assert kwargs.get('debugger') == debugger
|
||||||
|
|
||||||
|
def test_invalid_debugger_setup(self):
|
||||||
|
class RootController(object):
|
||||||
|
pass
|
||||||
|
|
||||||
|
debugger = 'not_a_valid_entry_point'
|
||||||
|
|
||||||
|
app_conf = dict(
|
||||||
|
debug=True,
|
||||||
|
debugger=debugger
|
||||||
|
)
|
||||||
|
with mock.patch('pecan.middleware.debug.DebugMiddleware') \
|
||||||
|
as patched_debug_middleware:
|
||||||
|
app = make_app(RootController(), **app_conf)
|
||||||
|
args, kwargs = patched_debug_middleware.call_args
|
||||||
|
assert kwargs.get('debugger') is None
|
||||||
|
|
||||||
|
|
||||||
class TestLogging(PecanTestCase):
|
class TestLogging(PecanTestCase):
|
||||||
|
|
||||||
def test_logging_setup(self):
|
def test_logging_setup(self):
|
||||||
|
|||||||
Reference in New Issue
Block a user