[Repoze-checkins] r1140 - in repoze.debug/trunk: . repoze/debug repoze/debug/tests
Chris McDonough
chrism at agendaless.com
Thu Jun 26 18:11:42 EDT 2008
Author: Chris McDonough <chrism at agendaless.com>
Date: Thu Jun 26 18:11:41 2008
New Revision: 1140
Log:
Add pdbpm middleware; recover from brownbag 0.3 (not all files added to dist).
Added:
repoze.debug/trunk/repoze/debug/canary.py (contents, props changed)
repoze.debug/trunk/repoze/debug/pdbpm.py (contents, props changed)
repoze.debug/trunk/repoze/debug/settings.py (contents, props changed)
repoze.debug/trunk/repoze/debug/tests/
repoze.debug/trunk/repoze/debug/tests/__init__.py (contents, props changed)
repoze.debug/trunk/repoze/debug/tests/test_canary.py (contents, props changed)
repoze.debug/trunk/repoze/debug/tests/test_pdbpm.py (contents, props changed)
repoze.debug/trunk/repoze/debug/tests/test_responselogger.py (contents, props changed)
Removed:
repoze.debug/trunk/repoze/debug/tests.py
Modified:
repoze.debug/trunk/CHANGES.txt
repoze.debug/trunk/README.txt
repoze.debug/trunk/setup.py
Modified: repoze.debug/trunk/CHANGES.txt
==============================================================================
--- repoze.debug/trunk/CHANGES.txt (original)
+++ repoze.debug/trunk/CHANGES.txt Thu Jun 26 18:11:41 2008
@@ -1,4 +1,9 @@
-Next release
+0.4 (2008/06/25)
+
+ - Add pdbpm middleware for dropping into the post-mortem debugger
+ upon an exception (copied from repoze.errorlog).
+
+0.3 (2008/06/25)
- Add 'canary' middleware for detecting environment dictionary
leaks. Add to your Paste config via 'egg:repoze.debug#canary'; it
Modified: repoze.debug/trunk/README.txt
==============================================================================
--- repoze.debug/trunk/README.txt (original)
+++ repoze.debug/trunk/README.txt Thu Jun 26 18:11:41 2008
@@ -147,6 +147,31 @@
know you are leaking WSGI environment dictionaries. Use e.g. Dozer to
find reference leaks.
+pdbpm middleware
+=================
+
+The 'pdbpm' middleware, when in the WSGI pipeline, will drop your
+(foregrounded) server process into the pdb post-mortem debugger upon
+any exception.
+
+Configuration via Python
+------------------------
+
+Wire up the middleware in your application::
+
+ from repoze.debug.pdbpm import PostMortemDebug
+ middleware = PostMortemDebug(app)
+
+Configuration via Paste
+------------------------
+
+Use the 'egg:repoze.debug#pdbpm' entry point in your Paste
+configuration, eg.::
+
+ [pipeline:main]
+ pipeline = egg:Paste#cgitb
+ egg:repoze.debug#pdbpm
+ myapp
Reporting Bugs / Development Versions
-------------------------------------
Added: repoze.debug/trunk/repoze/debug/canary.py
==============================================================================
--- (empty file)
+++ repoze.debug/trunk/repoze/debug/canary.py Thu Jun 26 18:11:41 2008
@@ -0,0 +1,14 @@
+class CanaryMiddleware:
+ def __init__(self, app):
+ self.app = app
+
+ def __call__(self, environ, start_response):
+ environ['repoze.debug.canary'] = Canary()
+ return self.app(environ, start_response)
+
+class Canary(object):
+ pass
+
+def make_middleware(app, global_conf):
+ """ Paste filter-app converter """
+ return CanaryMiddleware(app)
Added: repoze.debug/trunk/repoze/debug/pdbpm.py
==============================================================================
--- (empty file)
+++ repoze.debug/trunk/repoze/debug/pdbpm.py Thu Jun 26 18:11:41 2008
@@ -0,0 +1,19 @@
+import pdb
+import sys
+
+# stolen partly from z3c.evalexception
+def PostMortemDebug(application):
+ """Middleware that catches exceptions and invokes pdb's
+ post-mortem debugging facility."""
+ def middleware(environ, start_response):
+ try:
+ return application(environ, start_response)
+ except:
+ pdb.post_mortem(sys.exc_info()[2])
+ raise
+
+ return middleware
+
+def make_middleware(app, global_conf):
+ return PostMortemDebug(app)
+
Added: repoze.debug/trunk/repoze/debug/settings.py
==============================================================================
Added: repoze.debug/trunk/repoze/debug/tests/__init__.py
==============================================================================
--- (empty file)
+++ repoze.debug/trunk/repoze/debug/tests/__init__.py Thu Jun 26 18:11:41 2008
@@ -0,0 +1 @@
+# tests package
Added: repoze.debug/trunk/repoze/debug/tests/test_canary.py
==============================================================================
--- (empty file)
+++ repoze.debug/trunk/repoze/debug/tests/test_canary.py Thu Jun 26 18:11:41 2008
@@ -0,0 +1,38 @@
+import unittest
+
+class TestCanaryMiddleware(unittest.TestCase):
+ def _getTargetClass(self):
+ from repoze.debug.canary import CanaryMiddleware
+ return CanaryMiddleware
+
+ def _makeOne(self, app):
+ klass = self._getTargetClass()
+ return klass(app)
+
+ def test_call(self):
+ def app(environ, start_response):
+ environ['app_saw'] = True
+ return True
+ mw = self._makeOne(app)
+ environ = {}
+ result = mw(environ, None)
+ self.assertEqual(result, True)
+ from repoze.debug.canary import Canary
+ self.failUnless(isinstance(environ['repoze.debug.canary'], Canary))
+ self.assertEqual(environ['app_saw'], True)
+
+class TestMakeCanaryMiddleware(unittest.TestCase):
+ def _getFUT(self):
+ from repoze.debug.canary import make_middleware
+ return make_middleware
+
+ def test_maker(self):
+ f = self._getFUT()
+ mw = f(None, None)
+ self.assertEqual(mw.app, None)
+
+
+
+
+
+
Added: repoze.debug/trunk/repoze/debug/tests/test_pdbpm.py
==============================================================================
--- (empty file)
+++ repoze.debug/trunk/repoze/debug/tests/test_pdbpm.py Thu Jun 26 18:11:41 2008
@@ -0,0 +1,74 @@
+import unittest
+
+class TestPDBPM(unittest.TestCase):
+ def _getFUT(self):
+ from repoze.debug.pdbpm import PostMortemDebug
+ return PostMortemDebug
+
+ def _makeOne(self, app):
+ f = self._getFUT()
+ return f(app)
+
+ def test_post_mortem_withexc(self):
+ app = DummyApplication(KeyError)
+ mw = self._makeOne(app)
+ fake_pdb = FakePDB()
+ try:
+ import repoze.debug.pdbpm
+ old_pdb = repoze.debug.pdbpm.pdb
+ repoze.debug.pdbpm.pdb = fake_pdb
+ environ = {}
+ self.assertRaises(KeyError, mw, environ, None)
+ finally:
+ repoze.debug.pdb = old_pdb
+ self.assertEqual(fake_pdb.called, True)
+
+ def test_post_mortem_noexc(self):
+ app = DummyApplication()
+ mw = self._makeOne(app)
+ fake_pdb = FakePDB()
+ try:
+ import repoze.debug.pdbpm
+ old_pdb = repoze.debug.pdbpm.pdb
+ repoze.debug.pdbpm.pdb = fake_pdb
+ environ = {}
+ result = mw(environ, None)
+ finally:
+ repoze.debug.pdbpm.pdb = old_pdb
+ self.assertEqual(fake_pdb.called, False)
+ self.assertEqual(result, ['hello world'])
+
+ def test_paste_constructor(self):
+ app = DummyApplication()
+ from repoze.debug.pdbpm import make_middleware
+ mw = make_middleware(app, None)
+ fake_pdb = FakePDB()
+ try:
+ import repoze.debug.pdbpm
+ old_pdb = repoze.debug.pdbpm.pdb
+ repoze.debug.pdbpm.pdb = fake_pdb
+ environ = {}
+ result = mw(environ, None)
+ finally:
+ repoze.debug.pdbpm.pdb = old_pdb
+ self.assertEqual(fake_pdb.called, False)
+ self.assertEqual(result, ['hello world'])
+
+class FakePDB:
+ called = False
+ def post_mortem(self, *args):
+ self.called = True
+
+class DummyApplication:
+ def __init__(self, exc=None):
+ self.exc = exc
+
+ def __call__(self, environ, start_response):
+ if self.exc:
+ raise self.exc
+ self.environ = environ
+ self.start_response = start_response
+ return ['hello world']
+
+class DummyException(Exception):
+ pass
Added: repoze.debug/trunk/repoze/debug/tests/test_responselogger.py
==============================================================================
--- (empty file)
+++ repoze.debug/trunk/repoze/debug/tests/test_responselogger.py Thu Jun 26 18:11:41 2008
@@ -0,0 +1,123 @@
+import unittest
+
+class TestResponseLoggingMiddleware(unittest.TestCase):
+ def _getTargetClass(self):
+ from repoze.debug.responselogger import ResponseLoggingMiddleware
+ return ResponseLoggingMiddleware
+
+ def _makeOne(self, *arg, **kw):
+ klass = self._getTargetClass()
+ return klass(*arg, **kw)
+
+ def _makeEnviron(self):
+ environ = {
+ 'SERVER_NAME':'localhost',
+ 'SERVER_PORT':'80',
+ 'wsgi.version':(1,0),
+ 'wsgi.multiprocess':False,
+ 'wsgi.multithread':True,
+ 'wsgi.run_once':False,
+ 'wsgi.url_scheme':'http',
+ }
+ return environ
+
+ def test_call(self):
+ body = ['thebody']
+ app = DummyApp(body, '200 OK', [('HeaderKey', 'headervalue')])
+ logger = FakeLogger()
+ mw = self._makeOne(app, 0, logger)
+ environ = self._makeEnviron()
+ start_response = FakeStartResponse()
+ app_iter = mw(environ, start_response)
+ self.assertEqual(''.join(app_iter), 'thebody')
+ self.assertEqual(len(logger.logged), 2)
+ self.assertEqual(start_response.status, '200 OK')
+ self.assertEqual(len(start_response.headers), 1)
+ self.assertEqual(start_response.headers[0], ('HeaderKey','headervalue'))
+ self.assertEqual(start_response.exc_info, None)
+ self.assertEqual(app.called, True)
+
+ def test_call_overmaxbodylen(self):
+ body = ['thebody']
+ app = DummyApp(body, '200 OK', [('HeaderKey', 'headervalue')])
+ logger = FakeLogger()
+ mw = self._makeOne(app, 1, logger)
+ environ = self._makeEnviron()
+ start_response = FakeStartResponse()
+ app_iter = mw(environ, start_response)
+ self.assertEqual(''.join(app_iter), 'thebody')
+ self.assertEqual(len(logger.logged), 2)
+ self.failUnless('(truncated)' in logger.logged[1])
+
+ def test_call_contentlengthwrong(self):
+ body = ['thebody']
+ app = DummyApp(body, '200 OK', [('Content-Length', '1')])
+ logger = FakeLogger()
+ mw = self._makeOne(app, 1, logger)
+ environ = self._makeEnviron()
+ start_response = FakeStartResponse()
+ app_iter = mw(environ, start_response)
+ self.assertEqual(''.join(app_iter), 'thebody')
+ self.assertEqual(len(logger.logged), 2)
+ self.failUnless('WARNING-1' in logger.logged[1])
+
+ def test_call_sourceurl_in_response(self):
+ body = ['thebody']
+ app = DummyApp(body, '200 OK', [('Content-Length', '1')])
+ logger = FakeLogger()
+ mw = self._makeOne(app, 1, logger)
+ environ = self._makeEnviron()
+ start_response = FakeStartResponse()
+ app_iter = mw(environ, start_response)
+ self.assertEqual(''.join(app_iter), 'thebody')
+ self.assertEqual(len(logger.logged), 2)
+ self.failUnless('URL: http://localhost' in logger.logged[1])
+
+class TestMakeResponseLoggingMiddleware(unittest.TestCase):
+ def _getFUT(self):
+ from repoze.debug.responselogger import make_middleware
+ return make_middleware
+
+ def test_make_middleware_defaults(self):
+ f = self._getFUT()
+ app = DummyApp(None, None, None)
+ global_conf = {}
+ import tempfile
+ fn = tempfile.mktemp()
+ mw = f(app, global_conf, fn)
+ self.assertEqual(len(mw.logger.handlers), 1)
+ self.assertEqual(mw.max_bodylen, 0)
+
+ def test_make_middleware_nondefaults(self):
+ f = self._getFUT()
+ app = DummyApp(None, None, None)
+ global_conf = {}
+ import tempfile
+ fn = tempfile.mktemp()
+ mw = f(app, global_conf, fn, '0', '0')
+ self.assertEqual(len(mw.logger.handlers), 1)
+
+class FakeStartResponse:
+ def __call__(self, status, headers, exc_info=None):
+ self.status = status
+ self.headers = headers
+ self.exc_info = exc_info
+
+class FakeLogger:
+ def __init__(self):
+ self.logged = []
+
+ def info(self, msg):
+ self.logged.append(msg)
+
+class DummyApp:
+ def __init__(self, body, status, headers):
+ self.body = body
+ self.status = status
+ self.headers = headers
+
+ def __call__(self, environ, start_response):
+ start_response(self.status, self.headers)
+ self.called = True
+ return self.body
+
Modified: repoze.debug/trunk/setup.py
==============================================================================
--- repoze.debug/trunk/setup.py (original)
+++ repoze.debug/trunk/setup.py Thu Jun 26 18:11:41 2008
@@ -12,7 +12,7 @@
#
##############################################################################
-__version__ = '0.3'
+__version__ = '0.4'
import os
@@ -58,6 +58,7 @@
[paste.filter_app_factory]
responselogger = repoze.debug.responselogger:make_middleware
canary = repoze.debug.canary:make_middleware
+ pdbpm = repoze.debug.pdbpm:make_middleware
"""
)
More information about the Repoze-checkins
mailing list