Chris McDonough
2010-12-16 24bf2a83c5172e6974c997495e8f1c7922394617
Features
--------

- Added ``debug_routematch`` configuration setting that logs matched routes
(including the matchdict and predicates).

Documentation
-------------

- Added "Debugging Route Matching" section to the urldispatch narrative
documentation chapter.

- Added reference to ``BFG_DEBUG_ROUTEMATCH`` envvar and ``debug_routematch``
config file setting to the Environment narrative docs chapter.
25 files modified
204 ■■■■ changed files
CHANGES.txt 21 ●●●● patch | view | raw | blame | history
docs/narr/MyProject/development.ini 2 ●●● patch | view | raw | blame | history
docs/narr/environment.rst 15 ●●●●● patch | view | raw | blame | history
docs/narr/urldispatch.rst 31 ●●●●● patch | view | raw | blame | history
docs/tutorials/wiki/src/authorization/development.ini 2 ●●● patch | view | raw | blame | history
docs/tutorials/wiki/src/basiclayout/development.ini 2 ●●● patch | view | raw | blame | history
docs/tutorials/wiki/src/models/development.ini 2 ●●● patch | view | raw | blame | history
docs/tutorials/wiki/src/viewdecorators/development.ini 2 ●●● patch | view | raw | blame | history
docs/tutorials/wiki/src/views/development.ini 2 ●●● patch | view | raw | blame | history
docs/tutorials/wiki2/src/authorization/development.ini 2 ●●● patch | view | raw | blame | history
docs/tutorials/wiki2/src/basiclayout/development.ini 2 ●●● patch | view | raw | blame | history
docs/tutorials/wiki2/src/models/development.ini 2 ●●● patch | view | raw | blame | history
docs/tutorials/wiki2/src/views/development.ini 2 ●●● patch | view | raw | blame | history
pyramid/paster_templates/alchemy/development.ini_tmpl 2 ●●● patch | view | raw | blame | history
pyramid/paster_templates/pylons_basic/development.ini_tmpl 2 ●●● patch | view | raw | blame | history
pyramid/paster_templates/pylons_minimal/development.ini_tmpl 2 ●●● patch | view | raw | blame | history
pyramid/paster_templates/pylons_sqla/development.ini_tmpl 2 ●●● patch | view | raw | blame | history
pyramid/paster_templates/routesalchemy/development.ini_tmpl 2 ●●● patch | view | raw | blame | history
pyramid/paster_templates/starter/development.ini_tmpl 2 ●●● patch | view | raw | blame | history
pyramid/paster_templates/starter_zcml/development.ini_tmpl 2 ●●● patch | view | raw | blame | history
pyramid/paster_templates/zodb/development.ini_tmpl 2 ●●● patch | view | raw | blame | history
pyramid/router.py 25 ●●●●● patch | view | raw | blame | history
pyramid/settings.py 8 ●●●● patch | view | raw | blame | history
pyramid/tests/test_router.py 28 ●●●● patch | view | raw | blame | history
pyramid/tests/test_settings.py 40 ●●●● patch | view | raw | blame | history
CHANGES.txt
@@ -1,18 +1,27 @@
Next release
============
Features
--------
- Added ``debug_matched`` configuration setting that logs matched routes
  (including the matchdict and predicates).
Bug Fixes
---------
- Make it possible to succesfully run all tests via ``nosetests`` command
  directly (rather than indirectly via ``python setup.py nosetests``).
Features
--------
- Added ``debug_routematch`` configuration setting that logs matched routes
  (including the matchdict and predicates).
Documentation
-------------
- Added "Debugging Route Matching" section to the urldispatch narrative
  documentation chapter.
- Added reference to ``BFG_DEBUG_ROUTEMATCH`` envvar and ``debug_routematch``
  config file setting to the Environment narrative docs chapter.
