Michael Merickel
2018-10-18 66a767f0e1911543b77a4dd768821ee2ed40390a
commit | author | age
7e2c6c 1 import unittest
10ddb6 2 from zope.interface import Interface
MM 3 from zope.interface import implementer
e6fa66 4 import sys
7e2c6c 5
a00621 6 from pyramid import testing
849196 7 from pyramid.interfaces import IRequest
10ddb6 8 from pyramid.interfaces import IResponse
849196 9
0c29cf 10
d20d09 11 class BaseTest(object):
7e2c6c 12     def setUp(self):
a00621 13         self.config = testing.setUp()
7e2c6c 14
CM 15     def tearDown(self):
a00621 16         testing.tearDown()
7e2c6c 17
333bd0 18     def _registerView(self, reg, app, name):
b60bdb 19         from pyramid.interfaces import IViewClassifier
0c29cf 20
ff1213 21         for_ = (IViewClassifier, IRequest, IContext)
b60bdb 22         from pyramid.interfaces import IView
0c29cf 23
1c0210 24         reg.registerAdapter(app, for_, IView, name)
7e2c6c 25
CM 26     def _makeEnviron(self, **extras):
27         environ = {
0c29cf 28             'wsgi.url_scheme': 'http',
MM 29             'wsgi.version': (1, 0),
30             'SERVER_NAME': 'localhost',
31             'SERVER_PORT': '8080',
32             'REQUEST_METHOD': 'GET',
33             'PATH_INFO': '/',
34         }
7e2c6c 35         environ.update(extras)
CM 36         return environ
37
1c0210 38     def _makeRequest(self, **environ):
849196 39         from pyramid.request import Request
b60bdb 40         from pyramid.registry import Registry
0c29cf 41
1c0210 42         environ = self._makeEnviron(**environ)
CM 43         request = Request(environ)
44         request.registry = Registry()
45         return request
46
47     def _makeContext(self):
48         from zope.interface import directlyProvides
0c29cf 49
1c0210 50         context = DummyContext()
CM 51         directlyProvides(context, IContext)
52         return context
0db4a1 53
0c29cf 54
0db4a1 55 class Test_notfound_view_config(BaseTest, unittest.TestCase):
CM 56     def _makeOne(self, **kw):
57         from pyramid.view import notfound_view_config
0c29cf 58
0db4a1 59         return notfound_view_config(**kw)
CM 60
61     def test_ctor(self):
0c29cf 62         inst = self._makeOne(
MM 63             attr='attr', path_info='path_info', append_slash=True
64         )
65         self.assertEqual(
66             inst.__dict__,
67             {'attr': 'attr', 'path_info': 'path_info', 'append_slash': True},
68         )
0db4a1 69
CM 70     def test_it_function(self):
10ddb6 71         def view(request):  # pragma: no cover
0c29cf 72             pass
MM 73
74         decorator = self._makeOne(
75             attr='attr', renderer='renderer', append_slash=True
76         )
0db4a1 77         venusian = DummyVenusian()
CM 78         decorator.venusian = venusian
79         wrapped = decorator(view)
80         self.assertTrue(wrapped is view)
81         config = call_venusian(venusian)
82         settings = config.settings
83         self.assertEqual(
0c29cf 84             settings,
MM 85             [
86                 {
87                     'attr': 'attr',
88                     'venusian': venusian,
89                     'append_slash': True,
90                     'renderer': 'renderer',
91                     '_info': 'codeinfo',
92                     'view': None,
93                 }
94             ],
95         )
0db4a1 96
CM 97     def test_it_class(self):
98         decorator = self._makeOne()
99         venusian = DummyVenusian()
100         decorator.venusian = venusian
101         decorator.venusian.info.scope = 'class'
0c29cf 102
MM 103         class view(object):
104             pass
105
0db4a1 106         wrapped = decorator(view)
CM 107         self.assertTrue(wrapped is view)
108         config = call_venusian(venusian)
109         settings = config.settings
110         self.assertEqual(len(settings), 1)
8ec8e2 111         self.assertEqual(len(settings[0]), 4)
0db4a1 112         self.assertEqual(settings[0]['venusian'], venusian)
0c29cf 113         self.assertEqual(settings[0]['view'], None)  # comes from call_venusian
0db4a1 114         self.assertEqual(settings[0]['attr'], 'view')
CM 115         self.assertEqual(settings[0]['_info'], 'codeinfo')
1c0210 116
498158 117     def test_call_with_venusian_args(self):
MM 118         decorator = self._makeOne(_depth=1, _category='foo')
119         venusian = DummyVenusian()
120         decorator.venusian = venusian
0c29cf 121
10ddb6 122         def foo():  # pragma: no cover
0c29cf 123             pass
MM 124
498158 125         decorator(foo)
MM 126         attachments = venusian.attachments
127         category = attachments[0][2]
128         depth = attachments[0][3]
129         self.assertEqual(depth, 2)
130         self.assertEqual(category, 'foo')
131
0c29cf 132
a7fe30 133 class Test_forbidden_view_config(BaseTest, unittest.TestCase):
CM 134     def _makeOne(self, **kw):
135         from pyramid.view import forbidden_view_config
0c29cf 136
a7fe30 137         return forbidden_view_config(**kw)
CM 138
139     def test_ctor(self):
140         inst = self._makeOne(attr='attr', path_info='path_info')
0c29cf 141         self.assertEqual(
MM 142             inst.__dict__, {'attr': 'attr', 'path_info': 'path_info'}
143         )
a7fe30 144
CM 145     def test_it_function(self):
10ddb6 146         def view(request):  # pragma: no cover
0c29cf 147             pass
MM 148
a7fe30 149         decorator = self._makeOne(attr='attr', renderer='renderer')
CM 150         venusian = DummyVenusian()
151         decorator.venusian = venusian
152         wrapped = decorator(view)
153         self.assertTrue(wrapped is view)
154         config = call_venusian(venusian)
155         settings = config.settings
156         self.assertEqual(
0c29cf 157             settings,
MM 158             [
159                 {
160                     'attr': 'attr',
161                     'venusian': venusian,
162                     'renderer': 'renderer',
163                     '_info': 'codeinfo',
164                     'view': None,
165                 }
166             ],
167         )
a7fe30 168
CM 169     def test_it_class(self):
170         decorator = self._makeOne()
171         venusian = DummyVenusian()
172         decorator.venusian = venusian
173         decorator.venusian.info.scope = 'class'
0c29cf 174
MM 175         class view(object):
176             pass
177
a7fe30 178         wrapped = decorator(view)
CM 179         self.assertTrue(wrapped is view)
180         config = call_venusian(venusian)
181         settings = config.settings
182         self.assertEqual(len(settings), 1)
183         self.assertEqual(len(settings[0]), 4)
184         self.assertEqual(settings[0]['venusian'], venusian)
0c29cf 185         self.assertEqual(settings[0]['view'], None)  # comes from call_venusian
a7fe30 186         self.assertEqual(settings[0]['attr'], 'view')
CM 187         self.assertEqual(settings[0]['_info'], 'codeinfo')
498158 188
MM 189     def test_call_with_venusian_args(self):
190         decorator = self._makeOne(_depth=1, _category='foo')
191         venusian = DummyVenusian()
192         decorator.venusian = venusian
0c29cf 193
10ddb6 194         def foo():  # pragma: no cover
0c29cf 195             pass
MM 196
498158 197         decorator(foo)
MM 198         attachments = venusian.attachments
199         category = attachments[0][2]
200         depth = attachments[0][3]
201         self.assertEqual(depth, 2)
202         self.assertEqual(category, 'foo')
93c94b 203
0c29cf 204
93c94b 205 class Test_exception_view_config(BaseTest, unittest.TestCase):
e8c66a 206     def _makeOne(self, *args, **kw):
93c94b 207         from pyramid.view import exception_view_config
0c29cf 208
e8c66a 209         return exception_view_config(*args, **kw)
93c94b 210
AL 211     def test_ctor(self):
212         inst = self._makeOne(context=Exception, path_info='path_info')
0c29cf 213         self.assertEqual(
MM 214             inst.__dict__, {'context': Exception, 'path_info': 'path_info'}
215         )
93c94b 216
e8c66a 217     def test_ctor_positional_exception(self):
MM 218         inst = self._makeOne(Exception, path_info='path_info')
0c29cf 219         self.assertEqual(
MM 220             inst.__dict__, {'context': Exception, 'path_info': 'path_info'}
221         )
e8c66a 222
MM 223     def test_ctor_positional_extras(self):
224         from pyramid.exceptions import ConfigurationError
0c29cf 225
MM 226         self.assertRaises(
227             ConfigurationError, lambda: self._makeOne(Exception, True)
228         )
e8c66a 229
93c94b 230     def test_it_function(self):
10ddb6 231         def view(request):  # pragma: no cover
0c29cf 232             pass
MM 233
93c94b 234         decorator = self._makeOne(context=Exception, renderer='renderer')
AL 235         venusian = DummyVenusian()
236         decorator.venusian = venusian
237         wrapped = decorator(view)
238         self.assertTrue(wrapped is view)
239         config = call_venusian(venusian)
240         settings = config.settings
241         self.assertEqual(
242             settings,
0c29cf 243             [
MM 244                 {
245                     'venusian': venusian,
246                     'context': Exception,
247                     'renderer': 'renderer',
248                     '_info': 'codeinfo',
249                     'view': None,
250                 }
251             ],
252         )
93c94b 253
AL 254     def test_it_class(self):
255         decorator = self._makeOne()
256         venusian = DummyVenusian()
257         decorator.venusian = venusian
258         decorator.venusian.info.scope = 'class'
0c29cf 259
MM 260         class view(object):
261             pass
262
93c94b 263         wrapped = decorator(view)
AL 264         self.assertTrue(wrapped is view)
265         config = call_venusian(venusian)
266         settings = config.settings
267         self.assertEqual(len(settings), 1)
268         self.assertEqual(len(settings[0]), 4)
269         self.assertEqual(settings[0]['venusian'], venusian)
0c29cf 270         self.assertEqual(settings[0]['view'], None)  # comes from call_venusian
93c94b 271         self.assertEqual(settings[0]['attr'], 'view')
AL 272         self.assertEqual(settings[0]['_info'], 'codeinfo')
498158 273
MM 274     def test_call_with_venusian_args(self):
275         decorator = self._makeOne(_depth=1, _category='foo')
276         venusian = DummyVenusian()
277         decorator.venusian = venusian
0c29cf 278
10ddb6 279         def foo():  # pragma: no cover
0c29cf 280             pass
MM 281
498158 282         decorator(foo)
MM 283         attachments = venusian.attachments
284         category = attachments[0][2]
285         depth = attachments[0][3]
286         self.assertEqual(depth, 2)
287         self.assertEqual(category, 'foo')
93c94b 288
0c29cf 289
d1c4f0 290 class RenderViewToResponseTests(BaseTest, unittest.TestCase):
b3d74b 291     def _callFUT(self, *arg, **kw):
b60bdb 292         from pyramid.view import render_view_to_response
0c29cf 293
b3d74b 294         return render_view_to_response(*arg, **kw)
0c29cf 295
7e2c6c 296     def test_call_no_view_registered(self):
1c0210 297         request = self._makeRequest()
CM 298         context = self._makeContext()
b3d74b 299         result = self._callFUT(context, request, name='notregistered')
7e2c6c 300         self.assertEqual(result, None)
CM 301
45d08c 302     def test_call_no_registry_on_request(self):
CM 303         request = self._makeRequest()
304         del request.registry
305         context = self._makeContext()
306         result = self._callFUT(context, request, name='notregistered')
307         self.assertEqual(result, None)
308
d66bfb 309     def test_call_view_registered_secure(self):
1c0210 310         request = self._makeRequest()
CM 311         context = self._makeContext()
7e2c6c 312         response = DummyResponse()
CM 313         view = make_view(response)
1c0210 314         self._registerView(request.registry, view, 'registered')
0c29cf 315         response = self._callFUT(
MM 316             context, request, name='registered', secure=True
317         )
7e2c6c 318         self.assertEqual(response.status, '200 OK')
CM 319
d66bfb 320     def test_call_view_registered_insecure_no_call_permissive(self):
1c0210 321         context = self._makeContext()
CM 322         request = self._makeRequest()
7e2c6c 323         response = DummyResponse()
CM 324         view = make_view(response)
1c0210 325         self._registerView(request.registry, view, 'registered')
0c29cf 326         response = self._callFUT(
MM 327             context, request, name='registered', secure=False
328         )
7e2c6c 329         self.assertEqual(response.status, '200 OK')
d66bfb 330
CM 331     def test_call_view_registered_insecure_with_call_permissive(self):
1c0210 332         context = self._makeContext()
CM 333         request = self._makeRequest()
d66bfb 334         response = DummyResponse()
CM 335         view = make_view(response)
0c29cf 336
d66bfb 337         def anotherview(context, request):
CM 338             return DummyResponse('anotherview')
0c29cf 339
d66bfb 340         view.__call_permissive__ = anotherview
1c0210 341         self._registerView(request.registry, view, 'registered')
0c29cf 342         response = self._callFUT(
MM 343             context, request, name='registered', secure=False
344         )
d66bfb 345         self.assertEqual(response.status, '200 OK')
CM 346         self.assertEqual(response.app_iter, ['anotherview'])
7e2c6c 347
713bc5 348     def test_call_view_with_request_iface_on_request(self):
CM 349         # See https://github.com/Pylons/pyramid/issues/1643
350         from zope.interface import Interface
0c29cf 351
MM 352         class IWontBeFound(Interface):
353             pass
354
713bc5 355         context = self._makeContext()
CM 356         request = self._makeRequest()
357         request.request_iface = IWontBeFound
358         response = DummyResponse('aview')
359         view = make_view(response)
360         self._registerView(request.registry, view, 'aview')
361         response = self._callFUT(context, request, name='aview')
362         self.assertEqual(response.status, '200 OK')
363         self.assertEqual(response.app_iter, ['aview'])
364
0c29cf 365
d1c4f0 366 class RenderViewToIterableTests(BaseTest, unittest.TestCase):
b3d74b 367     def _callFUT(self, *arg, **kw):
b60bdb 368         from pyramid.view import render_view_to_iterable
0c29cf 369
b3d74b 370         return render_view_to_iterable(*arg, **kw)
0c29cf 371
7e2c6c 372     def test_call_no_view_registered(self):
1c0210 373         request = self._makeRequest()
CM 374         context = self._makeContext()
b3d74b 375         result = self._callFUT(context, request, name='notregistered')
7e2c6c 376         self.assertEqual(result, None)
CM 377
d66bfb 378     def test_call_view_registered_secure(self):
1c0210 379         request = self._makeRequest()
CM 380         context = self._makeContext()
7e2c6c 381         response = DummyResponse()
CM 382         view = make_view(response)
1c0210 383         self._registerView(request.registry, view, 'registered')
0c29cf 384         iterable = self._callFUT(
MM 385             context, request, name='registered', secure=True
386         )
7e2c6c 387         self.assertEqual(iterable, ())
CM 388
d66bfb 389     def test_call_view_registered_insecure_no_call_permissive(self):
1c0210 390         context = self._makeContext()
CM 391         request = self._makeRequest()
7e2c6c 392         response = DummyResponse()
CM 393         view = make_view(response)
1c0210 394         self._registerView(request.registry, view, 'registered')
0c29cf 395         iterable = self._callFUT(
MM 396             context, request, name='registered', secure=False
397         )
7e2c6c 398         self.assertEqual(iterable, ())
d66bfb 399
CM 400     def test_call_view_registered_insecure_with_call_permissive(self):
1c0210 401         context = self._makeContext()
CM 402         request = self._makeRequest()
d66bfb 403         response = DummyResponse()
CM 404         view = make_view(response)
0c29cf 405
d66bfb 406         def anotherview(context, request):
0a8ea9 407             return DummyResponse(b'anotherview')
0c29cf 408
d66bfb 409         view.__call_permissive__ = anotherview
1c0210 410         self._registerView(request.registry, view, 'registered')
0c29cf 411         iterable = self._callFUT(
MM 412             context, request, name='registered', secure=False
413         )
0a8ea9 414         self.assertEqual(iterable, [b'anotherview'])
MM 415
6ec5a6 416     def test_verify_output_bytestring(self):
AV 417         from pyramid.request import Request
418         from pyramid.config import Configurator
419         from pyramid.view import render_view
420         from webob.compat import text_type
0c29cf 421
6ec5a6 422         config = Configurator(settings={})
0c29cf 423
6ec5a6 424         def view(request):
AV 425             request.response.text = text_type('<body></body>')
426             return request.response
427
428         config.add_view(name='test', view=view)
429         config.commit()
430
431         r = Request({})
432         r.registry = config.registry
433         self.assertEqual(render_view(object(), r, 'test'), b'<body></body>')
7e2c6c 434
08ffc9 435     def test_call_request_has_no_registry(self):
CM 436         request = self._makeRequest()
437         del request.registry
438         registry = self.config.registry
439         context = self._makeContext()
440         response = DummyResponse()
441         view = make_view(response)
442         self._registerView(registry, view, 'registered')
0c29cf 443         iterable = self._callFUT(
MM 444             context, request, name='registered', secure=True
445         )
08ffc9 446         self.assertEqual(iterable, ())
0c29cf 447
08ffc9 448
1c0210 449 class RenderViewTests(BaseTest, unittest.TestCase):
b3d74b 450     def _callFUT(self, *arg, **kw):
b60bdb 451         from pyramid.view import render_view
0c29cf 452
b3d74b 453         return render_view(*arg, **kw)
0c29cf 454
885bfb 455     def test_call_no_view_registered(self):
1c0210 456         request = self._makeRequest()
CM 457         context = self._makeContext()
b3d74b 458         result = self._callFUT(context, request, name='notregistered')
885bfb 459         self.assertEqual(result, None)
CM 460
d66bfb 461     def test_call_view_registered_secure(self):
1c0210 462         request = self._makeRequest()
CM 463         context = self._makeContext()
885bfb 464         response = DummyResponse()
CM 465         view = make_view(response)
1c0210 466         self._registerView(request.registry, view, 'registered')
b3d74b 467         s = self._callFUT(context, request, name='registered', secure=True)
6ec5a6 468         self.assertEqual(s, b'')
885bfb 469
d66bfb 470     def test_call_view_registered_insecure_no_call_permissive(self):
1c0210 471         context = self._makeContext()
CM 472         request = self._makeRequest()
885bfb 473         response = DummyResponse()
CM 474         view = make_view(response)
1c0210 475         self._registerView(request.registry, view, 'registered')
b3d74b 476         s = self._callFUT(context, request, name='registered', secure=False)
6ec5a6 477         self.assertEqual(s, b'')
d66bfb 478
CM 479     def test_call_view_registered_insecure_with_call_permissive(self):
1c0210 480         context = self._makeContext()
CM 481         request = self._makeRequest()
d66bfb 482         response = DummyResponse()
CM 483         view = make_view(response)
0c29cf 484
d66bfb 485         def anotherview(context, request):
0a8ea9 486             return DummyResponse(b'anotherview')
0c29cf 487
d66bfb 488         view.__call_permissive__ = anotherview
1c0210 489         self._registerView(request.registry, view, 'registered')
d66bfb 490         s = self._callFUT(context, request, name='registered', secure=False)
6ec5a6 491         self.assertEqual(s, b'anotherview')
0c29cf 492
885bfb 493
197f0c 494 class TestViewConfigDecorator(unittest.TestCase):
5a7f9a 495     def setUp(self):
a00621 496         testing.setUp()
5a7f9a 497
CM 498     def tearDown(self):
a00621 499         testing.tearDown()
5a7f9a 500
CM 501     def _getTargetClass(self):
197f0c 502         from pyramid.view import view_config
0c29cf 503
197f0c 504         return view_config
5a7f9a 505
CM 506     def _makeOne(self, *arg, **kw):
507         return self._getTargetClass()(*arg, **kw)
508
509     def test_create_defaults(self):
510         decorator = self._makeOne()
4c29ef 511         self.assertEqual(decorator.__dict__, {})
b04bd5 512
CM 513     def test_create_context_trumps_for(self):
514         decorator = self._makeOne(context='123', for_='456')
515         self.assertEqual(decorator.context, '123')
516
517     def test_create_for_trumps_context_None(self):
518         decorator = self._makeOne(context=None, for_='456')
519         self.assertEqual(decorator.context, '456')
0c29cf 520
5a7f9a 521     def test_create_nondefaults(self):
4c29ef 522         decorator = self._makeOne(
0c29cf 523             name=None,
MM 524             request_type=None,
525             for_=None,
526             permission='foo',
527             mapper='mapper',
528             decorator='decorator',
529             match_param='match_param',
530         )
5a7f9a 531         self.assertEqual(decorator.name, None)
CM 532         self.assertEqual(decorator.request_type, None)
eecdbc 533         self.assertEqual(decorator.context, None)
5a7f9a 534         self.assertEqual(decorator.permission, 'foo')
5e3d64 535         self.assertEqual(decorator.mapper, 'mapper')
1d9ade 536         self.assertEqual(decorator.decorator, 'decorator')
bf5e0e 537         self.assertEqual(decorator.match_param, 'match_param')
8ec8e2 538
CM 539     def test_create_with_other_predicates(self):
540         decorator = self._makeOne(foo=1)
541         self.assertEqual(decorator.foo, 1)
76c9c2 542
R 543     def test_create_decorator_tuple(self):
544         decorator = self._makeOne(decorator=('decorator1', 'decorator2'))
545         self.assertEqual(decorator.decorator, ('decorator1', 'decorator2'))
0c29cf 546
5a11e2 547     def test_call_function(self):
CM 548         decorator = self._makeOne()
e6fa66 549         venusian = DummyVenusian()
CM 550         decorator.venusian = venusian
0c29cf 551
10ddb6 552         def foo():  # pragma: no cover
0c29cf 553             pass
MM 554
5a11e2 555         wrapped = decorator(foo)
a1d395 556         self.assertTrue(wrapped is foo)
b2c4e0 557         config = call_venusian(venusian)
CM 558         settings = config.settings
e6fa66 559         self.assertEqual(len(settings), 1)
4c29ef 560         self.assertEqual(len(settings), 1)
CM 561         self.assertEqual(len(settings[0]), 3)
562         self.assertEqual(settings[0]['venusian'], venusian)
0c29cf 563         self.assertEqual(settings[0]['view'], None)  # comes from call_venusian
4c29ef 564         self.assertEqual(settings[0]['_info'], 'codeinfo')
5a11e2 565
e6fa66 566     def test_call_class(self):
5a7f9a 567         decorator = self._makeOne()
e6fa66 568         venusian = DummyVenusian()
CM 569         decorator.venusian = venusian
570         decorator.venusian.info.scope = 'class'
0c29cf 571
MM 572         class foo(object):
573             pass
574
5a7f9a 575         wrapped = decorator(foo)
a1d395 576         self.assertTrue(wrapped is foo)
b2c4e0 577         config = call_venusian(venusian)
CM 578         settings = config.settings
e6fa66 579         self.assertEqual(len(settings), 1)
4c29ef 580         self.assertEqual(len(settings[0]), 4)
CM 581         self.assertEqual(settings[0]['venusian'], venusian)
0c29cf 582         self.assertEqual(settings[0]['view'], None)  # comes from call_venusian
b04bd5 583         self.assertEqual(settings[0]['attr'], 'foo')
4c29ef 584         self.assertEqual(settings[0]['_info'], 'codeinfo')
b04bd5 585
CM 586     def test_call_class_attr_already_set(self):
587         decorator = self._makeOne(attr='abc')
588         venusian = DummyVenusian()
589         decorator.venusian = venusian
590         decorator.venusian.info.scope = 'class'
0c29cf 591
MM 592         class foo(object):
593             pass
594
b04bd5 595         wrapped = decorator(foo)
a1d395 596         self.assertTrue(wrapped is foo)
b2c4e0 597         config = call_venusian(venusian)
CM 598         settings = config.settings
b04bd5 599         self.assertEqual(len(settings), 1)
4c29ef 600         self.assertEqual(len(settings[0]), 4)
CM 601         self.assertEqual(settings[0]['venusian'], venusian)
0c29cf 602         self.assertEqual(settings[0]['view'], None)  # comes from call_venusian
b04bd5 603         self.assertEqual(settings[0]['attr'], 'abc')
4c29ef 604         self.assertEqual(settings[0]['_info'], 'codeinfo')
5a7f9a 605
2cce43 606     def test_stacking(self):
CM 607         decorator1 = self._makeOne(name='1')
e6fa66 608         venusian1 = DummyVenusian()
CM 609         decorator1.venusian = venusian1
610         venusian2 = DummyVenusian()
2cce43 611         decorator2 = self._makeOne(name='2')
e6fa66 612         decorator2.venusian = venusian2
0c29cf 613
10ddb6 614         def foo():  # pragma: no cover
0c29cf 615             pass
MM 616
2cce43 617         wrapped1 = decorator1(foo)
CM 618         wrapped2 = decorator2(wrapped1)
a1d395 619         self.assertTrue(wrapped1 is foo)
CM 620         self.assertTrue(wrapped2 is foo)
b2c4e0 621         config1 = call_venusian(venusian1)
CM 622         self.assertEqual(len(config1.settings), 1)
623         self.assertEqual(config1.settings[0]['name'], '1')
624         config2 = call_venusian(venusian2)
625         self.assertEqual(len(config2.settings), 1)
626         self.assertEqual(config2.settings[0]['name'], '2')
2cce43 627
b2f929 628     def test_call_as_method(self):
CM 629         decorator = self._makeOne()
e6fa66 630         venusian = DummyVenusian()
CM 631         decorator.venusian = venusian
632         decorator.venusian.info.scope = 'class'
0c29cf 633
10ddb6 634         def foo(self):  # pragma: no cover
0c29cf 635             pass
MM 636
10ddb6 637         def bar(self):  # pragma: no cover
0c29cf 638             pass
MM 639
b2f929 640         class foo(object):
CM 641             foomethod = decorator(foo)
642             barmethod = decorator(bar)
0c29cf 643
b2c4e0 644         config = call_venusian(venusian)
CM 645         settings = config.settings
b2f929 646         self.assertEqual(len(settings), 2)
CM 647         self.assertEqual(settings[0]['attr'], 'foo')
648         self.assertEqual(settings[1]['attr'], 'bar')
649
6225a2 650     def test_with_custom_predicates(self):
CM 651         decorator = self._makeOne(custom_predicates=(1,))
e6fa66 652         venusian = DummyVenusian()
CM 653         decorator.venusian = venusian
0c29cf 654
10ddb6 655         def foo(context, request):  # pragma: no cover
0c29cf 656             pass
MM 657
6225a2 658         decorated = decorator(foo)
a1d395 659         self.assertTrue(decorated is foo)
b2c4e0 660         config = call_venusian(venusian)
CM 661         settings = config.settings
6225a2 662         self.assertEqual(settings[0]['custom_predicates'], (1,))
CM 663
3d9dd0 664     def test_call_with_renderer_string(self):
dd3cc8 665         import tests
0c29cf 666
89968d 667         decorator = self._makeOne(renderer='fixtures/minimal.pt')
e6fa66 668         venusian = DummyVenusian()
CM 669         decorator.venusian = venusian
0c29cf 670
10ddb6 671         def foo():  # pragma: no cover
0c29cf 672             pass
MM 673
89968d 674         wrapped = decorator(foo)
a1d395 675         self.assertTrue(wrapped is foo)
b2c4e0 676         config = call_venusian(venusian)
CM 677         settings = config.settings
e6fa66 678         self.assertEqual(len(settings), 1)
3d9dd0 679         renderer = settings[0]['renderer']
b2c4e0 680         self.assertEqual(renderer, 'fixtures/minimal.pt')
dd3cc8 681         self.assertEqual(config.pkg, tests)
89968d 682
3d9dd0 683     def test_call_with_renderer_dict(self):
dd3cc8 684         import tests
0c29cf 685
MM 686         decorator = self._makeOne(renderer={'a': 1})
e6fa66 687         venusian = DummyVenusian()
CM 688         decorator.venusian = venusian
0c29cf 689
10ddb6 690         def foo():  # pragma: no cover
0c29cf 691             pass
MM 692
89968d 693         wrapped = decorator(foo)
a1d395 694         self.assertTrue(wrapped is foo)
b2c4e0 695         config = call_venusian(venusian)
CM 696         settings = config.settings
e6fa66 697         self.assertEqual(len(settings), 1)
0c29cf 698         self.assertEqual(settings[0]['renderer'], {'a': 1})
dd3cc8 699         self.assertEqual(config.pkg, tests)
89968d 700
2ad827 701     def test_call_with_renderer_IRendererInfo(self):
dd3cc8 702         import tests
b2c4e0 703         from pyramid.interfaces import IRendererInfo
0c29cf 704
3b7334 705         @implementer(IRendererInfo)
2ad827 706         class DummyRendererHelper(object):
3b7334 707             pass
0c29cf 708
2ad827 709         renderer_helper = DummyRendererHelper()
CM 710         decorator = self._makeOne(renderer=renderer_helper)
711         venusian = DummyVenusian()
712         decorator.venusian = venusian
0c29cf 713
10ddb6 714         def foo():  # pragma: no cover
0c29cf 715             pass
MM 716
2ad827 717         wrapped = decorator(foo)
CM 718         self.assertTrue(wrapped is foo)
719         context = DummyVenusianContext()
b2c4e0 720         config = call_venusian(venusian, context)
CM 721         settings = config.settings
2ad827 722         self.assertEqual(len(settings), 1)
CM 723         renderer = settings[0]['renderer']
73c0ae 724         self.assertTrue(renderer is renderer_helper)
dd3cc8 725         self.assertEqual(config.pkg, tests)
2ad827 726
a8d71c 727     def test_call_withdepth(self):
ed1419 728         decorator = self._makeOne(_depth=1)
a8d71c 729         venusian = DummyVenusian()
CM 730         decorator.venusian = venusian
0c29cf 731
10ddb6 732         def foo():  # pragma: no cover
0c29cf 733             pass
MM 734
a8d71c 735         decorator(foo)
498158 736         attachments = venusian.attachments
MM 737         depth = attachments[0][3]
738         self.assertEqual(depth, 2)
a8d71c 739
4be1e6 740     def test_call_withoutcategory(self):
T 741         decorator = self._makeOne()
742         venusian = DummyVenusian()
743         decorator.venusian = venusian
0c29cf 744
10ddb6 745         def foo():  # pragma: no cover
0c29cf 746             pass
MM 747
4be1e6 748         decorator(foo)
T 749         attachments = venusian.attachments
750         category = attachments[0][2]
751         self.assertEqual(category, 'pyramid')
752
753     def test_call_withcategory(self):
0afdad 754         decorator = self._makeOne(_category='not_pyramid')
4be1e6 755         venusian = DummyVenusian()
T 756         decorator.venusian = venusian
0c29cf 757
10ddb6 758         def foo():  # pragma: no cover
0c29cf 759             pass
MM 760
4be1e6 761         decorator(foo)
T 762         attachments = venusian.attachments
763         category = attachments[0][2]
764         self.assertEqual(category, 'not_pyramid')
765
0c29cf 766
d96ff9 767 class Test_append_slash_notfound_view(BaseTest, unittest.TestCase):
3a61a3 768     def _callFUT(self, context, request):
b60bdb 769         from pyramid.view import append_slash_notfound_view
0c29cf 770
3a61a3 771         return append_slash_notfound_view(context, request)
CM 772
1c0210 773     def _registerMapper(self, reg, match=True):
b60bdb 774         from pyramid.interfaces import IRoutesMapper
0c29cf 775
3a61a3 776         class DummyRoute(object):
CM 777             def __init__(self, val):
778                 self.val = val
0c29cf 779
3a61a3 780             def match(self, path):
CM 781                 return self.val
0c29cf 782
3a61a3 783         class DummyMapper(object):
CM 784             def __init__(self):
0c29cf 785                 self.routelist = [DummyRoute(match)]
MM 786
06dad2 787             def get_routes(self):
CM 788                 return self.routelist
0c29cf 789
3a61a3 790         mapper = DummyMapper()
1c0210 791         reg.registerUtility(mapper, IRoutesMapper)
3a61a3 792         return mapper
CM 793
30e64f 794     def test_context_is_not_exception(self):
CM 795         request = self._makeRequest(PATH_INFO='/abc')
d96ff9 796         request.exception = ExceptionResponse()
30e64f 797         context = DummyContext()
CM 798         response = self._callFUT(context, request)
799         self.assertEqual(response.status, '404 Not Found')
d96ff9 800         self.assertEqual(response.app_iter, ['Not Found'])
30e64f 801
3a61a3 802     def test_no_mapper(self):
1c0210 803         request = self._makeRequest(PATH_INFO='/abc')
d96ff9 804         context = ExceptionResponse()
3a61a3 805         response = self._callFUT(context, request)
CM 806         self.assertEqual(response.status, '404 Not Found')
807
808     def test_no_path(self):
1c0210 809         request = self._makeRequest()
d96ff9 810         context = ExceptionResponse()
1c0210 811         self._registerMapper(request.registry, True)
3a61a3 812         response = self._callFUT(context, request)
CM 813         self.assertEqual(response.status, '404 Not Found')
814
815     def test_mapper_path_already_slash_ending(self):
1c0210 816         request = self._makeRequest(PATH_INFO='/abc/')
d96ff9 817         context = ExceptionResponse()
1c0210 818         self._registerMapper(request.registry, True)
3a61a3 819         response = self._callFUT(context, request)
CM 820         self.assertEqual(response.status, '404 Not Found')
821
d92958 822     def test_no_route_matches(self):
CM 823         request = self._makeRequest(PATH_INFO='/abc')
824         context = ExceptionResponse()
825         mapper = self._registerMapper(request.registry, True)
826         mapper.routelist[0].val = None
827         response = self._callFUT(context, request)
828         self.assertEqual(response.status, '404 Not Found')
829
3a61a3 830     def test_matches(self):
1c0210 831         request = self._makeRequest(PATH_INFO='/abc')
d96ff9 832         context = ExceptionResponse()
1c0210 833         self._registerMapper(request.registry, True)
3a61a3 834         response = self._callFUT(context, request)
b5422e 835         self.assertEqual(response.status, '307 Temporary Redirect')
3a61a3 836         self.assertEqual(response.location, '/abc/')
CM 837
b596e1 838     def test_matches_with_script_name(self):
CM 839         request = self._makeRequest(PATH_INFO='/abc', SCRIPT_NAME='/foo')
840         context = ExceptionResponse()
841         self._registerMapper(request.registry, True)
842         response = self._callFUT(context, request)
b5422e 843         self.assertEqual(response.status, '307 Temporary Redirect')
b596e1 844         self.assertEqual(response.location, '/foo/abc/')
CM 845
6ab71c 846     def test_with_query_string(self):
CM 847         request = self._makeRequest(PATH_INFO='/abc', QUERY_STRING='a=1&b=2')
848         context = ExceptionResponse()
849         self._registerMapper(request.registry, True)
850         response = self._callFUT(context, request)
b5422e 851         self.assertEqual(response.status, '307 Temporary Redirect')
6ab71c 852         self.assertEqual(response.location, '/abc/?a=1&b=2')
CM 853
0c29cf 854
d96ff9 855 class TestAppendSlashNotFoundViewFactory(BaseTest, unittest.TestCase):
CM 856     def _makeOne(self, notfound_view):
b60bdb 857         from pyramid.view import AppendSlashNotFoundViewFactory
0c29cf 858
d96ff9 859         return AppendSlashNotFoundViewFactory(notfound_view)
0c29cf 860
d96ff9 861     def test_custom_notfound_view(self):
CM 862         request = self._makeRequest(PATH_INFO='/abc')
863         context = ExceptionResponse()
0c29cf 864
d96ff9 865         def custom_notfound(context, request):
CM 866             return 'OK'
0c29cf 867
d96ff9 868         view = self._makeOne(custom_notfound)
CM 869         response = view(context, request)
870         self.assertEqual(response, 'OK')
871
0c29cf 872
d96ff9 873 class Test_default_exceptionresponse_view(unittest.TestCase):
CM 874     def _callFUT(self, context, request):
b60bdb 875         from pyramid.view import default_exceptionresponse_view
0c29cf 876
d96ff9 877         return default_exceptionresponse_view(context, request)
CM 878
879     def test_is_exception(self):
880         context = Exception()
881         result = self._callFUT(context, None)
a1d395 882         self.assertTrue(result is context)
d96ff9 883
b04bd5 884     def test_is_not_exception_context_is_false_still_chose(self):
d92958 885         request = DummyRequest()
CM 886         request.exception = 0
887         result = self._callFUT(None, request)
a1d395 888         self.assertTrue(result is None)
d92958 889
d96ff9 890     def test_is_not_exception_no_request_exception(self):
CM 891         context = object()
892         request = DummyRequest()
d92958 893         request.exception = None
d96ff9 894         result = self._callFUT(context, request)
a1d395 895         self.assertTrue(result is context)
d96ff9 896
CM 897     def test_is_not_exception_request_exception(self):
898         context = object()
899         request = DummyRequest()
900         request.exception = 'abc'
901         result = self._callFUT(context, request)
902         self.assertEqual(result, 'abc')
903
0c29cf 904
914abe 905 class Test_view_defaults(unittest.TestCase):
CM 906     def test_it(self):
907         from pyramid.view import view_defaults
0c29cf 908
914abe 909         @view_defaults(route_name='abc', renderer='def')
0c29cf 910         class Foo(object):
MM 911             pass
912
913         self.assertEqual(Foo.__view_defaults__['route_name'], 'abc')
914         self.assertEqual(Foo.__view_defaults__['renderer'], 'def')
914abe 915
4375cf 916     def test_it_inheritance_not_overridden(self):
914abe 917         from pyramid.view import view_defaults
0c29cf 918
914abe 919         @view_defaults(route_name='abc', renderer='def')
0c29cf 920         class Foo(object):
MM 921             pass
922
923         class Bar(Foo):
924             pass
925
926         self.assertEqual(Bar.__view_defaults__['route_name'], 'abc')
927         self.assertEqual(Bar.__view_defaults__['renderer'], 'def')
914abe 928
4375cf 929     def test_it_inheritance_overriden(self):
CM 930         from pyramid.view import view_defaults
0c29cf 931
4375cf 932         @view_defaults(route_name='abc', renderer='def')
0c29cf 933         class Foo(object):
MM 934             pass
935
4375cf 936         @view_defaults(route_name='ghi')
0c29cf 937         class Bar(Foo):
MM 938             pass
939
940         self.assertEqual(Bar.__view_defaults__['route_name'], 'ghi')
4c29ef 941         self.assertFalse('renderer' in Bar.__view_defaults__)
4375cf 942
CM 943     def test_it_inheritance_overriden_empty(self):
944         from pyramid.view import view_defaults
0c29cf 945
4375cf 946         @view_defaults(route_name='abc', renderer='def')
0c29cf 947         class Foo(object):
MM 948             pass
949
4375cf 950         @view_defaults()
0c29cf 951         class Bar(Foo):
MM 952             pass
953
4c29ef 954         self.assertEqual(Bar.__view_defaults__, {})
0c29cf 955
4375cf 956
d52257 957 class TestViewMethodsMixin(unittest.TestCase):
MM 958     def setUp(self):
959         self.config = testing.setUp()
960
961     def tearDown(self):
962         testing.tearDown()
963
964     def _makeOne(self, environ=None):
965         from pyramid.decorator import reify
966         from pyramid.view import ViewMethodsMixin
0c29cf 967
d52257 968         if environ is None:
MM 969             environ = {}
0c29cf 970
d52257 971         class Request(ViewMethodsMixin):
MM 972             def __init__(self, environ):
973                 self.environ = environ
974
975             @reify
976             def response(self):
977                 return DummyResponse()
0c29cf 978
d52257 979         request = Request(environ)
MM 980         request.registry = self.config.registry
981         return request
982
983     def test_it(self):
984         def exc_view(exc, request):
985             self.assertTrue(exc is dummy_exc)
986             self.assertTrue(request.exception is dummy_exc)
987             return DummyResponse(b'foo')
0c29cf 988
d52257 989         self.config.add_view(exc_view, context=RuntimeError)
MM 990         request = self._makeOne()
991         dummy_exc = RuntimeError()
992         try:
993             raise dummy_exc
994         except RuntimeError:
995             response = request.invoke_exception_view()
996             self.assertEqual(response.app_iter, [b'foo'])
0c29cf 997         else:  # pragma: no cover
d52257 998             self.fail()
MM 999
1000     def test_it_hides_attrs(self):
1001         def exc_view(exc, request):
1002             self.assertTrue(exc is not orig_exc)
1003             self.assertTrue(request.exception is not orig_exc)
1004             self.assertTrue(request.exc_info is not orig_exc_info)
1005             self.assertTrue(request.response is not orig_response)
1006             request.response.app_iter = [b'bar']
1007             return request.response
0c29cf 1008
d52257 1009         self.config.add_view(exc_view, context=RuntimeError)
MM 1010         request = self._makeOne()
1011         orig_exc = request.exception = DummyContext()
1012         orig_exc_info = request.exc_info = DummyContext()
1013         orig_response = request.response = DummyResponse(b'foo')
1014         try:
1015             raise RuntimeError
3b886e 1016         except RuntimeError as ex:
d52257 1017             response = request.invoke_exception_view()
MM 1018             self.assertEqual(response.app_iter, [b'bar'])
3b886e 1019             self.assertTrue(request.exception is ex)
MM 1020             self.assertTrue(request.exc_info[1] is ex)
d52257 1021             self.assertTrue(request.response is orig_response)
0c29cf 1022         else:  # pragma: no cover
d52257 1023             self.fail()
MM 1024
1025     def test_it_supports_alternate_requests(self):
1026         def exc_view(exc, request):
1027             self.assertTrue(request is other_req)
dda9fa 1028             from pyramid.threadlocal import get_current_request
0c29cf 1029
dda9fa 1030             self.assertTrue(get_current_request() is other_req)
d52257 1031             return DummyResponse(b'foo')
0c29cf 1032
d52257 1033         self.config.add_view(exc_view, context=RuntimeError)
MM 1034         request = self._makeOne()
1035         other_req = self._makeOne()
1036         try:
1037             raise RuntimeError
1038         except RuntimeError:
1039             response = request.invoke_exception_view(request=other_req)
1040             self.assertEqual(response.app_iter, [b'foo'])
0c29cf 1041         else:  # pragma: no cover
d52257 1042             self.fail()
MM 1043
1044     def test_it_supports_threadlocal_registry(self):
1045         def exc_view(exc, request):
1046             return DummyResponse(b'foo')
0c29cf 1047
d52257 1048         self.config.add_view(exc_view, context=RuntimeError)
MM 1049         request = self._makeOne()
1050         del request.registry
1051         try:
1052             raise RuntimeError
1053         except RuntimeError:
1054             response = request.invoke_exception_view()
1055             self.assertEqual(response.app_iter, [b'foo'])
0c29cf 1056         else:  # pragma: no cover
d52257 1057             self.fail()
MM 1058
dda9fa 1059     def test_it_raises_if_no_registry(self):
BJR 1060         request = self._makeOne()
1061         del request.registry
1062         from pyramid.threadlocal import manager
0c29cf 1063
dda9fa 1064         manager.push({'registry': None, 'request': request})
BJR 1065         try:
1066             raise RuntimeError
1067         except RuntimeError:
1068             try:
1069                 request.invoke_exception_view()
1070             except RuntimeError as e:
1071                 self.assertEqual(e.args[0], "Unable to retrieve registry")
0c29cf 1072         else:  # pragma: no cover
dda9fa 1073             self.fail()
BJR 1074         finally:
1075             manager.pop()
1076
d52257 1077     def test_it_supports_alternate_exc_info(self):
MM 1078         def exc_view(exc, request):
1079             self.assertTrue(request.exc_info is exc_info)
1080             return DummyResponse(b'foo')
0c29cf 1081
d52257 1082         self.config.add_view(exc_view, context=RuntimeError)
MM 1083         request = self._makeOne()
1084         try:
1085             raise RuntimeError
1086         except RuntimeError:
1087             exc_info = sys.exc_info()
1088         response = request.invoke_exception_view(exc_info=exc_info)
1089         self.assertEqual(response.app_iter, [b'foo'])
1090
1091     def test_it_rejects_secured_view(self):
1092         from pyramid.exceptions import Forbidden
0c29cf 1093
10ddb6 1094         def exc_view(exc, request):  # pragma: no cover
0c29cf 1095             pass
MM 1096
d52257 1097         self.config.testing_securitypolicy(permissive=False)
MM 1098         self.config.add_view(exc_view, context=RuntimeError, permission='view')
1099         request = self._makeOne()
1100         try:
1101             raise RuntimeError
1102         except RuntimeError:
1103             self.assertRaises(Forbidden, request.invoke_exception_view)
0c29cf 1104         else:  # pragma: no cover
d52257 1105             self.fail()
MM 1106
1107     def test_it_allows_secured_view(self):
1108         def exc_view(exc, request):
1109             return DummyResponse(b'foo')
0c29cf 1110
d52257 1111         self.config.testing_securitypolicy(permissive=False)
MM 1112         self.config.add_view(exc_view, context=RuntimeError, permission='view')
1113         request = self._makeOne()
1114         try:
1115             raise RuntimeError
1116         except RuntimeError:
1117             response = request.invoke_exception_view(secure=False)
1118             self.assertEqual(response.app_iter, [b'foo'])
0c29cf 1119         else:  # pragma: no cover
d52257 1120             self.fail()
MM 1121
e045cf 1122     def test_it_raises_if_not_found(self):
MM 1123         from pyramid.httpexceptions import HTTPNotFound
0c29cf 1124
e045cf 1125         request = self._makeOne()
MM 1126         dummy_exc = RuntimeError()
1127         try:
1128             raise dummy_exc
1129         except RuntimeError:
1130             self.assertRaises(HTTPNotFound, request.invoke_exception_view)
0c29cf 1131         else:  # pragma: no cover
e045cf 1132             self.fail()
MM 1133
6f2f04 1134     def test_it_reraises_if_not_found(self):
MM 1135         request = self._makeOne()
1136         dummy_exc = RuntimeError()
1137         try:
1138             raise dummy_exc
1139         except RuntimeError:
1140             self.assertRaises(
1141                 RuntimeError,
0c29cf 1142                 lambda: request.invoke_exception_view(reraise=True),
MM 1143             )
1144         else:  # pragma: no cover
6f2f04 1145             self.fail()
MM 1146
e045cf 1147     def test_it_raises_predicate_mismatch(self):
MM 1148         from pyramid.exceptions import PredicateMismatch
0c29cf 1149
10ddb6 1150         def exc_view(exc, request):  # pragma: no cover
0c29cf 1151             pass
MM 1152
1153         self.config.add_view(
1154             exc_view, context=Exception, request_method='POST'
1155         )
e045cf 1156         request = self._makeOne()
MM 1157         request.method = 'GET'
1158         dummy_exc = RuntimeError()
1159         try:
1160             raise dummy_exc
1161         except RuntimeError:
1162             self.assertRaises(PredicateMismatch, request.invoke_exception_view)
0c29cf 1163         else:  # pragma: no cover
e045cf 1164             self.fail()
MM 1165
6f2f04 1166     def test_it_reraises_after_predicate_mismatch(self):
10ddb6 1167         def exc_view(exc, request):  # pragma: no cover
0c29cf 1168             pass
MM 1169
1170         self.config.add_view(
1171             exc_view, context=Exception, request_method='POST'
1172         )
6f2f04 1173         request = self._makeOne()
MM 1174         request.method = 'GET'
1175         dummy_exc = RuntimeError()
1176         try:
1177             raise dummy_exc
1178         except RuntimeError:
1179             self.assertRaises(
1180                 RuntimeError,
0c29cf 1181                 lambda: request.invoke_exception_view(reraise=True),
MM 1182             )
1183         else:  # pragma: no cover
6f2f04 1184             self.fail()
0c29cf 1185
6f2f04 1186
d96ff9 1187 class ExceptionResponse(Exception):
CM 1188     status = '404 Not Found'
1189     app_iter = ['Not Found']
1190     headerlist = []
e06153 1191
0c29cf 1192
7e2c6c 1193 class DummyContext:
CM 1194     pass
0c29cf 1195
17ce57 1196
7e2c6c 1197 def make_view(response):
CM 1198     def view(context, request):
1199         return response
0c29cf 1200
7e2c6c 1201     return view
0c29cf 1202
7e2c6c 1203
d96ff9 1204 class DummyRequest:
d3e48e 1205     exception = None
849196 1206     request_iface = IRequest
d96ff9 1207
56d0fe 1208     def __init__(self, environ=None):
CM 1209         if environ is None:
1210             environ = {}
1211         self.environ = environ
0c29cf 1212
MM 1213
3b7334 1214 @implementer(IResponse)
d868ff 1215 class DummyResponse(object):
7e2c6c 1216     headerlist = ()
d868ff 1217     app_iter = ()
CM 1218     status = '200 OK'
1219     environ = None
0c29cf 1220
d66bfb 1221     def __init__(self, body=None):
CM 1222         if body is None:
1223             self.app_iter = ()
1224         else:
1225             self.app_iter = [body]
0c29cf 1226
MM 1227
1c0210 1228 class IContext(Interface):
CM 1229     pass
0c29cf 1230
e6fa66 1231
CM 1232 class DummyVenusianInfo(object):
1233     scope = 'notaclass'
dd3cc8 1234     module = sys.modules['tests']
14b78b 1235     codeinfo = 'codeinfo'
0c29cf 1236
e6fa66 1237
CM 1238 class DummyVenusian(object):
1239     def __init__(self, info=None):
1240         if info is None:
1241             info = DummyVenusianInfo()
1242         self.info = info
1243         self.attachments = []
1244
a8d71c 1245     def attach(self, wrapped, callback, category=None, depth=1):
498158 1246         self.attachments.append((wrapped, callback, category, depth))
e6fa66 1247         return self.info
CM 1248
0c29cf 1249
95c9f6 1250 class DummyRegistry(object):
CM 1251     pass
0c29cf 1252
95c9f6 1253
e6fa66 1254 class DummyConfig(object):
CM 1255     def __init__(self):
1256         self.settings = []
95c9f6 1257         self.registry = DummyRegistry()
e6fa66 1258
CM 1259     def add_view(self, **kw):
1260         self.settings.append(kw)
1261
93c94b 1262     add_notfound_view = add_forbidden_view = add_exception_view = add_view
0db4a1 1263
b2c4e0 1264     def with_package(self, pkg):
CM 1265         self.pkg = pkg
1266         return self
1267
0c29cf 1268
e6fa66 1269 class DummyVenusianContext(object):
CM 1270     def __init__(self):
1271         self.config = DummyConfig()
0c29cf 1272
MM 1273
2ad827 1274 def call_venusian(venusian, context=None):
CM 1275     if context is None:
1276         context = DummyVenusianContext()
498158 1277     for wrapped, callback, category, depth in venusian.attachments:
e6fa66 1278         callback(context, None, None)
b2c4e0 1279     return context.config