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