Chris Rossi
2010-11-10 51c305c772150a8ee8b12c5dbdcb1fc30cb3a251
Added class vars matchdict and matched_route to
pyramid.request.Request. Each is set to None.
7 files modified
172 ■■■■ changed files
CHANGES.txt 5 ●●●● patch | view | raw | blame | history
pyramid/configuration.py 36 ●●●● patch | view | raw | blame | history
pyramid/request.py 2 ●●●●● patch | view | raw | blame | history
pyramid/tests/test_configuration.py 87 ●●●● patch | view | raw | blame | history
pyramid/tests/test_request.py 14 ●●●● patch | view | raw | blame | history
pyramid/tests/test_traversal.py 19 ●●●● patch | view | raw | blame | history
pyramid/traversal.py 9 ●●●●● patch | view | raw | blame | history
CHANGES.txt
@@ -8,6 +8,9 @@
  represent the function that returns a WSGI application, each now uses
  WebError, each now has roughly the same shape of development.ini style.
- Added class vars ``matchdict`` and ``matched_route`` to
  ``pyramid.request.Request``.  Each is set to ``None``.
Bug Fixes
---------
@@ -154,7 +157,7 @@
- The deprecated API ``pyramid.testing.registerViewPermission``
  has been removed.
- The deprecated API named ``pyramid.testing.registerRoutesMapper``
- The deprecated API named ``pyramid.testing.registerRoutesMapper``
  has been removed.
- The deprecated API named ``pyramid.request.get_request`` was removed.
pyramid/configuration.py
@@ -263,7 +263,7 @@
        policy = self.maybe_dotted(policy)
        self.registry.registerUtility(policy, IAuthenticationPolicy,
                                      info=_info)
    def _set_authorization_policy(self, policy, _info=u''):
        """ Add a :app:`Pyramid` :term:`authorization policy` to
        the current configuration state (also accepts a :term:`dotted
@@ -472,7 +472,7 @@
    def derive_view(self, view, attr=None, renderer=None):
        """
        Create a :term:`view callable` using the function, instance,
        or class (or :term:`dotted Python name` referring to the same)
        provided as ``view`` object.
@@ -582,7 +582,7 @@
           config.add_settings({'external_uri':'http://example.com'})
        Or a set of key/value pairs::
           config.add_settings(external_uri='http://example.com')
        This function is useful when you need to test code that calls
