Michael Merickel
2018-10-15 3670c2cdb732d378ba6d38e72e7cd875ff726aa9
commit | author | age
5ed24b 1 import unittest
CM 2
b60bdb 3 from pyramid import testing
5ed24b 4
17b8bc 5 class TestRouter(unittest.TestCase):
5ed24b 6     def setUp(self):
32859f 7         self.config = testing.setUp()
CM 8         self.registry = self.config.registry
5ed24b 9
CM 10     def tearDown(self):
4de362 11         testing.tearDown()
5ed24b 12
cbfafb 13     def _registerRouteRequest(self, name):
b60bdb 14         from pyramid.interfaces import IRouteRequest
CM 15         from pyramid.request import route_request_iface
ff1213 16         iface = route_request_iface(name)
CM 17         self.registry.registerUtility(iface, IRouteRequest, name=name)
18         return iface
cbfafb 19
74409d 20     def _connectRoute(self, name, path, factory=None):
b60bdb 21         from pyramid.interfaces import IRoutesMapper
CM 22         from pyramid.urldispatch import RoutesMapper
4de362 23         mapper = self.registry.queryUtility(IRoutesMapper)
cbfafb 24         if mapper is None:
CM 25             mapper = RoutesMapper()
4de362 26             self.registry.registerUtility(mapper, IRoutesMapper)
0ccdc2 27         return mapper.connect(name, path, factory)
cbfafb 28
17ce57 29     def _registerLogger(self):
b60bdb 30         from pyramid.interfaces import IDebugLogger
a1a9fb 31         logger = DummyLogger()
bd39b1 32         self.registry.registerUtility(logger, IDebugLogger)
17ce57 33         return logger
CM 34
35     def _registerSettings(self, **kw):
831e70 36         settings = {'debug_authorization':False,
JK 37                     'debug_notfound':False,
24bf2a 38                     'debug_routematch':False}
37369c 39         settings.update(kw)
5a972b 40         self.registry.settings = settings
a1a9fb 41
0a0ffe 42     def _registerTraverserFactory(self, context, view_name='', subpath=None,
916f88 43                                   traversed=None, virtual_root=None,
29f5c1 44                                   virtual_root_path=None, raise_error=None,
CM 45                                   **kw):
b60bdb 46         from pyramid.interfaces import ITraverser
916f88 47
CM 48         if virtual_root is None:
49             virtual_root = context
50         if subpath is None:
51             subpath = []
52         if traversed is None:
53             traversed = []
54         if virtual_root_path is None:
55             virtual_root_path = []
56
57         class DummyTraverserFactory:
0a0ffe 58             def __init__(self, root):
916f88 59                 self.root = root
CM 60
acc776 61             def __call__(self, request):
29f5c1 62                 if raise_error:
CM 63                     raise raise_error
916f88 64                 values = {'root':self.root,
CM 65                           'context':context,
66                           'view_name':view_name,
67                           'subpath':subpath,
68                           'traversed':traversed,
69                           'virtual_root':virtual_root,
70                           'virtual_root_path':virtual_root_path}
71                 kw.update(values)
72                 return kw
077c3c 73
916f88 74         self.registry.registerAdapter(DummyTraverserFactory, (None,),
077c3c 75                                       ITraverser, name='')
7de404 76
ff1213 77     def _registerView(self, app, name, classifier, req_iface, ctx_iface):
b60bdb 78         from pyramid.interfaces import IView
ff1213 79         self.registry.registerAdapter(
CM 80             app, (classifier, req_iface, ctx_iface), IView, name)
7de404 81
c8cf22 82     def _registerEventListener(self, iface):
CM 83         L = []
84         def listener(event):
85             L.append(event)
971537 86         self.registry.registerHandler(listener, (iface,))
c8cf22 87         return L
a0423a 88
a1a9fb 89     def _registerRootFactory(self, val):
1eb861 90         rootfactory = DummyRootFactory(val)
b60bdb 91         from pyramid.interfaces import IRootFactory
a1a9fb 92         self.registry.registerUtility(rootfactory, IRootFactory)
CM 93         return rootfactory
358dc2 94
5ed24b 95     def _getTargetClass(self):
b60bdb 96         from pyramid.router import Router
5ed24b 97         return Router
CM 98
971537 99     def _makeOne(self):
5ed24b 100         klass = self._getTargetClass()
971537 101         return klass(self.registry)
5ed24b 102
799575 103     def _makeEnviron(self, **extras):
CM 104         environ = {
105             'wsgi.url_scheme':'http',
106             'SERVER_NAME':'localhost',
107             'SERVER_PORT':'8080',
108             'REQUEST_METHOD':'GET',
916f88 109             'PATH_INFO':'/',
799575 110             }
CM 111         environ.update(extras)
112         return environ
113
216f41 114     def test_ctor_registry_has_no_settings(self):
CM 115         self.registry.settings = None
116         router = self._makeOne()
74f9ae 117         self.assertEqual(router.debug_notfound, False)
CM 118         self.assertEqual(router.debug_routematch, False)
a1d395 119         self.assertFalse('debug_notfound' in router.__dict__)
CM 120         self.assertFalse('debug_routematch' in router.__dict__)
216f41 121
7cd5d4 122     def test_root_policy(self):
CM 123         context = DummyContext()
916f88 124         self._registerTraverserFactory(context)
dfc2b6 125         rootfactory = self._registerRootFactory('abc')
971537 126         router = self._makeOne()
7cd5d4 127         self.assertEqual(router.root_policy, rootfactory)
CM 128
81a833 129     def test_request_factory(self):
b60bdb 130         from pyramid.interfaces import IRequestFactory
81a833 131         class DummyRequestFactory(object):
CM 132             pass
133         self.registry.registerUtility(DummyRequestFactory, IRequestFactory)
134         router = self._makeOne()
135         self.assertEqual(router.request_factory, DummyRequestFactory)
136
b4843b 137     def test_tween_factories(self):
CM 138         from pyramid.interfaces import ITweens
5bf23f 139         from pyramid.config.tweens import Tweens
b4843b 140         from pyramid.response import Response
CM 141         from pyramid.interfaces import IViewClassifier
142         from pyramid.interfaces import IResponse
143         tweens = Tweens()
144         self.registry.registerUtility(tweens, ITweens)
28b404 145         L = []
b4843b 146         def tween_factory1(handler, registry):
28b404 147             L.append((handler, registry))
CM 148             def wrapper(request):
149                 request.environ['handled'].append('one')
150                 return handler(request)
151             wrapper.name = 'one'
152             wrapper.child = handler
153             return wrapper
b4843b 154         def tween_factory2(handler, registry):
28b404 155             L.append((handler, registry))
CM 156             def wrapper(request):
157                 request.environ['handled'] = ['two']
158                 return handler(request)
159             wrapper.name = 'two'
160             wrapper.child = handler
161             return wrapper
8517d4 162         tweens.add_implicit('one', tween_factory1)
CM 163         tweens.add_implicit('two', tween_factory2)
28b404 164         router = self._makeOne()
CM 165         self.assertEqual(router.handle_request.name, 'two')
166         self.assertEqual(router.handle_request.child.name, 'one')
167         self.assertEqual(router.handle_request.child.child.__name__,
168                          'handle_request')
169         context = DummyContext()
170         self._registerTraverserFactory(context)
171         environ = self._makeEnviron()
172         view = DummyView('abc')
173         self._registerView(self.config.derive_view(view), '',
174                            IViewClassifier, None, None)
175         start_response = DummyStartResponse()
176         def make_response(s):
177             return Response(s)
178         router.registry.registerAdapter(make_response, (str,), IResponse)
179         app_iter = router(environ, start_response)
8e606d 180         self.assertEqual(app_iter, [b'abc'])
28b404 181         self.assertEqual(start_response.status, '200 OK')
CM 182         self.assertEqual(environ['handled'], ['two', 'one'])
dc45ab 183
160f01 184     def test_call_traverser_default(self):
99edc5 185         from pyramid.httpexceptions import HTTPNotFound
160f01 186         environ = self._makeEnviron()
CM 187         logger = self._registerLogger()
188         router = self._makeOne()
189         start_response = DummyStartResponse()
a7e625 190         why = exc_raised(HTTPNotFound, router, environ, start_response)
478442 191         self.assertTrue('/' in why.args[0], why)
CM 192         self.assertFalse('debug_notfound' in why.args[0])
160f01 193         self.assertEqual(len(logger.messages), 0)
0d13f6 194
bc857e 195     def test_traverser_raises_notfound_class(self):
99edc5 196         from pyramid.httpexceptions import HTTPNotFound
bc857e 197         environ = self._makeEnviron()
CM 198         context = DummyContext()
a7e625 199         self._registerTraverserFactory(context, raise_error=HTTPNotFound)
bc857e 200         router = self._makeOne()
CM 201         start_response = DummyStartResponse()
a7e625 202         self.assertRaises(HTTPNotFound, router, environ, start_response)
bc857e 203
CM 204     def test_traverser_raises_notfound_instance(self):
99edc5 205         from pyramid.httpexceptions import HTTPNotFound
bc857e 206         environ = self._makeEnviron()
CM 207         context = DummyContext()
a7e625 208         self._registerTraverserFactory(context, raise_error=HTTPNotFound('foo'))
bc857e 209         router = self._makeOne()
CM 210         start_response = DummyStartResponse()
a7e625 211         why = exc_raised(HTTPNotFound, router, environ, start_response)
478442 212         self.assertTrue('foo' in why.args[0], why)
bc857e 213
CM 214     def test_traverser_raises_forbidden_class(self):
99edc5 215         from pyramid.httpexceptions import HTTPForbidden
bc857e 216         environ = self._makeEnviron()
CM 217         context = DummyContext()
99edc5 218         self._registerTraverserFactory(context, raise_error=HTTPForbidden)
bc857e 219         router = self._makeOne()
CM 220         start_response = DummyStartResponse()
99edc5 221         self.assertRaises(HTTPForbidden, router, environ, start_response)
bc857e 222
CM 223     def test_traverser_raises_forbidden_instance(self):
99edc5 224         from pyramid.httpexceptions import HTTPForbidden
bc857e 225         environ = self._makeEnviron()
CM 226         context = DummyContext()
99edc5 227         self._registerTraverserFactory(context,
CM 228                                        raise_error=HTTPForbidden('foo'))
bc857e 229         router = self._makeOne()
CM 230         start_response = DummyStartResponse()
99edc5 231         why = exc_raised(HTTPForbidden, router, environ, start_response)
478442 232         self.assertTrue('foo' in why.args[0], why)
bc857e 233
17ce57 234     def test_call_no_view_registered_no_isettings(self):
99edc5 235         from pyramid.httpexceptions import HTTPNotFound
799575 236         environ = self._makeEnviron()
7de404 237         context = DummyContext()
916f88 238         self._registerTraverserFactory(context)
17ce57 239         logger = self._registerLogger()
971537 240         router = self._makeOne()
7de404 241         start_response = DummyStartResponse()
a7e625 242         why = exc_raised(HTTPNotFound, router, environ, start_response)
478442 243         self.assertTrue('/' in why.args[0], why)
CM 244         self.assertFalse('debug_notfound' in why.args[0])
17ce57 245         self.assertEqual(len(logger.messages), 0)
CM 246
247     def test_call_no_view_registered_debug_notfound_false(self):
99edc5 248         from pyramid.httpexceptions import HTTPNotFound
17ce57 249         environ = self._makeEnviron()
CM 250         context = DummyContext()
916f88 251         self._registerTraverserFactory(context)
17ce57 252         logger = self._registerLogger()
CM 253         self._registerSettings(debug_notfound=False)
971537 254         router = self._makeOne()
17ce57 255         start_response = DummyStartResponse()
a7e625 256         why = exc_raised(HTTPNotFound, router, environ, start_response)
478442 257         self.assertTrue('/' in why.args[0], why)
CM 258         self.assertFalse('debug_notfound' in why.args[0])
17ce57 259         self.assertEqual(len(logger.messages), 0)
CM 260
261     def test_call_no_view_registered_debug_notfound_true(self):
99edc5 262         from pyramid.httpexceptions import HTTPNotFound
17ce57 263         environ = self._makeEnviron()
CM 264         context = DummyContext()
916f88 265         self._registerTraverserFactory(context)
17ce57 266         self._registerSettings(debug_notfound=True)
CM 267         logger = self._registerLogger()
971537 268         router = self._makeOne()
17ce57 269         start_response = DummyStartResponse()
a7e625 270         why = exc_raised(HTTPNotFound, router, environ, start_response)
a1d395 271         self.assertTrue(
7950a2 272             "debug_notfound of url http://localhost:8080/; " in why.args[0])
478442 273         self.assertTrue("view_name: '', subpath: []" in why.args[0])
CM 274         self.assertTrue('http://localhost:8080' in why.args[0], why)
ff1213 275
17ce57 276         self.assertEqual(len(logger.messages), 1)
CM 277         message = logger.messages[0]
a1d395 278         self.assertTrue('of url http://localhost:8080' in message)
7950a2 279         self.assertTrue("path_info: " in message)
478442 280         self.assertTrue('DummyContext' in message)
a1d395 281         self.assertTrue("view_name: ''" in message)
CM 282         self.assertTrue("subpath: []" in message)
5ed24b 283
d868ff 284     def test_call_view_returns_non_iresponse(self):
b60bdb 285         from pyramid.interfaces import IViewClassifier
7292d4 286         context = DummyContext()
916f88 287         self._registerTraverserFactory(context)
7292d4 288         environ = self._makeEnviron()
1eb861 289         view = DummyView('abc')
32859f 290         self._registerView(self.config.derive_view(view), '', IViewClassifier,
CM 291                            None, None)
b5f5b3 292         router = self._makeOne()
CM 293         start_response = DummyStartResponse()
294         self.assertRaises(ValueError, router, environ, start_response)
d868ff 295
CM 296     def test_call_view_returns_adapted_response(self):
297         from pyramid.response import Response
298         from pyramid.interfaces import IViewClassifier
299         from pyramid.interfaces import IResponse
300         context = DummyContext()
301         self._registerTraverserFactory(context)
302         environ = self._makeEnviron()
303         view = DummyView('abc')
32859f 304         self._registerView(self.config.derive_view(view), '',
CM 305                            IViewClassifier, None, None)
d868ff 306         router = self._makeOne()
CM 307         start_response = DummyStartResponse()
308         def make_response(s):
309             return Response(s)
310         router.registry.registerAdapter(make_response, (str,), IResponse)
311         app_iter = router(environ, start_response)
8e606d 312         self.assertEqual(app_iter, [b'abc'])
d868ff 313         self.assertEqual(start_response.status, '200 OK')
b5f5b3 314
735987 315     def test_call_with_request_extensions(self):
CM 316         from pyramid.interfaces import IViewClassifier
317         from pyramid.interfaces import IRequestExtensions
318         from pyramid.interfaces import IRequest
319         from pyramid.request import Request
04cc91 320         from pyramid.util import InstancePropertyHelper
735987 321         context = DummyContext()
CM 322         self._registerTraverserFactory(context)
323         class Extensions(object):
324             def __init__(self):
325                 self.methods = {}
326                 self.descriptors = {}
327         extensions = Extensions()
04cc91 328         ext_method = lambda r: 'bar'
MM 329         name, fn = InstancePropertyHelper.make_property(ext_method, name='foo')
330         extensions.descriptors[name] = fn
735987 331         request = Request.blank('/')
CM 332         request.request_iface = IRequest
333         request.registry = self.registry
334         def request_factory(environ):
335             return request
336         self.registry.registerUtility(extensions, IRequestExtensions)
337         environ = self._makeEnviron()
338         response = DummyResponse()
339         response.app_iter = ['Hello world']
340         view = DummyView(response)
341         self._registerView(self.config.derive_view(view), '',
342                            IViewClassifier, None, None)
343         router = self._makeOne()
344         router.request_factory = request_factory
345         start_response = DummyStartResponse()
346         router(environ, start_response)
04cc91 347         self.assertEqual(view.request.foo, 'bar')
735987 348
7de404 349     def test_call_view_registered_nonspecific_default_path(self):
b60bdb 350         from pyramid.interfaces import IViewClassifier
5ed24b 351         context = DummyContext()
916f88 352         self._registerTraverserFactory(context)
7de404 353         response = DummyResponse()
4df575 354         response.app_iter = ['Hello world']
1eb861 355         view = DummyView(response)
799575 356         environ = self._makeEnviron()
32859f 357         self._registerView(self.config.derive_view(view), '',
CM 358                            IViewClassifier, None, None)
9a038d 359         self._registerRootFactory(context)
971537 360         router = self._makeOne()
7de404 361         start_response = DummyStartResponse()
5ed24b 362         result = router(environ, start_response)
7de404 363         self.assertEqual(result, ['Hello world'])
CM 364         self.assertEqual(start_response.headers, ())
365         self.assertEqual(start_response.status, '200 OK')
164677 366         request = view.request
CM 367         self.assertEqual(request.view_name, '')
368         self.assertEqual(request.subpath, [])
369         self.assertEqual(request.context, context)
370         self.assertEqual(request.root, context)
5ed24b 371
916f88 372     def test_call_view_registered_nonspecific_nondefault_path_and_subpath(self):
b60bdb 373         from pyramid.interfaces import IViewClassifier
916f88 374         context = DummyContext()
CM 375         self._registerTraverserFactory(context, view_name='foo',
376                                        subpath=['bar'],
377                                        traversed=['context'])
9a038d 378         self._registerRootFactory(context)
916f88 379         response = DummyResponse()
CM 380         response.app_iter = ['Hello world']
1eb861 381         view = DummyView(response)
916f88 382         environ = self._makeEnviron()
ff1213 383         self._registerView(view, 'foo', IViewClassifier, None, None)
971537 384         router = self._makeOne()
7de404 385         start_response = DummyStartResponse()
5ed24b 386         result = router(environ, start_response)
7de404 387         self.assertEqual(result, ['Hello world'])
CM 388         self.assertEqual(start_response.headers, ())
389         self.assertEqual(start_response.status, '200 OK')
164677 390         request = view.request
CM 391         self.assertEqual(request.view_name, 'foo')
392         self.assertEqual(request.subpath, ['bar'])
393         self.assertEqual(request.context, context)
394         self.assertEqual(request.root, context)
799575 395
7de404 396     def test_call_view_registered_specific_success(self):
799575 397         from zope.interface import Interface
CM 398         from zope.interface import directlyProvides
399         class IContext(Interface):
400             pass
b60bdb 401         from pyramid.interfaces import IRequest
CM 402         from pyramid.interfaces import IViewClassifier
799575 403         context = DummyContext()
7de404 404         directlyProvides(context, IContext)
916f88 405         self._registerTraverserFactory(context)
9a038d 406         self._registerRootFactory(context)
7de404 407         response = DummyResponse()
4df575 408         response.app_iter = ['Hello world']
1eb861 409         view = DummyView(response)
7de404 410         environ = self._makeEnviron()
ff1213 411         self._registerView(view, '', IViewClassifier, IRequest, IContext)
971537 412         router = self._makeOne()
7de404 413         start_response = DummyStartResponse()
CM 414         result = router(environ, start_response)
415         self.assertEqual(result, ['Hello world'])
416         self.assertEqual(start_response.headers, ())
417         self.assertEqual(start_response.status, '200 OK')
164677 418         request = view.request
CM 419         self.assertEqual(request.view_name, '')
420         self.assertEqual(request.subpath, [])
421         self.assertEqual(request.context, context)
422         self.assertEqual(request.root, context)
7de404 423
CM 424     def test_call_view_registered_specific_fail(self):
799575 425         from zope.interface import Interface
CM 426         from zope.interface import directlyProvides
99edc5 427         from pyramid.httpexceptions import HTTPNotFound
b60bdb 428         from pyramid.interfaces import IViewClassifier
7de404 429         class IContext(Interface):
CM 430             pass
799575 431         class INotContext(Interface):
CM 432             pass
b60bdb 433         from pyramid.interfaces import IRequest
7de404 434         context = DummyContext()
799575 435         directlyProvides(context, INotContext)
916f88 436         self._registerTraverserFactory(context, subpath=[''])
7de404 437         response = DummyResponse()
1eb861 438         view = DummyView(response)
799575 439         environ = self._makeEnviron()
ff1213 440         self._registerView(view, '', IViewClassifier, IRequest, IContext)
971537 441         router = self._makeOne()
7de404 442         start_response = DummyStartResponse()
a7e625 443         self.assertRaises(HTTPNotFound, router, environ, start_response)
111593 444
ef5149 445     def test_call_view_raises_forbidden(self):
2466f6 446         from zope.interface import Interface
CM 447         from zope.interface import directlyProvides
99edc5 448         from pyramid.httpexceptions import HTTPForbidden
2466f6 449         class IContext(Interface):
CM 450             pass
b60bdb 451         from pyramid.interfaces import IRequest
CM 452         from pyramid.interfaces import IViewClassifier
2466f6 453         context = DummyContext()
CM 454         directlyProvides(context, IContext)
916f88 455         self._registerTraverserFactory(context, subpath=[''])
2466f6 456         response = DummyResponse()
99edc5 457         view = DummyView(response,
CM 458                          raise_exception=HTTPForbidden("unauthorized"))
2466f6 459         environ = self._makeEnviron()
ff1213 460         self._registerView(view, '', IViewClassifier, IRequest, IContext)
971537 461         router = self._makeOne()
2466f6 462         start_response = DummyStartResponse()
99edc5 463         why = exc_raised(HTTPForbidden, router, environ, start_response)
478442 464         self.assertEqual(why.args[0], 'unauthorized')
2466f6 465
d66bfb 466     def test_call_view_raises_notfound(self):
17ce57 467         from zope.interface import Interface
CM 468         from zope.interface import directlyProvides
469         class IContext(Interface):
470             pass
b60bdb 471         from pyramid.interfaces import IRequest
CM 472         from pyramid.interfaces import IViewClassifier
99edc5 473         from pyramid.httpexceptions import HTTPNotFound
17ce57 474         context = DummyContext()
CM 475         directlyProvides(context, IContext)
916f88 476         self._registerTraverserFactory(context, subpath=[''])
17ce57 477         response = DummyResponse()
a7e625 478         view = DummyView(response, raise_exception=HTTPNotFound("notfound"))
17ce57 479         environ = self._makeEnviron()
ff1213 480         self._registerView(view, '', IViewClassifier, IRequest, IContext)
971537 481         router = self._makeOne()
17ce57 482         start_response = DummyStartResponse()
a7e625 483         why = exc_raised(HTTPNotFound, router, environ, start_response)
478442 484         self.assertEqual(why.args[0], 'notfound')
ef5149 485
d05117 486     def test_call_view_raises_response_cleared(self):
CM 487         from zope.interface import Interface
488         from zope.interface import directlyProvides
489         from pyramid.interfaces import IExceptionViewClassifier
490         class IContext(Interface):
491             pass
492         from pyramid.interfaces import IRequest
493         from pyramid.interfaces import IViewClassifier
494         context = DummyContext()
495         directlyProvides(context, IContext)
496         self._registerTraverserFactory(context, subpath=[''])
497         def view(context, request):
498             request.response.a = 1
499             raise KeyError
500         def exc_view(context, request):
a80206 501             self.assertFalse(hasattr(request.response, 'a'))
8e606d 502             request.response.body = b'OK'
d05117 503             return request.response
CM 504         environ = self._makeEnviron()
505         self._registerView(view, '', IViewClassifier, IRequest, IContext)
506         self._registerView(exc_view, '', IExceptionViewClassifier,
507                            IRequest, KeyError)
508         router = self._makeOne()
509         start_response = DummyStartResponse()
510         itera = router(environ, start_response)
8e606d 511         self.assertEqual(itera, [b'OK'])
d05117 512
844e98 513     def test_call_request_has_response_callbacks(self):
839ea0 514         from zope.interface import Interface
CM 515         from zope.interface import directlyProvides
516         class IContext(Interface):
517             pass
b60bdb 518         from pyramid.interfaces import IRequest
CM 519         from pyramid.interfaces import IViewClassifier
839ea0 520         context = DummyContext()
CM 521         directlyProvides(context, IContext)
522         self._registerTraverserFactory(context, subpath=[''])
523         response = DummyResponse('200 OK')
164677 524         def view(context, request):
844e98 525             def callback(request, response):
CM 526                 response.called_back = True
39a03e 527             request.add_response_callback(callback)
164677 528             return response
839ea0 529         environ = self._makeEnviron()
ff1213 530         self._registerView(view, '', IViewClassifier, IRequest, IContext)
839ea0 531         router = self._makeOne()
CM 532         start_response = DummyStartResponse()
164677 533         router(environ, start_response)
844e98 534         self.assertEqual(response.called_back, True)
839ea0 535
ad6a67 536     def test_call_request_has_finished_callbacks_when_view_succeeds(self):
CM 537         from zope.interface import Interface
538         from zope.interface import directlyProvides
539         class IContext(Interface):
540             pass
b60bdb 541         from pyramid.interfaces import IRequest
CM 542         from pyramid.interfaces import IViewClassifier
ad6a67 543         context = DummyContext()
CM 544         directlyProvides(context, IContext)
545         self._registerTraverserFactory(context, subpath=[''])
546         response = DummyResponse('200 OK')
547         def view(context, request):
548             def callback(request):
549                 request.environ['called_back'] = True
39a03e 550             request.add_finished_callback(callback)
ad6a67 551             return response
CM 552         environ = self._makeEnviron()
553         self._registerView(view, '', IViewClassifier, IRequest, IContext)
554         router = self._makeOne()
555         start_response = DummyStartResponse()
556         router(environ, start_response)
557         self.assertEqual(environ['called_back'], True)
558
559     def test_call_request_has_finished_callbacks_when_view_raises(self):
560         from zope.interface import Interface
561         from zope.interface import directlyProvides
562         class IContext(Interface):
563             pass
b60bdb 564         from pyramid.interfaces import IRequest
CM 565         from pyramid.interfaces import IViewClassifier
ad6a67 566         context = DummyContext()
CM 567         directlyProvides(context, IContext)
568         self._registerTraverserFactory(context, subpath=[''])
569         def view(context, request):
570             def callback(request):
571                 request.environ['called_back'] = True
39a03e 572             request.add_finished_callback(callback)
ad6a67 573             raise NotImplementedError
CM 574         environ = self._makeEnviron()
575         self._registerView(view, '', IViewClassifier, IRequest, IContext)
576         router = self._makeOne()
577         start_response = DummyStartResponse()
578         exc_raised(NotImplementedError, router, environ, start_response)
579         self.assertEqual(environ['called_back'], True)
df15ed 580
ad6a67 581     def test_call_request_factory_raises(self):
CM 582         # making sure finally doesnt barf when a request cannot be created
583         environ = self._makeEnviron()
584         router = self._makeOne()
585         def dummy_request_factory(environ):
586             raise NotImplementedError
587         router.request_factory = dummy_request_factory
588         start_response = DummyStartResponse()
589         exc_raised(NotImplementedError, router, environ, start_response)
590
a0423a 591     def test_call_eventsends(self):
b60bdb 592         from pyramid.interfaces import INewRequest
CM 593         from pyramid.interfaces import INewResponse
59428d 594         from pyramid.interfaces import IBeforeTraversal
b60bdb 595         from pyramid.interfaces import IContextFound
CM 596         from pyramid.interfaces import IViewClassifier
a0423a 597         context = DummyContext()
916f88 598         self._registerTraverserFactory(context)
a0423a 599         response = DummyResponse()
CM 600         response.app_iter = ['Hello world']
1eb861 601         view = DummyView(response)
a0423a 602         environ = self._makeEnviron()
ff1213 603         self._registerView(view, '', IViewClassifier, None, None)
c8cf22 604         request_events = self._registerEventListener(INewRequest)
59428d 605         beforetraversal_events = self._registerEventListener(IBeforeTraversal)
4fe3ef 606         context_found_events = self._registerEventListener(IContextFound)
c8cf22 607         response_events = self._registerEventListener(INewResponse)
971537 608         router = self._makeOne()
a0423a 609         start_response = DummyStartResponse()
CM 610         result = router(environ, start_response)
611         self.assertEqual(len(request_events), 1)
612         self.assertEqual(request_events[0].request.environ, environ)
59428d 613         self.assertEqual(len(beforetraversal_events), 1)
BJR 614         self.assertEqual(beforetraversal_events[0].request.environ, environ)
4fe3ef 615         self.assertEqual(len(context_found_events), 1)
MA 616         self.assertEqual(context_found_events[0].request.environ, environ)
617         self.assertEqual(context_found_events[0].request.context, context)
a0423a 618         self.assertEqual(len(response_events), 1)
CM 619         self.assertEqual(response_events[0].response, response)
4fe3ef 620         self.assertEqual(response_events[0].request.context, context)
9a038d 621         self.assertEqual(result, response.app_iter)
a0b40c 622
ba2ac1 623     def test_call_newrequest_evllist_exc_can_be_caught_by_exceptionview(self):
CM 624         from pyramid.interfaces import INewRequest
625         from pyramid.interfaces import IExceptionViewClassifier
626         from pyramid.interfaces import IRequest
627         context = DummyContext()
628         self._registerTraverserFactory(context)
629         environ = self._makeEnviron()
630         def listener(event):
631             raise KeyError
632         self.registry.registerHandler(listener, (INewRequest,))
633         exception_response = DummyResponse()
634         exception_response.app_iter = ["Hello, world"]
635         exception_view = DummyView(exception_response)
636         environ = self._makeEnviron()
637         self._registerView(exception_view, '', IExceptionViewClassifier,
638                            IRequest, KeyError)
639         router = self._makeOne()
640         start_response = DummyStartResponse()
641         result = router(environ, start_response)
642         self.assertEqual(result, exception_response.app_iter)
643
cbfafb 644     def test_call_route_matches_and_has_factory(self):
b60bdb 645         from pyramid.interfaces import IViewClassifier
831e70 646         logger = self._registerLogger()
24bf2a 647         self._registerSettings(debug_routematch=True)
ff1213 648         self._registerRouteRequest('foo')
cbfafb 649         root = object()
CM 650         def factory(request):
651             return root
0ccdc2 652         route = self._connectRoute('foo', 'archives/:action/:article', factory)
CM 653         route.predicates = [DummyPredicate()]
cbfafb 654         context = DummyContext()
CM 655         self._registerTraverserFactory(context)
656         response = DummyResponse()
657         response.app_iter = ['Hello world']
658         view = DummyView(response)
659         environ = self._makeEnviron(PATH_INFO='/archives/action1/article1')
ff1213 660         self._registerView(view, '', IViewClassifier, None, None)
9a038d 661         self._registerRootFactory(context)
cbfafb 662         router = self._makeOne()
CM 663         start_response = DummyStartResponse()
664         result = router(environ, start_response)
665         self.assertEqual(result, ['Hello world'])
666         self.assertEqual(start_response.headers, ())
667         self.assertEqual(start_response.status, '200 OK')
668         request = view.request
669         self.assertEqual(request.view_name, '')
670         self.assertEqual(request.subpath, [])
671         self.assertEqual(request.context, context)
672         self.assertEqual(request.root, root)
81d3b5 673         matchdict = {'action':'action1', 'article':'article1'}
CM 674         self.assertEqual(request.matchdict, matchdict)
675         self.assertEqual(request.matched_route.name, 'foo')
831e70 676         self.assertEqual(len(logger.messages), 1)
a1d395 677         self.assertTrue(
89335f 678             logger.messages[0].startswith(
24bf2a 679             "route matched for url http://localhost:8080"
831e70 680             "/archives/action1/article1; "
24bf2a 681             "route_name: 'foo', "
0ccdc2 682             "path_info: ")
CM 683             )
684         self.assertTrue(
685             "predicates: 'predicate'" in logger.messages[0]
686             )
831e70 687
24bf2a 688     def test_call_route_match_miss_debug_routematch(self):
99edc5 689         from pyramid.httpexceptions import HTTPNotFound
24bf2a 690         logger = self._registerLogger()
CM 691         self._registerSettings(debug_routematch=True)
692         self._registerRouteRequest('foo')
693         self._connectRoute('foo', 'archives/:action/:article')
694         context = DummyContext()
695         self._registerTraverserFactory(context)
696         environ = self._makeEnviron(PATH_INFO='/wontmatch')
697         self._registerRootFactory(context)
698         router = self._makeOne()
699         start_response = DummyStartResponse()
a7e625 700         self.assertRaises(HTTPNotFound, router, environ, start_response)
24bf2a 701
CM 702         self.assertEqual(len(logger.messages), 1)
703         self.assertEqual(
704             logger.messages[0],
705             'no route matched for url http://localhost:8080/wontmatch')
706
cbfafb 707     def test_call_route_matches_doesnt_overwrite_subscriber_iface(self):
b60bdb 708         from pyramid.interfaces import INewRequest
CM 709         from pyramid.interfaces import IViewClassifier
cbfafb 710         from zope.interface import alsoProvides
CM 711         from zope.interface import Interface
ff1213 712         self._registerRouteRequest('foo')
cbfafb 713         class IFoo(Interface):
CM 714             pass
715         def listener(event):
716             alsoProvides(event.request, IFoo)
717         self.registry.registerHandler(listener, (INewRequest,))
718         root = object()
719         def factory(request):
720             return root
74409d 721         self._connectRoute('foo', 'archives/:action/:article', factory)
cbfafb 722         context = DummyContext()
CM 723         self._registerTraverserFactory(context)
724         response = DummyResponse()
725         response.app_iter = ['Hello world']
726         view = DummyView(response)
727         environ = self._makeEnviron(PATH_INFO='/archives/action1/article1')
ff1213 728         self._registerView(view, '', IViewClassifier, None, None)
9a038d 729         self._registerRootFactory(context)
cbfafb 730         router = self._makeOne()
CM 731         start_response = DummyStartResponse()
732         result = router(environ, start_response)
733         self.assertEqual(result, ['Hello world'])
734         self.assertEqual(start_response.headers, ())
735         self.assertEqual(start_response.status, '200 OK')
736         request = view.request
737         self.assertEqual(request.view_name, '')
738         self.assertEqual(request.subpath, [])
739         self.assertEqual(request.context, context)
740         self.assertEqual(request.root, root)
81d3b5 741         matchdict = {'action':'action1', 'article':'article1'}
CM 742         self.assertEqual(request.matchdict, matchdict)
743         self.assertEqual(request.matched_route.name, 'foo')
a1d395 744         self.assertTrue(IFoo.providedBy(request))
a1a9fb 745
29f5c1 746     def test_root_factory_raises_notfound(self):
b60bdb 747         from pyramid.interfaces import IRootFactory
99edc5 748         from pyramid.httpexceptions import HTTPNotFound
29f5c1 749         from zope.interface import Interface
CM 750         from zope.interface import directlyProvides
751         def rootfactory(request):
a7e625 752             raise HTTPNotFound('from root factory')
29f5c1 753         self.registry.registerUtility(rootfactory, IRootFactory)
CM 754         class IContext(Interface):
755             pass
756         context = DummyContext()
757         directlyProvides(context, IContext)
758         environ = self._makeEnviron()
759         router = self._makeOne()
760         start_response = DummyStartResponse()
a7e625 761         why = exc_raised(HTTPNotFound, router, environ, start_response)
478442 762         self.assertTrue('from root factory' in why.args[0])
29f5c1 763
CM 764     def test_root_factory_raises_forbidden(self):
b60bdb 765         from pyramid.interfaces import IRootFactory
99edc5 766         from pyramid.httpexceptions import HTTPForbidden
29f5c1 767         from zope.interface import Interface
CM 768         from zope.interface import directlyProvides
769         def rootfactory(request):
99edc5 770             raise HTTPForbidden('from root factory')
29f5c1 771         self.registry.registerUtility(rootfactory, IRootFactory)
CM 772         class IContext(Interface):
773             pass
774         context = DummyContext()
775         directlyProvides(context, IContext)
776         environ = self._makeEnviron()
777         router = self._makeOne()
778         start_response = DummyStartResponse()
99edc5 779         why = exc_raised(HTTPForbidden, router, environ, start_response)
478442 780         self.assertTrue('from root factory' in why.args[0])
ff1213 781
CM 782     def test_root_factory_exception_propagating(self):
b60bdb 783         from pyramid.interfaces import IRootFactory
ff1213 784         from zope.interface import Interface
CM 785         from zope.interface import directlyProvides
786         def rootfactory(request):
787             raise RuntimeError()
788         self.registry.registerUtility(rootfactory, IRootFactory)
789         class IContext(Interface):
790             pass
791         context = DummyContext()
792         directlyProvides(context, IContext)
793         environ = self._makeEnviron()
794         router = self._makeOne()
795         start_response = DummyStartResponse()
796         self.assertRaises(RuntimeError, router, environ, start_response)
797
798     def test_traverser_exception_propagating(self):
799         environ = self._makeEnviron()
800         context = DummyContext()
801         self._registerTraverserFactory(context, raise_error=RuntimeError())
802         router = self._makeOne()
803         start_response = DummyStartResponse()
804         self.assertRaises(RuntimeError, router, environ, start_response)
805
806     def test_call_view_exception_propagating(self):
807         from zope.interface import Interface
808         from zope.interface import directlyProvides
809         class IContext(Interface):
810             pass
b60bdb 811         from pyramid.interfaces import IRequest
CM 812         from pyramid.interfaces import IViewClassifier
813         from pyramid.interfaces import IRequestFactory
6456c2 814         from pyramid.interfaces import IExceptionViewClassifier
81d3b5 815         def rfactory(environ):
CM 816             return request
817         self.registry.registerUtility(rfactory, IRequestFactory)
b60bdb 818         from pyramid.request import Request
81d3b5 819         request = Request.blank('/')
ff1213 820         context = DummyContext()
CM 821         directlyProvides(context, IContext)
822         self._registerTraverserFactory(context, subpath=[''])
823         response = DummyResponse()
6456c2 824         response.app_iter = ['OK']
579a5f 825         error = RuntimeError()
CM 826         view = DummyView(response, raise_exception=error)
ff1213 827         environ = self._makeEnviron()
6456c2 828         def exception_view(context, request):
CM 829             self.assertEqual(request.exc_info[0], RuntimeError)
830             return response
ff1213 831         self._registerView(view, '', IViewClassifier, IRequest, IContext)
6456c2 832         self._registerView(exception_view, '', IExceptionViewClassifier,
CM 833                            IRequest, RuntimeError)
ff1213 834         router = self._makeOne()
CM 835         start_response = DummyStartResponse()
6456c2 836         result = router(environ, start_response)
CM 837         self.assertEqual(result, ['OK'])
579a5f 838         # exc_info and exception should still be around on the request after
CM 839         # the excview tween has run (see
840         # https://github.com/Pylons/pyramid/issues/1223)
841         self.assertEqual(request.exception, error)
842         self.assertEqual(request.exc_info[:2], (RuntimeError, error,))
95a379 843         
ff1213 844     def test_call_view_raises_exception_view(self):
b60bdb 845         from pyramid.interfaces import IViewClassifier
CM 846         from pyramid.interfaces import IExceptionViewClassifier
847         from pyramid.interfaces import IRequest
ff1213 848         response = DummyResponse()
CM 849         exception_response = DummyResponse()
850         exception_response.app_iter = ["Hello, world"]
851         view = DummyView(response, raise_exception=RuntimeError)
3e3fcd 852         def exception_view(context, request):
CM 853             self.assertEqual(request.exception.__class__, RuntimeError)
854             return exception_response
ff1213 855         environ = self._makeEnviron()
CM 856         self._registerView(view, '', IViewClassifier, IRequest, None)
857         self._registerView(exception_view, '', IExceptionViewClassifier,
858                            IRequest, RuntimeError)
859         router = self._makeOne()
860         start_response = DummyStartResponse()
861         result = router(environ, start_response)
862         self.assertEqual(result, ["Hello, world"])
863
864     def test_call_view_raises_super_exception_sub_exception_view(self):
b60bdb 865         from pyramid.interfaces import IViewClassifier
CM 866         from pyramid.interfaces import IExceptionViewClassifier
867         from pyramid.interfaces import IRequest
ff1213 868         class SuperException(Exception):
CM 869             pass
870         class SubException(SuperException):
871             pass
872         response = DummyResponse()
873         exception_response = DummyResponse()
874         exception_response.app_iter = ["Hello, world"]
875         view = DummyView(response, raise_exception=SuperException)
876         exception_view = DummyView(exception_response)
877         environ = self._makeEnviron()
878         self._registerView(view, '', IViewClassifier, IRequest, None)
879         self._registerView(exception_view, '', IExceptionViewClassifier,
880                            IRequest, SubException)
881         router = self._makeOne()
882         start_response = DummyStartResponse()
883         self.assertRaises(SuperException, router, environ, start_response)
884
885     def test_call_view_raises_sub_exception_super_exception_view(self):
b60bdb 886         from pyramid.interfaces import IViewClassifier
CM 887         from pyramid.interfaces import IExceptionViewClassifier
888         from pyramid.interfaces import IRequest
ff1213 889         class SuperException(Exception):
CM 890             pass
891         class SubException(SuperException):
892             pass
893         response = DummyResponse()
894         exception_response = DummyResponse()
895         exception_response.app_iter = ["Hello, world"]
896         view = DummyView(response, raise_exception=SubException)
897         exception_view = DummyView(exception_response)
898         environ = self._makeEnviron()
899         self._registerView(view, '', IViewClassifier, IRequest, None)
900         self._registerView(exception_view, '', IExceptionViewClassifier,
901                            IRequest, SuperException)
902         router = self._makeOne()
903         start_response = DummyStartResponse()
904         result = router(environ, start_response)
905         self.assertEqual(result, ["Hello, world"])
906
907     def test_call_view_raises_exception_another_exception_view(self):
b60bdb 908         from pyramid.interfaces import IViewClassifier
CM 909         from pyramid.interfaces import IExceptionViewClassifier
910         from pyramid.interfaces import IRequest
ff1213 911         class MyException(Exception):
CM 912             pass
913         class AnotherException(Exception):
914             pass
915         response = DummyResponse()
916         exception_response = DummyResponse()
917         exception_response.app_iter = ["Hello, world"]
918         view = DummyView(response, raise_exception=MyException)
919         exception_view = DummyView(exception_response)
920         environ = self._makeEnviron()
921         self._registerView(view, '', IViewClassifier, IRequest, None)
922         self._registerView(exception_view, '', IExceptionViewClassifier,
923                            IRequest, AnotherException)
924         router = self._makeOne()
925         start_response = DummyStartResponse()
926         self.assertRaises(MyException, router, environ, start_response)
927
928     def test_root_factory_raises_exception_view(self):
b60bdb 929         from pyramid.interfaces import IRootFactory
CM 930         from pyramid.interfaces import IRequest
931         from pyramid.interfaces import IExceptionViewClassifier
ff1213 932         def rootfactory(request):
CM 933             raise RuntimeError()
934         self.registry.registerUtility(rootfactory, IRootFactory)
935         exception_response = DummyResponse()
936         exception_response.app_iter = ["Hello, world"]
937         exception_view = DummyView(exception_response)
938         self._registerView(exception_view, '', IExceptionViewClassifier,
939                            IRequest, RuntimeError)
940         environ = self._makeEnviron()
941         router = self._makeOne()
942         start_response = DummyStartResponse()
29f5c1 943         app_iter = router(environ, start_response)
ff1213 944         self.assertEqual(app_iter, ["Hello, world"])
CM 945
946     def test_traverser_raises_exception_view(self):
b60bdb 947         from pyramid.interfaces import IRequest
CM 948         from pyramid.interfaces import IExceptionViewClassifier
ff1213 949         environ = self._makeEnviron()
CM 950         context = DummyContext()
951         self._registerTraverserFactory(context, raise_error=RuntimeError())
952         exception_response = DummyResponse()
953         exception_response.app_iter = ["Hello, world"]
954         exception_view = DummyView(exception_response)
955         self._registerView(exception_view, '', IExceptionViewClassifier,
956                            IRequest, RuntimeError)
957         router = self._makeOne()
958         start_response = DummyStartResponse()
959         result = router(environ, start_response)
960         self.assertEqual(result, ["Hello, world"])
961
d868ff 962     def test_exception_view_returns_non_iresponse(self):
b60bdb 963         from pyramid.interfaces import IRequest
CM 964         from pyramid.interfaces import IViewClassifier
965         from pyramid.interfaces import IExceptionViewClassifier
ff1213 966         environ = self._makeEnviron()
CM 967         response = DummyResponse()
968         view = DummyView(response, raise_exception=RuntimeError)
32859f 969         
CM 970         self._registerView(self.config.derive_view(view), '',
971                            IViewClassifier, IRequest, None)
ff1213 972         exception_view = DummyView(None)
32859f 973         self._registerView(self.config.derive_view(exception_view), '',
CM 974                            IExceptionViewClassifier,
ff1213 975                            IRequest, RuntimeError)
CM 976         router = self._makeOne()
977         start_response = DummyStartResponse()
978         self.assertRaises(ValueError, router, environ, start_response)
979
980     def test_call_route_raises_route_exception_view(self):
b60bdb 981         from pyramid.interfaces import IViewClassifier
CM 982         from pyramid.interfaces import IExceptionViewClassifier
ff1213 983         req_iface = self._registerRouteRequest('foo')
74409d 984         self._connectRoute('foo', 'archives/:action/:article', None)
ff1213 985         view = DummyView(DummyResponse(), raise_exception=RuntimeError)
CM 986         self._registerView(view, '', IViewClassifier, req_iface, None)
987         response = DummyResponse()
988         response.app_iter = ["Hello, world"]
989         exception_view = DummyView(response)
990         self._registerView(exception_view, '', IExceptionViewClassifier,
991                            req_iface, RuntimeError)
992         environ = self._makeEnviron(PATH_INFO='/archives/action1/article1')
993         start_response = DummyStartResponse()
994         router = self._makeOne()
995         result = router(environ, start_response)
996         self.assertEqual(result, ["Hello, world"])
997
998     def test_call_view_raises_exception_route_view(self):
b60bdb 999         from pyramid.interfaces import IViewClassifier
CM 1000         from pyramid.interfaces import IExceptionViewClassifier
1001         from pyramid.interfaces import IRequest
ff1213 1002         req_iface = self._registerRouteRequest('foo')
74409d 1003         self._connectRoute('foo', 'archives/:action/:article', None)
ff1213 1004         view = DummyView(DummyResponse(), raise_exception=RuntimeError)
CM 1005         self._registerView(view, '', IViewClassifier, IRequest, None)
1006         response = DummyResponse()
1007         response.app_iter = ["Hello, world"]
1008         exception_view = DummyView(response)
1009         self._registerView(exception_view, '', IExceptionViewClassifier,
1010                            req_iface, RuntimeError)
1011         environ = self._makeEnviron()
1012         start_response = DummyStartResponse()
1013         router = self._makeOne()
1014         self.assertRaises(RuntimeError, router, environ, start_response)
1015
1016     def test_call_route_raises_exception_view(self):
b60bdb 1017         from pyramid.interfaces import IViewClassifier
CM 1018         from pyramid.interfaces import IExceptionViewClassifier
1019         from pyramid.interfaces import IRequest
ff1213 1020         req_iface = self._registerRouteRequest('foo')
74409d 1021         self._connectRoute('foo', 'archives/:action/:article', None)
ff1213 1022         view = DummyView(DummyResponse(), raise_exception=RuntimeError)
CM 1023         self._registerView(view, '', IViewClassifier, req_iface, None)
1024         response = DummyResponse()
1025         response.app_iter = ["Hello, world"]
1026         exception_view = DummyView(response)
1027         self._registerView(exception_view, '', IExceptionViewClassifier,
1028                            IRequest, RuntimeError)
1029         environ = self._makeEnviron(PATH_INFO='/archives/action1/article1')
1030         start_response = DummyStartResponse()
1031         router = self._makeOne()
1032         result = router(environ, start_response)
1033         self.assertEqual(result, ["Hello, world"])
1034
1035     def test_call_route_raises_super_exception_sub_exception_view(self):
b60bdb 1036         from pyramid.interfaces import IViewClassifier
CM 1037         from pyramid.interfaces import IExceptionViewClassifier
1038         from pyramid.interfaces import IRequest
ff1213 1039         class SuperException(Exception):
CM 1040             pass
1041         class SubException(SuperException):
1042             pass
1043         req_iface = self._registerRouteRequest('foo')
74409d 1044         self._connectRoute('foo', 'archives/:action/:article', None)
ff1213 1045         view = DummyView(DummyResponse(), raise_exception=SuperException)
CM 1046         self._registerView(view, '', IViewClassifier, req_iface, None)
1047         response = DummyResponse()
1048         response.app_iter = ["Hello, world"]
1049         exception_view = DummyView(response)
1050         self._registerView(exception_view, '', IExceptionViewClassifier,
1051                            IRequest, SubException)
1052         environ = self._makeEnviron(PATH_INFO='/archives/action1/article1')
1053         start_response = DummyStartResponse()
1054         router = self._makeOne()
1055         self.assertRaises(SuperException, router, environ, start_response)
1056
1057     def test_call_route_raises_sub_exception_super_exception_view(self):
b60bdb 1058         from pyramid.interfaces import IViewClassifier
CM 1059         from pyramid.interfaces import IExceptionViewClassifier
1060         from pyramid.interfaces import IRequest
ff1213 1061         class SuperException(Exception):
CM 1062             pass
1063         class SubException(SuperException):
1064             pass
1065         req_iface = self._registerRouteRequest('foo')
74409d 1066         self._connectRoute('foo', 'archives/:action/:article', None)
ff1213 1067         view = DummyView(DummyResponse(), raise_exception=SubException)
CM 1068         self._registerView(view, '', IViewClassifier, req_iface, None)
1069         response = DummyResponse()
1070         response.app_iter = ["Hello, world"]
1071         exception_view = DummyView(response)
1072         self._registerView(exception_view, '', IExceptionViewClassifier,
1073                            IRequest, SuperException)
1074         environ = self._makeEnviron(PATH_INFO='/archives/action1/article1')
1075         start_response = DummyStartResponse()
1076         router = self._makeOne()
1077         result = router(environ, start_response)
1078         self.assertEqual(result, ["Hello, world"])
1079
1080     def test_call_route_raises_exception_another_exception_view(self):
b60bdb 1081         from pyramid.interfaces import IViewClassifier
CM 1082         from pyramid.interfaces import IExceptionViewClassifier
1083         from pyramid.interfaces import IRequest
ff1213 1084         class MyException(Exception):
CM 1085             pass
1086         class AnotherException(Exception):
1087             pass
1088         req_iface = self._registerRouteRequest('foo')
74409d 1089         self._connectRoute('foo', 'archives/:action/:article', None)
ff1213 1090         view = DummyView(DummyResponse(), raise_exception=MyException)
CM 1091         self._registerView(view, '', IViewClassifier, req_iface, None)
1092         response = DummyResponse()
1093         response.app_iter = ["Hello, world"]
1094         exception_view = DummyView(response)
1095         self._registerView(exception_view, '', IExceptionViewClassifier,
1096                            IRequest, AnotherException)
1097         environ = self._makeEnviron(PATH_INFO='/archives/action1/article1')
1098         start_response = DummyStartResponse()
1099         router = self._makeOne()
1100         self.assertRaises(MyException, router, environ, start_response)
1101
1102     def test_call_route_raises_exception_view_specializing(self):
b60bdb 1103         from pyramid.interfaces import IViewClassifier
CM 1104         from pyramid.interfaces import IExceptionViewClassifier
1105         from pyramid.interfaces import IRequest
ff1213 1106         req_iface = self._registerRouteRequest('foo')
74409d 1107         self._connectRoute('foo', 'archives/:action/:article', None)
ff1213 1108         view = DummyView(DummyResponse(), raise_exception=RuntimeError)
CM 1109         self._registerView(view, '', IViewClassifier, req_iface, None)
1110         response = DummyResponse()
1111         response.app_iter = ["Hello, world"]
1112         exception_view = DummyView(response)
1113         self._registerView(exception_view, '', IExceptionViewClassifier,
1114                            IRequest, RuntimeError)
1115         response_spec = DummyResponse()
1116         response_spec.app_iter = ["Hello, special world"]
1117         exception_view_spec = DummyView(response_spec)
1118         self._registerView(exception_view_spec, '', IExceptionViewClassifier,
1119                            req_iface, RuntimeError)
1120         environ = self._makeEnviron(PATH_INFO='/archives/action1/article1')
1121         start_response = DummyStartResponse()
1122         router = self._makeOne()
1123         result = router(environ, start_response)
1124         self.assertEqual(result, ["Hello, special world"])
1125
1126     def test_call_route_raises_exception_view_another_route(self):
b60bdb 1127         from pyramid.interfaces import IViewClassifier
CM 1128         from pyramid.interfaces import IExceptionViewClassifier
ff1213 1129         req_iface = self._registerRouteRequest('foo')
CM 1130         another_req_iface = self._registerRouteRequest('bar')
74409d 1131         self._connectRoute('foo', 'archives/:action/:article', None)
ff1213 1132         view = DummyView(DummyResponse(), raise_exception=RuntimeError)
CM 1133         self._registerView(view, '', IViewClassifier, req_iface, None)
1134         response = DummyResponse()
1135         response.app_iter = ["Hello, world"]
1136         exception_view = DummyView(response)
1137         self._registerView(exception_view, '', IExceptionViewClassifier,
1138                            another_req_iface, RuntimeError)
1139         environ = self._makeEnviron(PATH_INFO='/archives/action1/article1')
1140         start_response = DummyStartResponse()
1141         router = self._makeOne()
1142         self.assertRaises(RuntimeError, router, environ, start_response)
1143
1144     def test_call_view_raises_exception_view_route(self):
b60bdb 1145         from pyramid.interfaces import IRequest
CM 1146         from pyramid.interfaces import IViewClassifier
1147         from pyramid.interfaces import IExceptionViewClassifier
ff1213 1148         req_iface = self._registerRouteRequest('foo')
CM 1149         response = DummyResponse()
1150         exception_response = DummyResponse()
1151         exception_response.app_iter = ["Hello, world"]
1152         view = DummyView(response, raise_exception=RuntimeError)
1153         exception_view = DummyView(exception_response)
1154         environ = self._makeEnviron()
1155         self._registerView(view, '', IViewClassifier, IRequest, None)
1156         self._registerView(exception_view, '', IExceptionViewClassifier,
1157                            req_iface, RuntimeError)
1158         router = self._makeOne()
1159         start_response = DummyStartResponse()
1160         self.assertRaises(RuntimeError, router, environ, start_response)
29f5c1 1161
b3643d 1162     def test_call_view_raises_predicate_mismatch(self):
AL 1163         from pyramid.exceptions import PredicateMismatch
1164         from pyramid.interfaces import IViewClassifier
1165         from pyramid.interfaces import IRequest
1166         view = DummyView(DummyResponse(), raise_exception=PredicateMismatch)
1167         self._registerView(view, '', IViewClassifier, IRequest, None)
1168         environ = self._makeEnviron()
1169         router = self._makeOne()
1170         start_response = DummyStartResponse()
1171         self.assertRaises(PredicateMismatch, router, environ, start_response)
1172
1173     def test_call_view_predicate_mismatch_doesnt_hide_views(self):
1174         from pyramid.exceptions import PredicateMismatch
1175         from pyramid.interfaces import IViewClassifier
1176         from pyramid.interfaces import IRequest, IResponse
1177         from pyramid.response import Response
f3bffd 1178         class BaseContext:
b3643d 1179             pass
f3bffd 1180         class DummyContext(BaseContext):
b3643d 1181             pass
AL 1182         context = DummyContext()
1183         self._registerTraverserFactory(context)
1184         view = DummyView(DummyResponse(), raise_exception=PredicateMismatch)
1185         self._registerView(view, '', IViewClassifier, IRequest,
1186                            DummyContext)
1187         good_view = DummyView('abc')
1188         self._registerView(self.config.derive_view(good_view),
f3bffd 1189                             '', IViewClassifier, IRequest, BaseContext)
b3643d 1190         router = self._makeOne()
AL 1191         def make_response(s):
1192             return Response(s)
1193         router.registry.registerAdapter(make_response, (str,), IResponse)
1194         environ = self._makeEnviron()
1195         start_response = DummyStartResponse()
1196         app_iter = router(environ, start_response)
1197         self.assertEqual(app_iter, [b'abc'])
1198
1199     def test_call_view_multiple_predicate_mismatches_dont_hide_views(self):
1200         from pyramid.exceptions import PredicateMismatch
1201         from pyramid.interfaces import IViewClassifier
1202         from pyramid.interfaces import IRequest, IResponse
1203         from pyramid.response import Response
1204         from zope.interface import Interface, implementer
1205         class IBaseContext(Interface):
1206             pass
1207         class IContext(IBaseContext):
1208             pass
1209         @implementer(IContext)
1210         class DummyContext:
1211             pass
1212         context = DummyContext()
1213         self._registerTraverserFactory(context)
1214         view1 = DummyView(DummyResponse(), raise_exception=PredicateMismatch)
1215         self._registerView(view1, '', IViewClassifier, IRequest,
1216                            DummyContext)
1217         view2 = DummyView(DummyResponse(), raise_exception=PredicateMismatch)
1218         self._registerView(view2, '', IViewClassifier, IRequest,
1219                            IContext)
1220         good_view = DummyView('abc')
1221         self._registerView(self.config.derive_view(good_view),
1222                             '', IViewClassifier, IRequest, IBaseContext)
1223         router = self._makeOne()
1224         def make_response(s):
1225             return Response(s)
1226         router.registry.registerAdapter(make_response, (str,), IResponse)
1227         environ = self._makeEnviron()
1228         start_response = DummyStartResponse()
1229         app_iter = router(environ, start_response)
1230         self.assertEqual(app_iter, [b'abc'])
1231
69c3ad 1232     def test_call_view_predicate_mismatch_doesnt_find_unrelated_views(self):
MM 1233         from pyramid.exceptions import PredicateMismatch
1234         from pyramid.interfaces import IViewClassifier
1235         from pyramid.interfaces import IRequest
1236         from zope.interface import Interface, implementer
1237         class IContext(Interface):
1238             pass
1239         class IOtherContext(Interface):
1240             pass
1241         @implementer(IContext)
1242         class DummyContext:
1243             pass
1244         context = DummyContext()
1245         self._registerTraverserFactory(context)
1246         view = DummyView(DummyResponse(), raise_exception=PredicateMismatch)
1247         self._registerView(view, '', IViewClassifier, IRequest,
1248                            DummyContext)
1249         please_dont_call_me_view = DummyView('abc')
1250         self._registerView(self.config.derive_view(please_dont_call_me_view),
1251                             '', IViewClassifier, IRequest, IOtherContext)
1252         router = self._makeOne()
1253         environ = self._makeEnviron()
1254         router = self._makeOne()
1255         start_response = DummyStartResponse()
1256         self.assertRaises(PredicateMismatch, router, environ, start_response)
1257
0bee84 1258     def test_custom_execution_policy(self):
MM 1259         from pyramid.interfaces import IExecutionPolicy
1260         from pyramid.request import Request
1261         from pyramid.response import Response
1262         registry = self.config.registry
1263         def dummy_policy(environ, router):
1264             return Response(status=200, body=b'foo')
1265         registry.registerUtility(dummy_policy, IExecutionPolicy)
1266         router = self._makeOne()
1267         resp = Request.blank('/').get_response(router)
1268         self.assertEqual(resp.status_code, 200)
1269         self.assertEqual(resp.body, b'foo')
1270
07e0e1 1271     def test_execution_policy_handles_exception(self):
MM 1272         from pyramid.interfaces import IViewClassifier
1273         from pyramid.interfaces import IExceptionViewClassifier
1274         from pyramid.interfaces import IRequest
1275         class Exception1(Exception):
1276             pass
1277         class Exception2(Exception):
1278             pass
1279         req_iface = self._registerRouteRequest('foo')
1280         self._connectRoute('foo', 'archives/:action/:article', None)
1281         view = DummyView(DummyResponse(), raise_exception=Exception1)
1282         self._registerView(view, '', IViewClassifier, req_iface, None)
1283         exception_view1 = DummyView(DummyResponse(),
1284                                     raise_exception=Exception2)
1285         self._registerView(exception_view1, '', IExceptionViewClassifier,
1286                            IRequest, Exception1)
1287         response = DummyResponse()
1288         response.app_iter = ["Hello, world"]
1289         exception_view2 = DummyView(response)
1290         self._registerView(exception_view2, '', IExceptionViewClassifier,
1291                            IRequest, Exception2)
1292         environ = self._makeEnviron(PATH_INFO='/archives/action1/article1')
1293         start_response = DummyStartResponse()
1294         router = self._makeOne()
1295         result = router(environ, start_response)
1296         self.assertEqual(result, ["Hello, world"])
1297
822653 1298     def test_request_context_with_statement(self):
MM 1299         from pyramid.threadlocal import get_current_request
1300         from pyramid.interfaces import IExecutionPolicy
1301         from pyramid.request import Request
1302         from pyramid.response import Response
1303         registry = self.config.registry
1304         result = []
1305         def dummy_policy(environ, router):
1306             with router.request_context(environ):
1307                 result.append(get_current_request())
1308             result.append(get_current_request())
1309             return Response(status=200, body=b'foo')
1310         registry.registerUtility(dummy_policy, IExecutionPolicy)
1311         router = self._makeOne()
1312         resp = Request.blank('/test_path').get_response(router)
1313         self.assertEqual(resp.status_code, 200)
1314         self.assertEqual(resp.body, b'foo')
1315         self.assertEqual(result[0].path_info, '/test_path')
1316         self.assertEqual(result[1], None)
1317
1318     def test_request_context_manually(self):
1319         from pyramid.threadlocal import get_current_request
1320         from pyramid.interfaces import IExecutionPolicy
1321         from pyramid.request import Request
1322         from pyramid.response import Response
1323         registry = self.config.registry
1324         result = []
1325         def dummy_policy(environ, router):
1326             ctx = router.request_context(environ)
1327             ctx.begin()
1328             result.append(get_current_request())
1329             ctx.end()
1330             result.append(get_current_request())
1331             return Response(status=200, body=b'foo')
1332         registry.registerUtility(dummy_policy, IExecutionPolicy)
1333         router = self._makeOne()
1334         resp = Request.blank('/test_path').get_response(router)
1335         self.assertEqual(resp.status_code, 200)
1336         self.assertEqual(resp.body, b'foo')
1337         self.assertEqual(result[0].path_info, '/test_path')
1338         self.assertEqual(result[1], None)
1339
0ccdc2 1340 class DummyPredicate(object):
CM 1341     def __call__(self, info, request):
1342         return True
1343     def text(self):
1344         return 'predicate'
1345
5ed24b 1346 class DummyContext:
CM 1347     pass
1348
1eb861 1349 class DummyView:
ff1213 1350     def __init__(self, response, raise_exception=None):
1eb861 1351         self.response = response
ff1213 1352         self.raise_exception = raise_exception
2466f6 1353
1eb861 1354     def __call__(self, context, request):
164677 1355         self.context = context
CM 1356         self.request = request
0f2a11 1357         if self.raise_exception is not None:
ff1213 1358             raise self.raise_exception
1eb861 1359         return self.response
CM 1360
1361 class DummyRootFactory:
1362     def __init__(self, root):
1363         self.root = root
1364
1365     def __call__(self, environ):
1366         return self.root
111593 1367
7de404 1368 class DummyStartResponse:
CM 1369     status = ()
1370     headers = ()
1371     def __call__(self, status, headers):
1372         self.status = status
1373         self.headers = headers
99edc5 1374
d868ff 1375 from pyramid.interfaces import IResponse
3b7334 1376 from zope.interface import implementer
d868ff 1377
3b7334 1378 @implementer(IResponse)
d868ff 1379 class DummyResponse(object):
7de404 1380     headerlist = ()
CM 1381     app_iter = ()
d868ff 1382     environ = None
ef5149 1383     def __init__(self, status='200 OK'):
CM 1384         self.status = status
99edc5 1385
CM 1386     def __call__(self, environ, start_response):
1387         self.environ = environ
1388         start_response(self.status, self.headerlist)
1389         return self.app_iter
a1a9fb 1390     
CM 1391 class DummyAuthenticationPolicy:
1392     pass
c7b7ad 1393
CM 1394 class DummyLogger:
1395     def __init__(self):
1396         self.messages = []
1397     def info(self, msg):
1398         self.messages.append(msg)
1399     warn = info
1400     debug = info
1401
ff1213 1402 def exc_raised(exc, func, *arg, **kw):
CM 1403     try:
1404         func(*arg, **kw)
e91639 1405     except exc as e:
ff1213 1406         return e
CM 1407     else:
1408         raise AssertionError('%s not raised' % exc) # pragma: no cover
1409
1410