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