1.0a6 (2010-12-15)
==================
docs/narr/MyProject/development.ini
@@ -3,7 +3,7 @@
reload_templates = true
debug_authorization = false
debug_notfound = false
debug_matched = false
debug_routematch = false
debug_templates = true
default_locale_name = en
docs/narr/environment.rst
@@ -97,6 +97,21 @@
|                                 |                             |
+---------------------------------+-----------------------------+
Debugging Route Matching
------------------------
Print debugging messages related to :term:`url dispatch` route matching when
this value is true.  See also :ref:`debug_routematch_section`.
+---------------------------------+-----------------------------+
| Environment Variable Name       | Config File Setting Name    |
+=================================+=============================+
| ``BFG_DEBUG_ROUTEMATCH``        |  ``debug_routematch``       |
|                                 |                             |
|                                 |                             |
|                                 |                             |
+---------------------------------+-----------------------------+
Debugging All
-------------
docs/narr/urldispatch.rst
@@ -1268,6 +1268,37 @@
.. note:: See :ref:`security_chapter` for more information about
   :app:`Pyramid` security and ACLs.
.. _debug_routematch_section:
Debugging Route Matching
------------------------
It's useful to be able to take a peek under the hood when requests that enter
your application arent matching your routes as you expect them to.  To debug
route matching, use the ``BFG_DEBUG_ROUTEMATCH`` environment variable or the
``debug_routematch`` configuration file setting (set either to ``true``).
Details of the route matching decision for a particular request to the
:app:`Pyramid` application will be printed to the ``stderr`` of the console
which you started the application from.  For example:
.. code-block:: text
   :linenos:
    [chrism@thinko pylonsbasic]$ BFG_DEBUG_ROUTEMATCH=true \
                                 bin/paster serve development.ini
    Starting server in PID 13586.
    serving on 0.0.0.0:6543 view at http://127.0.0.1:6543
    2010-12-16 14:45:19,956 no route matched for url \
                                        http://localhost:6543/wontmatch
    2010-12-16 14:45:20,010 no route matched for url \
                                http://localhost:6543/favicon.ico
    2010-12-16 14:41:52,084 route matched for url \
                                http://localhost:6543/static/logo.png; \
                                route_name: 'static/', ....