@@ -658,7 +658,7 @@
        """ Add a Pylons-style view handler.  This function adds a
        route and some number of views based on a handler object
        (usually a class).
        ``route_name`` is the name of the route (to be used later in
        URL generation).
@@ -668,7 +668,7 @@
        ``route_name`` is used.  If ``pattern`` is ``None`` and no
        route named ``route_name`` exists, a ``ConfigurationError`` is
        raised.
        ``handler`` is a dotted name of (or direct reference to) a
        Python handler class,
        e.g. ``'my.package.handlers.MyHandler'``.
@@ -698,7 +698,7 @@
                    'The "pattern" parameter may only be "None" when a route '
                    'with the route_name argument was previously registered. '
                    'No such route named %r exists' % route_name)
            pattern = route.pattern
        path_has_action = ':action' in pattern or '{action}' in pattern
@@ -735,7 +735,7 @@
            method_name = action
            if method_name is None:
                method_name = '__call__'
            # Scan the controller for any other methods with this action name
            for meth_name, method in inspect.getmembers(
                handler, inspect.ismethod):
@@ -754,7 +754,7 @@
                    del view_args['name']
                    self.add_view(view=handler, attr=meth_name,
                                  route_name=route_name, **view_args)
            # Now register the method itself
            method = getattr(handler, method_name, None)
            configs = getattr(method, '__exposed__', [{}])
@@ -1001,7 +1001,7 @@
          variable.  If the regex matches, this predicate will be
          ``True``.
        custom_predicates
          This value should be a sequence of references to custom
@@ -1145,11 +1145,11 @@
            #   the same predicate hash as this view; this registration
            #   is therefore an override.
            regclosure()
        else:
            # - A view or multiview was already registered for this
            #   triad, and the new view is not an override.
            # XXX we could try to be more efficient here and register
            # a non-secured view for a multiview if none of the
            # multiview's consituent views have a permission
@@ -1401,7 +1401,7 @@
          A Python object or :term:`dotted Python name` to the same
          object that will be used as a view callable when this route
          matches. e.g. ``mypackage.views.my_view``.
        view_context
          A class or an :term:`interface` or :term:`dotted Python
@@ -1487,7 +1487,7 @@
            traverse=traverse,
            custom=custom_predicates
            )
        request_iface = self.registry.queryUtility(IRouteRequest, name=name)
        if request_iface is None:
            bases = use_global_views and (IRequest,) or ()
@@ -1524,7 +1524,7 @@
            pattern = path
        if pattern is None:
            raise ConfigurationError('"pattern" argument may not be None')
        return mapper.connect(name, pattern, factory, predicates=predicates,
                              pregenerator=pregenerator)
@@ -2731,7 +2731,7 @@
    the resolver's ``resolve`` and ``maybe_resolve`` methods.  A
    dotted name which has a ``.`` (dot) or ``:`` (colon) as its first
    character is treated as relative.
    If the value ``None`` is supplied as the package name, the
    resolver will only be able to resolve fully qualified (not
    relative) names.  Any attempt to resolve a relative name when the
@@ -2839,7 +2839,7 @@
                raise ConfigurationError(
                    'The dotted name %r cannot be imported' % (dotted,))
        return dotted
class ActionPredicate(object):
    action_name = 'action'
@@ -2851,7 +2851,7 @@
            raise ConfigurationError(why[0])
    def __call__(self, context, request):
        matchdict = getattr(request, 'matchdict', None)
        matchdict = request.matchdict
        if matchdict is None:
            return False
        action = matchdict.get(self.action_name)
@@ -2863,4 +2863,4 @@
        # allow this predicate's phash to be compared as equal to
        # others that share the same action name
        return hash(self.action)
pyramid/request.py
@@ -37,6 +37,8 @@
    response_callbacks = ()
    finished_callbacks = ()
    exception = None
    matchdict = None
    matched_route = None
    @reify
    def tmpl_context(self):
pyramid/tests/test_configuration.py
@@ -567,7 +567,7 @@
        self.assertEqual(L[0], event)
        config.registry.subscribers((event.object, IDummy), None)
        self.assertEqual(len(L), 1)
    def test_make_wsgi_app(self):
        from pyramid.router import Router
        from pyramid.interfaces import IApplicationCreated
@@ -1934,7 +1934,7 @@
    def test_add_handler_with_action_and_action_in_path(self):
        from pyramid.exceptions import ConfigurationError
        config = self._makeOne()
        self.assertRaises(ConfigurationError, config.add_handler,
        self.assertRaises(ConfigurationError, config.add_handler,
                          'name', '/{action}', DummyHandler, action='abc')
    def test_add_handler_with_explicit_action(self):
@@ -1970,7 +1970,7 @@
        self.assertEqual(view['attr'], None)
        self.assertEqual(view['route_name'], 'name')
        self.assertEqual(view['view'], DummyHandler)
    def test_add_handler_with_multiple_action(self):
        config = self._makeOne()
        class DummyHandler(object):
@@ -2584,7 +2584,7 @@
        self.failUnless(result is view)
        self.failIf(hasattr(result, '__call_permissive__'))
        self.assertEqual(view(None, None), 'OK')
    def test__derive_view_as_function_requestonly(self):
        def view(request):
            return 'OK'
@@ -2611,7 +2611,7 @@
        self.assertEqual(view.__name__, result.__name__)
        self.failIf(hasattr(result, '__call_permissive__'))
        self.assertEqual(result(None, None), 'OK')
    def test__derive_view_as_newstyle_class_requestonly(self):
        class view(object):
            def __init__(self, context, request):
@@ -2641,7 +2641,7 @@
        self.assertEqual(view.__name__, result.__name__)
        self.failIf(hasattr(result, '__call_permissive__'))
        self.assertEqual(result(None, None), 'OK')
    def test__derive_view_as_oldstyle_class_requestonly(self):
        class view:
            def __init__(self, context, request):
@@ -2667,7 +2667,7 @@
        self.failUnless(result is view)
        self.failIf(hasattr(result, '__call_permissive__'))
        self.assertEqual(result(None, None), 'OK')
    def test__derive_view_as_instance_requestonly(self):
        class View:
            def __call__(self, request):
@@ -2745,7 +2745,7 @@
        self.assertEqual(logger.messages[0],
                         "debug_authorization of url url (view name "
                         "'view_name' against context None): True")
    def test__derive_view_debug_auth_permission_authpol_denied(self):
        from pyramid.exceptions import Forbidden
        view = lambda *arg: 'OK'
@@ -3028,10 +3028,10 @@
        result = render_view_to_response(ctx, req, 'stacked_method2')
        self.assertEqual(result, 'stacked_method')
        result = render_view_to_response(ctx, req, 'subpackage_init')
        self.assertEqual(result, 'subpackage_init')
        result = render_view_to_response(ctx, req, 'subpackage_notinit')
        self.assertEqual(result, 'subpackage_notinit')
@@ -3132,7 +3132,7 @@
        self.assertEqual(len(L), 2)
        self.assertEqual(L[0], 'foo')
        self.assertEqual(L[1], event)
    def test_testing_add_subscriber_defaults(self):
        config = self._makeOne()
        L = config.testing_add_subscriber()
@@ -3149,7 +3149,7 @@
        config = self._makeOne()
        config.hook_zca(getSiteManager=gsm)
        self.assertEqual(gsm.hook, get_current_registry)
    def test_unhook_zca(self):
        gsm = DummyGetSiteManager()
        config = self._makeOne()
@@ -3170,7 +3170,7 @@
        renderer.assert_(foo=1)
        renderer.assert_(bar=2)
        renderer.assert_(request=request)
    def test_testing_add_renderer_explicitrenderer(self):
        config = self._makeOne()
        class E(Exception): pass
@@ -3188,7 +3188,7 @@
        except E:
            pass
        else: # pragma: no cover
            raise AssertionError
            raise AssertionError
    def test_testing_add_template(self):
        config = self._makeOne()
@@ -3214,7 +3214,7 @@
    def tearDown(self):
        del self.registry
        testing.tearDown()
    def _registerRenderer(self, typ='.txt'):
        from pyramid.interfaces import IRendererFactory
        from pyramid.interfaces import ITemplateRenderer
@@ -3237,7 +3237,7 @@
    def _callFUT(self, *arg, **kw):
        from pyramid.configuration import _map_view
        return _map_view(*arg, **kw)
    def test__map_view_as_function_context_and_request(self):
        def view(context, request):
            return 'OK'
@@ -3259,7 +3259,7 @@
        result = self._callFUT(view, attr='__name__', renderer=info)
        self.failIf(result is view)
        self.assertRaises(TypeError, result, None, None)
    def test__map_view_as_function_requestonly(self):
        def view(request):
            return 'OK'
@@ -3322,7 +3322,7 @@
        self.assertEqual(view.__name__, result.__name__)
        request = self._makeRequest()
        self.assertEqual(result(None, request).body, 'Hello!')
    def test__map_view_as_newstyle_class_requestonly(self):
        class view(object):
            def __init__(self, request):
@@ -3457,7 +3457,7 @@
        result = self._callFUT(view)
        self.failUnless(result is view)
        self.assertEqual(result(None, None), 'OK')
    def test__map_view_as_instance_context_and_request_and_attr(self):
        class View:
            def index(self, context, request):
@@ -3547,7 +3547,7 @@
    def _callFUT(self, wrapped, original):
        from pyramid.configuration import decorate_view
        return decorate_view(wrapped, original)
    def test_it_same(self):
        def view(context, request):
            """ """
@@ -3700,7 +3700,7 @@
            )
        order3, _, _ = self._callFUT(
            path_info='path_info',
            )
            )
        order4, _, _ = self._callFUT(
            request_param='param',
            )
@@ -3809,7 +3809,7 @@
    def _makeOne(self, name='name'):
        return self._getTargetClass()(name)
    def test_class_implements_ISecuredView(self):
        from zope.interface.verify import verifyClass
        from pyramid.interfaces import ISecuredView
@@ -3925,7 +3925,7 @@
            """ """
        mv.views = [(100, view, None)]
        self.assertEqual(mv.__permitted__(None, None), True)
    def test_permitted(self):
        mv = self._makeOne()
        def view(context, request):
@@ -4047,13 +4047,13 @@
        mv.accepts = ['text/xml']
        response = mv(context, request)
        self.assertEqual(response, expected_response)
class TestRequestOnly(unittest.TestCase):
    def _callFUT(self, arg):
        from pyramid.configuration import requestonly
        return requestonly(arg)
    def test_newstyle_class_no_init(self):
        class foo(object):
            """ """
@@ -4064,7 +4064,7 @@
            def __init__(self, context, request):
                """ """
        self.assertFalse(self._callFUT(foo))
    def test_newstyle_class_init_onearg_named_request(self):
        class foo(object):
            def __init__(self, request):
@@ -4105,7 +4105,7 @@
            def __init__(self, context, request):
                """ """
        self.assertFalse(self._callFUT(foo))
    def test_oldstyle_class_init_onearg_named_request(self):
        class foo:
            def __init__(self, request):
@@ -4140,7 +4140,7 @@
        def foo(context, request):
            """ """
        self.assertFalse(self._callFUT(foo))
    def test_function_onearg_named_request(self):
        def foo(request):
            """ """
@@ -4172,7 +4172,7 @@
                """ """
        foo = Foo()
        self.assertFalse(self._callFUT(foo))
    def test_instance_defaultargs_onearg_named_request(self):
        class Foo:
            def __call__(self, request):
@@ -4269,7 +4269,7 @@
        result = typ._zope_dottedname_style(
            'pyramid.tests.test_configuration.TestDottedNameResolver')
        self.assertEqual(result, self.__class__)
    def test_zope_dottedname_style_irrresolveable_absolute(self):
        typ = self._makeOne()
        self.assertRaises(ImportError, typ._zope_dottedname_style,
@@ -4339,7 +4339,7 @@
        result = typ._pkg_resources_style(
            'pyramid.tests.test_configuration:TestDottedNameResolver')
        self.assertEqual(result, self.__class__)
    def test__pkg_resources_style_irrresolveable_absolute(self):
        typ = self._makeOne()
        self.assertRaises(ImportError, typ._pkg_resources_style,
@@ -4357,7 +4357,7 @@
        typ = self._makeOne(package=pyramid.tests)
        result = typ._pkg_resources_style('.')
        self.assertEqual(result, pyramid.tests)
    def test__pkg_resources_style_resolve_relative_nocurrentpackage(self):
        typ = self._makeOne()
        from pyramid.exceptions import ConfigurationError
@@ -4431,7 +4431,7 @@
    def _callFUT(self, ob):
        from pyramid.configuration import isexception
        return isexception(ob)
    def test_is_exception_instance(self):
        class E(Exception):
            pass
@@ -4457,7 +4457,7 @@
    def _getTargetClass(self):
        from pyramid.configuration import ActionPredicate
        return ActionPredicate
    def _makeOne(self, action='myaction'):
        return self._getTargetClass()(action)
@@ -4501,11 +4501,12 @@
        self.assertEqual(hash(pred1), hash(pred2))
        self.assertNotEqual(hash(pred1), hash(pred3))
        self.assertNotEqual(hash(pred2), hash(pred3))
class DummyRequest:
    subpath = ()
    matchdict = None
    def __init__(self):
        self.environ = {'PATH_INFO':'/static'}
        self.params = {}
@@ -4524,7 +4525,7 @@
    def release(self):
        self.released = True
class DummyPackage:
    def __init__(self, name):
        self.__name__ = name
@@ -4592,13 +4593,13 @@
    def load_zcml(self, filename):
        self.zcml_file = filename
    def make_wsgi_app(self):
        return self
    def hook_zca(self):
        self.zca_hooked = True
class DummyAccept(object):
    def __init__(self, *matches):
@@ -4632,7 +4633,7 @@
        self.hook = hook
    def reset(self):
        self.unhooked = True
class DummyThreadLocalManager(object):
    pushed = None
    popped = False
@@ -4648,17 +4649,17 @@
    implements(IFactory)
    def __call__(self):
        """ """
class DummyEvent:
    implements(IDummy)
class DummyStaticURLInfo:
    def __init__(self):
        self.added = []
    def add(self, name, spec, **kw):
        self.added.append((name, spec, kw))
def dummy_view(request):
    return 'OK'
pyramid/tests/test_request.py
@@ -8,7 +8,7 @@
    def tearDown(self):
        self.config.end()
    def _makeOne(self, environ):
        return self._getTargetClass()(environ)
@@ -23,6 +23,14 @@
    def test_exception_defaults_to_None(self):
        r = self._makeOne({'PATH_INFO':'/'})
        self.assertEqual(r.exception, None)
    def test_matchdict_defaults_to_None(self):
        r = self._makeOne({'PATH_INFO':'/'})
        self.assertEqual(r.matchdict, None)
    def test_matched_route_defaults_to_None(self):
        r = self._makeOne({'PATH_INFO':'/'})
        self.assertEqual(r.matched_route, None)
    def test_params_decoded_from_utf_8_by_default(self):
        environ = {
@@ -48,7 +56,7 @@
        inst = self._makeOne({})
        result = inst.tmpl_context
        self.assertEqual(result.__class__, TemplateContext)
    def test_session_configured(self):
        from pyramid.interfaces import ISessionFactory
        inst = self._makeOne({})
@@ -107,7 +115,7 @@
        environ = {'zooma':1}
        inst = self._makeOne(environ)
        self.assertEqual(inst.get('zooma'), 1)
    def test_has_key(self):
        environ = {'zooma':1}
        inst = self._makeOne(environ)
pyramid/tests/test_traversal.py
@@ -6,7 +6,7 @@
    def _callFUT(self, path):
        from pyramid.traversal import traversal_path
        return traversal_path(path)
    def test_path_startswith_endswith(self):
        self.assertEqual(self._callFUT('/foo/'), (u'foo',))
@@ -41,7 +41,7 @@
        decoded = unicode(la, 'utf-8')
        path = '/'.join([encoded, encoded])
        self.assertEqual(self._callFUT(path), (decoded, decoded))
    def test_utf16(self):
        from pyramid.exceptions import URLDecodeError
        import urllib
@@ -626,7 +626,7 @@
        root.__name__ = None
        result = self._callFUT(root)
        self.assertEqual(result, ('',))
    def test_nonroot_default(self):
        root = DummyContext()
        root.__parent__ = None
@@ -750,7 +750,7 @@
        context_url = self._makeOne(two, request)
        result = context_url()
        self.assertEqual(result, 'http://example.com:5432/two/')
        request = DummyRequest({VH_ROOT_KEY:'/one/two'})
        context_url = self._makeOne(two, request)
        result = context_url()
@@ -973,8 +973,9 @@
        return self._getTargetClass()(environ)
    def test_no_matchdict(self):
        environ = {}
        root = self._makeOne(environ)
        class DummyRequest:
            matchdict = None
        root = self._makeOne(DummyRequest())
        self.assertEqual(root.__parent__, None)
        self.assertEqual(root.__name__, None)
@@ -997,13 +998,13 @@
            self.context.request = request
            return result
    return DummyTraverser
class DummyContext(object):
    __parent__ = None
    def __init__(self, next=None, name=None):
        self.next = next
        self.__name__ = name
    def __getitem__(self, name):
        if self.next is None:
            raise KeyError, name
@@ -1018,7 +1019,7 @@
        if environ is None:
            environ = {}
        self.environ = environ
class DummyContextURL:
    def __init__(self, context, request):
        pass
pyramid/traversal.py
@@ -592,7 +592,7 @@
                            'virtual_root':vroot,
                            'virtual_root_path':vroot_tuple,
                            'root':root}
                if i == vroot_idx:
                if i == vroot_idx:
                    vroot = next
                ob = next
                i += 1
@@ -623,7 +623,7 @@
            return self.request.root
        except AttributeError:
            return find_root(self.context)
    def __call__(self):
        """ Generate a URL based on the :term:`lineage` of a
        :term:`model` object obtained via :term:`traversal`.  If any
@@ -658,8 +658,9 @@
    __parent__ = None
    __name__ = None
    def __init__(self, request):
        matchdict = getattr(request, 'matchdict', {})
        matchdict = request.matchdict
        # provide backwards compatibility for applications which
        # used routes (at least apps without any custom "context
        # factory") in BFG 0.9.X and before
        self.__dict__.update(matchdict)
        if matchdict is not None:
            self.__dict__.update(matchdict)