See :ref:`environment_chapter` for more information about how, and where to
set these values.
References
----------
docs/tutorials/wiki/src/authorization/development.ini
@@ -3,7 +3,7 @@
reload_templates = true
debug_authorization = false
debug_notfound = false
debug_matched = false
debug_routematch = false
zodb_uri = file://%(here)s/Data.fs?connection_cache_size=20000
[pipeline:main]
docs/tutorials/wiki/src/basiclayout/development.ini
@@ -3,7 +3,7 @@
reload_templates = true
debug_authorization = false
debug_notfound = false
debug_matched = false
debug_routematch = false
zodb_uri = file://%(here)s/Data.fs?connection_cache_size=20000
[pipeline:main]
docs/tutorials/wiki/src/models/development.ini
@@ -3,7 +3,7 @@
reload_templates = true
debug_authorization = false
debug_notfound = false
debug_matched = false
debug_routematch = false
zodb_uri = file://%(here)s/Data.fs?connection_cache_size=20000
[pipeline:main]
docs/tutorials/wiki/src/viewdecorators/development.ini
@@ -3,7 +3,7 @@
reload_templates = true
debug_authorization = false
debug_notfound = false
debug_matched = false
debug_routematch = false
zodb_uri = file://%(here)s/Data.fs?connection_cache_size=20000
[pipeline:main]
docs/tutorials/wiki/src/views/development.ini
@@ -3,7 +3,7 @@
reload_templates = true
debug_authorization = false
debug_notfound = false
debug_matched = false
debug_routematch = false
zodb_uri = file://%(here)s/Data.fs?connection_cache_size=20000
[pipeline:main]
docs/tutorials/wiki2/src/authorization/development.ini
@@ -3,7 +3,7 @@
reload_templates = true
debug_authorization = false
debug_notfound = false
debug_matched = false
debug_routematch = false
debug_templates = true
default_locale_name = en
sqlalchemy.url = sqlite:///%(here)s/tutorial.db
docs/tutorials/wiki2/src/basiclayout/development.ini
@@ -3,7 +3,7 @@
reload_templates = true
debug_authorization = false
debug_notfound = false
debug_matched = false
debug_routematch = false
debug_templates = true
default_locale_name = en
sqlalchemy.url = sqlite:///%(here)s/tutorial.db
docs/tutorials/wiki2/src/models/development.ini
@@ -3,7 +3,7 @@
reload_templates = true
debug_authorization = false
debug_notfound = false
debug_matched = false
debug_routematch = false
debug_templates = true
default_locale_name = en
sqlalchemy.url = sqlite:///%(here)s/tutorial.db
docs/tutorials/wiki2/src/views/development.ini
@@ -3,7 +3,7 @@
reload_templates = true
debug_authorization = false
debug_notfound = false
debug_matched = false
debug_routematch = false
debug_templates = true
default_locale_name = en
sqlalchemy.url = sqlite:///%(here)s/tutorial.db
pyramid/paster_templates/alchemy/development.ini_tmpl
@@ -3,7 +3,7 @@
reload_templates = true
debug_authorization = false
debug_notfound = false
debug_matched = false
debug_routematch = false
debug_templates = true
default_locale_name = en
sqlalchemy.url = sqlite:///%(here)s/{{project}}.db
pyramid/paster_templates/pylons_basic/development.ini_tmpl
@@ -4,7 +4,7 @@
mako.directories = {{package}}:templates
debug_authorization = false
debug_notfound = false
debug_matched = false
debug_routematch = false
debug_templates = true
default_locale_name = en
session.type = file
pyramid/paster_templates/pylons_minimal/development.ini_tmpl
@@ -4,7 +4,7 @@
mako.directories = {{package}}:templates
debug_authorization = false
debug_notfound = false
debug_matched = false
debug_routematch = false
debug_templates = true
default_locale_name = en
session.type = file
pyramid/paster_templates/pylons_sqla/development.ini_tmpl
@@ -3,7 +3,7 @@
reload_templates = true
debug_authorization = false
debug_notfound = false
debug_matched = false
debug_routematch = false
debug_templates = true
default_locale_name = en
mako.directories = {{package}}:templates
pyramid/paster_templates/routesalchemy/development.ini_tmpl
@@ -3,7 +3,7 @@
reload_templates = true
debug_authorization = false
debug_notfound = false
debug_matched = false
debug_routematch = false
debug_templates = true
default_locale_name = en
sqlalchemy.url = sqlite:///%(here)s/{{project}}.db
pyramid/paster_templates/starter/development.ini_tmpl
@@ -3,7 +3,7 @@
reload_templates = true
debug_authorization = false
debug_notfound = false
debug_matched = false
debug_routematch = false
debug_templates = true
default_locale_name = en
pyramid/paster_templates/starter_zcml/development.ini_tmpl
@@ -3,7 +3,7 @@
reload_templates = true
debug_authorization = false
debug_notfound = false
debug_matched = false
debug_routematch = false
debug_templates = true
default_locale_name = en
pyramid/paster_templates/zodb/development.ini_tmpl
@@ -3,7 +3,7 @@
reload_templates = true
debug_authorization = false
debug_notfound = false
debug_matched = false
debug_routematch = false
debug_templates = true
default_locale_name = en
zodb_uri = file://%(here)s/Data.fs?connection_cache_size=20000
pyramid/router.py
@@ -30,7 +30,7 @@
    implements(IRouter)
    debug_notfound = False
    debug_matched = False
    debug_routematch = False
    threadlocal_manager = manager
@@ -46,7 +46,7 @@
        if settings is not None:
            self.debug_notfound = settings['debug_notfound']
            self.debug_matched = settings['debug_matched']
            self.debug_routematch = settings['debug_routematch']
    def __call__(self, environ, start_response):
        """
@@ -84,7 +84,12 @@
                    if self.routes_mapper is not None:
                        info = self.routes_mapper(request)
                        match, route = info['match'], info['route']
                        if route is not None:
                        if route is None:
                            if self.debug_routematch:
                                msg = ('no route matched for url %s' %
                                       request.url)
                                logger and logger.debug(msg)
                        else:
                            # TODO: kill off bfg.routes.* environ keys when
                            # traverser requires request arg, and cant cope
                            # with environ anymore (they are docs-deprecated as
@@ -94,14 +99,18 @@
                            attrs['matchdict'] = match
                            attrs['matched_route'] = route
                            if self.debug_matched:
                            if self.debug_routematch:
                                msg = (
                                    'debug_matched of url %s; path_info: %r, '
                                    'route_name: %r, pattern: %r, '
                                    'route matched for url %s; '
                                    'route_name: %r, '
                                    'path_info: %r, '
                                    'pattern: %r, '
                                    'matchdict: %r, '
                                    'predicates: %r' % (
                                        request.url, request.path_info,
                                        route.name, route.pattern, match,
                                        request.url,
                                        route.name,
                                        request.path_info,
                                        route.pattern, match,
                                        route.predicates)
                                    )
                                logger and logger.debug(msg)
pyramid/settings.py
@@ -29,9 +29,9 @@
        config_debug_notfound = self.get('debug_notfound', '')
        eff_debug_notfound = asbool(eget('BFG_DEBUG_NOTFOUND',
                                         config_debug_notfound))
        config_debug_matched = self.get('debug_matched', '')
        eff_debug_matched = asbool(eget('BFG_DEBUG_MATCHED',
                                         config_debug_matched))
        config_debug_routematch = self.get('debug_routematch', '')
        eff_debug_routematch = asbool(eget('BFG_DEBUG_ROUTEMATCH',
                                         config_debug_routematch))
        config_debug_templates = self.get('debug_templates', '')
        eff_debug_templates = asbool(eget('BFG_DEBUG_TEMPLATES',
                                          config_debug_templates))
@@ -49,7 +49,7 @@
        update = {
            'debug_authorization': eff_debug_all or eff_debug_auth,
            'debug_notfound': eff_debug_all or eff_debug_notfound,
            'debug_matched': eff_debug_all or eff_debug_matched,
            'debug_routematch': eff_debug_all or eff_debug_routematch,
            'debug_templates': eff_debug_all or eff_debug_templates,
            'reload_templates': eff_reload_all or eff_reload_templates,
            'reload_resources':eff_reload_all or eff_reload_resources,
pyramid/tests/test_router.py
@@ -36,7 +36,7 @@
    def _registerSettings(self, **kw):
        settings = {'debug_authorization':False,
                    'debug_notfound':False,
                    'debug_matched':False}
                    'debug_routematch':False}
        settings.update(kw)
        self.registry.settings = settings
@@ -496,7 +496,7 @@
    def test_call_route_matches_and_has_factory(self):
        from pyramid.interfaces import IViewClassifier
        logger = self._registerLogger()
        self._registerSettings(debug_matched=True)
        self._registerSettings(debug_routematch=True)
        self._registerRouteRequest('foo')
        root = object()
        def factory(request):
@@ -529,13 +529,33 @@
        self.assertEqual(len(logger.messages), 1)
        self.assertEqual(logger.messages[0],
            "debug_matched of url http://localhost:8080"
            "route matched for url http://localhost:8080"
            "/archives/action1/article1; "
            "route_name: 'foo', "
            "path_info: '/archives/action1/article1', "
            "route_name: 'foo', pattern: 'archives/:action/:article', "
            "pattern: 'archives/:action/:article', "
            "matchdict: {'action': u'action1', 'article': u'article1'}, "
            "predicates: ()")
    def test_call_route_match_miss_debug_routematch(self):
        from pyramid.exceptions import NotFound
        logger = self._registerLogger()
        self._registerSettings(debug_routematch=True)
        self._registerRouteRequest('foo')
        self._connectRoute('foo', 'archives/:action/:article')
        context = DummyContext()
        self._registerTraverserFactory(context)
        environ = self._makeEnviron(PATH_INFO='/wontmatch')
        self._registerRootFactory(context)
        router = self._makeOne()
        start_response = DummyStartResponse()
        self.assertRaises(NotFound, router, environ, start_response)
        self.assertEqual(len(logger.messages), 1)
        self.assertEqual(
            logger.messages[0],
            'no route matched for url http://localhost:8080/wontmatch')
    def test_call_route_matches_doesnt_overwrite_subscriber_iface(self):
        from pyramid.interfaces import INewRequest
        from pyramid.interfaces import IViewClassifier
pyramid/tests/test_settings.py
@@ -24,7 +24,7 @@
        settings = self._makeOne()
        self.assertEqual(settings['debug_authorization'], False)
        self.assertEqual(settings['debug_notfound'], False)
        self.assertEqual(settings['debug_matched'], False)
        self.assertEqual(settings['debug_routematch'], False)
        self.assertEqual(settings['reload_templates'], False)
        self.assertEqual(settings['reload_resources'], False)
        self.assertEqual(settings['configure_zcml'], '')
@@ -110,20 +110,20 @@
                             {'BFG_DEBUG_NOTFOUND':'1'})
        self.assertEqual(result['debug_notfound'], True)
    def test_debug_matched(self):
    def test_debug_routematch(self):
        result = self._makeOne({})
        self.assertEqual(result['debug_matched'], False)
        result = self._makeOne({'debug_matched':'false'})
        self.assertEqual(result['debug_matched'], False)
        result = self._makeOne({'debug_matched':'t'})
        self.assertEqual(result['debug_matched'], True)
        result = self._makeOne({'debug_matched':'1'})
        self.assertEqual(result['debug_matched'], True)
        result = self._makeOne({}, {'BFG_DEBUG_MATCHED':'1'})
        self.assertEqual(result['debug_matched'], True)
        result = self._makeOne({'debug_matched':'false'},
                             {'BFG_DEBUG_MATCHED':'1'})
        self.assertEqual(result['debug_matched'], True)
        self.assertEqual(result['debug_routematch'], False)
        result = self._makeOne({'debug_routematch':'false'})
        self.assertEqual(result['debug_routematch'], False)
        result = self._makeOne({'debug_routematch':'t'})
        self.assertEqual(result['debug_routematch'], True)
        result = self._makeOne({'debug_routematch':'1'})
        self.assertEqual(result['debug_routematch'], True)
        result = self._makeOne({}, {'BFG_DEBUG_ROUTEMATCH':'1'})
        self.assertEqual(result['debug_routematch'], True)
        result = self._makeOne({'debug_routematch':'false'},
                             {'BFG_DEBUG_ROUTEMATCH':'1'})
        self.assertEqual(result['debug_routematch'], True)
    def test_debug_templates(self):
        result = self._makeOne({})
@@ -143,33 +143,33 @@
    def test_debug_all(self):
        result = self._makeOne({})
        self.assertEqual(result['debug_notfound'], False)
        self.assertEqual(result['debug_matched'], False)
        self.assertEqual(result['debug_routematch'], False)
        self.assertEqual(result['debug_authorization'], False)
        self.assertEqual(result['debug_templates'], False)
        result = self._makeOne({'debug_all':'false'})
        self.assertEqual(result['debug_notfound'], False)
        self.assertEqual(result['debug_matched'], False)
        self.assertEqual(result['debug_routematch'], False)
        self.assertEqual(result['debug_authorization'], False)
        self.assertEqual(result['debug_templates'], False)
        result = self._makeOne({'debug_all':'t'})
        self.assertEqual(result['debug_notfound'], True)
        self.assertEqual(result['debug_matched'], True)
        self.assertEqual(result['debug_routematch'], True)
        self.assertEqual(result['debug_authorization'], True)
        self.assertEqual(result['debug_templates'], True)
        result = self._makeOne({'debug_all':'1'})
        self.assertEqual(result['debug_notfound'], True)
        self.assertEqual(result['debug_matched'], True)
        self.assertEqual(result['debug_routematch'], True)
        self.assertEqual(result['debug_authorization'], True)
        self.assertEqual(result['debug_templates'], True)
        result = self._makeOne({}, {'BFG_DEBUG_ALL':'1'})
        self.assertEqual(result['debug_notfound'], True)
        self.assertEqual(result['debug_matched'], True)
        self.assertEqual(result['debug_routematch'], True)
        self.assertEqual(result['debug_authorization'], True)
        self.assertEqual(result['debug_templates'], True)
        result = self._makeOne({'debug_all':'false'},
                             {'BFG_DEBUG_ALL':'1'})
        self.assertEqual(result['debug_notfound'], True)
        self.assertEqual(result['debug_matched'], True)
        self.assertEqual(result['debug_routematch'], True)
        self.assertEqual(result['debug_authorization'], True)
        self.assertEqual(result['debug_templates'], True)