diff options
Diffstat (limited to 'tests/test_config')
32 files changed, 11483 insertions, 0 deletions
diff --git a/tests/test_config/__init__.py b/tests/test_config/__init__.py new file mode 100644 index 000000000..ac1f19667 --- /dev/null +++ b/tests/test_config/__init__.py @@ -0,0 +1,70 @@ +# package +from functools import partial +from zope.interface import implementer +from zope.interface import Interface + + +class IFactory(Interface): + pass + + +def dummy_tween_factory(handler, registry): # pragma: no cover + pass + + +def dummy_tween_factory2(handler, registry): # pragma: no cover + pass + + +def dummy_include(config): + config.registry.included = True + config.action('discrim', None, config.package) + + +def dummy_include2(config): + config.registry.also_included = True + config.action('discrim', None, config.package) + + +includeme = dummy_include + + +class DummyContext: + pass + + +@implementer(IFactory) +class DummyFactory(object): + def __call__(self): + """ """ + + +def dummyfactory(request): + """ """ + + +class IDummy(Interface): + pass + + +def dummy_view(request): + return 'OK' + + +def dummy_extend(config, discrim): + config.action(discrim, None, config.package) + + +def dummy_extend2(config, discrim): + config.action(discrim, None, config.registry) + + +dummy_partial = partial(dummy_extend, discrim='partial') + + +class DummyCallable(object): + def __call__(self, config, discrim): + config.action(discrim, None, config.package) + + +dummy_callable = DummyCallable() diff --git a/tests/test_config/files/assets/dummy.txt b/tests/test_config/files/assets/dummy.txt new file mode 100644 index 000000000..18832d351 --- /dev/null +++ b/tests/test_config/files/assets/dummy.txt @@ -0,0 +1 @@ +Hello. diff --git a/tests/test_config/files/minimal.txt b/tests/test_config/files/minimal.txt new file mode 100644 index 000000000..19fe66dfa --- /dev/null +++ b/tests/test_config/files/minimal.txt @@ -0,0 +1 @@ +<div clas="header"></div> diff --git a/tests/test_config/path/scanerror/__init__.py b/tests/test_config/path/scanerror/__init__.py new file mode 100644 index 000000000..934d6d3ad --- /dev/null +++ b/tests/test_config/path/scanerror/__init__.py @@ -0,0 +1 @@ +# scan error package diff --git a/tests/test_config/path/scanerror/will_raise_error.py b/tests/test_config/path/scanerror/will_raise_error.py new file mode 100644 index 000000000..9098ff1fe --- /dev/null +++ b/tests/test_config/path/scanerror/will_raise_error.py @@ -0,0 +1 @@ +import wont.exist diff --git a/tests/test_config/pkgs/__init__.py b/tests/test_config/pkgs/__init__.py new file mode 100644 index 000000000..5bb534f79 --- /dev/null +++ b/tests/test_config/pkgs/__init__.py @@ -0,0 +1 @@ +# package diff --git a/tests/test_config/pkgs/asset/__init__.py b/tests/test_config/pkgs/asset/__init__.py new file mode 100644 index 000000000..5bb534f79 --- /dev/null +++ b/tests/test_config/pkgs/asset/__init__.py @@ -0,0 +1 @@ +# package diff --git a/tests/test_config/pkgs/asset/subpackage/__init__.py b/tests/test_config/pkgs/asset/subpackage/__init__.py new file mode 100644 index 000000000..5bb534f79 --- /dev/null +++ b/tests/test_config/pkgs/asset/subpackage/__init__.py @@ -0,0 +1 @@ +# package diff --git a/tests/test_config/pkgs/asset/subpackage/templates/bar.pt b/tests/test_config/pkgs/asset/subpackage/templates/bar.pt new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/tests/test_config/pkgs/asset/subpackage/templates/bar.pt diff --git a/tests/test_config/pkgs/scanextrakw/__init__.py b/tests/test_config/pkgs/scanextrakw/__init__.py new file mode 100644 index 000000000..ddda504e1 --- /dev/null +++ b/tests/test_config/pkgs/scanextrakw/__init__.py @@ -0,0 +1,17 @@ +import venusian + + +def foo(wrapped): + def bar(scanner, name, wrapped): + scanner.config.a = scanner.a + + venusian.attach(wrapped, bar) + return wrapped + + +@foo +def hello(): + pass + + +hello() # appease coverage diff --git a/tests/test_config/pkgs/scannable/__init__.py b/tests/test_config/pkgs/scannable/__init__.py new file mode 100644 index 000000000..585f4357b --- /dev/null +++ b/tests/test_config/pkgs/scannable/__init__.py @@ -0,0 +1,117 @@ +from pyramid.view import view_config +from pyramid.renderers import null_renderer + + +@view_config(renderer=null_renderer) +def grokked(context, request): + return 'grokked' + + +@view_config(request_method='POST', renderer=null_renderer) +def grokked_post(context, request): + return 'grokked_post' + + +@view_config(name='stacked2', renderer=null_renderer) +@view_config(name='stacked1', renderer=null_renderer) +def stacked(context, request): + return 'stacked' + + +class stacked_class(object): + def __init__(self, context, request): + self.context = context + self.request = request + + def __call__(self): + return 'stacked_class' + + +stacked_class = view_config(name='stacked_class1', renderer=null_renderer)( + stacked_class +) +stacked_class = view_config(name='stacked_class2', renderer=null_renderer)( + stacked_class +) + + +class oldstyle_grokked_class: + def __init__(self, context, request): + self.context = context + self.request = request + + def __call__(self): + return 'oldstyle_grokked_class' + + +oldstyle_grokked_class = view_config( + name='oldstyle_grokked_class', renderer=null_renderer +)(oldstyle_grokked_class) + + +class grokked_class(object): + def __init__(self, context, request): + self.context = context + self.request = request + + def __call__(self): + return 'grokked_class' + + +grokked_class = view_config(name='grokked_class', renderer=null_renderer)( + grokked_class +) + + +class Foo(object): + def __call__(self, context, request): + return 'grokked_instance' + + +grokked_instance = Foo() +grokked_instance = view_config( + name='grokked_instance', renderer=null_renderer +)(grokked_instance) + + +class Base(object): + @view_config(name='basemethod', renderer=null_renderer) + def basemethod(self): + """ """ + + +class MethodViews(Base): + def __init__(self, context, request): + self.context = context + self.request = request + + @view_config(name='method1', renderer=null_renderer) + def method1(self): + return 'method1' + + @view_config(name='method2', renderer=null_renderer) + def method2(self): + return 'method2' + + @view_config(name='stacked_method2', renderer=null_renderer) + @view_config(name='stacked_method1', renderer=null_renderer) + def stacked(self): + return 'stacked_method' + + +# ungrokkable + +A = 1 +B = {} + + +def stuff(): + """ """ + + +class Whatever(object): + pass + + +class Whatever2: + pass diff --git a/tests/test_config/pkgs/scannable/another.py b/tests/test_config/pkgs/scannable/another.py new file mode 100644 index 000000000..e8b71e5e3 --- /dev/null +++ b/tests/test_config/pkgs/scannable/another.py @@ -0,0 +1,83 @@ +from pyramid.view import view_config +from pyramid.renderers import null_renderer + + +@view_config(name='another', renderer=null_renderer) +def grokked(context, request): + return 'another_grokked' + + +@view_config(request_method='POST', name='another', renderer=null_renderer) +def grokked_post(context, request): + return 'another_grokked_post' + + +@view_config(name='another_stacked2', renderer=null_renderer) +@view_config(name='another_stacked1', renderer=null_renderer) +def stacked(context, request): + return 'another_stacked' + + +class stacked_class(object): + def __init__(self, context, request): + self.context = context + self.request = request + + def __call__(self): + return 'another_stacked_class' + + +stacked_class = view_config( + name='another_stacked_class1', renderer=null_renderer +)(stacked_class) +stacked_class = view_config( + name='another_stacked_class2', renderer=null_renderer +)(stacked_class) + + +class oldstyle_grokked_class: + def __init__(self, context, request): + self.context = context + self.request = request + + def __call__(self): + return 'another_oldstyle_grokked_class' + + +oldstyle_grokked_class = view_config( + name='another_oldstyle_grokked_class', renderer=null_renderer +)(oldstyle_grokked_class) + + +class grokked_class(object): + def __init__(self, context, request): + self.context = context + self.request = request + + def __call__(self): + return 'another_grokked_class' + + +grokked_class = view_config( + name='another_grokked_class', renderer=null_renderer +)(grokked_class) + + +class Foo(object): + def __call__(self, context, request): + return 'another_grokked_instance' + + +grokked_instance = Foo() +grokked_instance = view_config( + name='another_grokked_instance', renderer=null_renderer +)(grokked_instance) + +# ungrokkable + +A = 1 +B = {} + + +def stuff(): + """ """ diff --git a/tests/test_config/pkgs/scannable/pod/notinit.py b/tests/test_config/pkgs/scannable/pod/notinit.py new file mode 100644 index 000000000..03c93857f --- /dev/null +++ b/tests/test_config/pkgs/scannable/pod/notinit.py @@ -0,0 +1,7 @@ +from pyramid.view import view_config +from pyramid.renderers import null_renderer + + +@view_config(name='pod_notinit', renderer=null_renderer) +def subpackage_notinit(context, request): + return 'pod_notinit' diff --git a/tests/test_config/pkgs/scannable/subpackage/__init__.py b/tests/test_config/pkgs/scannable/subpackage/__init__.py new file mode 100644 index 000000000..f89ca33f7 --- /dev/null +++ b/tests/test_config/pkgs/scannable/subpackage/__init__.py @@ -0,0 +1,7 @@ +from pyramid.view import view_config +from pyramid.renderers import null_renderer + + +@view_config(name='subpackage_init', renderer=null_renderer) +def subpackage_init(context, request): + return 'subpackage_init' diff --git a/tests/test_config/pkgs/scannable/subpackage/notinit.py b/tests/test_config/pkgs/scannable/subpackage/notinit.py new file mode 100644 index 000000000..65c2a4929 --- /dev/null +++ b/tests/test_config/pkgs/scannable/subpackage/notinit.py @@ -0,0 +1,7 @@ +from pyramid.view import view_config +from pyramid.renderers import null_renderer + + +@view_config(name='subpackage_notinit', renderer=null_renderer) +def subpackage_notinit(context, request): + return 'subpackage_notinit' diff --git a/tests/test_config/pkgs/scannable/subpackage/subsubpackage/__init__.py b/tests/test_config/pkgs/scannable/subpackage/subsubpackage/__init__.py new file mode 100644 index 000000000..ec4bab818 --- /dev/null +++ b/tests/test_config/pkgs/scannable/subpackage/subsubpackage/__init__.py @@ -0,0 +1,7 @@ +from pyramid.view import view_config +from pyramid.renderers import null_renderer + + +@view_config(name='subsubpackage_init', renderer=null_renderer) +def subpackage_init(context, request): + return 'subsubpackage_init' diff --git a/tests/test_config/pkgs/selfscan/__init__.py b/tests/test_config/pkgs/selfscan/__init__.py new file mode 100644 index 000000000..8bc8761ca --- /dev/null +++ b/tests/test_config/pkgs/selfscan/__init__.py @@ -0,0 +1,14 @@ +from pyramid.view import view_config + + +@view_config(renderer='string') +def abc(request): + return 'root' + + +def main(): + from pyramid.config import Configurator + + c = Configurator() + c.scan() + return c diff --git a/tests/test_config/pkgs/selfscan/another.py b/tests/test_config/pkgs/selfscan/another.py new file mode 100644 index 000000000..79e0b08de --- /dev/null +++ b/tests/test_config/pkgs/selfscan/another.py @@ -0,0 +1,6 @@ +from pyramid.view import view_config + + +@view_config(name='two', renderer='string') +def two(request): + return 'two' diff --git a/tests/test_config/test_actions.py b/tests/test_config/test_actions.py new file mode 100644 index 000000000..a72d0d7b1 --- /dev/null +++ b/tests/test_config/test_actions.py @@ -0,0 +1,1090 @@ +import unittest + +from pyramid.exceptions import ConfigurationConflictError +from pyramid.exceptions import ConfigurationExecutionError + +from pyramid.interfaces import IRequest + + +class ActionConfiguratorMixinTests(unittest.TestCase): + def _makeOne(self, *arg, **kw): + from pyramid.config import Configurator + + config = Configurator(*arg, **kw) + return config + + def _getViewCallable( + self, + config, + ctx_iface=None, + request_iface=None, + name='', + exception_view=False, + ): + from zope.interface import Interface + from pyramid.interfaces import IView + from pyramid.interfaces import IViewClassifier + from pyramid.interfaces import IExceptionViewClassifier + + if exception_view: # pragma: no cover + classifier = IExceptionViewClassifier + else: + classifier = IViewClassifier + if ctx_iface is None: + ctx_iface = Interface + if request_iface is None: + request_iface = IRequest + return config.registry.adapters.lookup( + (classifier, request_iface, ctx_iface), + IView, + name=name, + default=None, + ) + + def test_action_branching_kw_is_None(self): + config = self._makeOne(autocommit=True) + self.assertEqual(config.action('discrim'), None) + + def test_action_branching_kw_is_not_None(self): + config = self._makeOne(autocommit=True) + self.assertEqual(config.action('discrim', kw={'a': 1}), None) + + def test_action_autocommit_with_introspectables(self): + from pyramid.config.actions import ActionInfo + + config = self._makeOne(autocommit=True) + intr = DummyIntrospectable() + config.action('discrim', introspectables=(intr,)) + self.assertEqual(len(intr.registered), 1) + self.assertEqual(intr.registered[0][0], config.introspector) + self.assertEqual(intr.registered[0][1].__class__, ActionInfo) + + def test_action_autocommit_with_introspectables_introspection_off(self): + config = self._makeOne(autocommit=True) + config.introspection = False + intr = DummyIntrospectable() + config.action('discrim', introspectables=(intr,)) + self.assertEqual(len(intr.registered), 0) + + def test_action_branching_nonautocommit_with_config_info(self): + config = self._makeOne(autocommit=False) + config.info = 'abc' + state = DummyActionState() + state.autocommit = False + config.action_state = state + config.action('discrim', kw={'a': 1}) + self.assertEqual( + state.actions, + [ + ( + (), + { + 'args': (), + 'callable': None, + 'discriminator': 'discrim', + 'includepath': (), + 'info': 'abc', + 'introspectables': (), + 'kw': {'a': 1}, + 'order': 0, + }, + ) + ], + ) + + def test_action_branching_nonautocommit_without_config_info(self): + config = self._makeOne(autocommit=False) + config.info = '' + config._ainfo = ['z'] + state = DummyActionState() + config.action_state = state + state.autocommit = False + config.action('discrim', kw={'a': 1}) + self.assertEqual( + state.actions, + [ + ( + (), + { + 'args': (), + 'callable': None, + 'discriminator': 'discrim', + 'includepath': (), + 'info': 'z', + 'introspectables': (), + 'kw': {'a': 1}, + 'order': 0, + }, + ) + ], + ) + + def test_action_branching_nonautocommit_with_introspectables(self): + config = self._makeOne(autocommit=False) + config.info = '' + config._ainfo = [] + state = DummyActionState() + config.action_state = state + state.autocommit = False + intr = DummyIntrospectable() + config.action('discrim', introspectables=(intr,)) + self.assertEqual(state.actions[0][1]['introspectables'], (intr,)) + + def test_action_nonautocommit_with_introspectables_introspection_off(self): + config = self._makeOne(autocommit=False) + config.info = '' + config._ainfo = [] + config.introspection = False + state = DummyActionState() + config.action_state = state + state.autocommit = False + intr = DummyIntrospectable() + config.action('discrim', introspectables=(intr,)) + self.assertEqual(state.actions[0][1]['introspectables'], ()) + + def test_commit_conflict_simple(self): + config = self._makeOne() + + def view1(request): # pragma: no cover + pass + + def view2(request): # pragma: no cover + pass + + config.add_view(view1) + config.add_view(view2) + self.assertRaises(ConfigurationConflictError, config.commit) + + def test_commit_conflict_resolved_with_include(self): + config = self._makeOne() + + def view1(request): # pragma: no cover + pass + + def view2(request): # pragma: no cover + pass + + def includeme(config): + config.add_view(view2) + + config.add_view(view1) + config.include(includeme) + config.commit() + registeredview = self._getViewCallable(config) + self.assertEqual(registeredview.__name__, 'view1') + + def test_commit_conflict_with_two_includes(self): + config = self._makeOne() + + def view1(request): # pragma: no cover + pass + + def view2(request): # pragma: no cover + pass + + def includeme1(config): + config.add_view(view1) + + def includeme2(config): + config.add_view(view2) + + config.include(includeme1) + config.include(includeme2) + try: + config.commit() + except ConfigurationConflictError as why: + c1, c2 = _conflictFunctions(why) + self.assertEqual(c1, 'includeme1') + self.assertEqual(c2, 'includeme2') + else: # pragma: no cover + raise AssertionError + + def test_commit_conflict_resolved_with_two_includes_and_local(self): + config = self._makeOne() + + def view1(request): # pragma: no cover + pass + + def view2(request): # pragma: no cover + pass + + def view3(request): # pragma: no cover + pass + + def includeme1(config): + config.add_view(view1) + + def includeme2(config): + config.add_view(view2) + + config.include(includeme1) + config.include(includeme2) + config.add_view(view3) + config.commit() + registeredview = self._getViewCallable(config) + self.assertEqual(registeredview.__name__, 'view3') + + def test_autocommit_no_conflicts(self): + from pyramid.renderers import null_renderer + + config = self._makeOne(autocommit=True) + + def view1(request): # pragma: no cover + pass + + def view2(request): # pragma: no cover + pass + + def view3(request): # pragma: no cover + pass + + config.add_view(view1, renderer=null_renderer) + config.add_view(view2, renderer=null_renderer) + config.add_view(view3, renderer=null_renderer) + config.commit() + registeredview = self._getViewCallable(config) + self.assertEqual(registeredview.__name__, 'view3') + + def test_conflict_set_notfound_view(self): + config = self._makeOne() + + def view1(request): # pragma: no cover + pass + + def view2(request): # pragma: no cover + pass + + config.set_notfound_view(view1) + config.set_notfound_view(view2) + try: + config.commit() + except ConfigurationConflictError as why: + c1, c2 = _conflictFunctions(why) + self.assertEqual(c1, 'test_conflict_set_notfound_view') + self.assertEqual(c2, 'test_conflict_set_notfound_view') + else: # pragma: no cover + raise AssertionError + + def test_conflict_set_forbidden_view(self): + config = self._makeOne() + + def view1(request): # pragma: no cover + pass + + def view2(request): # pragma: no cover + pass + + config.set_forbidden_view(view1) + config.set_forbidden_view(view2) + try: + config.commit() + except ConfigurationConflictError as why: + c1, c2 = _conflictFunctions(why) + self.assertEqual(c1, 'test_conflict_set_forbidden_view') + self.assertEqual(c2, 'test_conflict_set_forbidden_view') + else: # pragma: no cover + raise AssertionError + + +class TestActionState(unittest.TestCase): + def _makeOne(self): + from pyramid.config.actions import ActionState + + return ActionState() + + def test_it(self): + c = self._makeOne() + self.assertEqual(c.actions, []) + + def test_action_simple(self): + from . import dummyfactory as f + + c = self._makeOne() + c.actions = [] + c.action(1, f, (1,), {'x': 1}) + self.assertEqual( + c.actions, + [ + { + 'args': (1,), + 'callable': f, + 'discriminator': 1, + 'includepath': (), + 'info': None, + 'introspectables': (), + 'kw': {'x': 1}, + 'order': 0, + } + ], + ) + c.action(None) + self.assertEqual( + c.actions, + [ + { + 'args': (1,), + 'callable': f, + 'discriminator': 1, + 'includepath': (), + 'info': None, + 'introspectables': (), + 'kw': {'x': 1}, + 'order': 0, + }, + { + 'args': (), + 'callable': None, + 'discriminator': None, + 'includepath': (), + 'info': None, + 'introspectables': (), + 'kw': {}, + 'order': 0, + }, + ], + ) + + def test_action_with_includepath(self): + c = self._makeOne() + c.actions = [] + c.action(None, includepath=('abc',)) + self.assertEqual( + c.actions, + [ + { + 'args': (), + 'callable': None, + 'discriminator': None, + 'includepath': ('abc',), + 'info': None, + 'introspectables': (), + 'kw': {}, + 'order': 0, + } + ], + ) + + def test_action_with_info(self): + c = self._makeOne() + c.action(None, info='abc') + self.assertEqual( + c.actions, + [ + { + 'args': (), + 'callable': None, + 'discriminator': None, + 'includepath': (), + 'info': 'abc', + 'introspectables': (), + 'kw': {}, + 'order': 0, + } + ], + ) + + def test_action_with_includepath_and_info(self): + c = self._makeOne() + c.action(None, includepath=('spec',), info='bleh') + self.assertEqual( + c.actions, + [ + { + 'args': (), + 'callable': None, + 'discriminator': None, + 'includepath': ('spec',), + 'info': 'bleh', + 'introspectables': (), + 'kw': {}, + 'order': 0, + } + ], + ) + + def test_action_with_order(self): + c = self._makeOne() + c.actions = [] + c.action(None, order=99999) + self.assertEqual( + c.actions, + [ + { + 'args': (), + 'callable': None, + 'discriminator': None, + 'includepath': (), + 'info': None, + 'introspectables': (), + 'kw': {}, + 'order': 99999, + } + ], + ) + + def test_action_with_introspectables(self): + c = self._makeOne() + c.actions = [] + intr = DummyIntrospectable() + c.action(None, introspectables=(intr,)) + self.assertEqual( + c.actions, + [ + { + 'args': (), + 'callable': None, + 'discriminator': None, + 'includepath': (), + 'info': None, + 'introspectables': (intr,), + 'kw': {}, + 'order': 0, + } + ], + ) + + def test_processSpec(self): + c = self._makeOne() + self.assertTrue(c.processSpec('spec')) + self.assertFalse(c.processSpec('spec')) + + def test_execute_actions_tuples(self): + output = [] + + def f(*a, **k): + output.append((a, k)) + + c = self._makeOne() + c.actions = [ + (1, f, (1,)), + (1, f, (11,), {}, ('x',)), + (2, f, (2,)), + (None, None), + ] + c.execute_actions() + self.assertEqual(output, [((1,), {}), ((2,), {})]) + + def test_execute_actions_dicts(self): + output = [] + + def f(*a, **k): + output.append((a, k)) + + c = self._makeOne() + c.actions = [ + { + 'discriminator': 1, + 'callable': f, + 'args': (1,), + 'kw': {}, + 'order': 0, + 'includepath': (), + 'info': None, + 'introspectables': (), + }, + { + 'discriminator': 1, + 'callable': f, + 'args': (11,), + 'kw': {}, + 'includepath': ('x',), + 'order': 0, + 'info': None, + 'introspectables': (), + }, + { + 'discriminator': 2, + 'callable': f, + 'args': (2,), + 'kw': {}, + 'order': 0, + 'includepath': (), + 'info': None, + 'introspectables': (), + }, + { + 'discriminator': None, + 'callable': None, + 'args': (), + 'kw': {}, + 'order': 0, + 'includepath': (), + 'info': None, + 'introspectables': (), + }, + ] + c.execute_actions() + self.assertEqual(output, [((1,), {}), ((2,), {})]) + + def test_execute_actions_with_introspectables(self): + output = [] + + def f(*a, **k): + output.append((a, k)) + + c = self._makeOne() + intr = DummyIntrospectable() + c.actions = [ + { + 'discriminator': 1, + 'callable': f, + 'args': (1,), + 'kw': {}, + 'order': 0, + 'includepath': (), + 'info': None, + 'introspectables': (intr,), + } + ] + introspector = object() + c.execute_actions(introspector=introspector) + self.assertEqual(output, [((1,), {})]) + self.assertEqual(intr.registered, [(introspector, None)]) + + def test_execute_actions_with_introspectable_no_callable(self): + c = self._makeOne() + intr = DummyIntrospectable() + c.actions = [ + { + 'discriminator': 1, + 'callable': None, + 'args': (1,), + 'kw': {}, + 'order': 0, + 'includepath': (), + 'info': None, + 'introspectables': (intr,), + } + ] + introspector = object() + c.execute_actions(introspector=introspector) + self.assertEqual(intr.registered, [(introspector, None)]) + + def test_execute_actions_error(self): + output = [] + + def f(*a, **k): + output.append(('f', a, k)) + + def bad(): + raise NotImplementedError + + c = self._makeOne() + c.actions = [ + (1, f, (1,)), + (1, f, (11,), {}, ('x',)), + (2, f, (2,)), + (3, bad, (), {}, (), 'oops'), + ] + self.assertRaises(ConfigurationExecutionError, c.execute_actions) + self.assertEqual(output, [('f', (1,), {}), ('f', (2,), {})]) + + def test_reentrant_action(self): + output = [] + c = self._makeOne() + + def f(*a, **k): + output.append(('f', a, k)) + c.actions.append((3, g, (8,), {})) + + def g(*a, **k): + output.append(('g', a, k)) + + c.actions = [(1, f, (1,))] + c.execute_actions() + self.assertEqual(output, [('f', (1,), {}), ('g', (8,), {})]) + + def test_reentrant_action_with_deferred_discriminator(self): + # see https://github.com/Pylons/pyramid/issues/2697 + from pyramid.registry import Deferred + + output = [] + c = self._makeOne() + + def f(*a, **k): + output.append(('f', a, k)) + c.actions.append((4, g, (4,), {}, (), None, 2)) + + def g(*a, **k): + output.append(('g', a, k)) + + def h(*a, **k): + output.append(('h', a, k)) + + def discrim(): + self.assertEqual(output, [('f', (1,), {}), ('g', (2,), {})]) + return 3 + + d = Deferred(discrim) + c.actions = [ + (d, h, (3,), {}, (), None, 1), # order 1 + (1, f, (1,)), # order 0 + (2, g, (2,)), # order 0 + ] + c.execute_actions() + self.assertEqual( + output, + [ + ('f', (1,), {}), + ('g', (2,), {}), + ('h', (3,), {}), + ('g', (4,), {}), + ], + ) + + def test_reentrant_action_error(self): + from pyramid.exceptions import ConfigurationError + + c = self._makeOne() + + def f(*a, **k): + c.actions.append((3, g, (8,), {}, (), None, -1)) + + def g(*a, **k): # pragma: no cover + pass + + c.actions = [(1, f, (1,))] + self.assertRaises(ConfigurationError, c.execute_actions) + + def test_reentrant_action_without_clear(self): + c = self._makeOne() + + def f(*a, **k): + c.actions.append((3, g, (8,))) + + def g(*a, **k): + pass + + c.actions = [(1, f, (1,))] + c.execute_actions(clear=False) + self.assertEqual(c.actions, [(1, f, (1,)), (3, g, (8,))]) + + def test_executing_conflicting_action_across_orders(self): + from pyramid.exceptions import ConfigurationConflictError + + c = self._makeOne() + + def f(*a, **k): + pass + + def g(*a, **k): # pragma: no cover + pass + + c.actions = [(1, f, (1,), {}, (), None, -1), (1, g, (2,))] + self.assertRaises(ConfigurationConflictError, c.execute_actions) + + def test_executing_conflicting_action_across_reentrant_orders(self): + from pyramid.exceptions import ConfigurationConflictError + + c = self._makeOne() + + def f(*a, **k): + c.actions.append((1, g, (8,))) + + def g(*a, **k): # pragma: no cover + pass + + c.actions = [(1, f, (1,), {}, (), None, -1)] + self.assertRaises(ConfigurationConflictError, c.execute_actions) + + +class Test_reentrant_action_functional(unittest.TestCase): + def _makeConfigurator(self, *arg, **kw): + from pyramid.config import Configurator + + config = Configurator(*arg, **kw) + return config + + def test_functional(self): + def add_auto_route(config, name, view): + def register(): + config.add_view(route_name=name, view=view) + config.add_route(name, '/' + name) + + config.action(('auto route', name), register, order=-30) + + config = self._makeConfigurator() + config.add_directive('add_auto_route', add_auto_route) + + def my_view(request): # pragma: no cover + return request.response + + config.add_auto_route('foo', my_view) + config.commit() + from pyramid.interfaces import IRoutesMapper + + mapper = config.registry.getUtility(IRoutesMapper) + routes = mapper.get_routes() + route = routes[0] + self.assertEqual(len(routes), 1) + self.assertEqual(route.name, 'foo') + self.assertEqual(route.path, '/foo') + + def test_deferred_discriminator(self): + # see https://github.com/Pylons/pyramid/issues/2697 + from pyramid.config import PHASE0_CONFIG + + config = self._makeConfigurator() + + def deriver(view, info): + return view + + deriver.options = ('foo',) + config.add_view_deriver(deriver, 'foo_view') + # add_view uses a deferred discriminator and will fail if executed + # prior to add_view_deriver executing its action + config.add_view(lambda r: r.response, name='', foo=1) + + def dummy_action(): + # trigger a re-entrant action + config.action(None, lambda: None) + + config.action(None, dummy_action, order=PHASE0_CONFIG) + config.commit() + + +class Test_resolveConflicts(unittest.TestCase): + def _callFUT(self, actions): + from pyramid.config.actions import resolveConflicts + + return resolveConflicts(actions) + + def test_it_success_tuples(self): + from . import dummyfactory as f + + result = self._callFUT( + [ + (None, f), + (1, f, (1,), {}, (), 'first'), + (1, f, (2,), {}, ('x',), 'second'), + (1, f, (3,), {}, ('y',), 'third'), + (4, f, (4,), {}, ('y',), 'should be last', 99999), + (3, f, (3,), {}, ('y',)), + (None, f, (5,), {}, ('y',)), + ] + ) + result = list(result) + self.assertEqual( + result, + [ + { + 'info': None, + 'args': (), + 'callable': f, + 'introspectables': (), + 'kw': {}, + 'discriminator': None, + 'includepath': (), + 'order': 0, + }, + { + 'info': 'first', + 'args': (1,), + 'callable': f, + 'introspectables': (), + 'kw': {}, + 'discriminator': 1, + 'includepath': (), + 'order': 0, + }, + { + 'info': None, + 'args': (3,), + 'callable': f, + 'introspectables': (), + 'kw': {}, + 'discriminator': 3, + 'includepath': ('y',), + 'order': 0, + }, + { + 'info': None, + 'args': (5,), + 'callable': f, + 'introspectables': (), + 'kw': {}, + 'discriminator': None, + 'includepath': ('y',), + 'order': 0, + }, + { + 'info': 'should be last', + 'args': (4,), + 'callable': f, + 'introspectables': (), + 'kw': {}, + 'discriminator': 4, + 'includepath': ('y',), + 'order': 99999, + }, + ], + ) + + def test_it_success_dicts(self): + from . import dummyfactory as f + + result = self._callFUT( + [ + (None, f), + (1, f, (1,), {}, (), 'first'), + (1, f, (2,), {}, ('x',), 'second'), + (1, f, (3,), {}, ('y',), 'third'), + (4, f, (4,), {}, ('y',), 'should be last', 99999), + (3, f, (3,), {}, ('y',)), + (None, f, (5,), {}, ('y',)), + ] + ) + result = list(result) + self.assertEqual( + result, + [ + { + 'info': None, + 'args': (), + 'callable': f, + 'introspectables': (), + 'kw': {}, + 'discriminator': None, + 'includepath': (), + 'order': 0, + }, + { + 'info': 'first', + 'args': (1,), + 'callable': f, + 'introspectables': (), + 'kw': {}, + 'discriminator': 1, + 'includepath': (), + 'order': 0, + }, + { + 'info': None, + 'args': (3,), + 'callable': f, + 'introspectables': (), + 'kw': {}, + 'discriminator': 3, + 'includepath': ('y',), + 'order': 0, + }, + { + 'info': None, + 'args': (5,), + 'callable': f, + 'introspectables': (), + 'kw': {}, + 'discriminator': None, + 'includepath': ('y',), + 'order': 0, + }, + { + 'info': 'should be last', + 'args': (4,), + 'callable': f, + 'introspectables': (), + 'kw': {}, + 'discriminator': 4, + 'includepath': ('y',), + 'order': 99999, + }, + ], + ) + + def test_it_conflict(self): + from . import dummyfactory as f + + result = self._callFUT( + [ + (None, f), + (1, f, (2,), {}, ('x',), 'eek'), # will conflict + (1, f, (3,), {}, ('y',), 'ack'), # will conflict + (4, f, (4,), {}, ('y',)), + (3, f, (3,), {}, ('y',)), + (None, f, (5,), {}, ('y',)), + ] + ) + self.assertRaises(ConfigurationConflictError, list, result) + + def test_it_with_actions_grouped_by_order(self): + from . import dummyfactory as f + + result = self._callFUT( + [ + (None, f), # X + (1, f, (1,), {}, (), 'third', 10), # X + (1, f, (2,), {}, ('x',), 'fourth', 10), + (1, f, (3,), {}, ('y',), 'fifth', 10), + (2, f, (1,), {}, (), 'sixth', 10), # X + (3, f, (1,), {}, (), 'seventh', 10), # X + (5, f, (4,), {}, ('y',), 'eighth', 99999), # X + (4, f, (3,), {}, (), 'first', 5), # X + (4, f, (5,), {}, ('y',), 'second', 5), + ] + ) + result = list(result) + self.assertEqual(len(result), 6) + # resolved actions should be grouped by (order, i) + self.assertEqual( + result, + [ + { + 'info': None, + 'args': (), + 'callable': f, + 'introspectables': (), + 'kw': {}, + 'discriminator': None, + 'includepath': (), + 'order': 0, + }, + { + 'info': 'first', + 'args': (3,), + 'callable': f, + 'introspectables': (), + 'kw': {}, + 'discriminator': 4, + 'includepath': (), + 'order': 5, + }, + { + 'info': 'third', + 'args': (1,), + 'callable': f, + 'introspectables': (), + 'kw': {}, + 'discriminator': 1, + 'includepath': (), + 'order': 10, + }, + { + 'info': 'sixth', + 'args': (1,), + 'callable': f, + 'introspectables': (), + 'kw': {}, + 'discriminator': 2, + 'includepath': (), + 'order': 10, + }, + { + 'info': 'seventh', + 'args': (1,), + 'callable': f, + 'introspectables': (), + 'kw': {}, + 'discriminator': 3, + 'includepath': (), + 'order': 10, + }, + { + 'info': 'eighth', + 'args': (4,), + 'callable': f, + 'introspectables': (), + 'kw': {}, + 'discriminator': 5, + 'includepath': ('y',), + 'order': 99999, + }, + ], + ) + + def test_override_success_across_orders(self): + from . import dummyfactory as f + + result = self._callFUT( + [ + (1, f, (2,), {}, ('x',), 'eek', 0), + (1, f, (3,), {}, ('x', 'y'), 'ack', 10), + ] + ) + result = list(result) + self.assertEqual( + result, + [ + { + 'info': 'eek', + 'args': (2,), + 'callable': f, + 'introspectables': (), + 'kw': {}, + 'discriminator': 1, + 'includepath': ('x',), + 'order': 0, + } + ], + ) + + def test_conflicts_across_orders(self): + from . import dummyfactory as f + + result = self._callFUT( + [ + (1, f, (2,), {}, ('x', 'y'), 'eek', 0), + (1, f, (3,), {}, ('x'), 'ack', 10), + ] + ) + self.assertRaises(ConfigurationConflictError, list, result) + + +class TestActionInfo(unittest.TestCase): + def _getTargetClass(self): + from pyramid.config.actions import ActionInfo + + return ActionInfo + + def _makeOne(self, filename, lineno, function, linerepr): + return self._getTargetClass()(filename, lineno, function, linerepr) + + def test_class_conforms(self): + from zope.interface.verify import verifyClass + from pyramid.interfaces import IActionInfo + + verifyClass(IActionInfo, self._getTargetClass()) + + def test_instance_conforms(self): + from zope.interface.verify import verifyObject + from pyramid.interfaces import IActionInfo + + verifyObject(IActionInfo, self._makeOne('f', 0, 'f', 'f')) + + def test_ctor(self): + inst = self._makeOne('filename', 10, 'function', 'src') + self.assertEqual(inst.file, 'filename') + self.assertEqual(inst.line, 10) + self.assertEqual(inst.function, 'function') + self.assertEqual(inst.src, 'src') + + def test___str__(self): + inst = self._makeOne('filename', 0, 'function', ' linerepr ') + self.assertEqual( + str(inst), "Line 0 of file filename:\n linerepr " + ) + + +def _conflictFunctions(e): + conflicts = e._conflicts.values() + for conflict in conflicts: + for confinst in conflict: + yield confinst.function + + +class DummyActionState(object): + autocommit = False + info = '' + + def __init__(self): + self.actions = [] + + def action(self, *arg, **kw): + self.actions.append((arg, kw)) + + +class DummyIntrospectable(object): + def __init__(self): + self.registered = [] + + def register(self, introspector, action_info): + self.registered.append((introspector, action_info)) diff --git a/tests/test_config/test_adapters.py b/tests/test_config/test_adapters.py new file mode 100644 index 000000000..d871e8825 --- /dev/null +++ b/tests/test_config/test_adapters.py @@ -0,0 +1,431 @@ +import unittest + +from pyramid.compat import PY2 +from . import IDummy + + +class AdaptersConfiguratorMixinTests(unittest.TestCase): + def _makeOne(self, *arg, **kw): + from pyramid.config import Configurator + + config = Configurator(*arg, **kw) + return config + + def test_add_subscriber_defaults(self): + from zope.interface import implementer + from zope.interface import Interface + + class IEvent(Interface): + pass + + @implementer(IEvent) + class Event: + pass + + L = [] + + def subscriber(event): + L.append(event) + + config = self._makeOne(autocommit=True) + config.add_subscriber(subscriber) + event = Event() + config.registry.notify(event) + self.assertEqual(len(L), 1) + self.assertEqual(L[0], event) + config.registry.notify(object()) + self.assertEqual(len(L), 2) + + def test_add_subscriber_iface_specified(self): + from zope.interface import implementer + from zope.interface import Interface + + class IEvent(Interface): + pass + + @implementer(IEvent) + class Event: + pass + + L = [] + + def subscriber(event): + L.append(event) + + config = self._makeOne(autocommit=True) + config.add_subscriber(subscriber, IEvent) + event = Event() + config.registry.notify(event) + self.assertEqual(len(L), 1) + self.assertEqual(L[0], event) + config.registry.notify(object()) + self.assertEqual(len(L), 1) + + def test_add_subscriber_dottednames(self): + import tests.test_config + from pyramid.interfaces import INewRequest + + config = self._makeOne(autocommit=True) + config.add_subscriber( + 'tests.test_config', 'pyramid.interfaces.INewRequest' + ) + handlers = list(config.registry.registeredHandlers()) + self.assertEqual(len(handlers), 1) + handler = handlers[0] + self.assertEqual(handler.handler, tests.test_config) + self.assertEqual(handler.required, (INewRequest,)) + + def test_add_object_event_subscriber(self): + from zope.interface import implementer + from zope.interface import Interface + + class IEvent(Interface): + pass + + @implementer(IEvent) + class Event: + object = 'foo' + + event = Event() + L = [] + + def subscriber(object, event): + L.append(event) + + config = self._makeOne(autocommit=True) + config.add_subscriber(subscriber, (Interface, IEvent)) + config.registry.subscribers((event.object, event), None) + self.assertEqual(len(L), 1) + self.assertEqual(L[0], event) + config.registry.subscribers((event.object, IDummy), None) + self.assertEqual(len(L), 1) + + def test_add_subscriber_with_specific_type_and_predicates_True(self): + from zope.interface import implementer + from zope.interface import Interface + + class IEvent(Interface): + pass + + @implementer(IEvent) + class Event: + pass + + L = [] + + def subscriber(event): + L.append(event) + + config = self._makeOne(autocommit=True) + predlist = config.get_predlist('subscriber') + jam_predicate = predicate_maker('jam') + jim_predicate = predicate_maker('jim') + predlist.add('jam', jam_predicate) + predlist.add('jim', jim_predicate) + config.add_subscriber(subscriber, IEvent, jam=True, jim=True) + event = Event() + event.jam = True + event.jim = True + config.registry.notify(event) + self.assertEqual(len(L), 1) + self.assertEqual(L[0], event) + config.registry.notify(object()) + self.assertEqual(len(L), 1) + + def test_add_subscriber_with_default_type_predicates_True(self): + from zope.interface import implementer + from zope.interface import Interface + + class IEvent(Interface): + pass + + @implementer(IEvent) + class Event: + pass + + L = [] + + def subscriber(event): + L.append(event) + + config = self._makeOne(autocommit=True) + predlist = config.get_predlist('subscriber') + jam_predicate = predicate_maker('jam') + jim_predicate = predicate_maker('jim') + predlist.add('jam', jam_predicate) + predlist.add('jim', jim_predicate) + config.add_subscriber(subscriber, jam=True, jim=True) + event = Event() + event.jam = True + event.jim = True + config.registry.notify(event) + self.assertEqual(len(L), 1) + self.assertEqual(L[0], event) + config.registry.notify(object()) + self.assertEqual(len(L), 1) + + def test_add_subscriber_with_specific_type_and_predicates_False(self): + from zope.interface import implementer + from zope.interface import Interface + + class IEvent(Interface): + pass + + @implementer(IEvent) + class Event: + pass + + L = [] + + def subscriber(event): # pragma: no cover + L.append(event) + + config = self._makeOne(autocommit=True) + predlist = config.get_predlist('subscriber') + jam_predicate = predicate_maker('jam') + jim_predicate = predicate_maker('jim') + predlist.add('jam', jam_predicate) + predlist.add('jim', jim_predicate) + config.add_subscriber(subscriber, IEvent, jam=True, jim=True) + event = Event() + event.jam = True + event.jim = False + config.registry.notify(event) + self.assertEqual(len(L), 0) + + def test_add_subscriber_with_default_type_predicates_False(self): + from zope.interface import implementer + from zope.interface import Interface + + class IEvent(Interface): + pass + + @implementer(IEvent) + class Event: + pass + + L = [] + + def subscriber(event): # pragma: no cover + L.append(event) + + config = self._makeOne(autocommit=True) + predlist = config.get_predlist('subscriber') + jam_predicate = predicate_maker('jam') + jim_predicate = predicate_maker('jim') + predlist.add('jam', jam_predicate) + predlist.add('jim', jim_predicate) + config.add_subscriber(subscriber, jam=True, jim=True) + event = Event() + event.jam = False + event.jim = True + config.registry.notify(event) + self.assertEqual(len(L), 0) + + def test_add_subscriber_predicate(self): + config = self._makeOne() + L = [] + + def add_predicate( + type, name, factory, weighs_less_than=None, weighs_more_than=None + ): + self.assertEqual(type, 'subscriber') + self.assertEqual(name, 'name') + self.assertEqual(factory, 'factory') + self.assertEqual(weighs_more_than, 1) + self.assertEqual(weighs_less_than, 2) + L.append(1) + + config._add_predicate = add_predicate + config.add_subscriber_predicate('name', 'factory', 1, 2) + self.assertTrue(L) + + def test_add_response_adapter(self): + from pyramid.interfaces import IResponse + + config = self._makeOne(autocommit=True) + + class Adapter(object): + def __init__(self, other): + self.other = other + + config.add_response_adapter(Adapter, str) + result = config.registry.queryAdapter('foo', IResponse) + self.assertTrue(result.other, 'foo') + + def test_add_response_adapter_self(self): + from pyramid.interfaces import IResponse + + config = self._makeOne(autocommit=True) + + class Adapter(object): + pass + + config.add_response_adapter(None, Adapter) + adapter = Adapter() + result = config.registry.queryAdapter(adapter, IResponse) + self.assertTrue(result is adapter) + + def test_add_response_adapter_dottednames(self): + from pyramid.interfaces import IResponse + + config = self._makeOne(autocommit=True) + if PY2: + str_name = '__builtin__.str' + else: + str_name = 'builtins.str' + config.add_response_adapter('pyramid.response.Response', str_name) + result = config.registry.queryAdapter('foo', IResponse) + self.assertTrue(result.body, b'foo') + + def test_add_traverser_dotted_names(self): + from pyramid.interfaces import ITraverser + + config = self._makeOne(autocommit=True) + config.add_traverser( + 'tests.test_config.test_adapters.DummyTraverser', + 'tests.test_config.test_adapters.DummyIface', + ) + iface = DummyIface() + traverser = config.registry.getAdapter(iface, ITraverser) + self.assertEqual(traverser.__class__, DummyTraverser) + self.assertEqual(traverser.root, iface) + + def test_add_traverser_default_iface_means_Interface(self): + from pyramid.interfaces import ITraverser + + config = self._makeOne(autocommit=True) + config.add_traverser(DummyTraverser) + traverser = config.registry.getAdapter(None, ITraverser) + self.assertEqual(traverser.__class__, DummyTraverser) + + def test_add_traverser_nondefault_iface(self): + from pyramid.interfaces import ITraverser + + config = self._makeOne(autocommit=True) + config.add_traverser(DummyTraverser, DummyIface) + iface = DummyIface() + traverser = config.registry.getAdapter(iface, ITraverser) + self.assertEqual(traverser.__class__, DummyTraverser) + self.assertEqual(traverser.root, iface) + + def test_add_traverser_introspectables(self): + config = self._makeOne() + config.add_traverser(DummyTraverser, DummyIface) + actions = config.action_state.actions + self.assertEqual(len(actions), 1) + intrs = actions[0]['introspectables'] + self.assertEqual(len(intrs), 1) + intr = intrs[0] + self.assertEqual(intr.type_name, 'traverser') + self.assertEqual(intr.discriminator, ('traverser', DummyIface)) + self.assertEqual(intr.category_name, 'traversers') + self.assertEqual(intr.title, 'traverser for %r' % DummyIface) + self.assertEqual(intr['adapter'], DummyTraverser) + self.assertEqual(intr['iface'], DummyIface) + + def test_add_resource_url_adapter_dotted_names(self): + from pyramid.interfaces import IResourceURL + + config = self._makeOne(autocommit=True) + config.add_resource_url_adapter( + 'tests.test_config.test_adapters.DummyResourceURL', + 'tests.test_config.test_adapters.DummyIface', + ) + iface = DummyIface() + adapter = config.registry.getMultiAdapter((iface, iface), IResourceURL) + self.assertEqual(adapter.__class__, DummyResourceURL) + self.assertEqual(adapter.resource, iface) + self.assertEqual(adapter.request, iface) + + def test_add_resource_url_default_resource_iface_means_Interface(self): + from pyramid.interfaces import IResourceURL + + config = self._makeOne(autocommit=True) + config.add_resource_url_adapter(DummyResourceURL) + iface = DummyIface() + adapter = config.registry.getMultiAdapter((iface, iface), IResourceURL) + self.assertEqual(adapter.__class__, DummyResourceURL) + self.assertEqual(adapter.resource, iface) + self.assertEqual(adapter.request, iface) + + def test_add_resource_url_nodefault_resource_iface(self): + from zope.interface import Interface + from pyramid.interfaces import IResourceURL + + config = self._makeOne(autocommit=True) + config.add_resource_url_adapter(DummyResourceURL, DummyIface) + iface = DummyIface() + adapter = config.registry.getMultiAdapter((iface, iface), IResourceURL) + self.assertEqual(adapter.__class__, DummyResourceURL) + self.assertEqual(adapter.resource, iface) + self.assertEqual(adapter.request, iface) + bad_result = config.registry.queryMultiAdapter( + (Interface, Interface), IResourceURL + ) + self.assertEqual(bad_result, None) + + def test_add_resource_url_adapter_introspectables(self): + config = self._makeOne() + config.add_resource_url_adapter(DummyResourceURL, DummyIface) + actions = config.action_state.actions + self.assertEqual(len(actions), 1) + intrs = actions[0]['introspectables'] + self.assertEqual(len(intrs), 1) + intr = intrs[0] + self.assertEqual(intr.type_name, 'resource url adapter') + self.assertEqual( + intr.discriminator, ('resource url adapter', DummyIface) + ) + self.assertEqual(intr.category_name, 'resource url adapters') + self.assertEqual( + intr.title, + "resource url adapter for resource iface " + "<class 'tests.test_config.test_adapters.DummyIface'>", + ) + self.assertEqual(intr['adapter'], DummyResourceURL) + self.assertEqual(intr['resource_iface'], DummyIface) + + +class Test_eventonly(unittest.TestCase): + def _callFUT(self, callee): + from pyramid.config.adapters import eventonly + + return eventonly(callee) + + def test_defaults(self): + def acallable(event, a=1, b=2): # pragma: no cover + pass + + self.assertTrue(self._callFUT(acallable)) + + +class DummyTraverser(object): + def __init__(self, root): + self.root = root + + +class DummyIface(object): + pass + + +class DummyResourceURL(object): + def __init__(self, resource, request): + self.resource = resource + self.request = request + + +def predicate_maker(name): + class Predicate(object): + def __init__(self, val, config): + self.val = val + + def phash(self): + return 'phash' + + text = phash + + def __call__(self, event): + return getattr(event, name, None) == self.val + + return Predicate diff --git a/tests/test_config/test_assets.py b/tests/test_config/test_assets.py new file mode 100644 index 000000000..875846dbd --- /dev/null +++ b/tests/test_config/test_assets.py @@ -0,0 +1,1081 @@ +import os.path +import unittest +from pyramid.testing import cleanUp + +# we use this folder +here = os.path.dirname(os.path.abspath(__file__)) + + +class TestAssetsConfiguratorMixin(unittest.TestCase): + def _makeOne(self, *arg, **kw): + from pyramid.config import Configurator + + config = Configurator(*arg, **kw) + return config + + def test_override_asset_samename(self): + from pyramid.exceptions import ConfigurationError + + config = self._makeOne() + self.assertRaises(ConfigurationError, config.override_asset, 'a', 'a') + + def test_override_asset_directory_with_file(self): + from pyramid.exceptions import ConfigurationError + + config = self._makeOne() + self.assertRaises( + ConfigurationError, + config.override_asset, + 'a:foo/', + 'tests.test_config.pkgs.asset:foo.pt', + ) + + def test_override_asset_file_with_directory(self): + from pyramid.exceptions import ConfigurationError + + config = self._makeOne() + self.assertRaises( + ConfigurationError, + config.override_asset, + 'a:foo.pt', + 'tests.test_config.pkgs.asset:templates/', + ) + + def test_override_asset_file_with_package(self): + from pyramid.exceptions import ConfigurationError + + config = self._makeOne() + self.assertRaises( + ConfigurationError, + config.override_asset, + 'a:foo.pt', + 'tests.test_config.pkgs.asset', + ) + + def test_override_asset_file_with_file(self): + from pyramid.config.assets import PackageAssetSource + + config = self._makeOne(autocommit=True) + override = DummyUnderOverride() + config.override_asset( + 'tests.test_config.pkgs.asset:templates/foo.pt', + 'tests.test_config.pkgs.asset.subpackage:templates/bar.pt', + _override=override, + ) + from tests.test_config.pkgs import asset + from tests.test_config.pkgs.asset import subpackage + + self.assertEqual(override.package, asset) + self.assertEqual(override.path, 'templates/foo.pt') + source = override.source + self.assertTrue(isinstance(source, PackageAssetSource)) + self.assertEqual(source.package, subpackage) + self.assertEqual(source.prefix, 'templates/bar.pt') + + resource_name = '' + expected = os.path.join( + here, 'pkgs', 'asset', 'subpackage', 'templates', 'bar.pt' + ) + self.assertEqual(override.source.get_filename(resource_name), expected) + + def test_override_asset_package_with_package(self): + from pyramid.config.assets import PackageAssetSource + + config = self._makeOne(autocommit=True) + override = DummyUnderOverride() + config.override_asset( + 'tests.test_config.pkgs.asset', + 'tests.test_config.pkgs.asset.subpackage', + _override=override, + ) + from tests.test_config.pkgs import asset + from tests.test_config.pkgs.asset import subpackage + + self.assertEqual(override.package, asset) + self.assertEqual(override.path, '') + source = override.source + self.assertTrue(isinstance(source, PackageAssetSource)) + self.assertEqual(source.package, subpackage) + self.assertEqual(source.prefix, '') + + resource_name = 'templates/bar.pt' + expected = os.path.join( + here, 'pkgs', 'asset', 'subpackage', 'templates', 'bar.pt' + ) + self.assertEqual(override.source.get_filename(resource_name), expected) + + def test_override_asset_directory_with_directory(self): + from pyramid.config.assets import PackageAssetSource + + config = self._makeOne(autocommit=True) + override = DummyUnderOverride() + config.override_asset( + 'tests.test_config.pkgs.asset:templates/', + 'tests.test_config.pkgs.asset.subpackage:templates/', + _override=override, + ) + from tests.test_config.pkgs import asset + from tests.test_config.pkgs.asset import subpackage + + self.assertEqual(override.package, asset) + self.assertEqual(override.path, 'templates/') + source = override.source + self.assertTrue(isinstance(source, PackageAssetSource)) + self.assertEqual(source.package, subpackage) + self.assertEqual(source.prefix, 'templates/') + + resource_name = 'bar.pt' + expected = os.path.join( + here, 'pkgs', 'asset', 'subpackage', 'templates', 'bar.pt' + ) + self.assertEqual(override.source.get_filename(resource_name), expected) + + def test_override_asset_directory_with_package(self): + from pyramid.config.assets import PackageAssetSource + + config = self._makeOne(autocommit=True) + override = DummyUnderOverride() + config.override_asset( + 'tests.test_config.pkgs.asset:templates/', + 'tests.test_config.pkgs.asset.subpackage', + _override=override, + ) + from tests.test_config.pkgs import asset + from tests.test_config.pkgs.asset import subpackage + + self.assertEqual(override.package, asset) + self.assertEqual(override.path, 'templates/') + source = override.source + self.assertTrue(isinstance(source, PackageAssetSource)) + self.assertEqual(source.package, subpackage) + self.assertEqual(source.prefix, '') + + resource_name = 'templates/bar.pt' + expected = os.path.join( + here, 'pkgs', 'asset', 'subpackage', 'templates', 'bar.pt' + ) + self.assertEqual(override.source.get_filename(resource_name), expected) + + def test_override_asset_package_with_directory(self): + from pyramid.config.assets import PackageAssetSource + + config = self._makeOne(autocommit=True) + override = DummyUnderOverride() + config.override_asset( + 'tests.test_config.pkgs.asset', + 'tests.test_config.pkgs.asset.subpackage:templates/', + _override=override, + ) + from tests.test_config.pkgs import asset + from tests.test_config.pkgs.asset import subpackage + + self.assertEqual(override.package, asset) + self.assertEqual(override.path, '') + source = override.source + self.assertTrue(isinstance(source, PackageAssetSource)) + self.assertEqual(source.package, subpackage) + self.assertEqual(source.prefix, 'templates/') + + resource_name = 'bar.pt' + expected = os.path.join( + here, 'pkgs', 'asset', 'subpackage', 'templates', 'bar.pt' + ) + self.assertEqual(override.source.get_filename(resource_name), expected) + + def test_override_asset_directory_with_absfile(self): + from pyramid.exceptions import ConfigurationError + + config = self._makeOne() + self.assertRaises( + ConfigurationError, + config.override_asset, + 'a:foo/', + os.path.join(here, 'pkgs', 'asset', 'foo.pt'), + ) + + def test_override_asset_file_with_absdirectory(self): + from pyramid.exceptions import ConfigurationError + + config = self._makeOne() + abspath = os.path.join( + here, 'pkgs', 'asset', 'subpackage', 'templates' + ) + self.assertRaises( + ConfigurationError, config.override_asset, 'a:foo.pt', abspath + ) + + def test_override_asset_file_with_missing_abspath(self): + from pyramid.exceptions import ConfigurationError + + config = self._makeOne() + self.assertRaises( + ConfigurationError, + config.override_asset, + 'a:foo.pt', + os.path.join(here, 'wont_exist'), + ) + + def test_override_asset_file_with_absfile(self): + from pyramid.config.assets import FSAssetSource + + config = self._makeOne(autocommit=True) + override = DummyUnderOverride() + abspath = os.path.join( + here, 'pkgs', 'asset', 'subpackage', 'templates', 'bar.pt' + ) + config.override_asset( + 'tests.test_config.pkgs.asset:templates/foo.pt', + abspath, + _override=override, + ) + from tests.test_config.pkgs import asset + + self.assertEqual(override.package, asset) + self.assertEqual(override.path, 'templates/foo.pt') + source = override.source + self.assertTrue(isinstance(source, FSAssetSource)) + self.assertEqual(source.prefix, abspath) + + resource_name = '' + expected = os.path.join( + here, 'pkgs', 'asset', 'subpackage', 'templates', 'bar.pt' + ) + self.assertEqual(override.source.get_filename(resource_name), expected) + + def test_override_asset_directory_with_absdirectory(self): + from pyramid.config.assets import FSAssetSource + + config = self._makeOne(autocommit=True) + override = DummyUnderOverride() + abspath = os.path.join( + here, 'pkgs', 'asset', 'subpackage', 'templates' + ) + config.override_asset( + 'tests.test_config.pkgs.asset:templates/', + abspath, + _override=override, + ) + from tests.test_config.pkgs import asset + + self.assertEqual(override.package, asset) + self.assertEqual(override.path, 'templates/') + source = override.source + self.assertTrue(isinstance(source, FSAssetSource)) + self.assertEqual(source.prefix, abspath) + + resource_name = 'bar.pt' + expected = os.path.join( + here, 'pkgs', 'asset', 'subpackage', 'templates', 'bar.pt' + ) + self.assertEqual(override.source.get_filename(resource_name), expected) + + def test_override_asset_package_with_absdirectory(self): + from pyramid.config.assets import FSAssetSource + + config = self._makeOne(autocommit=True) + override = DummyUnderOverride() + abspath = os.path.join( + here, 'pkgs', 'asset', 'subpackage', 'templates' + ) + config.override_asset( + 'tests.test_config.pkgs.asset', abspath, _override=override + ) + from tests.test_config.pkgs import asset + + self.assertEqual(override.package, asset) + self.assertEqual(override.path, '') + source = override.source + self.assertTrue(isinstance(source, FSAssetSource)) + self.assertEqual(source.prefix, abspath) + + resource_name = 'bar.pt' + expected = os.path.join( + here, 'pkgs', 'asset', 'subpackage', 'templates', 'bar.pt' + ) + self.assertEqual(override.source.get_filename(resource_name), expected) + + def test__override_not_yet_registered(self): + from pyramid.interfaces import IPackageOverrides + + package = DummyPackage('package') + source = DummyAssetSource() + config = self._makeOne() + config._override( + package, 'path', source, PackageOverrides=DummyPackageOverrides + ) + overrides = config.registry.queryUtility( + IPackageOverrides, name='package' + ) + self.assertEqual(overrides.inserted, [('path', source)]) + self.assertEqual(overrides.package, package) + + def test__override_already_registered(self): + from pyramid.interfaces import IPackageOverrides + + package = DummyPackage('package') + source = DummyAssetSource() + overrides = DummyPackageOverrides(package) + config = self._makeOne() + config.registry.registerUtility( + overrides, IPackageOverrides, name='package' + ) + config._override( + package, 'path', source, PackageOverrides=DummyPackageOverrides + ) + self.assertEqual(overrides.inserted, [('path', source)]) + self.assertEqual(overrides.package, package) + + +class TestOverrideProvider(unittest.TestCase): + def setUp(self): + cleanUp() + + def tearDown(self): + cleanUp() + + def _getTargetClass(self): + from pyramid.config.assets import OverrideProvider + + return OverrideProvider + + def _makeOne(self, module): + klass = self._getTargetClass() + return klass(module) + + def _registerOverrides(self, overrides, name='tests.test_config'): + from pyramid.interfaces import IPackageOverrides + from pyramid.threadlocal import get_current_registry + + reg = get_current_registry() + reg.registerUtility(overrides, IPackageOverrides, name=name) + + def test_get_resource_filename_no_overrides(self): + resource_name = 'test_assets.py' + import tests.test_config + + provider = self._makeOne(tests.test_config) + expected = os.path.join(here, resource_name) + result = provider.get_resource_filename(None, resource_name) + self.assertEqual(result, expected) + + def test_get_resource_stream_no_overrides(self): + resource_name = 'test_assets.py' + import tests.test_config + + provider = self._makeOne(tests.test_config) + with provider.get_resource_stream(None, resource_name) as result: + _assertBody(result.read(), os.path.join(here, resource_name)) + + def test_get_resource_string_no_overrides(self): + resource_name = 'test_assets.py' + import tests.test_config + + provider = self._makeOne(tests.test_config) + result = provider.get_resource_string(None, resource_name) + _assertBody(result, os.path.join(here, resource_name)) + + def test_has_resource_no_overrides(self): + resource_name = 'test_assets.py' + import tests.test_config + + provider = self._makeOne(tests.test_config) + result = provider.has_resource(resource_name) + self.assertEqual(result, True) + + def test_resource_isdir_no_overrides(self): + file_resource_name = 'test_assets.py' + directory_resource_name = 'files' + import tests.test_config + + provider = self._makeOne(tests.test_config) + result = provider.resource_isdir(file_resource_name) + self.assertEqual(result, False) + result = provider.resource_isdir(directory_resource_name) + self.assertEqual(result, True) + + def test_resource_listdir_no_overrides(self): + resource_name = 'files' + import tests.test_config + + provider = self._makeOne(tests.test_config) + result = provider.resource_listdir(resource_name) + self.assertTrue(result) + + def test_get_resource_filename_override_returns_None(self): + overrides = DummyOverrides(None) + self._registerOverrides(overrides) + resource_name = 'test_assets.py' + import tests.test_config + + provider = self._makeOne(tests.test_config) + expected = os.path.join(here, resource_name) + result = provider.get_resource_filename(None, resource_name) + self.assertEqual(result, expected) + + def test_get_resource_stream_override_returns_None(self): + overrides = DummyOverrides(None) + self._registerOverrides(overrides) + resource_name = 'test_assets.py' + import tests.test_config + + provider = self._makeOne(tests.test_config) + with provider.get_resource_stream(None, resource_name) as result: + _assertBody(result.read(), os.path.join(here, resource_name)) + + def test_get_resource_string_override_returns_None(self): + overrides = DummyOverrides(None) + self._registerOverrides(overrides) + resource_name = 'test_assets.py' + import tests.test_config + + provider = self._makeOne(tests.test_config) + result = provider.get_resource_string(None, resource_name) + _assertBody(result, os.path.join(here, resource_name)) + + def test_has_resource_override_returns_None(self): + overrides = DummyOverrides(None) + self._registerOverrides(overrides) + resource_name = 'test_assets.py' + import tests.test_config + + provider = self._makeOne(tests.test_config) + result = provider.has_resource(resource_name) + self.assertEqual(result, True) + + def test_resource_isdir_override_returns_None(self): + overrides = DummyOverrides(None) + self._registerOverrides(overrides) + resource_name = 'files' + import tests.test_config + + provider = self._makeOne(tests.test_config) + result = provider.resource_isdir(resource_name) + self.assertEqual(result, True) + + def test_resource_listdir_override_returns_None(self): + overrides = DummyOverrides(None) + self._registerOverrides(overrides) + resource_name = 'files' + import tests.test_config + + provider = self._makeOne(tests.test_config) + result = provider.resource_listdir(resource_name) + self.assertTrue(result) + + def test_get_resource_filename_override_returns_value(self): + overrides = DummyOverrides('value') + import tests.test_config + + self._registerOverrides(overrides) + provider = self._makeOne(tests.test_config) + result = provider.get_resource_filename(None, 'test_assets.py') + self.assertEqual(result, 'value') + + def test_get_resource_stream_override_returns_value(self): + from io import BytesIO + + overrides = DummyOverrides(BytesIO(b'value')) + import tests.test_config + + self._registerOverrides(overrides) + provider = self._makeOne(tests.test_config) + with provider.get_resource_stream(None, 'test_assets.py') as stream: + self.assertEqual(stream.getvalue(), b'value') + + def test_get_resource_string_override_returns_value(self): + overrides = DummyOverrides('value') + import tests.test_config + + self._registerOverrides(overrides) + provider = self._makeOne(tests.test_config) + result = provider.get_resource_string(None, 'test_assets.py') + self.assertEqual(result, 'value') + + def test_has_resource_override_returns_True(self): + overrides = DummyOverrides(True) + import tests.test_config + + self._registerOverrides(overrides) + provider = self._makeOne(tests.test_config) + result = provider.has_resource('test_assets.py') + self.assertEqual(result, True) + + def test_resource_isdir_override_returns_False(self): + overrides = DummyOverrides(False) + import tests.test_config + + self._registerOverrides(overrides) + provider = self._makeOne(tests.test_config) + result = provider.resource_isdir('files') + self.assertEqual(result, False) + + def test_resource_listdir_override_returns_values(self): + overrides = DummyOverrides(['a']) + import tests.test_config + + self._registerOverrides(overrides) + provider = self._makeOne(tests.test_config) + result = provider.resource_listdir('files') + self.assertEqual(result, ['a']) + + +class TestPackageOverrides(unittest.TestCase): + def _getTargetClass(self): + from pyramid.config.assets import PackageOverrides + + return PackageOverrides + + def _makeOne(self, package=None, pkg_resources=None): + if package is None: + package = DummyPackage('package') + klass = self._getTargetClass() + if pkg_resources is None: + pkg_resources = DummyPkgResources() + return klass(package, pkg_resources=pkg_resources) + + def test_class_conforms_to_IPackageOverrides(self): + from zope.interface.verify import verifyClass + from pyramid.interfaces import IPackageOverrides + + verifyClass(IPackageOverrides, self._getTargetClass()) + + def test_instance_conforms_to_IPackageOverrides(self): + from zope.interface.verify import verifyObject + from pyramid.interfaces import IPackageOverrides + + verifyObject(IPackageOverrides, self._makeOne()) + + def test_class_conforms_to_IPEP302Loader(self): + from zope.interface.verify import verifyClass + from pyramid.interfaces import IPEP302Loader + + verifyClass(IPEP302Loader, self._getTargetClass()) + + def test_instance_conforms_to_IPEP302Loader(self): + from zope.interface.verify import verifyObject + from pyramid.interfaces import IPEP302Loader + + verifyObject(IPEP302Loader, self._makeOne()) + + def test_ctor_package_already_has_loader_of_different_type(self): + package = DummyPackage('package') + loader = package.__loader__ = DummyLoader() + po = self._makeOne(package) + self.assertTrue(package.__loader__ is po) + self.assertTrue(po.real_loader is loader) + + def test_ctor_package_already_has_loader_of_same_type(self): + package = DummyPackage('package') + package.__loader__ = self._makeOne(package) + po = self._makeOne(package) + self.assertEqual(package.__loader__, po) + + def test_ctor_sets_loader(self): + package = DummyPackage('package') + po = self._makeOne(package) + self.assertEqual(package.__loader__, po) + + def test_ctor_registers_loader_type(self): + from pyramid.config.assets import OverrideProvider + + dummy_pkg_resources = DummyPkgResources() + package = DummyPackage('package') + po = self._makeOne(package, dummy_pkg_resources) + self.assertEqual( + dummy_pkg_resources.registered, [(po.__class__, OverrideProvider)] + ) + + def test_ctor_sets_local_state(self): + package = DummyPackage('package') + po = self._makeOne(package) + self.assertEqual(po.overrides, []) + self.assertEqual(po.overridden_package_name, 'package') + + def test_insert_directory(self): + from pyramid.config.assets import DirectoryOverride + + package = DummyPackage('package') + po = self._makeOne(package) + po.overrides = [None] + po.insert('foo/', DummyAssetSource()) + self.assertEqual(len(po.overrides), 2) + override = po.overrides[0] + self.assertEqual(override.__class__, DirectoryOverride) + + def test_insert_file(self): + from pyramid.config.assets import FileOverride + + package = DummyPackage('package') + po = self._makeOne(package) + po.overrides = [None] + po.insert('foo.pt', DummyAssetSource()) + self.assertEqual(len(po.overrides), 2) + override = po.overrides[0] + self.assertEqual(override.__class__, FileOverride) + + def test_insert_emptystring(self): + # XXX is this a valid case for a directory? + from pyramid.config.assets import DirectoryOverride + + package = DummyPackage('package') + po = self._makeOne(package) + po.overrides = [None] + source = DummyAssetSource() + po.insert('', source) + self.assertEqual(len(po.overrides), 2) + override = po.overrides[0] + self.assertEqual(override.__class__, DirectoryOverride) + + def test_filtered_sources(self): + overrides = [DummyOverride(None), DummyOverride('foo')] + package = DummyPackage('package') + po = self._makeOne(package) + po.overrides = overrides + self.assertEqual(list(po.filtered_sources('whatever')), ['foo']) + + def test_get_filename(self): + source = DummyAssetSource(filename='foo.pt') + overrides = [DummyOverride(None), DummyOverride((source, ''))] + package = DummyPackage('package') + po = self._makeOne(package) + po.overrides = overrides + result = po.get_filename('whatever') + self.assertEqual(result, 'foo.pt') + self.assertEqual(source.resource_name, '') + + def test_get_filename_file_doesnt_exist(self): + source = DummyAssetSource(filename=None) + overrides = [ + DummyOverride(None), + DummyOverride((source, 'wont_exist')), + ] + package = DummyPackage('package') + po = self._makeOne(package) + po.overrides = overrides + self.assertEqual(po.get_filename('whatever'), None) + self.assertEqual(source.resource_name, 'wont_exist') + + def test_get_stream(self): + source = DummyAssetSource(stream='a stream?') + overrides = [DummyOverride(None), DummyOverride((source, 'foo.pt'))] + package = DummyPackage('package') + po = self._makeOne(package) + po.overrides = overrides + self.assertEqual(po.get_stream('whatever'), 'a stream?') + self.assertEqual(source.resource_name, 'foo.pt') + + def test_get_stream_file_doesnt_exist(self): + source = DummyAssetSource(stream=None) + overrides = [ + DummyOverride(None), + DummyOverride((source, 'wont_exist')), + ] + package = DummyPackage('package') + po = self._makeOne(package) + po.overrides = overrides + self.assertEqual(po.get_stream('whatever'), None) + self.assertEqual(source.resource_name, 'wont_exist') + + def test_get_string(self): + source = DummyAssetSource(string='a string') + overrides = [DummyOverride(None), DummyOverride((source, 'foo.pt'))] + package = DummyPackage('package') + po = self._makeOne(package) + po.overrides = overrides + self.assertEqual(po.get_string('whatever'), 'a string') + self.assertEqual(source.resource_name, 'foo.pt') + + def test_get_string_file_doesnt_exist(self): + source = DummyAssetSource(string=None) + overrides = [ + DummyOverride(None), + DummyOverride((source, 'wont_exist')), + ] + package = DummyPackage('package') + po = self._makeOne(package) + po.overrides = overrides + self.assertEqual(po.get_string('whatever'), None) + self.assertEqual(source.resource_name, 'wont_exist') + + def test_has_resource(self): + source = DummyAssetSource(exists=True) + overrides = [DummyOverride(None), DummyOverride((source, 'foo.pt'))] + package = DummyPackage('package') + po = self._makeOne(package) + po.overrides = overrides + self.assertEqual(po.has_resource('whatever'), True) + self.assertEqual(source.resource_name, 'foo.pt') + + def test_has_resource_file_doesnt_exist(self): + source = DummyAssetSource(exists=None) + overrides = [ + DummyOverride(None), + DummyOverride((source, 'wont_exist')), + ] + package = DummyPackage('package') + po = self._makeOne(package) + po.overrides = overrides + self.assertEqual(po.has_resource('whatever'), None) + self.assertEqual(source.resource_name, 'wont_exist') + + def test_isdir_false(self): + source = DummyAssetSource(isdir=False) + overrides = [DummyOverride(None), DummyOverride((source, 'foo.pt'))] + package = DummyPackage('package') + po = self._makeOne(package) + po.overrides = overrides + self.assertEqual(po.isdir('whatever'), False) + self.assertEqual(source.resource_name, 'foo.pt') + + def test_isdir_true(self): + source = DummyAssetSource(isdir=True) + overrides = [DummyOverride(None), DummyOverride((source, 'foo.pt'))] + package = DummyPackage('package') + po = self._makeOne(package) + po.overrides = overrides + self.assertEqual(po.isdir('whatever'), True) + self.assertEqual(source.resource_name, 'foo.pt') + + def test_isdir_doesnt_exist(self): + source = DummyAssetSource(isdir=None) + overrides = [ + DummyOverride(None), + DummyOverride((source, 'wont_exist')), + ] + package = DummyPackage('package') + po = self._makeOne(package) + po.overrides = overrides + self.assertEqual(po.isdir('whatever'), None) + self.assertEqual(source.resource_name, 'wont_exist') + + def test_listdir(self): + source = DummyAssetSource(listdir=True) + overrides = [DummyOverride(None), DummyOverride((source, 'foo.pt'))] + package = DummyPackage('package') + po = self._makeOne(package) + po.overrides = overrides + self.assertEqual(po.listdir('whatever'), True) + self.assertEqual(source.resource_name, 'foo.pt') + + def test_listdir_doesnt_exist(self): + source = DummyAssetSource(listdir=None) + overrides = [ + DummyOverride(None), + DummyOverride((source, 'wont_exist')), + ] + package = DummyPackage('package') + po = self._makeOne(package) + po.overrides = overrides + self.assertEqual(po.listdir('whatever'), None) + self.assertEqual(source.resource_name, 'wont_exist') + + # PEP 302 __loader__ extensions: use the "real" __loader__, if present. + def test_get_data_pkg_has_no___loader__(self): + package = DummyPackage('package') + po = self._makeOne(package) + self.assertRaises(NotImplementedError, po.get_data, 'whatever') + + def test_get_data_pkg_has___loader__(self): + package = DummyPackage('package') + loader = package.__loader__ = DummyLoader() + po = self._makeOne(package) + self.assertEqual(po.get_data('whatever'), b'DEADBEEF') + self.assertEqual(loader._got_data, 'whatever') + + def test_is_package_pkg_has_no___loader__(self): + package = DummyPackage('package') + po = self._makeOne(package) + self.assertRaises(NotImplementedError, po.is_package, 'whatever') + + def test_is_package_pkg_has___loader__(self): + package = DummyPackage('package') + loader = package.__loader__ = DummyLoader() + po = self._makeOne(package) + self.assertTrue(po.is_package('whatever')) + self.assertEqual(loader._is_package, 'whatever') + + def test_get_code_pkg_has_no___loader__(self): + package = DummyPackage('package') + po = self._makeOne(package) + self.assertRaises(NotImplementedError, po.get_code, 'whatever') + + def test_get_code_pkg_has___loader__(self): + package = DummyPackage('package') + loader = package.__loader__ = DummyLoader() + po = self._makeOne(package) + self.assertEqual(po.get_code('whatever'), b'DEADBEEF') + self.assertEqual(loader._got_code, 'whatever') + + def test_get_source_pkg_has_no___loader__(self): + package = DummyPackage('package') + po = self._makeOne(package) + self.assertRaises(NotImplementedError, po.get_source, 'whatever') + + def test_get_source_pkg_has___loader__(self): + package = DummyPackage('package') + loader = package.__loader__ = DummyLoader() + po = self._makeOne(package) + self.assertEqual(po.get_source('whatever'), 'def foo():\n pass') + self.assertEqual(loader._got_source, 'whatever') + + +class AssetSourceIntegrationTests(object): + def test_get_filename(self): + source = self._makeOne('') + self.assertEqual( + source.get_filename('test_assets.py'), + os.path.join(here, 'test_assets.py'), + ) + + def test_get_filename_with_prefix(self): + source = self._makeOne('test_assets.py') + self.assertEqual( + source.get_filename(''), os.path.join(here, 'test_assets.py') + ) + + def test_get_filename_file_doesnt_exist(self): + source = self._makeOne('') + self.assertEqual(source.get_filename('wont_exist'), None) + + def test_get_stream(self): + source = self._makeOne('') + with source.get_stream('test_assets.py') as stream: + _assertBody(stream.read(), os.path.join(here, 'test_assets.py')) + + def test_get_stream_with_prefix(self): + source = self._makeOne('test_assets.py') + with source.get_stream('') as stream: + _assertBody(stream.read(), os.path.join(here, 'test_assets.py')) + + def test_get_stream_file_doesnt_exist(self): + source = self._makeOne('') + self.assertEqual(source.get_stream('wont_exist'), None) + + def test_get_string(self): + source = self._makeOne('') + _assertBody( + source.get_string('test_assets.py'), + os.path.join(here, 'test_assets.py'), + ) + + def test_get_string_with_prefix(self): + source = self._makeOne('test_assets.py') + _assertBody( + source.get_string(''), os.path.join(here, 'test_assets.py') + ) + + def test_get_string_file_doesnt_exist(self): + source = self._makeOne('') + self.assertEqual(source.get_string('wont_exist'), None) + + def test_exists(self): + source = self._makeOne('') + self.assertEqual(source.exists('test_assets.py'), True) + + def test_exists_with_prefix(self): + source = self._makeOne('test_assets.py') + self.assertEqual(source.exists(''), True) + + def test_exists_file_doesnt_exist(self): + source = self._makeOne('') + self.assertEqual(source.exists('wont_exist'), None) + + def test_isdir_false(self): + source = self._makeOne('') + self.assertEqual(source.isdir('test_assets.py'), False) + + def test_isdir_true(self): + source = self._makeOne('') + self.assertEqual(source.isdir('files'), True) + + def test_isdir_doesnt_exist(self): + source = self._makeOne('') + self.assertEqual(source.isdir('wont_exist'), None) + + def test_listdir(self): + source = self._makeOne('') + self.assertTrue(source.listdir('files')) + + def test_listdir_doesnt_exist(self): + source = self._makeOne('') + self.assertEqual(source.listdir('wont_exist'), None) + + +class TestPackageAssetSource(AssetSourceIntegrationTests, unittest.TestCase): + def _getTargetClass(self): + from pyramid.config.assets import PackageAssetSource + + return PackageAssetSource + + def _makeOne(self, prefix, package='tests.test_config'): + klass = self._getTargetClass() + return klass(package, prefix) + + +class TestFSAssetSource(AssetSourceIntegrationTests, unittest.TestCase): + def _getTargetClass(self): + from pyramid.config.assets import FSAssetSource + + return FSAssetSource + + def _makeOne(self, prefix, base_prefix=here): + klass = self._getTargetClass() + return klass(os.path.join(base_prefix, prefix)) + + +class TestDirectoryOverride(unittest.TestCase): + def _getTargetClass(self): + from pyramid.config.assets import DirectoryOverride + + return DirectoryOverride + + def _makeOne(self, path, source): + klass = self._getTargetClass() + return klass(path, source) + + def test_it_match(self): + source = DummyAssetSource() + o = self._makeOne('foo/', source) + result = o('foo/something.pt') + self.assertEqual(result, (source, 'something.pt')) + + def test_it_no_match(self): + source = DummyAssetSource() + o = self._makeOne('foo/', source) + result = o('baz/notfound.pt') + self.assertEqual(result, None) + + +class TestFileOverride(unittest.TestCase): + def _getTargetClass(self): + from pyramid.config.assets import FileOverride + + return FileOverride + + def _makeOne(self, path, source): + klass = self._getTargetClass() + return klass(path, source) + + def test_it_match(self): + source = DummyAssetSource() + o = self._makeOne('foo.pt', source) + result = o('foo.pt') + self.assertEqual(result, (source, '')) + + def test_it_no_match(self): + source = DummyAssetSource() + o = self._makeOne('foo.pt', source) + result = o('notfound.pt') + self.assertEqual(result, None) + + +class DummyOverride: + def __init__(self, result): + self.result = result + + def __call__(self, resource_name): + return self.result + + +class DummyOverrides: + def __init__(self, result): + self.result = result + + def get_filename(self, resource_name): + return self.result + + listdir = isdir = has_resource = get_stream = get_string = get_filename + + +class DummyPackageOverrides: + def __init__(self, package): + self.package = package + self.inserted = [] + + def insert(self, path, source): + self.inserted.append((path, source)) + + +class DummyPkgResources: + def __init__(self): + self.registered = [] + + def register_loader_type(self, typ, inst): + self.registered.append((typ, inst)) + + +class DummyPackage: + def __init__(self, name): + self.__name__ = name + + +class DummyAssetSource: + def __init__(self, **kw): + self.kw = kw + + def get_filename(self, resource_name): + self.resource_name = resource_name + return self.kw['filename'] + + def get_stream(self, resource_name): + self.resource_name = resource_name + return self.kw['stream'] + + def get_string(self, resource_name): + self.resource_name = resource_name + return self.kw['string'] + + def exists(self, resource_name): + self.resource_name = resource_name + return self.kw['exists'] + + def isdir(self, resource_name): + self.resource_name = resource_name + return self.kw['isdir'] + + def listdir(self, resource_name): + self.resource_name = resource_name + return self.kw['listdir'] + + +class DummyLoader: + _got_data = _is_package = None + + def get_data(self, path): + self._got_data = path + return b'DEADBEEF' + + def is_package(self, fullname): + self._is_package = fullname + return True + + def get_code(self, fullname): + self._got_code = fullname + return b'DEADBEEF' + + def get_source(self, fullname): + self._got_source = fullname + return 'def foo():\n pass' + + +class DummyUnderOverride: + def __call__(self, package, path, source, _info=''): + self.package = package + self.path = path + self.source = source + + +def read_(src): + with open(src, 'rb') as f: + contents = f.read() + return contents + + +def _assertBody(body, filename): + # strip both \n and \r for windows + body = body.replace(b'\r', b'') + body = body.replace(b'\n', b'') + data = read_(filename) + data = data.replace(b'\r', b'') + data = data.replace(b'\n', b'') + assert body == data diff --git a/tests/test_config/test_factories.py b/tests/test_config/test_factories.py new file mode 100644 index 000000000..c03d3f68b --- /dev/null +++ b/tests/test_config/test_factories.py @@ -0,0 +1,203 @@ +import unittest + +from . import dummyfactory + + +class TestFactoriesMixin(unittest.TestCase): + def _makeOne(self, *arg, **kw): + from pyramid.config import Configurator + + config = Configurator(*arg, **kw) + return config + + def test_set_request_factory(self): + from pyramid.interfaces import IRequestFactory + + config = self._makeOne(autocommit=True) + factory = object() + config.set_request_factory(factory) + self.assertEqual(config.registry.getUtility(IRequestFactory), factory) + + def test_set_request_factory_dottedname(self): + from pyramid.interfaces import IRequestFactory + + config = self._makeOne(autocommit=True) + config.set_request_factory('tests.test_config.dummyfactory') + self.assertEqual( + config.registry.getUtility(IRequestFactory), dummyfactory + ) + + def test_set_response_factory(self): + from pyramid.interfaces import IResponseFactory + + config = self._makeOne(autocommit=True) + factory = lambda r: object() + config.set_response_factory(factory) + self.assertEqual(config.registry.getUtility(IResponseFactory), factory) + + def test_set_response_factory_dottedname(self): + from pyramid.interfaces import IResponseFactory + + config = self._makeOne(autocommit=True) + config.set_response_factory('tests.test_config.dummyfactory') + self.assertEqual( + config.registry.getUtility(IResponseFactory), dummyfactory + ) + + def test_set_root_factory(self): + from pyramid.interfaces import IRootFactory + + config = self._makeOne() + config.set_root_factory(dummyfactory) + self.assertEqual(config.registry.queryUtility(IRootFactory), None) + config.commit() + self.assertEqual( + config.registry.getUtility(IRootFactory), dummyfactory + ) + + def test_set_root_factory_as_None(self): + from pyramid.interfaces import IRootFactory + from pyramid.traversal import DefaultRootFactory + + config = self._makeOne() + config.set_root_factory(None) + self.assertEqual(config.registry.queryUtility(IRootFactory), None) + config.commit() + self.assertEqual( + config.registry.getUtility(IRootFactory), DefaultRootFactory + ) + + def test_set_root_factory_dottedname(self): + from pyramid.interfaces import IRootFactory + + config = self._makeOne() + config.set_root_factory('tests.test_config.dummyfactory') + self.assertEqual(config.registry.queryUtility(IRootFactory), None) + config.commit() + self.assertEqual( + config.registry.getUtility(IRootFactory), dummyfactory + ) + + def test_set_session_factory(self): + from pyramid.interfaces import ISessionFactory + + config = self._makeOne() + config.set_session_factory(dummyfactory) + self.assertEqual(config.registry.queryUtility(ISessionFactory), None) + config.commit() + self.assertEqual( + config.registry.getUtility(ISessionFactory), dummyfactory + ) + + def test_set_session_factory_dottedname(self): + from pyramid.interfaces import ISessionFactory + + config = self._makeOne() + config.set_session_factory('tests.test_config.dummyfactory') + self.assertEqual(config.registry.queryUtility(ISessionFactory), None) + config.commit() + self.assertEqual( + config.registry.getUtility(ISessionFactory), dummyfactory + ) + + def test_add_request_method_with_callable(self): + from pyramid.interfaces import IRequestExtensions + + config = self._makeOne(autocommit=True) + callable = lambda x: None + config.add_request_method(callable, name='foo') + exts = config.registry.getUtility(IRequestExtensions) + self.assertTrue('foo' in exts.methods) + + def test_add_request_method_with_unnamed_callable(self): + from pyramid.interfaces import IRequestExtensions + + config = self._makeOne(autocommit=True) + + def foo(self): # pragma: no cover + pass + + config.add_request_method(foo) + exts = config.registry.getUtility(IRequestExtensions) + self.assertTrue('foo' in exts.methods) + + def test_set_multiple_request_methods_conflict(self): + from pyramid.exceptions import ConfigurationConflictError + + config = self._makeOne() + + def foo(self): # pragma: no cover + pass + + def bar(self): # pragma: no cover + pass + + config.add_request_method(foo, name='bar') + config.add_request_method(bar, name='bar') + self.assertRaises(ConfigurationConflictError, config.commit) + + def test_add_request_method_with_None_callable(self): + from pyramid.interfaces import IRequestExtensions + + config = self._makeOne(autocommit=True) + config.add_request_method(name='foo') + exts = config.registry.queryUtility(IRequestExtensions) + self.assertTrue(exts is None) + + def test_add_request_method_with_None_callable_conflict(self): + from pyramid.exceptions import ConfigurationConflictError + + config = self._makeOne() + + def bar(self): # pragma: no cover + pass + + config.add_request_method(name='foo') + config.add_request_method(bar, name='foo') + self.assertRaises(ConfigurationConflictError, config.commit) + + def test_add_request_method_with_None_callable_and_no_name(self): + config = self._makeOne(autocommit=True) + self.assertRaises(AttributeError, config.add_request_method) + + def test_add_request_method_with_text_type_name(self): + from pyramid.compat import text_, PY2 + from pyramid.exceptions import ConfigurationError + + config = self._makeOne(autocommit=True) + + def boomshaka(r): # pragma: no cover + pass + + def get_bad_name(): + if PY2: + name = text_(b'La Pe\xc3\xb1a', 'utf-8') + else: + name = b'La Pe\xc3\xb1a' + + config.add_request_method(boomshaka, name=name) + + self.assertRaises(ConfigurationError, get_bad_name) + + def test_set_execution_policy(self): + from pyramid.interfaces import IExecutionPolicy + + config = self._makeOne(autocommit=True) + + def dummy_policy(environ, router): # pragma: no cover + pass + + config.set_execution_policy(dummy_policy) + registry = config.registry + result = registry.queryUtility(IExecutionPolicy) + self.assertEqual(result, dummy_policy) + + def test_set_execution_policy_to_None(self): + from pyramid.interfaces import IExecutionPolicy + from pyramid.router import default_execution_policy + + config = self._makeOne(autocommit=True) + config.set_execution_policy(None) + registry = config.registry + result = registry.queryUtility(IExecutionPolicy) + self.assertEqual(result, default_execution_policy) diff --git a/tests/test_config/test_i18n.py b/tests/test_config/test_i18n.py new file mode 100644 index 000000000..b840c1976 --- /dev/null +++ b/tests/test_config/test_i18n.py @@ -0,0 +1,171 @@ +import os +import unittest + +from . import dummyfactory + +here = os.path.dirname(__file__) +locale = os.path.abspath( + os.path.join(here, '..', 'pkgs', 'localeapp', 'locale') +) +locale2 = os.path.abspath( + os.path.join(here, '..', 'pkgs', 'localeapp', 'locale2') +) +locale3 = os.path.abspath( + os.path.join(here, '..', 'pkgs', 'localeapp', 'locale3') +) + + +class TestI18NConfiguratorMixin(unittest.TestCase): + def _makeOne(self, *arg, **kw): + from pyramid.config import Configurator + + config = Configurator(*arg, **kw) + return config + + def test_set_locale_negotiator(self): + from pyramid.interfaces import ILocaleNegotiator + + config = self._makeOne(autocommit=True) + + def negotiator(request): # pragma: no cover + pass + + config.set_locale_negotiator(negotiator) + self.assertEqual( + config.registry.getUtility(ILocaleNegotiator), negotiator + ) + + def test_set_locale_negotiator_dottedname(self): + from pyramid.interfaces import ILocaleNegotiator + + config = self._makeOne(autocommit=True) + config.set_locale_negotiator('tests.test_config.dummyfactory') + self.assertEqual( + config.registry.getUtility(ILocaleNegotiator), dummyfactory + ) + + def test_add_translation_dirs_missing_dir(self): + from pyramid.exceptions import ConfigurationError + + config = self._makeOne() + config.add_translation_dirs('/wont/exist/on/my/system') + self.assertRaises(ConfigurationError, config.commit) + + def test_add_translation_dirs_no_specs(self): + from pyramid.interfaces import ITranslationDirectories + + config = self._makeOne() + config.add_translation_dirs() + self.assertEqual( + config.registry.queryUtility(ITranslationDirectories), None + ) + + def test_add_translation_dirs_asset_spec(self): + from pyramid.interfaces import ITranslationDirectories + + config = self._makeOne(autocommit=True) + config.add_translation_dirs('tests.pkgs.localeapp:locale') + self.assertEqual( + config.registry.getUtility(ITranslationDirectories), [locale] + ) + + def test_add_translation_dirs_asset_spec_existing_translation_dirs(self): + from pyramid.interfaces import ITranslationDirectories + + config = self._makeOne(autocommit=True) + directories = ['abc'] + config.registry.registerUtility(directories, ITranslationDirectories) + config.add_translation_dirs('tests.pkgs.localeapp:locale') + result = config.registry.getUtility(ITranslationDirectories) + self.assertEqual(result, [locale, 'abc']) + + def test_add_translation_dirs_multiple_specs(self): + from pyramid.interfaces import ITranslationDirectories + + config = self._makeOne(autocommit=True) + config.add_translation_dirs( + 'tests.pkgs.localeapp:locale', 'tests.pkgs.localeapp:locale2' + ) + self.assertEqual( + config.registry.getUtility(ITranslationDirectories), + [locale, locale2], + ) + + def test_add_translation_dirs_multiple_specs_multiple_calls(self): + from pyramid.interfaces import ITranslationDirectories + + config = self._makeOne(autocommit=True) + config.add_translation_dirs( + 'tests.pkgs.localeapp:locale', 'tests.pkgs.localeapp:locale2' + ) + config.add_translation_dirs('tests.pkgs.localeapp:locale3') + self.assertEqual( + config.registry.getUtility(ITranslationDirectories), + [locale3, locale, locale2], + ) + + def test_add_translation_dirs_override_multiple_specs_multiple_calls(self): + from pyramid.interfaces import ITranslationDirectories + + config = self._makeOne(autocommit=True) + config.add_translation_dirs( + 'tests.pkgs.localeapp:locale', 'tests.pkgs.localeapp:locale2' + ) + config.add_translation_dirs( + 'tests.pkgs.localeapp:locale3', override=True + ) + self.assertEqual( + config.registry.getUtility(ITranslationDirectories), + [locale, locale2, locale3], + ) + + def test_add_translation_dirs_invalid_kwargs(self): + config = self._makeOne(autocommit=True) + with self.assertRaises(TypeError): + config.add_translation_dirs('tests.pkgs.localeapp:locale', foo=1) + + def test_add_translation_dirs_abspath(self): + from pyramid.interfaces import ITranslationDirectories + + config = self._makeOne(autocommit=True) + config.add_translation_dirs(locale) + self.assertEqual( + config.registry.getUtility(ITranslationDirectories), [locale] + ) + + def test_add_translation_dirs_uses_override_out_of_order(self): + from pyramid.interfaces import ITranslationDirectories + + config = self._makeOne() + config.add_translation_dirs('tests.pkgs.localeapp:locale') + config.override_asset( + 'tests.pkgs.localeapp:locale/', 'tests.pkgs.localeapp:locale2/' + ) + config.commit() + self.assertEqual( + config.registry.getUtility(ITranslationDirectories), [locale2] + ) + + def test_add_translation_dirs_doesnt_use_override_w_autocommit(self): + from pyramid.interfaces import ITranslationDirectories + + config = self._makeOne(autocommit=True) + config.add_translation_dirs('tests.pkgs.localeapp:locale') + config.override_asset( + 'tests.pkgs.localeapp:locale/', 'tests.pkgs.localeapp:locale2/' + ) + self.assertEqual( + config.registry.getUtility(ITranslationDirectories), [locale] + ) + + def test_add_translation_dirs_uses_override_w_autocommit(self): + from pyramid.interfaces import ITranslationDirectories + + config = self._makeOne(autocommit=True) + config.override_asset( + 'tests.pkgs.localeapp:locale/', 'tests.pkgs.localeapp:locale2/' + ) + config.add_translation_dirs('tests.pkgs.localeapp:locale') + self.assertEqual( + config.registry.getUtility(ITranslationDirectories), [locale2] + ) diff --git a/tests/test_config/test_init.py b/tests/test_config/test_init.py new file mode 100644 index 000000000..811672fb3 --- /dev/null +++ b/tests/test_config/test_init.py @@ -0,0 +1,1455 @@ +import os +import unittest + +from pyramid.compat import im_func +from pyramid.testing import skip_on + +from . import dummy_tween_factory +from . import dummy_include +from . import dummy_extend +from . import dummy_extend2 +from . import DummyContext + +from pyramid.exceptions import ConfigurationExecutionError +from pyramid.exceptions import ConfigurationConflictError + +from pyramid.interfaces import IRequest + + +class ConfiguratorTests(unittest.TestCase): + def _makeOne(self, *arg, **kw): + from pyramid.config import Configurator + + config = Configurator(*arg, **kw) + return config + + def _getViewCallable( + self, + config, + ctx_iface=None, + request_iface=None, + name='', + exception_view=False, + ): + from pyramid.interfaces import IView + from pyramid.interfaces import IViewClassifier + from pyramid.interfaces import IExceptionViewClassifier + + if exception_view: # pragma: no cover + classifier = IExceptionViewClassifier + else: + classifier = IViewClassifier + return config.registry.adapters.lookup( + (classifier, request_iface, ctx_iface), + IView, + name=name, + default=None, + ) + + def _registerEventListener(self, config, event_iface=None): + if event_iface is None: # pragma: no cover + from zope.interface import Interface + + event_iface = Interface + L = [] + + def subscriber(*event): + L.extend(event) + + config.registry.registerHandler(subscriber, (event_iface,)) + return L + + def _makeRequest(self, config): + request = DummyRequest() + request.registry = config.registry + return request + + def test_ctor_no_registry(self): + import sys + from pyramid.interfaces import ISettings + from pyramid.config import Configurator + from pyramid.interfaces import IRendererFactory + + config = Configurator() + this_pkg = sys.modules['tests.test_config'] + self.assertTrue(config.registry.getUtility(ISettings)) + self.assertEqual(config.package, this_pkg) + config.commit() + self.assertTrue(config.registry.getUtility(IRendererFactory, 'json')) + self.assertTrue(config.registry.getUtility(IRendererFactory, 'string')) + + def test_begin(self): + from pyramid.config import Configurator + + config = Configurator() + manager = DummyThreadLocalManager() + config.manager = manager + config.begin() + self.assertEqual( + manager.pushed, {'registry': config.registry, 'request': None} + ) + self.assertEqual(manager.popped, False) + + def test_begin_with_request(self): + from pyramid.config import Configurator + + config = Configurator() + request = object() + manager = DummyThreadLocalManager() + config.manager = manager + config.begin(request=request) + self.assertEqual( + manager.pushed, {'registry': config.registry, 'request': request} + ) + self.assertEqual(manager.popped, False) + + def test_begin_overrides_request(self): + from pyramid.config import Configurator + + config = Configurator() + manager = DummyThreadLocalManager() + req = object() + # set it up for auto-propagation + pushed = {'registry': config.registry, 'request': None} + manager.pushed = pushed + config.manager = manager + config.begin(req) + self.assertTrue(manager.pushed is not pushed) + self.assertEqual(manager.pushed['request'], req) + self.assertEqual(manager.pushed['registry'], config.registry) + + def test_begin_propagates_request_for_same_registry(self): + from pyramid.config import Configurator + + config = Configurator() + manager = DummyThreadLocalManager() + req = object() + pushed = {'registry': config.registry, 'request': req} + manager.pushed = pushed + config.manager = manager + config.begin() + self.assertTrue(manager.pushed is not pushed) + self.assertEqual(manager.pushed['request'], req) + self.assertEqual(manager.pushed['registry'], config.registry) + + def test_begin_does_not_propagate_request_for_diff_registry(self): + from pyramid.config import Configurator + + config = Configurator() + manager = DummyThreadLocalManager() + req = object() + pushed = {'registry': object(), 'request': req} + manager.pushed = pushed + config.manager = manager + config.begin() + self.assertTrue(manager.pushed is not pushed) + self.assertEqual(manager.pushed['request'], None) + self.assertEqual(manager.pushed['registry'], config.registry) + + def test_end(self): + from pyramid.config import Configurator + + config = Configurator() + manager = DummyThreadLocalManager() + pushed = manager.pushed + config.manager = manager + config.end() + self.assertEqual(manager.pushed, pushed) + self.assertEqual(manager.popped, True) + + def test_context_manager(self): + from pyramid.config import Configurator + + config = Configurator() + manager = DummyThreadLocalManager() + config.manager = manager + view = lambda r: None + with config as ctx: + self.assertTrue(config is ctx) + self.assertEqual( + manager.pushed, {'registry': config.registry, 'request': None} + ) + self.assertFalse(manager.popped) + config.add_view(view) + self.assertTrue(manager.popped) + config.add_view(view) # did not raise a conflict because of commit + config.commit() + + def test_ctor_with_package_registry(self): + import sys + from pyramid.config import Configurator + + pkg = sys.modules['pyramid'] + config = Configurator(package=pkg) + self.assertEqual(config.package, pkg) + + def test_ctor_noreg_custom_settings(self): + from pyramid.interfaces import ISettings + + settings = {'reload_templates': True, 'mysetting': True} + config = self._makeOne(settings=settings) + settings = config.registry.getUtility(ISettings) + self.assertEqual(settings['reload_templates'], True) + self.assertEqual(settings['debug_authorization'], False) + self.assertEqual(settings['mysetting'], True) + + def test_ctor_noreg_debug_logger_None_default(self): + from pyramid.interfaces import IDebugLogger + + config = self._makeOne() + logger = config.registry.getUtility(IDebugLogger) + self.assertEqual(logger.name, 'tests.test_config') + + def test_ctor_noreg_debug_logger_non_None(self): + from pyramid.interfaces import IDebugLogger + + logger = object() + config = self._makeOne(debug_logger=logger) + result = config.registry.getUtility(IDebugLogger) + self.assertEqual(logger, result) + + def test_ctor_authentication_policy(self): + from pyramid.interfaces import IAuthenticationPolicy + + policy = object() + config = self._makeOne(authentication_policy=policy) + config.commit() + result = config.registry.getUtility(IAuthenticationPolicy) + self.assertEqual(policy, result) + + def test_ctor_authorization_policy_only(self): + policy = object() + config = self._makeOne(authorization_policy=policy) + self.assertRaises(ConfigurationExecutionError, config.commit) + + def test_ctor_no_root_factory(self): + from pyramid.interfaces import IRootFactory + + config = self._makeOne() + self.assertEqual(config.registry.queryUtility(IRootFactory), None) + config.commit() + self.assertEqual(config.registry.queryUtility(IRootFactory), None) + + def test_ctor_with_root_factory(self): + from pyramid.interfaces import IRootFactory + + factory = object() + config = self._makeOne(root_factory=factory) + self.assertEqual(config.registry.queryUtility(IRootFactory), None) + config.commit() + self.assertEqual(config.registry.queryUtility(IRootFactory), factory) + + def test_ctor_alternate_renderers(self): + from pyramid.interfaces import IRendererFactory + + renderer = object() + config = self._makeOne(renderers=[('yeah', renderer)]) + config.commit() + self.assertEqual( + config.registry.getUtility(IRendererFactory, 'yeah'), renderer + ) + + def test_ctor_default_renderers(self): + from pyramid.interfaces import IRendererFactory + from pyramid.renderers import json_renderer_factory + + config = self._makeOne() + self.assertEqual( + config.registry.getUtility(IRendererFactory, 'json'), + json_renderer_factory, + ) + + def test_ctor_default_permission(self): + from pyramid.interfaces import IDefaultPermission + + config = self._makeOne(default_permission='view') + config.commit() + self.assertEqual( + config.registry.getUtility(IDefaultPermission), 'view' + ) + + def test_ctor_session_factory(self): + from pyramid.interfaces import ISessionFactory + + factory = object() + config = self._makeOne(session_factory=factory) + self.assertEqual(config.registry.queryUtility(ISessionFactory), None) + config.commit() + self.assertEqual(config.registry.getUtility(ISessionFactory), factory) + + def test_ctor_default_view_mapper(self): + from pyramid.interfaces import IViewMapperFactory + + mapper = object() + config = self._makeOne(default_view_mapper=mapper) + config.commit() + self.assertEqual( + config.registry.getUtility(IViewMapperFactory), mapper + ) + + def test_ctor_httpexception_view_default(self): + from pyramid.interfaces import IExceptionResponse + from pyramid.httpexceptions import default_exceptionresponse_view + + config = self._makeOne() + view = self._getViewCallable( + config, ctx_iface=IExceptionResponse, request_iface=IRequest + ) + self.assertTrue(view.__wraps__ is default_exceptionresponse_view) + + def test_ctor_exceptionresponse_view_None(self): + from pyramid.interfaces import IExceptionResponse + + config = self._makeOne(exceptionresponse_view=None) + view = self._getViewCallable( + config, ctx_iface=IExceptionResponse, request_iface=IRequest + ) + self.assertTrue(view is None) + + def test_ctor_exceptionresponse_view_custom(self): + from pyramid.interfaces import IExceptionResponse + + def exceptionresponse_view(context, request): # pragma: no cover + pass + + config = self._makeOne(exceptionresponse_view=exceptionresponse_view) + view = self._getViewCallable( + config, ctx_iface=IExceptionResponse, request_iface=IRequest + ) + self.assertTrue(view.__wraps__ is exceptionresponse_view) + + def test_ctor_with_introspection(self): + config = self._makeOne(introspection=False) + self.assertEqual(config.introspection, False) + + def test_ctor_default_webob_response_adapter_registered(self): + from webob import Response as WebobResponse + + response = WebobResponse() + from pyramid.interfaces import IResponse + + config = self._makeOne(autocommit=True) + result = config.registry.queryAdapter(response, IResponse) + self.assertEqual(result, response) + + def test_with_package_module(self): + from . import test_init + + config = self._makeOne() + newconfig = config.with_package(test_init) + import tests.test_config + + self.assertEqual(newconfig.package, tests.test_config) + + def test_with_package_package(self): + from tests import test_config + + config = self._makeOne() + newconfig = config.with_package(test_config) + self.assertEqual(newconfig.package, test_config) + + def test_with_package(self): + import tests + + config = self._makeOne() + config.basepath = 'basepath' + config.info = 'info' + config.includepath = ('spec',) + config.autocommit = True + config.route_prefix = 'prefix' + newconfig = config.with_package(tests) + self.assertEqual(newconfig.package, tests) + self.assertEqual(newconfig.registry, config.registry) + self.assertEqual(newconfig.autocommit, True) + self.assertEqual(newconfig.route_prefix, 'prefix') + self.assertEqual(newconfig.info, 'info') + self.assertEqual(newconfig.basepath, 'basepath') + self.assertEqual(newconfig.includepath, ('spec',)) + + def test_maybe_dotted_string_success(self): + import tests.test_config + + config = self._makeOne() + result = config.maybe_dotted('tests.test_config') + self.assertEqual(result, tests.test_config) + + def test_maybe_dotted_string_fail(self): + config = self._makeOne() + self.assertRaises(ImportError, config.maybe_dotted, 'cant.be.found') + + def test_maybe_dotted_notstring_success(self): + import tests.test_config + + config = self._makeOne() + result = config.maybe_dotted(tests.test_config) + self.assertEqual(result, tests.test_config) + + def test_absolute_asset_spec_already_absolute(self): + import tests.test_config + + config = self._makeOne(package=tests.test_config) + result = config.absolute_asset_spec('already:absolute') + self.assertEqual(result, 'already:absolute') + + def test_absolute_asset_spec_notastring(self): + import tests.test_config + + config = self._makeOne(package=tests.test_config) + result = config.absolute_asset_spec(None) + self.assertEqual(result, None) + + def test_absolute_asset_spec_relative(self): + import tests.test_config + + config = self._makeOne(package=tests.test_config) + result = config.absolute_asset_spec('files') + self.assertEqual(result, 'tests.test_config:files') + + def test__fix_registry_has_listeners(self): + reg = DummyRegistry() + config = self._makeOne(reg) + config._fix_registry() + self.assertEqual(reg.has_listeners, True) + + def test__fix_registry_notify(self): + reg = DummyRegistry() + config = self._makeOne(reg) + config._fix_registry() + self.assertEqual(reg.notify(1), None) + self.assertEqual(reg.events, (1,)) + + def test__fix_registry_queryAdapterOrSelf(self): + from zope.interface import Interface + from zope.interface import implementer + + class IFoo(Interface): + pass + + @implementer(IFoo) + class Foo(object): + pass + + class Bar(object): + pass + + adaptation = () + foo = Foo() + bar = Bar() + reg = DummyRegistry(adaptation) + config = self._makeOne(reg) + config._fix_registry() + self.assertTrue(reg.queryAdapterOrSelf(foo, IFoo) is foo) + self.assertTrue(reg.queryAdapterOrSelf(bar, IFoo) is adaptation) + + def test__fix_registry_registerSelfAdapter(self): + reg = DummyRegistry() + config = self._makeOne(reg) + config._fix_registry() + reg.registerSelfAdapter('required', 'provided', name='abc') + self.assertEqual(len(reg.adapters), 1) + args, kw = reg.adapters[0] + self.assertEqual(args[0]('abc'), 'abc') + self.assertEqual( + kw, + { + 'info': '', + 'provided': 'provided', + 'required': 'required', + 'name': 'abc', + 'event': True, + }, + ) + + def test__fix_registry_adds__lock(self): + reg = DummyRegistry() + config = self._makeOne(reg) + config._fix_registry() + self.assertTrue(hasattr(reg, '_lock')) + + def test__fix_registry_adds_clear_view_lookup_cache(self): + reg = DummyRegistry() + config = self._makeOne(reg) + self.assertFalse(hasattr(reg, '_clear_view_lookup_cache')) + config._fix_registry() + self.assertFalse(hasattr(reg, '_view_lookup_cache')) + reg._clear_view_lookup_cache() + self.assertEqual(reg._view_lookup_cache, {}) + + def test_setup_registry_calls_fix_registry(self): + reg = DummyRegistry() + config = self._makeOne(reg) + config.add_view = lambda *arg, **kw: False + config._add_tween = lambda *arg, **kw: False + config.setup_registry() + self.assertEqual(reg.has_listeners, True) + + def test_setup_registry_registers_default_exceptionresponse_views(self): + from webob.exc import WSGIHTTPException + from pyramid.interfaces import IExceptionResponse + from pyramid.view import default_exceptionresponse_view + + reg = DummyRegistry() + config = self._makeOne(reg) + views = [] + config.add_view = lambda *arg, **kw: views.append((arg, kw)) + config.add_default_view_predicates = lambda *arg: None + config._add_tween = lambda *arg, **kw: False + config.setup_registry() + self.assertEqual( + views[0], + ( + (default_exceptionresponse_view,), + {'context': IExceptionResponse}, + ), + ) + self.assertEqual( + views[1], + ( + (default_exceptionresponse_view,), + {'context': WSGIHTTPException}, + ), + ) + + def test_setup_registry_registers_default_view_predicates(self): + reg = DummyRegistry() + config = self._makeOne(reg) + vp_called = [] + config.add_view = lambda *arg, **kw: None + config.add_default_view_predicates = lambda *arg: vp_called.append( + True + ) + config._add_tween = lambda *arg, **kw: False + config.setup_registry() + self.assertTrue(vp_called) + + def test_setup_registry_registers_default_webob_iresponse_adapter(self): + from webob import Response + from pyramid.interfaces import IResponse + + config = self._makeOne() + config.setup_registry() + response = Response() + self.assertTrue( + config.registry.queryAdapter(response, IResponse) is response + ) + + def test_setup_registry_explicit_notfound_trumps_iexceptionresponse(self): + from pyramid.renderers import null_renderer + from zope.interface import implementedBy + from pyramid.httpexceptions import HTTPNotFound + from pyramid.registry import Registry + + reg = Registry() + config = self._makeOne(reg, autocommit=True) + config.setup_registry() # registers IExceptionResponse default view + + def myview(context, request): + return 'OK' + + config.add_view(myview, context=HTTPNotFound, renderer=null_renderer) + request = self._makeRequest(config) + view = self._getViewCallable( + config, + ctx_iface=implementedBy(HTTPNotFound), + request_iface=IRequest, + ) + result = view(None, request) + self.assertEqual(result, 'OK') + + def test_setup_registry_custom_settings(self): + from pyramid.registry import Registry + from pyramid.interfaces import ISettings + + settings = {'reload_templates': True, 'mysetting': True} + reg = Registry() + config = self._makeOne(reg) + config.setup_registry(settings=settings) + settings = reg.getUtility(ISettings) + self.assertEqual(settings['reload_templates'], True) + self.assertEqual(settings['debug_authorization'], False) + self.assertEqual(settings['mysetting'], True) + + def test_setup_registry_debug_logger_None_default(self): + from pyramid.registry import Registry + from pyramid.interfaces import IDebugLogger + + reg = Registry() + config = self._makeOne(reg) + config.setup_registry() + logger = reg.getUtility(IDebugLogger) + self.assertEqual(logger.name, 'tests.test_config') + + def test_setup_registry_debug_logger_non_None(self): + from pyramid.registry import Registry + from pyramid.interfaces import IDebugLogger + + logger = object() + reg = Registry() + config = self._makeOne(reg) + config.setup_registry(debug_logger=logger) + result = reg.getUtility(IDebugLogger) + self.assertEqual(logger, result) + + def test_setup_registry_debug_logger_name(self): + from pyramid.registry import Registry + from pyramid.interfaces import IDebugLogger + + reg = Registry() + config = self._makeOne(reg) + config.setup_registry(debug_logger='foo') + result = reg.getUtility(IDebugLogger) + self.assertEqual(result.name, 'foo') + + def test_setup_registry_authentication_policy(self): + from pyramid.registry import Registry + from pyramid.interfaces import IAuthenticationPolicy + + policy = object() + reg = Registry() + config = self._makeOne(reg) + config.setup_registry(authentication_policy=policy) + config.commit() + result = reg.getUtility(IAuthenticationPolicy) + self.assertEqual(policy, result) + + def test_setup_registry_authentication_policy_dottedname(self): + from pyramid.registry import Registry + from pyramid.interfaces import IAuthenticationPolicy + + reg = Registry() + config = self._makeOne(reg) + config.setup_registry(authentication_policy='tests.test_config') + config.commit() + result = reg.getUtility(IAuthenticationPolicy) + import tests.test_config + + self.assertEqual(result, tests.test_config) + + def test_setup_registry_authorization_policy_dottedname(self): + from pyramid.registry import Registry + from pyramid.interfaces import IAuthorizationPolicy + + reg = Registry() + config = self._makeOne(reg) + dummy = object() + config.setup_registry( + authentication_policy=dummy, + authorization_policy='tests.test_config', + ) + config.commit() + result = reg.getUtility(IAuthorizationPolicy) + import tests.test_config + + self.assertEqual(result, tests.test_config) + + def test_setup_registry_authorization_policy_only(self): + from pyramid.registry import Registry + + policy = object() + reg = Registry() + config = self._makeOne(reg) + config.setup_registry(authorization_policy=policy) + config = self.assertRaises(ConfigurationExecutionError, config.commit) + + def test_setup_registry_no_default_root_factory(self): + from pyramid.registry import Registry + from pyramid.interfaces import IRootFactory + + reg = Registry() + config = self._makeOne(reg) + config.setup_registry() + config.commit() + self.assertEqual(reg.queryUtility(IRootFactory), None) + + def test_setup_registry_dottedname_root_factory(self): + from pyramid.registry import Registry + from pyramid.interfaces import IRootFactory + + reg = Registry() + config = self._makeOne(reg) + import tests.test_config + + config.setup_registry(root_factory='tests.test_config') + self.assertEqual(reg.queryUtility(IRootFactory), None) + config.commit() + self.assertEqual(reg.getUtility(IRootFactory), tests.test_config) + + def test_setup_registry_locale_negotiator_dottedname(self): + from pyramid.registry import Registry + from pyramid.interfaces import ILocaleNegotiator + + reg = Registry() + config = self._makeOne(reg) + import tests.test_config + + config.setup_registry(locale_negotiator='tests.test_config') + self.assertEqual(reg.queryUtility(ILocaleNegotiator), None) + config.commit() + utility = reg.getUtility(ILocaleNegotiator) + self.assertEqual(utility, tests.test_config) + + def test_setup_registry_locale_negotiator(self): + from pyramid.registry import Registry + from pyramid.interfaces import ILocaleNegotiator + + reg = Registry() + config = self._makeOne(reg) + negotiator = object() + config.setup_registry(locale_negotiator=negotiator) + self.assertEqual(reg.queryUtility(ILocaleNegotiator), None) + config.commit() + utility = reg.getUtility(ILocaleNegotiator) + self.assertEqual(utility, negotiator) + + def test_setup_registry_request_factory(self): + from pyramid.registry import Registry + from pyramid.interfaces import IRequestFactory + + reg = Registry() + config = self._makeOne(reg) + factory = object() + config.setup_registry(request_factory=factory) + self.assertEqual(reg.queryUtility(IRequestFactory), None) + config.commit() + utility = reg.getUtility(IRequestFactory) + self.assertEqual(utility, factory) + + def test_setup_registry_response_factory(self): + from pyramid.registry import Registry + from pyramid.interfaces import IResponseFactory + + reg = Registry() + config = self._makeOne(reg) + factory = lambda r: object() + config.setup_registry(response_factory=factory) + self.assertEqual(reg.queryUtility(IResponseFactory), None) + config.commit() + utility = reg.getUtility(IResponseFactory) + self.assertEqual(utility, factory) + + def test_setup_registry_request_factory_dottedname(self): + from pyramid.registry import Registry + from pyramid.interfaces import IRequestFactory + + reg = Registry() + config = self._makeOne(reg) + import tests.test_config + + config.setup_registry(request_factory='tests.test_config') + self.assertEqual(reg.queryUtility(IRequestFactory), None) + config.commit() + utility = reg.getUtility(IRequestFactory) + self.assertEqual(utility, tests.test_config) + + def test_setup_registry_alternate_renderers(self): + from pyramid.registry import Registry + from pyramid.interfaces import IRendererFactory + + renderer = object() + reg = Registry() + config = self._makeOne(reg) + config.setup_registry(renderers=[('yeah', renderer)]) + config.commit() + self.assertEqual(reg.getUtility(IRendererFactory, 'yeah'), renderer) + + def test_setup_registry_default_permission(self): + from pyramid.registry import Registry + from pyramid.interfaces import IDefaultPermission + + reg = Registry() + config = self._makeOne(reg) + config.setup_registry(default_permission='view') + config.commit() + self.assertEqual(reg.getUtility(IDefaultPermission), 'view') + + def test_setup_registry_includes(self): + from pyramid.registry import Registry + + reg = Registry() + config = self._makeOne(reg) + settings = { + 'pyramid.includes': """tests.test_config.dummy_include +tests.test_config.dummy_include2""" + } + config.setup_registry(settings=settings) + self.assertTrue(reg.included) + self.assertTrue(reg.also_included) + + def test_setup_registry_includes_spaces(self): + from pyramid.registry import Registry + + reg = Registry() + config = self._makeOne(reg) + settings = { + 'pyramid.includes': """tests.test_config.dummy_include tests.\ +test_config.dummy_include2""" + } + config.setup_registry(settings=settings) + self.assertTrue(reg.included) + self.assertTrue(reg.also_included) + + def test_setup_registry_tweens(self): + from pyramid.interfaces import ITweens + from pyramid.registry import Registry + + reg = Registry() + config = self._makeOne(reg) + settings = {'pyramid.tweens': 'tests.test_config.dummy_tween_factory'} + config.setup_registry(settings=settings) + config.commit() + tweens = config.registry.getUtility(ITweens) + self.assertEqual( + tweens.explicit, + [('tests.test_config.dummy_tween_factory', dummy_tween_factory)], + ) + + def test_introspector_decorator(self): + inst = self._makeOne() + default = inst.introspector + self.assertTrue(hasattr(default, 'add')) + self.assertEqual(inst.introspector, inst.registry.introspector) + introspector = object() + inst.introspector = introspector + new = inst.introspector + self.assertTrue(new is introspector) + self.assertEqual(inst.introspector, inst.registry.introspector) + del inst.introspector + default = inst.introspector + self.assertFalse(default is new) + self.assertTrue(hasattr(default, 'add')) + + def test_make_wsgi_app(self): + import pyramid.config + from pyramid.router import Router + from pyramid.interfaces import IApplicationCreated + + manager = DummyThreadLocalManager() + config = self._makeOne() + subscriber = self._registerEventListener(config, IApplicationCreated) + config.manager = manager + app = config.make_wsgi_app() + self.assertEqual(app.__class__, Router) + self.assertEqual(manager.pushed['registry'], config.registry) + self.assertEqual(manager.pushed['request'], None) + self.assertTrue(manager.popped) + self.assertEqual(pyramid.config.global_registries.last, app.registry) + self.assertEqual(len(subscriber), 1) + self.assertTrue(IApplicationCreated.providedBy(subscriber[0])) + pyramid.config.global_registries.empty() + + def test_include_with_dotted_name(self): + from tests import test_config + + config = self._makeOne() + config.include('tests.test_config.dummy_include') + after = config.action_state + actions = after.actions + self.assertEqual(len(actions), 1) + action = after.actions[0] + self.assertEqual(action['discriminator'], 'discrim') + self.assertEqual(action['callable'], None) + self.assertEqual(action['args'], test_config) + + def test_include_with_python_callable(self): + from tests import test_config + + config = self._makeOne() + config.include(dummy_include) + after = config.action_state + actions = after.actions + self.assertEqual(len(actions), 1) + action = actions[0] + self.assertEqual(action['discriminator'], 'discrim') + self.assertEqual(action['callable'], None) + self.assertEqual(action['args'], test_config) + + def test_include_with_module_defaults_to_includeme(self): + from tests import test_config + + config = self._makeOne() + config.include('tests.test_config') + after = config.action_state + actions = after.actions + self.assertEqual(len(actions), 1) + action = actions[0] + self.assertEqual(action['discriminator'], 'discrim') + self.assertEqual(action['callable'], None) + self.assertEqual(action['args'], test_config) + + def test_include_with_module_defaults_to_includeme_missing(self): + from pyramid.exceptions import ConfigurationError + + config = self._makeOne() + self.assertRaises(ConfigurationError, config.include, 'tests') + + def test_include_with_route_prefix(self): + root_config = self._makeOne(autocommit=True) + + def dummy_subapp(config): + self.assertEqual(config.route_prefix, 'root') + + root_config.include(dummy_subapp, route_prefix='root') + + def test_include_with_nested_route_prefix(self): + root_config = self._makeOne(autocommit=True, route_prefix='root') + + def dummy_subapp2(config): + self.assertEqual(config.route_prefix, 'root/nested') + + def dummy_subapp3(config): + self.assertEqual(config.route_prefix, 'root/nested/nested2') + config.include(dummy_subapp4) + + def dummy_subapp4(config): + self.assertEqual(config.route_prefix, 'root/nested/nested2') + + def dummy_subapp(config): + self.assertEqual(config.route_prefix, 'root/nested') + config.include(dummy_subapp2) + config.include(dummy_subapp3, route_prefix='nested2') + + root_config.include(dummy_subapp, route_prefix='nested') + + def test_include_with_missing_source_file(self): + from pyramid.exceptions import ConfigurationError + import inspect + + config = self._makeOne() + + class DummyInspect(object): + def getmodule(self, c): + return inspect.getmodule(c) + + def getsourcefile(self, c): + return None + + config.inspect = DummyInspect() + try: + config.include('tests.test_config.dummy_include') + except ConfigurationError as e: + self.assertEqual( + e.args[0], + "No source file for module 'tests.test_config' (.py " + "file must exist, refusing to use orphan .pyc or .pyo file).", + ) + else: # pragma: no cover + raise AssertionError + + def test_include_constant_root_package(self): + import tests + from tests import test_config + + config = self._makeOne(root_package=tests) + results = {} + + def include(config): + results['package'] = config.package + results['root_package'] = config.root_package + + config.include(include) + self.assertEqual(results['root_package'], tests) + self.assertEqual(results['package'], test_config) + + def test_include_threadlocals_active(self): + from pyramid.threadlocal import get_current_registry + + stack = [] + + def include(config): + stack.append(get_current_registry()) + + config = self._makeOne() + config.include(include) + self.assertTrue(stack[0] is config.registry) + + def test_scan_integration(self): + from zope.interface import alsoProvides + from pyramid.view import render_view_to_response + import tests.test_config.pkgs.scannable as package + + config = self._makeOne(autocommit=True) + config.scan(package) + + ctx = DummyContext() + req = DummyRequest() + alsoProvides(req, IRequest) + req.registry = config.registry + + req.method = 'GET' + result = render_view_to_response(ctx, req, '') + self.assertEqual(result, 'grokked') + + req.method = 'POST' + result = render_view_to_response(ctx, req, '') + self.assertEqual(result, 'grokked_post') + + result = render_view_to_response(ctx, req, 'grokked_class') + self.assertEqual(result, 'grokked_class') + + result = render_view_to_response(ctx, req, 'grokked_instance') + self.assertEqual(result, 'grokked_instance') + + result = render_view_to_response(ctx, req, 'oldstyle_grokked_class') + self.assertEqual(result, 'oldstyle_grokked_class') + + req.method = 'GET' + result = render_view_to_response(ctx, req, 'another') + self.assertEqual(result, 'another_grokked') + + req.method = 'POST' + result = render_view_to_response(ctx, req, 'another') + self.assertEqual(result, 'another_grokked_post') + + result = render_view_to_response(ctx, req, 'another_grokked_class') + self.assertEqual(result, 'another_grokked_class') + + result = render_view_to_response(ctx, req, 'another_grokked_instance') + self.assertEqual(result, 'another_grokked_instance') + + result = render_view_to_response( + ctx, req, 'another_oldstyle_grokked_class' + ) + self.assertEqual(result, 'another_oldstyle_grokked_class') + + result = render_view_to_response(ctx, req, 'stacked1') + self.assertEqual(result, 'stacked') + + result = render_view_to_response(ctx, req, 'stacked2') + self.assertEqual(result, 'stacked') + + result = render_view_to_response(ctx, req, 'another_stacked1') + self.assertEqual(result, 'another_stacked') + + result = render_view_to_response(ctx, req, 'another_stacked2') + self.assertEqual(result, 'another_stacked') + + result = render_view_to_response(ctx, req, 'stacked_class1') + self.assertEqual(result, 'stacked_class') + + result = render_view_to_response(ctx, req, 'stacked_class2') + self.assertEqual(result, 'stacked_class') + + result = render_view_to_response(ctx, req, 'another_stacked_class1') + self.assertEqual(result, 'another_stacked_class') + + result = render_view_to_response(ctx, req, 'another_stacked_class2') + self.assertEqual(result, 'another_stacked_class') + + # NB: on Jython, a class without an __init__ apparently accepts + # any number of arguments without raising a TypeError, so the next + # assertion may fail there. We don't support Jython at the moment, + # this is just a note to a future self. + + self.assertRaises( + TypeError, render_view_to_response, ctx, req, 'basemethod' + ) + + result = render_view_to_response(ctx, req, 'method1') + self.assertEqual(result, 'method1') + + result = render_view_to_response(ctx, req, 'method2') + self.assertEqual(result, 'method2') + + result = render_view_to_response(ctx, req, 'stacked_method1') + self.assertEqual(result, 'stacked_method') + + result = render_view_to_response(ctx, req, 'stacked_method2') + self.assertEqual(result, 'stacked_method') + + result = render_view_to_response(ctx, req, 'subpackage_init') + self.assertEqual(result, 'subpackage_init') + + result = render_view_to_response(ctx, req, 'subpackage_notinit') + self.assertEqual(result, 'subpackage_notinit') + + result = render_view_to_response(ctx, req, 'subsubpackage_init') + self.assertEqual(result, 'subsubpackage_init') + + result = render_view_to_response(ctx, req, 'pod_notinit') + self.assertEqual(result, None) + + def test_scan_integration_with_ignore(self): + from zope.interface import alsoProvides + from pyramid.view import render_view_to_response + import tests.test_config.pkgs.scannable as package + + config = self._makeOne(autocommit=True) + config.scan(package, ignore='tests.test_config.pkgs.scannable.another') + + ctx = DummyContext() + req = DummyRequest() + alsoProvides(req, IRequest) + req.registry = config.registry + + req.method = 'GET' + result = render_view_to_response(ctx, req, '') + self.assertEqual(result, 'grokked') + + # ignored + v = render_view_to_response(ctx, req, 'another_stacked_class2') + self.assertEqual(v, None) + + def test_scan_integration_dottedname_package(self): + from zope.interface import alsoProvides + from pyramid.view import render_view_to_response + + config = self._makeOne(autocommit=True) + config.scan('tests.test_config.pkgs.scannable') + + ctx = DummyContext() + req = DummyRequest() + alsoProvides(req, IRequest) + req.registry = config.registry + + req.method = 'GET' + result = render_view_to_response(ctx, req, '') + self.assertEqual(result, 'grokked') + + def test_scan_integration_with_extra_kw(self): + config = self._makeOne(autocommit=True) + config.scan('tests.test_config.pkgs.scanextrakw', a=1) + self.assertEqual(config.a, 1) + + def test_scan_integration_with_onerror(self): + # fancy sys.path manipulation here to appease "setup.py test" which + # fails miserably when it can't import something in the package + import sys + + try: + here = os.path.dirname(__file__) + path = os.path.join(here, 'path') + sys.path.append(path) + config = self._makeOne(autocommit=True) + + class FooException(Exception): + pass + + def onerror(name): + raise FooException + + self.assertRaises( + FooException, config.scan, 'scanerror', onerror=onerror + ) + finally: + sys.path.remove(path) + + def test_scan_integration_conflict(self): + from tests.test_config.pkgs import selfscan + from pyramid.config import Configurator + + c = Configurator() + c.scan(selfscan) + c.scan(selfscan) + try: + c.commit() + except ConfigurationConflictError as why: + + def scanconflicts(e): + conflicts = e._conflicts.values() + for conflict in conflicts: + for confinst in conflict: + yield confinst.src + + which = list(scanconflicts(why)) + self.assertEqual(len(which), 4) + self.assertTrue("@view_config(renderer='string')" in which) + self.assertTrue( + "@view_config(name='two', renderer='string')" in which + ) + + @skip_on('py3') + def test_hook_zca(self): + from zope.component import getSiteManager + + def foo(): + '123' + + try: + config = self._makeOne() + config.hook_zca() + config.begin() + sm = getSiteManager() + self.assertEqual(sm, config.registry) + finally: + getSiteManager.reset() + + @skip_on('py3') + def test_unhook_zca(self): + from zope.component import getSiteManager + + def foo(): + '123' + + try: + getSiteManager.sethook(foo) + config = self._makeOne() + config.unhook_zca() + sm = getSiteManager() + self.assertNotEqual(sm, '123') + finally: + getSiteManager.reset() + + def test___getattr__missing_when_directives_exist(self): + config = self._makeOne() + directives = {} + config.registry._directives = directives + self.assertRaises(AttributeError, config.__getattr__, 'wontexist') + + def test___getattr__missing_when_directives_dont_exist(self): + config = self._makeOne() + self.assertRaises(AttributeError, config.__getattr__, 'wontexist') + + def test___getattr__matches(self): + config = self._makeOne() + + def foo(config): # pragma: no cover + pass + + directives = {'foo': (foo, True)} + config.registry._directives = directives + foo_meth = config.foo + self.assertTrue(getattr(foo_meth, im_func).__docobj__ is foo) + + def test___getattr__matches_no_action_wrap(self): + config = self._makeOne() + + def foo(config): # pragma: no cover + pass + + directives = {'foo': (foo, False)} + config.registry._directives = directives + foo_meth = config.foo + self.assertTrue(getattr(foo_meth, im_func) is foo) + + +class TestConfigurator_add_directive(unittest.TestCase): + def setUp(self): + from pyramid.config import Configurator + + self.config = Configurator() + + def test_extend_with_dotted_name(self): + from tests import test_config + + config = self.config + config.add_directive('dummy_extend', 'tests.test_config.dummy_extend') + self.assertTrue(hasattr(config, 'dummy_extend')) + config.dummy_extend('discrim') + after = config.action_state + action = after.actions[-1] + self.assertEqual(action['discriminator'], 'discrim') + self.assertEqual(action['callable'], None) + self.assertEqual(action['args'], test_config) + + def test_add_directive_with_partial(self): + from tests import test_config + + config = self.config + config.add_directive( + 'dummy_partial', 'tests.test_config.dummy_partial' + ) + self.assertTrue(hasattr(config, 'dummy_partial')) + config.dummy_partial() + after = config.action_state + action = after.actions[-1] + self.assertEqual(action['discriminator'], 'partial') + self.assertEqual(action['callable'], None) + self.assertEqual(action['args'], test_config) + + def test_add_directive_with_custom_callable(self): + from tests import test_config + + config = self.config + config.add_directive( + 'dummy_callable', 'tests.test_config.dummy_callable' + ) + self.assertTrue(hasattr(config, 'dummy_callable')) + config.dummy_callable('discrim') + after = config.action_state + action = after.actions[-1] + self.assertEqual(action['discriminator'], 'discrim') + self.assertEqual(action['callable'], None) + self.assertEqual(action['args'], test_config) + + def test_extend_with_python_callable(self): + from tests import test_config + + config = self.config + config.add_directive('dummy_extend', dummy_extend) + self.assertTrue(hasattr(config, 'dummy_extend')) + config.dummy_extend('discrim') + after = config.action_state + action = after.actions[-1] + self.assertEqual(action['discriminator'], 'discrim') + self.assertEqual(action['callable'], None) + self.assertEqual(action['args'], test_config) + + def test_extend_same_name_doesnt_conflict(self): + config = self.config + config.add_directive('dummy_extend', dummy_extend) + config.add_directive('dummy_extend', dummy_extend2) + self.assertTrue(hasattr(config, 'dummy_extend')) + config.dummy_extend('discrim') + after = config.action_state + action = after.actions[-1] + self.assertEqual(action['discriminator'], 'discrim') + self.assertEqual(action['callable'], None) + self.assertEqual(action['args'], config.registry) + + def test_extend_action_method_successful(self): + config = self.config + config.add_directive('dummy_extend', dummy_extend) + config.dummy_extend('discrim') + config.dummy_extend('discrim') + self.assertRaises(ConfigurationConflictError, config.commit) + + def test_directive_persists_across_configurator_creations(self): + config = self.config + config.add_directive('dummy_extend', dummy_extend) + config2 = config.with_package('tests') + config2.dummy_extend('discrim') + after = config2.action_state + actions = after.actions + self.assertEqual(len(actions), 1) + action = actions[0] + self.assertEqual(action['discriminator'], 'discrim') + self.assertEqual(action['callable'], None) + self.assertEqual(action['args'], config2.package) + + +class TestConfigurator__add_predicate(unittest.TestCase): + def _makeOne(self): + from pyramid.config import Configurator + + return Configurator() + + def test_factory_as_object(self): + config = self._makeOne() + + def _fakeAction( + discriminator, + callable=None, + args=(), + kw=None, + order=0, + introspectables=(), + **extra + ): + self.assertEqual(len(introspectables), 1) + self.assertEqual(introspectables[0]['name'], 'testing') + self.assertEqual(introspectables[0]['factory'], DummyPredicate) + + config.action = _fakeAction + config._add_predicate('route', 'testing', DummyPredicate) + + def test_factory_as_dotted_name(self): + config = self._makeOne() + + def _fakeAction( + discriminator, + callable=None, + args=(), + kw=None, + order=0, + introspectables=(), + **extra + ): + self.assertEqual(len(introspectables), 1) + self.assertEqual(introspectables[0]['name'], 'testing') + self.assertEqual(introspectables[0]['factory'], DummyPredicate) + + config.action = _fakeAction + config._add_predicate( + 'route', 'testing', 'tests.test_config.test_init.DummyPredicate' + ) + + +class TestGlobalRegistriesIntegration(unittest.TestCase): + def setUp(self): + from pyramid.config import global_registries + + global_registries.empty() + + tearDown = setUp + + def _makeConfigurator(self, *arg, **kw): + from pyramid.config import Configurator + + config = Configurator(*arg, **kw) + return config + + def test_global_registries_empty(self): + from pyramid.config import global_registries + + self.assertEqual(global_registries.last, None) + + def test_global_registries(self): + from pyramid.config import global_registries + + config1 = self._makeConfigurator() + config1.make_wsgi_app() + self.assertEqual(global_registries.last, config1.registry) + config2 = self._makeConfigurator() + config2.make_wsgi_app() + self.assertEqual(global_registries.last, config2.registry) + self.assertEqual( + list(global_registries), [config1.registry, config2.registry] + ) + global_registries.remove(config2.registry) + self.assertEqual(global_registries.last, config1.registry) + + +class DummyRequest: + subpath = () + matchdict = None + request_iface = IRequest + + def __init__(self, environ=None): + if environ is None: + environ = {} + self.environ = environ + self.params = {} + self.cookies = {} + + +class DummyThreadLocalManager(object): + def __init__(self): + self.pushed = {'registry': None, 'request': None} + self.popped = False + + def push(self, d): + self.pushed = d + + def get(self): + return self.pushed + + def pop(self): + self.popped = True + + +class DummyRegistry(object): + def __init__(self, adaptation=None, util=None): + self.utilities = [] + self.adapters = [] + self.adaptation = adaptation + self.util = util + + def subscribers(self, events, name): + self.events = events + return events + + def registerUtility(self, *arg, **kw): + self.utilities.append((arg, kw)) + + def registerAdapter(self, *arg, **kw): + self.adapters.append((arg, kw)) + + def queryAdapter(self, *arg, **kw): + return self.adaptation + + def queryUtility(self, *arg, **kw): + return self.util + + +class DummyPredicate(object): + pass diff --git a/tests/test_config/test_predicates.py b/tests/test_config/test_predicates.py new file mode 100644 index 000000000..079652b39 --- /dev/null +++ b/tests/test_config/test_predicates.py @@ -0,0 +1,480 @@ +import unittest + +from pyramid.compat import text_ + + +class TestPredicateList(unittest.TestCase): + def _makeOne(self): + from pyramid.config.predicates import PredicateList + from pyramid import predicates + + inst = PredicateList() + for name, factory in ( + ('xhr', predicates.XHRPredicate), + ('request_method', predicates.RequestMethodPredicate), + ('path_info', predicates.PathInfoPredicate), + ('request_param', predicates.RequestParamPredicate), + ('header', predicates.HeaderPredicate), + ('accept', predicates.AcceptPredicate), + ('containment', predicates.ContainmentPredicate), + ('request_type', predicates.RequestTypePredicate), + ('match_param', predicates.MatchParamPredicate), + ('custom', predicates.CustomPredicate), + ('traverse', predicates.TraversePredicate), + ): + inst.add(name, factory) + return inst + + def _callFUT(self, **kw): + inst = self._makeOne() + config = DummyConfigurator() + return inst.make(config, **kw) + + def test_ordering_xhr_and_request_method_trump_only_containment(self): + order1, _, _ = self._callFUT(xhr=True, request_method='GET') + order2, _, _ = self._callFUT(containment=True) + self.assertTrue(order1 < order2) + + def test_ordering_number_of_predicates(self): + from pyramid.config.predicates import predvalseq + + order1, _, _ = self._callFUT( + xhr='xhr', + request_method='request_method', + path_info='path_info', + request_param='param', + match_param='foo=bar', + header='header', + accept='accept', + containment='containment', + request_type='request_type', + custom=predvalseq([DummyCustomPredicate()]), + ) + order2, _, _ = self._callFUT( + xhr='xhr', + request_method='request_method', + path_info='path_info', + request_param='param', + match_param='foo=bar', + header='header', + accept='accept', + containment='containment', + request_type='request_type', + custom=predvalseq([DummyCustomPredicate()]), + ) + order3, _, _ = self._callFUT( + xhr='xhr', + request_method='request_method', + path_info='path_info', + request_param='param', + match_param='foo=bar', + header='header', + accept='accept', + containment='containment', + request_type='request_type', + ) + order4, _, _ = self._callFUT( + xhr='xhr', + request_method='request_method', + path_info='path_info', + request_param='param', + match_param='foo=bar', + header='header', + accept='accept', + containment='containment', + ) + order5, _, _ = self._callFUT( + xhr='xhr', + request_method='request_method', + path_info='path_info', + request_param='param', + match_param='foo=bar', + header='header', + accept='accept', + ) + order6, _, _ = self._callFUT( + xhr='xhr', + request_method='request_method', + path_info='path_info', + request_param='param', + match_param='foo=bar', + header='header', + ) + order7, _, _ = self._callFUT( + xhr='xhr', + request_method='request_method', + path_info='path_info', + request_param='param', + match_param='foo=bar', + ) + order8, _, _ = self._callFUT( + xhr='xhr', + request_method='request_method', + path_info='path_info', + request_param='param', + ) + order9, _, _ = self._callFUT( + xhr='xhr', request_method='request_method', path_info='path_info' + ) + order10, _, _ = self._callFUT( + xhr='xhr', request_method='request_method' + ) + order11, _, _ = self._callFUT(xhr='xhr') + order12, _, _ = self._callFUT() + self.assertEqual(order1, order2) + self.assertTrue(order3 > order2) + self.assertTrue(order4 > order3) + self.assertTrue(order5 > order4) + self.assertTrue(order6 > order5) + self.assertTrue(order7 > order6) + self.assertTrue(order8 > order7) + self.assertTrue(order9 > order8) + self.assertTrue(order10 > order9) + self.assertTrue(order11 > order10) + self.assertTrue(order12 > order10) + + def test_ordering_importance_of_predicates(self): + from pyramid.config.predicates import predvalseq + + order1, _, _ = self._callFUT(xhr='xhr') + order2, _, _ = self._callFUT(request_method='request_method') + order3, _, _ = self._callFUT(path_info='path_info') + order4, _, _ = self._callFUT(request_param='param') + order5, _, _ = self._callFUT(header='header') + order6, _, _ = self._callFUT(accept='accept') + order7, _, _ = self._callFUT(containment='containment') + order8, _, _ = self._callFUT(request_type='request_type') + order9, _, _ = self._callFUT(match_param='foo=bar') + order10, _, _ = self._callFUT( + custom=predvalseq([DummyCustomPredicate()]) + ) + self.assertTrue(order1 > order2) + self.assertTrue(order2 > order3) + self.assertTrue(order3 > order4) + self.assertTrue(order4 > order5) + self.assertTrue(order5 > order6) + self.assertTrue(order6 > order7) + self.assertTrue(order7 > order8) + self.assertTrue(order8 > order9) + self.assertTrue(order9 > order10) + + def test_ordering_importance_and_number(self): + from pyramid.config.predicates import predvalseq + + order1, _, _ = self._callFUT( + xhr='xhr', request_method='request_method' + ) + order2, _, _ = self._callFUT( + custom=predvalseq([DummyCustomPredicate()]) + ) + self.assertTrue(order1 < order2) + + order1, _, _ = self._callFUT( + xhr='xhr', request_method='request_method' + ) + order2, _, _ = self._callFUT( + request_method='request_method', + custom=predvalseq([DummyCustomPredicate()]), + ) + self.assertTrue(order1 > order2) + + order1, _, _ = self._callFUT( + xhr='xhr', request_method='request_method', path_info='path_info' + ) + order2, _, _ = self._callFUT( + request_method='request_method', + custom=predvalseq([DummyCustomPredicate()]), + ) + self.assertTrue(order1 < order2) + + order1, _, _ = self._callFUT( + xhr='xhr', request_method='request_method', path_info='path_info' + ) + order2, _, _ = self._callFUT( + xhr='xhr', + request_method='request_method', + custom=predvalseq([DummyCustomPredicate()]), + ) + self.assertTrue(order1 > order2) + + def test_different_custom_predicates_with_same_hash(self): + from pyramid.config.predicates import predvalseq + + class PredicateWithHash(object): + def __hash__(self): + return 1 + + a = PredicateWithHash() + b = PredicateWithHash() + _, _, a_phash = self._callFUT(custom=predvalseq([a])) + _, _, b_phash = self._callFUT(custom=predvalseq([b])) + self.assertEqual(a_phash, b_phash) + + def test_traverse_has_remainder_already(self): + order, predicates, phash = self._callFUT(traverse='/1/:a/:b') + self.assertEqual(len(predicates), 1) + pred = predicates[0] + info = {'traverse': 'abc'} + request = DummyRequest() + result = pred(info, request) + self.assertEqual(result, True) + self.assertEqual(info, {'traverse': 'abc'}) + + def test_traverse_matches(self): + order, predicates, phash = self._callFUT(traverse='/1/:a/:b') + self.assertEqual(len(predicates), 1) + pred = predicates[0] + info = {'match': {'a': 'a', 'b': 'b'}} + request = DummyRequest() + result = pred(info, request) + self.assertEqual(result, True) + self.assertEqual( + info, {'match': {'a': 'a', 'b': 'b', 'traverse': ('1', 'a', 'b')}} + ) + + def test_traverse_matches_with_highorder_chars(self): + order, predicates, phash = self._callFUT( + traverse=text_(b'/La Pe\xc3\xb1a/{x}', 'utf-8') + ) + self.assertEqual(len(predicates), 1) + pred = predicates[0] + info = {'match': {'x': text_(b'Qu\xc3\xa9bec', 'utf-8')}} + request = DummyRequest() + result = pred(info, request) + self.assertEqual(result, True) + self.assertEqual( + info['match']['traverse'], + ( + text_(b'La Pe\xc3\xb1a', 'utf-8'), + text_(b'Qu\xc3\xa9bec', 'utf-8'), + ), + ) + + def test_custom_predicates_can_affect_traversal(self): + from pyramid.config.predicates import predvalseq + + def custom(info, request): + m = info['match'] + m['dummy'] = 'foo' + return True + + _, predicates, _ = self._callFUT( + custom=predvalseq([custom]), traverse='/1/:dummy/:a' + ) + self.assertEqual(len(predicates), 2) + info = {'match': {'a': 'a'}} + request = DummyRequest() + self.assertTrue(all([p(info, request) for p in predicates])) + self.assertEqual( + info, + { + 'match': { + 'a': 'a', + 'dummy': 'foo', + 'traverse': ('1', 'foo', 'a'), + } + }, + ) + + def test_predicate_text_is_correct(self): + from pyramid.config.predicates import predvalseq + + _, predicates, _ = self._callFUT( + xhr='xhr', + request_method='request_method', + path_info='path_info', + request_param='param', + header='header', + accept='accept', + containment='containment', + request_type='request_type', + custom=predvalseq( + [ + DummyCustomPredicate(), + DummyCustomPredicate.classmethod_predicate, + DummyCustomPredicate.classmethod_predicate_no_text, + ] + ), + match_param='foo=bar', + ) + self.assertEqual(predicates[0].text(), 'xhr = True') + self.assertEqual( + predicates[1].text(), "request_method = request_method" + ) + self.assertEqual(predicates[2].text(), 'path_info = path_info') + self.assertEqual(predicates[3].text(), 'request_param param') + self.assertEqual(predicates[4].text(), 'header header') + self.assertEqual(predicates[5].text(), 'accept = accept') + self.assertEqual(predicates[6].text(), 'containment = containment') + self.assertEqual(predicates[7].text(), 'request_type = request_type') + self.assertEqual(predicates[8].text(), "match_param foo=bar") + self.assertEqual(predicates[9].text(), 'custom predicate') + self.assertEqual(predicates[10].text(), 'classmethod predicate') + self.assertTrue(predicates[11].text().startswith('custom predicate')) + + def test_match_param_from_string(self): + _, predicates, _ = self._callFUT(match_param='foo=bar') + request = DummyRequest() + request.matchdict = {'foo': 'bar', 'baz': 'bum'} + self.assertTrue(predicates[0](Dummy(), request)) + + def test_match_param_from_string_fails(self): + _, predicates, _ = self._callFUT(match_param='foo=bar') + request = DummyRequest() + request.matchdict = {'foo': 'bum', 'baz': 'bum'} + self.assertFalse(predicates[0](Dummy(), request)) + + def test_match_param_from_dict(self): + _, predicates, _ = self._callFUT(match_param=('foo=bar', 'baz=bum')) + request = DummyRequest() + request.matchdict = {'foo': 'bar', 'baz': 'bum'} + self.assertTrue(predicates[0](Dummy(), request)) + + def test_match_param_from_dict_fails(self): + _, predicates, _ = self._callFUT(match_param=('foo=bar', 'baz=bum')) + request = DummyRequest() + request.matchdict = {'foo': 'bar', 'baz': 'foo'} + self.assertFalse(predicates[0](Dummy(), request)) + + def test_request_method_sequence(self): + _, predicates, _ = self._callFUT(request_method=('GET', 'HEAD')) + request = DummyRequest() + request.method = 'HEAD' + self.assertTrue(predicates[0](Dummy(), request)) + request.method = 'GET' + self.assertTrue(predicates[0](Dummy(), request)) + request.method = 'POST' + self.assertFalse(predicates[0](Dummy(), request)) + + def test_request_method_ordering_hashes_same(self): + hash1, _, __ = self._callFUT(request_method=('GET', 'HEAD')) + hash2, _, __ = self._callFUT(request_method=('HEAD', 'GET')) + self.assertEqual(hash1, hash2) + hash1, _, __ = self._callFUT(request_method=('GET',)) + hash2, _, __ = self._callFUT(request_method='GET') + self.assertEqual(hash1, hash2) + + def test_unknown_predicate(self): + from pyramid.exceptions import ConfigurationError + + self.assertRaises(ConfigurationError, self._callFUT, unknown=1) + + def test_predicate_close_matches(self): + from pyramid.exceptions import ConfigurationError + + with self.assertRaises(ConfigurationError) as context: + self._callFUT(method='GET') + expected_msg = ( + "Unknown predicate values: {'method': 'GET'} " + "(did you mean request_method)" + ) + self.assertEqual(context.exception.args[0], expected_msg) + + def test_notted(self): + from pyramid.config import not_ + from pyramid.testing import DummyRequest + + request = DummyRequest() + _, predicates, _ = self._callFUT( + xhr='xhr', request_method=not_('POST'), header=not_('header') + ) + self.assertEqual(predicates[0].text(), 'xhr = True') + self.assertEqual(predicates[1].text(), "!request_method = POST") + self.assertEqual(predicates[2].text(), '!header header') + self.assertEqual(predicates[1](None, request), True) + self.assertEqual(predicates[2](None, request), True) + + +class Test_sort_accept_offers(unittest.TestCase): + def _callFUT(self, offers, order=None): + from pyramid.config.predicates import sort_accept_offers + + return sort_accept_offers(offers, order) + + def test_default_specificities(self): + result = self._callFUT(['text/html', 'text/html;charset=utf8']) + self.assertEqual(result, ['text/html;charset=utf8', 'text/html']) + + def test_specific_type_order(self): + result = self._callFUT( + [ + 'text/html', + 'application/json', + 'text/html;charset=utf8', + 'text/plain', + ], + ['application/json', 'text/html'], + ) + self.assertEqual( + result, + [ + 'application/json', + 'text/html;charset=utf8', + 'text/html', + 'text/plain', + ], + ) + + def test_params_order(self): + result = self._callFUT( + [ + 'text/html;charset=utf8', + 'text/html;charset=latin1', + 'text/html;foo=bar', + ], + ['text/html;charset=latin1', 'text/html;charset=utf8'], + ) + self.assertEqual( + result, + [ + 'text/html;charset=latin1', + 'text/html;charset=utf8', + 'text/html;foo=bar', + ], + ) + + def test_params_inherit_type_prefs(self): + result = self._callFUT( + ['text/html;charset=utf8', 'text/plain;charset=latin1'], + ['text/plain', 'text/html'], + ) + self.assertEqual( + result, ['text/plain;charset=latin1', 'text/html;charset=utf8'] + ) + + +class DummyCustomPredicate(object): + def __init__(self): + self.__text__ = 'custom predicate' + + def classmethod_predicate(*args): # pragma: no cover + pass + + classmethod_predicate.__text__ = 'classmethod predicate' + classmethod_predicate = classmethod(classmethod_predicate) + + @classmethod + def classmethod_predicate_no_text(*args): + pass # pragma: no cover + + +class Dummy(object): + def __init__(self, **kw): + self.__dict__.update(**kw) + + +class DummyRequest: + subpath = () + matchdict = None + + def __init__(self, environ=None): + if environ is None: + environ = {} + self.environ = environ + self.params = {} + self.cookies = {} + + +class DummyConfigurator(object): + def maybe_dotted(self, thing): + return thing diff --git a/tests/test_config/test_rendering.py b/tests/test_config/test_rendering.py new file mode 100644 index 000000000..a33977c28 --- /dev/null +++ b/tests/test_config/test_rendering.py @@ -0,0 +1,43 @@ +import unittest + + +class TestRenderingConfiguratorMixin(unittest.TestCase): + def _makeOne(self, *arg, **kw): + from pyramid.config import Configurator + + config = Configurator(*arg, **kw) + return config + + def test_add_default_renderers(self): + from pyramid.config.rendering import DEFAULT_RENDERERS + from pyramid.interfaces import IRendererFactory + + config = self._makeOne(autocommit=True) + config.add_default_renderers() + for name, impl in DEFAULT_RENDERERS: + self.assertTrue( + config.registry.queryUtility(IRendererFactory, name) + is not None + ) + + def test_add_renderer(self): + from pyramid.interfaces import IRendererFactory + + config = self._makeOne(autocommit=True) + renderer = object() + config.add_renderer('name', renderer) + self.assertEqual( + config.registry.getUtility(IRendererFactory, 'name'), renderer + ) + + def test_add_renderer_dottedname_factory(self): + from pyramid.interfaces import IRendererFactory + + config = self._makeOne(autocommit=True) + import tests.test_config + + config.add_renderer('name', 'tests.test_config') + self.assertEqual( + config.registry.getUtility(IRendererFactory, 'name'), + tests.test_config, + ) diff --git a/tests/test_config/test_routes.py b/tests/test_config/test_routes.py new file mode 100644 index 000000000..1c1ed6700 --- /dev/null +++ b/tests/test_config/test_routes.py @@ -0,0 +1,322 @@ +import unittest + +from . import dummyfactory +from . import DummyContext +from pyramid.compat import text_ + + +class RoutesConfiguratorMixinTests(unittest.TestCase): + def _makeOne(self, *arg, **kw): + from pyramid.config import Configurator + + config = Configurator(*arg, **kw) + return config + + def _assertRoute(self, config, name, path, num_predicates=0): + from pyramid.interfaces import IRoutesMapper + + mapper = config.registry.getUtility(IRoutesMapper) + routes = mapper.get_routes() + route = routes[0] + self.assertEqual(len(routes), 1) + self.assertEqual(route.name, name) + self.assertEqual(route.path, path) + self.assertEqual(len(routes[0].predicates), num_predicates) + return route + + def _makeRequest(self, config): + request = DummyRequest() + request.registry = config.registry + return request + + def test_get_routes_mapper_not_yet_registered(self): + config = self._makeOne() + mapper = config.get_routes_mapper() + self.assertEqual(mapper.routelist, []) + + def test_get_routes_mapper_already_registered(self): + from pyramid.interfaces import IRoutesMapper + + config = self._makeOne() + mapper = object() + config.registry.registerUtility(mapper, IRoutesMapper) + result = config.get_routes_mapper() + self.assertEqual(result, mapper) + + def test_add_route_defaults(self): + config = self._makeOne(autocommit=True) + config.add_route('name', 'path') + self._assertRoute(config, 'name', 'path') + + def test_add_route_with_route_prefix(self): + config = self._makeOne(autocommit=True) + config.route_prefix = 'root' + config.add_route('name', 'path') + self._assertRoute(config, 'name', 'root/path') + + def test_add_route_with_empty_string_with_route_prefix(self): + config = self._makeOne(autocommit=True) + config.route_prefix = 'root' + config.add_route('name', '') + self._assertRoute(config, 'name', 'root') + + def test_add_route_with_root_slash_with_route_prefix(self): + config = self._makeOne(autocommit=True) + config.route_prefix = 'root' + config.add_route('name', '/') + self._assertRoute(config, 'name', 'root/') + + def test_add_route_discriminator(self): + config = self._makeOne() + config.add_route('name', 'path') + self.assertEqual( + config.action_state.actions[-1]['discriminator'], ('route', 'name') + ) + + def test_add_route_with_factory(self): + config = self._makeOne(autocommit=True) + factory = object() + config.add_route('name', 'path', factory=factory) + route = self._assertRoute(config, 'name', 'path') + self.assertEqual(route.factory, factory) + + def test_add_route_with_static(self): + config = self._makeOne(autocommit=True) + config.add_route('name', 'path/{foo}', static=True) + mapper = config.get_routes_mapper() + self.assertEqual(len(mapper.get_routes()), 0) + self.assertEqual(mapper.generate('name', {"foo": "a"}), '/path/a') + + def test_add_route_with_factory_dottedname(self): + config = self._makeOne(autocommit=True) + config.add_route( + 'name', 'path', factory='tests.test_config.dummyfactory' + ) + route = self._assertRoute(config, 'name', 'path') + self.assertEqual(route.factory, dummyfactory) + + def test_add_route_with_xhr(self): + config = self._makeOne(autocommit=True) + config.add_route('name', 'path', xhr=True) + route = self._assertRoute(config, 'name', 'path', 1) + predicate = route.predicates[0] + request = self._makeRequest(config) + request.is_xhr = True + self.assertEqual(predicate(None, request), True) + request = self._makeRequest(config) + request.is_xhr = False + self.assertEqual(predicate(None, request), False) + + def test_add_route_with_request_method(self): + config = self._makeOne(autocommit=True) + config.add_route('name', 'path', request_method='GET') + route = self._assertRoute(config, 'name', 'path', 1) + predicate = route.predicates[0] + request = self._makeRequest(config) + request.method = 'GET' + self.assertEqual(predicate(None, request), True) + request = self._makeRequest(config) + request.method = 'POST' + self.assertEqual(predicate(None, request), False) + + def test_add_route_with_path_info(self): + config = self._makeOne(autocommit=True) + config.add_route('name', 'path', path_info='/foo') + route = self._assertRoute(config, 'name', 'path', 1) + predicate = route.predicates[0] + request = self._makeRequest(config) + request.upath_info = '/foo' + self.assertEqual(predicate(None, request), True) + request = self._makeRequest(config) + request.upath_info = '/' + self.assertEqual(predicate(None, request), False) + + def test_add_route_with_path_info_highorder(self): + config = self._makeOne(autocommit=True) + config.add_route( + 'name', 'path', path_info=text_(b'/La Pe\xc3\xb1a', 'utf-8') + ) + route = self._assertRoute(config, 'name', 'path', 1) + predicate = route.predicates[0] + request = self._makeRequest(config) + request.upath_info = text_(b'/La Pe\xc3\xb1a', 'utf-8') + self.assertEqual(predicate(None, request), True) + request = self._makeRequest(config) + request.upath_info = text_('/') + self.assertEqual(predicate(None, request), False) + + def test_add_route_with_path_info_regex(self): + config = self._makeOne(autocommit=True) + config.add_route( + 'name', 'path', path_info=text_(br'/La Pe\w*', 'utf-8') + ) + route = self._assertRoute(config, 'name', 'path', 1) + predicate = route.predicates[0] + request = self._makeRequest(config) + request.upath_info = text_(b'/La Pe\xc3\xb1a', 'utf-8') + self.assertEqual(predicate(None, request), True) + request = self._makeRequest(config) + request.upath_info = text_('/') + self.assertEqual(predicate(None, request), False) + + def test_add_route_with_request_param(self): + config = self._makeOne(autocommit=True) + config.add_route('name', 'path', request_param='abc') + route = self._assertRoute(config, 'name', 'path', 1) + predicate = route.predicates[0] + request = self._makeRequest(config) + request.params = {'abc': '123'} + self.assertEqual(predicate(None, request), True) + request = self._makeRequest(config) + request.params = {} + self.assertEqual(predicate(None, request), False) + + def test_add_route_with_custom_predicates(self): + import warnings + + config = self._makeOne(autocommit=True) + + def pred1(context, request): # pragma: no cover + pass + + def pred2(context, request): # pragma: no cover + pass + + with warnings.catch_warnings(record=True) as w: + warnings.filterwarnings('always') + config.add_route('name', 'path', custom_predicates=(pred1, pred2)) + self.assertEqual(len(w), 1) + route = self._assertRoute(config, 'name', 'path', 2) + self.assertEqual(len(route.predicates), 2) + + def test_add_route_with_header(self): + config = self._makeOne(autocommit=True) + config.add_route('name', 'path', header='Host') + route = self._assertRoute(config, 'name', 'path', 1) + predicate = route.predicates[0] + request = self._makeRequest(config) + request.headers = {'Host': 'example.com'} + self.assertEqual(predicate(None, request), True) + request = self._makeRequest(config) + request.headers = {} + self.assertEqual(predicate(None, request), False) + + def test_add_route_with_accept(self): + config = self._makeOne(autocommit=True) + config.add_route('name', 'path', accept='text/xml') + route = self._assertRoute(config, 'name', 'path', 1) + predicate = route.predicates[0] + request = self._makeRequest(config) + request.accept = DummyAccept('text/xml') + self.assertEqual(predicate(None, request), True) + request = self._makeRequest(config) + request.accept = DummyAccept('text/html') + self.assertEqual(predicate(None, request), False) + + def test_add_route_with_accept_list(self): + config = self._makeOne(autocommit=True) + config.add_route('name', 'path', accept=['text/xml', 'text/plain']) + route = self._assertRoute(config, 'name', 'path', 1) + predicate = route.predicates[0] + request = self._makeRequest(config) + request.accept = DummyAccept('text/xml') + self.assertEqual(predicate(None, request), True) + request = self._makeRequest(config) + request.accept = DummyAccept('text/plain') + self.assertEqual(predicate(None, request), True) + request = self._makeRequest(config) + request.accept = DummyAccept('text/html') + self.assertEqual(predicate(None, request), False) + + def test_add_route_with_wildcard_accept_raises(self): + config = self._makeOne(autocommit=True) + self.assertRaises( + ValueError, + lambda: config.add_route('name', 'path', accept='text/*'), + ) + + def test_add_route_no_pattern_with_path(self): + config = self._makeOne(autocommit=True) + config.add_route('name', path='path') + self._assertRoute(config, 'name', 'path') + + def test_add_route_no_path_no_pattern(self): + from pyramid.exceptions import ConfigurationError + + config = self._makeOne() + self.assertRaises(ConfigurationError, config.add_route, 'name') + + def test_add_route_with_pregenerator(self): + config = self._makeOne(autocommit=True) + config.add_route('name', 'pattern', pregenerator='123') + route = self._assertRoute(config, 'name', 'pattern') + self.assertEqual(route.pregenerator, '123') + + def test_add_route_no_view_with_view_attr(self): + config = self._makeOne(autocommit=True) + from pyramid.exceptions import ConfigurationError + + try: + config.add_route('name', '/pattern', view_attr='abc') + except ConfigurationError: + pass + else: # pragma: no cover + raise AssertionError + + def test_add_route_no_view_with_view_context(self): + config = self._makeOne(autocommit=True) + from pyramid.exceptions import ConfigurationError + + try: + config.add_route('name', '/pattern', view_context=DummyContext) + except ConfigurationError: + pass + else: # pragma: no cover + raise AssertionError + + def test_add_route_no_view_with_view_permission(self): + config = self._makeOne(autocommit=True) + from pyramid.exceptions import ConfigurationError + + try: + config.add_route('name', '/pattern', view_permission='edit') + except ConfigurationError: + pass + else: # pragma: no cover + raise AssertionError + + def test_add_route_no_view_with_view_renderer(self): + config = self._makeOne(autocommit=True) + from pyramid.exceptions import ConfigurationError + + try: + config.add_route('name', '/pattern', view_renderer='json') + except ConfigurationError: + pass + else: # pragma: no cover + raise AssertionError + + +class DummyRequest: + subpath = () + matchdict = None + + def __init__(self, environ=None): + if environ is None: + environ = {} + self.environ = environ + self.params = {} + self.cookies = {} + + +class DummyAccept(object): + def __init__(self, *matches, **kw): + self.matches = list(matches) + self.contains = kw.pop('contains', False) + + def acceptable_offers(self, offers): + results = [] + for match in self.matches: + if match in offers: + results.append((match, 1.0)) + return results diff --git a/tests/test_config/test_security.py b/tests/test_config/test_security.py new file mode 100644 index 000000000..5ebd78f8d --- /dev/null +++ b/tests/test_config/test_security.py @@ -0,0 +1,151 @@ +import unittest + +from pyramid.exceptions import ConfigurationExecutionError +from pyramid.exceptions import ConfigurationError + + +class ConfiguratorSecurityMethodsTests(unittest.TestCase): + def _makeOne(self, *arg, **kw): + from pyramid.config import Configurator + + config = Configurator(*arg, **kw) + return config + + def test_set_authentication_policy_no_authz_policy(self): + config = self._makeOne() + policy = object() + config.set_authentication_policy(policy) + self.assertRaises(ConfigurationExecutionError, config.commit) + + def test_set_authentication_policy_no_authz_policy_autocommit(self): + config = self._makeOne(autocommit=True) + policy = object() + self.assertRaises( + ConfigurationError, config.set_authentication_policy, policy + ) + + def test_set_authentication_policy_with_authz_policy(self): + from pyramid.interfaces import IAuthenticationPolicy + from pyramid.interfaces import IAuthorizationPolicy + + config = self._makeOne() + authn_policy = object() + authz_policy = object() + config.registry.registerUtility(authz_policy, IAuthorizationPolicy) + config.set_authentication_policy(authn_policy) + config.commit() + self.assertEqual( + config.registry.getUtility(IAuthenticationPolicy), authn_policy + ) + + def test_set_authentication_policy_with_authz_policy_autocommit(self): + from pyramid.interfaces import IAuthenticationPolicy + from pyramid.interfaces import IAuthorizationPolicy + + config = self._makeOne(autocommit=True) + authn_policy = object() + authz_policy = object() + config.registry.registerUtility(authz_policy, IAuthorizationPolicy) + config.set_authentication_policy(authn_policy) + config.commit() + self.assertEqual( + config.registry.getUtility(IAuthenticationPolicy), authn_policy + ) + + def test_set_authorization_policy_no_authn_policy(self): + config = self._makeOne() + policy = object() + config.set_authorization_policy(policy) + self.assertRaises(ConfigurationExecutionError, config.commit) + + def test_set_authorization_policy_no_authn_policy_autocommit(self): + from pyramid.interfaces import IAuthorizationPolicy + + config = self._makeOne(autocommit=True) + policy = object() + config.set_authorization_policy(policy) + self.assertEqual( + config.registry.getUtility(IAuthorizationPolicy), policy + ) + + def test_set_authorization_policy_with_authn_policy(self): + from pyramid.interfaces import IAuthorizationPolicy + from pyramid.interfaces import IAuthenticationPolicy + + config = self._makeOne() + authn_policy = object() + authz_policy = object() + config.registry.registerUtility(authn_policy, IAuthenticationPolicy) + config.set_authorization_policy(authz_policy) + config.commit() + self.assertEqual( + config.registry.getUtility(IAuthorizationPolicy), authz_policy + ) + + def test_set_authorization_policy_with_authn_policy_autocommit(self): + from pyramid.interfaces import IAuthorizationPolicy + from pyramid.interfaces import IAuthenticationPolicy + + config = self._makeOne(autocommit=True) + authn_policy = object() + authz_policy = object() + config.registry.registerUtility(authn_policy, IAuthenticationPolicy) + config.set_authorization_policy(authz_policy) + self.assertEqual( + config.registry.getUtility(IAuthorizationPolicy), authz_policy + ) + + def test_set_default_permission(self): + from pyramid.interfaces import IDefaultPermission + + config = self._makeOne(autocommit=True) + config.set_default_permission('view') + self.assertEqual( + config.registry.getUtility(IDefaultPermission), 'view' + ) + + def test_add_permission(self): + config = self._makeOne(autocommit=True) + config.add_permission('perm') + cat = config.registry.introspector.get_category('permissions') + self.assertEqual(len(cat), 1) + D = cat[0] + intr = D['introspectable'] + self.assertEqual(intr['value'], 'perm') + + def test_set_default_csrf_options(self): + from pyramid.interfaces import IDefaultCSRFOptions + + config = self._makeOne(autocommit=True) + config.set_default_csrf_options() + result = config.registry.getUtility(IDefaultCSRFOptions) + self.assertEqual(result.require_csrf, True) + self.assertEqual(result.token, 'csrf_token') + self.assertEqual(result.header, 'X-CSRF-Token') + self.assertEqual( + list(sorted(result.safe_methods)), + ['GET', 'HEAD', 'OPTIONS', 'TRACE'], + ) + self.assertTrue(result.callback is None) + + def test_changing_set_default_csrf_options(self): + from pyramid.interfaces import IDefaultCSRFOptions + + config = self._makeOne(autocommit=True) + + def callback(request): # pragma: no cover + return True + + config.set_default_csrf_options( + require_csrf=False, + token='DUMMY', + header=None, + safe_methods=('PUT',), + callback=callback, + ) + result = config.registry.getUtility(IDefaultCSRFOptions) + self.assertEqual(result.require_csrf, False) + self.assertEqual(result.token, 'DUMMY') + self.assertEqual(result.header, None) + self.assertEqual(list(sorted(result.safe_methods)), ['PUT']) + self.assertTrue(result.callback is callback) diff --git a/tests/test_config/test_settings.py b/tests/test_config/test_settings.py new file mode 100644 index 000000000..2fe769add --- /dev/null +++ b/tests/test_config/test_settings.py @@ -0,0 +1,635 @@ +import unittest + + +class TestSettingsConfiguratorMixin(unittest.TestCase): + def _makeOne(self, *arg, **kw): + from pyramid.config import Configurator + + config = Configurator(*arg, **kw) + return config + + def test__set_settings_as_None(self): + config = self._makeOne() + settings = config._set_settings(None) + self.assertTrue(settings) + + def test__set_settings_does_not_uses_original_dict(self): + config = self._makeOne() + dummy = {} + result = config._set_settings(dummy) + self.assertTrue(dummy is not result) + self.assertNotIn('pyramid.debug_all', dummy) + + def test__set_settings_as_dictwithvalues(self): + config = self._makeOne() + settings = config._set_settings({'a': '1'}) + self.assertEqual(settings['a'], '1') + + def test_get_settings_nosettings(self): + from pyramid.registry import Registry + + reg = Registry() + config = self._makeOne(reg) + self.assertEqual(config.get_settings(), None) + + def test_get_settings_withsettings(self): + settings = {'a': 1} + config = self._makeOne() + config.registry.settings = settings + self.assertEqual(config.get_settings(), settings) + + def test_add_settings_settings_already_registered(self): + from pyramid.registry import Registry + + reg = Registry() + config = self._makeOne(reg) + config._set_settings({'a': 1}) + config.add_settings({'b': 2}) + settings = reg.settings + self.assertEqual(settings['a'], 1) + self.assertEqual(settings['b'], 2) + + def test_add_settings_settings_not_yet_registered(self): + from pyramid.registry import Registry + from pyramid.interfaces import ISettings + + reg = Registry() + config = self._makeOne(reg) + config.add_settings({'a': 1}) + settings = reg.getUtility(ISettings) + self.assertEqual(settings['a'], 1) + + def test_add_settings_settings_None(self): + from pyramid.registry import Registry + from pyramid.interfaces import ISettings + + reg = Registry() + config = self._makeOne(reg) + config.add_settings(None, a=1) + settings = reg.getUtility(ISettings) + self.assertEqual(settings['a'], 1) + + def test_settings_parameter_dict_is_never_updated(self): + class ReadOnlyDict(dict): + def __readonly__(self, *args, **kwargs): # pragma: no cover + raise RuntimeError("Cannot modify ReadOnlyDict") + + __setitem__ = __readonly__ + __delitem__ = __readonly__ + pop = __readonly__ + popitem = __readonly__ + clear = __readonly__ + update = __readonly__ + setdefault = __readonly__ + del __readonly__ + + initial = ReadOnlyDict() + config = self._makeOne(settings=initial) + config._set_settings({'a': '1'}) + + +class TestSettings(unittest.TestCase): + def _getTargetClass(self): + from pyramid.config.settings import Settings + + return Settings + + def _makeOne(self, d=None, environ=None): + if environ is None: + environ = {} + klass = self._getTargetClass() + return klass(d, _environ_=environ) + + def test_noargs(self): + settings = self._makeOne() + self.assertEqual(settings['debug_authorization'], False) + self.assertEqual(settings['debug_notfound'], False) + self.assertEqual(settings['debug_routematch'], False) + self.assertEqual(settings['reload_templates'], False) + self.assertEqual(settings['reload_resources'], False) + + self.assertEqual(settings['pyramid.debug_authorization'], False) + self.assertEqual(settings['pyramid.debug_notfound'], False) + self.assertEqual(settings['pyramid.debug_routematch'], False) + self.assertEqual(settings['pyramid.reload_templates'], False) + self.assertEqual(settings['pyramid.reload_resources'], False) + + def test_prevent_http_cache(self): + settings = self._makeOne({}) + self.assertEqual(settings['prevent_http_cache'], False) + self.assertEqual(settings['pyramid.prevent_http_cache'], False) + result = self._makeOne({'prevent_http_cache': 'false'}) + self.assertEqual(result['prevent_http_cache'], False) + self.assertEqual(result['pyramid.prevent_http_cache'], False) + result = self._makeOne({'prevent_http_cache': 't'}) + self.assertEqual(result['prevent_http_cache'], True) + self.assertEqual(result['pyramid.prevent_http_cache'], True) + result = self._makeOne({'prevent_http_cache': '1'}) + self.assertEqual(result['prevent_http_cache'], True) + self.assertEqual(result['pyramid.prevent_http_cache'], True) + result = self._makeOne({'pyramid.prevent_http_cache': 't'}) + self.assertEqual(result['prevent_http_cache'], True) + self.assertEqual(result['pyramid.prevent_http_cache'], True) + result = self._makeOne({}, {'PYRAMID_PREVENT_HTTP_CACHE': '1'}) + self.assertEqual(result['prevent_http_cache'], True) + self.assertEqual(result['pyramid.prevent_http_cache'], True) + result = self._makeOne( + {'prevent_http_cache': 'false', 'pyramid.prevent_http_cache': '1'} + ) + self.assertEqual(result['prevent_http_cache'], True) + self.assertEqual(result['pyramid.prevent_http_cache'], True) + result = self._makeOne( + {'prevent_http_cache': 'false', 'pyramid.prevent_http_cache': 'f'}, + {'PYRAMID_PREVENT_HTTP_CACHE': '1'}, + ) + self.assertEqual(result['prevent_http_cache'], True) + self.assertEqual(result['pyramid.prevent_http_cache'], True) + + def test_prevent_cachebust(self): + settings = self._makeOne({}) + self.assertEqual(settings['prevent_cachebust'], False) + self.assertEqual(settings['pyramid.prevent_cachebust'], False) + result = self._makeOne({'prevent_cachebust': 'false'}) + self.assertEqual(result['prevent_cachebust'], False) + self.assertEqual(result['pyramid.prevent_cachebust'], False) + result = self._makeOne({'prevent_cachebust': 't'}) + self.assertEqual(result['prevent_cachebust'], True) + self.assertEqual(result['pyramid.prevent_cachebust'], True) + result = self._makeOne({'prevent_cachebust': '1'}) + self.assertEqual(result['prevent_cachebust'], True) + self.assertEqual(result['pyramid.prevent_cachebust'], True) + result = self._makeOne({'pyramid.prevent_cachebust': 't'}) + self.assertEqual(result['prevent_cachebust'], True) + self.assertEqual(result['pyramid.prevent_cachebust'], True) + result = self._makeOne({}, {'PYRAMID_PREVENT_CACHEBUST': '1'}) + self.assertEqual(result['prevent_cachebust'], True) + self.assertEqual(result['pyramid.prevent_cachebust'], True) + result = self._makeOne( + {'prevent_cachebust': 'false', 'pyramid.prevent_cachebust': '1'} + ) + self.assertEqual(result['prevent_cachebust'], True) + self.assertEqual(result['pyramid.prevent_cachebust'], True) + result = self._makeOne( + {'prevent_cachebust': 'false', 'pyramid.prevent_cachebust': 'f'}, + {'PYRAMID_PREVENT_CACHEBUST': '1'}, + ) + self.assertEqual(result['prevent_cachebust'], True) + self.assertEqual(result['pyramid.prevent_cachebust'], True) + + def test_reload_templates(self): + settings = self._makeOne({}) + self.assertEqual(settings['reload_templates'], False) + self.assertEqual(settings['pyramid.reload_templates'], False) + result = self._makeOne({'reload_templates': 'false'}) + self.assertEqual(result['reload_templates'], False) + self.assertEqual(result['pyramid.reload_templates'], False) + result = self._makeOne({'reload_templates': 't'}) + self.assertEqual(result['reload_templates'], True) + self.assertEqual(result['pyramid.reload_templates'], True) + result = self._makeOne({'reload_templates': '1'}) + self.assertEqual(result['reload_templates'], True) + self.assertEqual(result['pyramid.reload_templates'], True) + result = self._makeOne({'pyramid.reload_templates': '1'}) + self.assertEqual(result['reload_templates'], True) + self.assertEqual(result['pyramid.reload_templates'], True) + result = self._makeOne({}, {'PYRAMID_RELOAD_TEMPLATES': '1'}) + self.assertEqual(result['reload_templates'], True) + self.assertEqual(result['pyramid.reload_templates'], True) + result = self._makeOne( + {'reload_templates': 'false', 'pyramid.reload_templates': '1'} + ) + self.assertEqual(result['reload_templates'], True) + self.assertEqual(result['pyramid.reload_templates'], True) + result = self._makeOne( + {'reload_templates': 'false'}, {'PYRAMID_RELOAD_TEMPLATES': '1'} + ) + self.assertEqual(result['reload_templates'], True) + self.assertEqual(result['pyramid.reload_templates'], True) + + def test_reload_resources(self): + # alias for reload_assets + result = self._makeOne({}) + self.assertEqual(result['reload_resources'], False) + self.assertEqual(result['reload_assets'], False) + self.assertEqual(result['pyramid.reload_resources'], False) + self.assertEqual(result['pyramid.reload_assets'], False) + result = self._makeOne({'reload_resources': 'false'}) + self.assertEqual(result['reload_resources'], False) + self.assertEqual(result['reload_assets'], False) + self.assertEqual(result['pyramid.reload_resources'], False) + self.assertEqual(result['pyramid.reload_assets'], False) + result = self._makeOne({'reload_resources': 't'}) + self.assertEqual(result['reload_resources'], True) + self.assertEqual(result['reload_assets'], True) + self.assertEqual(result['pyramid.reload_resources'], True) + self.assertEqual(result['pyramid.reload_assets'], True) + result = self._makeOne({'reload_resources': '1'}) + self.assertEqual(result['reload_resources'], True) + self.assertEqual(result['reload_assets'], True) + self.assertEqual(result['pyramid.reload_resources'], True) + self.assertEqual(result['pyramid.reload_assets'], True) + result = self._makeOne({'pyramid.reload_resources': '1'}) + self.assertEqual(result['reload_resources'], True) + self.assertEqual(result['reload_assets'], True) + self.assertEqual(result['pyramid.reload_resources'], True) + self.assertEqual(result['pyramid.reload_assets'], True) + result = self._makeOne({}, {'PYRAMID_RELOAD_RESOURCES': '1'}) + self.assertEqual(result['reload_resources'], True) + self.assertEqual(result['reload_assets'], True) + self.assertEqual(result['pyramid.reload_resources'], True) + self.assertEqual(result['pyramid.reload_assets'], True) + result = self._makeOne( + {'reload_resources': 'false', 'pyramid.reload_resources': '1'} + ) + self.assertEqual(result['reload_resources'], True) + self.assertEqual(result['reload_assets'], True) + self.assertEqual(result['pyramid.reload_resources'], True) + self.assertEqual(result['pyramid.reload_assets'], True) + result = self._makeOne( + {'reload_resources': 'false', 'pyramid.reload_resources': 'false'}, + {'PYRAMID_RELOAD_RESOURCES': '1'}, + ) + self.assertEqual(result['reload_resources'], True) + self.assertEqual(result['reload_assets'], True) + self.assertEqual(result['pyramid.reload_resources'], True) + self.assertEqual(result['pyramid.reload_assets'], True) + + def test_reload_assets(self): + # alias for reload_resources + result = self._makeOne({}) + self.assertEqual(result['reload_assets'], False) + self.assertEqual(result['reload_resources'], False) + self.assertEqual(result['pyramid.reload_assets'], False) + self.assertEqual(result['pyramid.reload_resources'], False) + result = self._makeOne({'reload_assets': 'false'}) + self.assertEqual(result['reload_resources'], False) + self.assertEqual(result['reload_assets'], False) + self.assertEqual(result['pyramid.reload_assets'], False) + self.assertEqual(result['pyramid.reload_resources'], False) + result = self._makeOne({'reload_assets': 't'}) + self.assertEqual(result['reload_assets'], True) + self.assertEqual(result['reload_resources'], True) + self.assertEqual(result['pyramid.reload_assets'], True) + self.assertEqual(result['pyramid.reload_resources'], True) + result = self._makeOne({'reload_assets': '1'}) + self.assertEqual(result['reload_assets'], True) + self.assertEqual(result['reload_resources'], True) + self.assertEqual(result['pyramid.reload_assets'], True) + self.assertEqual(result['pyramid.reload_resources'], True) + result = self._makeOne({'pyramid.reload_assets': '1'}) + self.assertEqual(result['reload_assets'], True) + self.assertEqual(result['reload_resources'], True) + self.assertEqual(result['pyramid.reload_assets'], True) + self.assertEqual(result['pyramid.reload_resources'], True) + result = self._makeOne({}, {'PYRAMID_RELOAD_ASSETS': '1'}) + self.assertEqual(result['reload_assets'], True) + self.assertEqual(result['reload_resources'], True) + self.assertEqual(result['pyramid.reload_assets'], True) + self.assertEqual(result['pyramid.reload_resources'], True) + result = self._makeOne( + {'reload_assets': 'false', 'pyramid.reload_assets': '1'} + ) + self.assertEqual(result['reload_assets'], True) + self.assertEqual(result['reload_resources'], True) + self.assertEqual(result['pyramid.reload_assets'], True) + self.assertEqual(result['pyramid.reload_resources'], True) + result = self._makeOne( + {'reload_assets': 'false', 'pyramid.reload_assets': 'false'}, + {'PYRAMID_RELOAD_ASSETS': '1'}, + ) + self.assertEqual(result['reload_assets'], True) + self.assertEqual(result['reload_resources'], True) + self.assertEqual(result['pyramid.reload_assets'], True) + self.assertEqual(result['pyramid.reload_resources'], True) + + def test_reload_all(self): + result = self._makeOne({}) + self.assertEqual(result['reload_templates'], False) + self.assertEqual(result['reload_resources'], False) + self.assertEqual(result['reload_assets'], False) + self.assertEqual(result['pyramid.reload_templates'], False) + self.assertEqual(result['pyramid.reload_resources'], False) + self.assertEqual(result['pyramid.reload_assets'], False) + result = self._makeOne({'reload_all': 'false'}) + self.assertEqual(result['reload_templates'], False) + self.assertEqual(result['reload_resources'], False) + self.assertEqual(result['reload_assets'], False) + self.assertEqual(result['pyramid.reload_templates'], False) + self.assertEqual(result['pyramid.reload_resources'], False) + self.assertEqual(result['pyramid.reload_assets'], False) + result = self._makeOne({'reload_all': 't'}) + self.assertEqual(result['reload_templates'], True) + self.assertEqual(result['reload_resources'], True) + self.assertEqual(result['reload_assets'], True) + self.assertEqual(result['pyramid.reload_templates'], True) + self.assertEqual(result['pyramid.reload_resources'], True) + self.assertEqual(result['pyramid.reload_assets'], True) + result = self._makeOne({'reload_all': '1'}) + self.assertEqual(result['reload_templates'], True) + self.assertEqual(result['reload_resources'], True) + self.assertEqual(result['reload_assets'], True) + self.assertEqual(result['pyramid.reload_templates'], True) + self.assertEqual(result['pyramid.reload_resources'], True) + self.assertEqual(result['pyramid.reload_assets'], True) + result = self._makeOne({'pyramid.reload_all': '1'}) + self.assertEqual(result['reload_templates'], True) + self.assertEqual(result['reload_resources'], True) + self.assertEqual(result['reload_assets'], True) + self.assertEqual(result['pyramid.reload_templates'], True) + self.assertEqual(result['pyramid.reload_resources'], True) + self.assertEqual(result['pyramid.reload_assets'], True) + result = self._makeOne({}, {'PYRAMID_RELOAD_ALL': '1'}) + self.assertEqual(result['reload_templates'], True) + self.assertEqual(result['reload_resources'], True) + self.assertEqual(result['reload_assets'], True) + self.assertEqual(result['pyramid.reload_templates'], True) + self.assertEqual(result['pyramid.reload_resources'], True) + self.assertEqual(result['pyramid.reload_assets'], True) + result = self._makeOne( + {'reload_all': 'false', 'pyramid.reload_all': '1'} + ) + self.assertEqual(result['reload_templates'], True) + self.assertEqual(result['reload_resources'], True) + self.assertEqual(result['reload_assets'], True) + self.assertEqual(result['pyramid.reload_templates'], True) + self.assertEqual(result['pyramid.reload_resources'], True) + self.assertEqual(result['pyramid.reload_assets'], True) + result = self._makeOne( + {'reload_all': 'false', 'pyramid.reload_all': 'false'}, + {'PYRAMID_RELOAD_ALL': '1'}, + ) + self.assertEqual(result['reload_templates'], True) + self.assertEqual(result['reload_resources'], True) + self.assertEqual(result['reload_assets'], True) + self.assertEqual(result['pyramid.reload_templates'], True) + self.assertEqual(result['pyramid.reload_resources'], True) + self.assertEqual(result['pyramid.reload_assets'], True) + + def test_debug_authorization(self): + result = self._makeOne({}) + self.assertEqual(result['debug_authorization'], False) + self.assertEqual(result['pyramid.debug_authorization'], False) + result = self._makeOne({'debug_authorization': 'false'}) + self.assertEqual(result['debug_authorization'], False) + self.assertEqual(result['pyramid.debug_authorization'], False) + result = self._makeOne({'debug_authorization': 't'}) + self.assertEqual(result['debug_authorization'], True) + self.assertEqual(result['pyramid.debug_authorization'], True) + result = self._makeOne({'debug_authorization': '1'}) + self.assertEqual(result['debug_authorization'], True) + self.assertEqual(result['pyramid.debug_authorization'], True) + result = self._makeOne({'pyramid.debug_authorization': '1'}) + self.assertEqual(result['debug_authorization'], True) + self.assertEqual(result['pyramid.debug_authorization'], True) + result = self._makeOne({}, {'PYRAMID_DEBUG_AUTHORIZATION': '1'}) + self.assertEqual(result['debug_authorization'], True) + self.assertEqual(result['pyramid.debug_authorization'], True) + result = self._makeOne( + { + 'debug_authorization': 'false', + 'pyramid.debug_authorization': '1', + } + ) + self.assertEqual(result['debug_authorization'], True) + self.assertEqual(result['pyramid.debug_authorization'], True) + result = self._makeOne( + { + 'debug_authorization': 'false', + 'pyramid.debug_authorization': 'false', + }, + {'PYRAMID_DEBUG_AUTHORIZATION': '1'}, + ) + self.assertEqual(result['debug_authorization'], True) + self.assertEqual(result['pyramid.debug_authorization'], True) + + def test_debug_notfound(self): + result = self._makeOne({}) + self.assertEqual(result['debug_notfound'], False) + self.assertEqual(result['pyramid.debug_notfound'], False) + result = self._makeOne({'debug_notfound': 'false'}) + self.assertEqual(result['debug_notfound'], False) + self.assertEqual(result['pyramid.debug_notfound'], False) + result = self._makeOne({'debug_notfound': 't'}) + self.assertEqual(result['debug_notfound'], True) + self.assertEqual(result['pyramid.debug_notfound'], True) + result = self._makeOne({'debug_notfound': '1'}) + self.assertEqual(result['debug_notfound'], True) + self.assertEqual(result['pyramid.debug_notfound'], True) + result = self._makeOne({'pyramid.debug_notfound': '1'}) + self.assertEqual(result['debug_notfound'], True) + self.assertEqual(result['pyramid.debug_notfound'], True) + result = self._makeOne({}, {'PYRAMID_DEBUG_NOTFOUND': '1'}) + self.assertEqual(result['debug_notfound'], True) + self.assertEqual(result['pyramid.debug_notfound'], True) + result = self._makeOne( + {'debug_notfound': 'false', 'pyramid.debug_notfound': '1'} + ) + self.assertEqual(result['debug_notfound'], True) + self.assertEqual(result['pyramid.debug_notfound'], True) + result = self._makeOne( + {'debug_notfound': 'false', 'pyramid.debug_notfound': 'false'}, + {'PYRAMID_DEBUG_NOTFOUND': '1'}, + ) + self.assertEqual(result['debug_notfound'], True) + self.assertEqual(result['pyramid.debug_notfound'], True) + + def test_debug_routematch(self): + result = self._makeOne({}) + self.assertEqual(result['debug_routematch'], False) + self.assertEqual(result['pyramid.debug_routematch'], False) + result = self._makeOne({'debug_routematch': 'false'}) + self.assertEqual(result['debug_routematch'], False) + self.assertEqual(result['pyramid.debug_routematch'], False) + result = self._makeOne({'debug_routematch': 't'}) + self.assertEqual(result['debug_routematch'], True) + self.assertEqual(result['pyramid.debug_routematch'], True) + result = self._makeOne({'debug_routematch': '1'}) + self.assertEqual(result['debug_routematch'], True) + self.assertEqual(result['pyramid.debug_routematch'], True) + result = self._makeOne({'pyramid.debug_routematch': '1'}) + self.assertEqual(result['debug_routematch'], True) + self.assertEqual(result['pyramid.debug_routematch'], True) + result = self._makeOne({}, {'PYRAMID_DEBUG_ROUTEMATCH': '1'}) + self.assertEqual(result['debug_routematch'], True) + self.assertEqual(result['pyramid.debug_routematch'], True) + result = self._makeOne( + {'debug_routematch': 'false', 'pyramid.debug_routematch': '1'} + ) + self.assertEqual(result['debug_routematch'], True) + self.assertEqual(result['pyramid.debug_routematch'], True) + result = self._makeOne( + {'debug_routematch': 'false', 'pyramid.debug_routematch': 'false'}, + {'PYRAMID_DEBUG_ROUTEMATCH': '1'}, + ) + self.assertEqual(result['debug_routematch'], True) + self.assertEqual(result['pyramid.debug_routematch'], True) + + def test_debug_templates(self): + result = self._makeOne({}) + self.assertEqual(result['debug_templates'], False) + self.assertEqual(result['pyramid.debug_templates'], False) + result = self._makeOne({'debug_templates': 'false'}) + self.assertEqual(result['debug_templates'], False) + self.assertEqual(result['pyramid.debug_templates'], False) + result = self._makeOne({'debug_templates': 't'}) + self.assertEqual(result['debug_templates'], True) + self.assertEqual(result['pyramid.debug_templates'], True) + result = self._makeOne({'debug_templates': '1'}) + self.assertEqual(result['debug_templates'], True) + self.assertEqual(result['pyramid.debug_templates'], True) + result = self._makeOne({'pyramid.debug_templates': '1'}) + self.assertEqual(result['debug_templates'], True) + self.assertEqual(result['pyramid.debug_templates'], True) + result = self._makeOne({}, {'PYRAMID_DEBUG_TEMPLATES': '1'}) + self.assertEqual(result['debug_templates'], True) + self.assertEqual(result['pyramid.debug_templates'], True) + result = self._makeOne( + {'debug_templates': 'false', 'pyramid.debug_templates': '1'} + ) + self.assertEqual(result['debug_templates'], True) + self.assertEqual(result['pyramid.debug_templates'], True) + result = self._makeOne( + {'debug_templates': 'false', 'pyramid.debug_templates': 'false'}, + {'PYRAMID_DEBUG_TEMPLATES': '1'}, + ) + self.assertEqual(result['debug_templates'], True) + self.assertEqual(result['pyramid.debug_templates'], True) + + def test_debug_all(self): + result = self._makeOne({}) + self.assertEqual(result['debug_notfound'], False) + self.assertEqual(result['debug_routematch'], False) + self.assertEqual(result['debug_authorization'], False) + self.assertEqual(result['debug_templates'], False) + self.assertEqual(result['pyramid.debug_notfound'], False) + self.assertEqual(result['pyramid.debug_routematch'], False) + self.assertEqual(result['pyramid.debug_authorization'], False) + self.assertEqual(result['pyramid.debug_templates'], False) + result = self._makeOne({'debug_all': 'false'}) + self.assertEqual(result['debug_notfound'], False) + self.assertEqual(result['debug_routematch'], False) + self.assertEqual(result['debug_authorization'], False) + self.assertEqual(result['debug_templates'], False) + self.assertEqual(result['pyramid.debug_notfound'], False) + self.assertEqual(result['pyramid.debug_routematch'], False) + self.assertEqual(result['pyramid.debug_authorization'], False) + self.assertEqual(result['pyramid.debug_templates'], False) + result = self._makeOne({'debug_all': 't'}) + self.assertEqual(result['debug_notfound'], True) + self.assertEqual(result['debug_routematch'], True) + self.assertEqual(result['debug_authorization'], True) + self.assertEqual(result['debug_templates'], True) + self.assertEqual(result['pyramid.debug_notfound'], True) + self.assertEqual(result['pyramid.debug_routematch'], True) + self.assertEqual(result['pyramid.debug_authorization'], True) + self.assertEqual(result['pyramid.debug_templates'], True) + result = self._makeOne({'debug_all': '1'}) + self.assertEqual(result['debug_notfound'], True) + self.assertEqual(result['debug_routematch'], True) + self.assertEqual(result['debug_authorization'], True) + self.assertEqual(result['debug_templates'], True) + self.assertEqual(result['pyramid.debug_notfound'], True) + self.assertEqual(result['pyramid.debug_routematch'], True) + self.assertEqual(result['pyramid.debug_authorization'], True) + self.assertEqual(result['pyramid.debug_templates'], True) + result = self._makeOne({'pyramid.debug_all': '1'}) + self.assertEqual(result['debug_notfound'], True) + self.assertEqual(result['debug_routematch'], True) + self.assertEqual(result['debug_authorization'], True) + self.assertEqual(result['debug_templates'], True) + self.assertEqual(result['pyramid.debug_notfound'], True) + self.assertEqual(result['pyramid.debug_routematch'], True) + self.assertEqual(result['pyramid.debug_authorization'], True) + self.assertEqual(result['pyramid.debug_templates'], True) + result = self._makeOne({}, {'PYRAMID_DEBUG_ALL': '1'}) + self.assertEqual(result['debug_notfound'], True) + self.assertEqual(result['debug_routematch'], True) + self.assertEqual(result['debug_authorization'], True) + self.assertEqual(result['debug_templates'], True) + self.assertEqual(result['pyramid.debug_notfound'], True) + self.assertEqual(result['pyramid.debug_routematch'], True) + self.assertEqual(result['pyramid.debug_authorization'], True) + self.assertEqual(result['pyramid.debug_templates'], True) + result = self._makeOne( + {'debug_all': 'false', 'pyramid.debug_all': '1'} + ) + self.assertEqual(result['debug_notfound'], True) + self.assertEqual(result['debug_routematch'], True) + self.assertEqual(result['debug_authorization'], True) + self.assertEqual(result['debug_templates'], True) + self.assertEqual(result['pyramid.debug_notfound'], True) + self.assertEqual(result['pyramid.debug_routematch'], True) + self.assertEqual(result['pyramid.debug_authorization'], True) + self.assertEqual(result['pyramid.debug_templates'], True) + result = self._makeOne( + {'debug_all': 'false', 'pyramid.debug_all': 'false'}, + {'PYRAMID_DEBUG_ALL': '1'}, + ) + self.assertEqual(result['debug_notfound'], True) + self.assertEqual(result['debug_routematch'], True) + self.assertEqual(result['debug_authorization'], True) + self.assertEqual(result['debug_templates'], True) + self.assertEqual(result['pyramid.debug_notfound'], True) + self.assertEqual(result['pyramid.debug_routematch'], True) + self.assertEqual(result['pyramid.debug_authorization'], True) + self.assertEqual(result['pyramid.debug_templates'], True) + + def test_default_locale_name(self): + result = self._makeOne({}) + self.assertEqual(result['default_locale_name'], 'en') + self.assertEqual(result['pyramid.default_locale_name'], 'en') + result = self._makeOne({'default_locale_name': 'abc'}) + self.assertEqual(result['default_locale_name'], 'abc') + self.assertEqual(result['pyramid.default_locale_name'], 'abc') + result = self._makeOne({'pyramid.default_locale_name': 'abc'}) + self.assertEqual(result['default_locale_name'], 'abc') + self.assertEqual(result['pyramid.default_locale_name'], 'abc') + result = self._makeOne({}, {'PYRAMID_DEFAULT_LOCALE_NAME': 'abc'}) + self.assertEqual(result['default_locale_name'], 'abc') + self.assertEqual(result['pyramid.default_locale_name'], 'abc') + result = self._makeOne( + { + 'default_locale_name': 'def', + 'pyramid.default_locale_name': 'abc', + } + ) + self.assertEqual(result['default_locale_name'], 'abc') + self.assertEqual(result['pyramid.default_locale_name'], 'abc') + result = self._makeOne( + { + 'default_locale_name': 'def', + 'pyramid.default_locale_name': 'ghi', + }, + {'PYRAMID_DEFAULT_LOCALE_NAME': 'abc'}, + ) + self.assertEqual(result['default_locale_name'], 'abc') + self.assertEqual(result['pyramid.default_locale_name'], 'abc') + + def test_csrf_trusted_origins(self): + result = self._makeOne({}) + self.assertEqual(result['pyramid.csrf_trusted_origins'], []) + result = self._makeOne({'pyramid.csrf_trusted_origins': 'example.com'}) + self.assertEqual( + result['pyramid.csrf_trusted_origins'], ['example.com'] + ) + result = self._makeOne( + {'pyramid.csrf_trusted_origins': ['example.com']} + ) + self.assertEqual( + result['pyramid.csrf_trusted_origins'], ['example.com'] + ) + result = self._makeOne( + { + 'pyramid.csrf_trusted_origins': ( + 'example.com foo.example.com\nasdf.example.com' + ) + } + ) + self.assertEqual( + result['pyramid.csrf_trusted_origins'], + ['example.com', 'foo.example.com', 'asdf.example.com'], + ) + + def test_originals_kept(self): + result = self._makeOne({'a': 'i am so a'}) + self.assertEqual(result['a'], 'i am so a') diff --git a/tests/test_config/test_testing.py b/tests/test_config/test_testing.py new file mode 100644 index 000000000..ede31e1b6 --- /dev/null +++ b/tests/test_config/test_testing.py @@ -0,0 +1,235 @@ +import unittest +from zope.interface import implementer + +from pyramid.compat import text_ +from pyramid.security import AuthenticationAPIMixin, AuthorizationAPIMixin +from . import IDummy + + +class TestingConfiguratorMixinTests(unittest.TestCase): + def _makeOne(self, *arg, **kw): + from pyramid.config import Configurator + + config = Configurator(*arg, **kw) + return config + + def test_testing_securitypolicy(self): + from pyramid.testing import DummySecurityPolicy + + config = self._makeOne(autocommit=True) + config.testing_securitypolicy( + 'user', ('group1', 'group2'), permissive=False + ) + from pyramid.interfaces import IAuthenticationPolicy + from pyramid.interfaces import IAuthorizationPolicy + + ut = config.registry.getUtility(IAuthenticationPolicy) + self.assertTrue(isinstance(ut, DummySecurityPolicy)) + ut = config.registry.getUtility(IAuthorizationPolicy) + self.assertEqual(ut.userid, 'user') + self.assertEqual(ut.groupids, ('group1', 'group2')) + self.assertEqual(ut.permissive, False) + + def test_testing_securitypolicy_remember_result(self): + from pyramid.security import remember + + config = self._makeOne(autocommit=True) + pol = config.testing_securitypolicy( + 'user', + ('group1', 'group2'), + permissive=False, + remember_result=True, + ) + request = DummyRequest() + request.registry = config.registry + val = remember(request, 'fred') + self.assertEqual(pol.remembered, 'fred') + self.assertEqual(val, True) + + def test_testing_securitypolicy_forget_result(self): + from pyramid.security import forget + + config = self._makeOne(autocommit=True) + pol = config.testing_securitypolicy( + 'user', ('group1', 'group2'), permissive=False, forget_result=True + ) + request = DummyRequest() + request.registry = config.registry + val = forget(request) + self.assertEqual(pol.forgotten, True) + self.assertEqual(val, True) + + def test_testing_resources(self): + from pyramid.traversal import find_resource + from pyramid.interfaces import ITraverser + + ob1 = object() + ob2 = object() + resources = {'/ob1': ob1, '/ob2': ob2} + config = self._makeOne(autocommit=True) + config.testing_resources(resources) + adapter = config.registry.getAdapter(None, ITraverser) + result = adapter(DummyRequest({'PATH_INFO': '/ob1'})) + self.assertEqual(result['context'], ob1) + self.assertEqual(result['view_name'], '') + self.assertEqual(result['subpath'], ()) + self.assertEqual(result['traversed'], (text_('ob1'),)) + self.assertEqual(result['virtual_root'], ob1) + self.assertEqual(result['virtual_root_path'], ()) + result = adapter(DummyRequest({'PATH_INFO': '/ob2'})) + self.assertEqual(result['context'], ob2) + self.assertEqual(result['view_name'], '') + self.assertEqual(result['subpath'], ()) + self.assertEqual(result['traversed'], (text_('ob2'),)) + self.assertEqual(result['virtual_root'], ob2) + self.assertEqual(result['virtual_root_path'], ()) + self.assertRaises( + KeyError, adapter, DummyRequest({'PATH_INFO': '/ob3'}) + ) + try: + config.begin() + self.assertEqual(find_resource(None, '/ob1'), ob1) + finally: + config.end() + + def test_testing_add_subscriber_single(self): + config = self._makeOne(autocommit=True) + L = config.testing_add_subscriber(IDummy) + event = DummyEvent() + config.registry.notify(event) + self.assertEqual(len(L), 1) + self.assertEqual(L[0], event) + config.registry.notify(object()) + self.assertEqual(len(L), 1) + + def test_testing_add_subscriber_dottedname(self): + config = self._makeOne(autocommit=True) + L = config.testing_add_subscriber('tests.test_config.IDummy') + event = DummyEvent() + config.registry.notify(event) + self.assertEqual(len(L), 1) + self.assertEqual(L[0], event) + config.registry.notify(object()) + self.assertEqual(len(L), 1) + + def test_testing_add_subscriber_multiple(self): + from zope.interface import Interface + + config = self._makeOne(autocommit=True) + L = config.testing_add_subscriber((Interface, IDummy)) + event = DummyEvent() + event.object = 'foo' + # the below is the equivalent of z.c.event.objectEventNotify(event) + config.registry.subscribers((event.object, event), None) + self.assertEqual(len(L), 2) + self.assertEqual(L[0], 'foo') + self.assertEqual(L[1], event) + + def test_testing_add_subscriber_defaults(self): + config = self._makeOne(autocommit=True) + L = config.testing_add_subscriber() + event = object() + config.registry.notify(event) + self.assertEqual(L[-1], event) + event2 = object() + config.registry.notify(event2) + self.assertEqual(L[-1], event2) + + def test_testing_add_renderer(self): + config = self._makeOne(autocommit=True) + renderer = config.testing_add_renderer('templates/foo.pt') + from pyramid.testing import DummyTemplateRenderer + + self.assertTrue(isinstance(renderer, DummyTemplateRenderer)) + from pyramid.renderers import render_to_response + + # must provide request to pass in registry (this is a functest) + request = DummyRequest() + request.registry = config.registry + render_to_response( + 'templates/foo.pt', {'foo': 1, 'bar': 2}, request=request + ) + renderer.assert_(foo=1) + renderer.assert_(bar=2) + renderer.assert_(request=request) + + def test_testing_add_renderer_twice(self): + config = self._makeOne(autocommit=True) + renderer1 = config.testing_add_renderer('templates/foo.pt') + renderer2 = config.testing_add_renderer('templates/bar.pt') + from pyramid.testing import DummyTemplateRenderer + + self.assertTrue(isinstance(renderer1, DummyTemplateRenderer)) + self.assertTrue(isinstance(renderer2, DummyTemplateRenderer)) + from pyramid.renderers import render_to_response + + # must provide request to pass in registry (this is a functest) + request = DummyRequest() + request.registry = config.registry + render_to_response( + 'templates/foo.pt', {'foo': 1, 'bar': 2}, request=request + ) + renderer1.assert_(foo=1) + renderer1.assert_(bar=2) + renderer1.assert_(request=request) + render_to_response( + 'templates/bar.pt', {'foo': 1, 'bar': 2}, request=request + ) + renderer2.assert_(foo=1) + renderer2.assert_(bar=2) + renderer2.assert_(request=request) + + def test_testing_add_renderer_explicitrenderer(self): + config = self._makeOne(autocommit=True) + + class E(Exception): + pass + + def renderer(kw, system): + self.assertEqual(kw, {'foo': 1, 'bar': 2}) + raise E + + renderer = config.testing_add_renderer('templates/foo.pt', renderer) + from pyramid.renderers import render_to_response + + # must provide request to pass in registry (this is a functest) + request = DummyRequest() + request.registry = config.registry + try: + render_to_response( + 'templates/foo.pt', {'foo': 1, 'bar': 2}, request=request + ) + except E: + pass + else: # pragma: no cover + raise AssertionError + + def test_testing_add_template(self): + config = self._makeOne(autocommit=True) + renderer = config.testing_add_template('templates/foo.pt') + from pyramid.testing import DummyTemplateRenderer + + self.assertTrue(isinstance(renderer, DummyTemplateRenderer)) + from pyramid.renderers import render_to_response + + # must provide request to pass in registry (this is a functest) + request = DummyRequest() + request.registry = config.registry + render_to_response( + 'templates/foo.pt', dict(foo=1, bar=2), request=request + ) + renderer.assert_(foo=1) + renderer.assert_(bar=2) + renderer.assert_(request=request) + + +@implementer(IDummy) +class DummyEvent: + pass + + +class DummyRequest(AuthenticationAPIMixin, AuthorizationAPIMixin): + def __init__(self, environ=None): + if environ is None: + environ = {} + self.environ = environ diff --git a/tests/test_config/test_tweens.py b/tests/test_config/test_tweens.py new file mode 100644 index 000000000..805310c9a --- /dev/null +++ b/tests/test_config/test_tweens.py @@ -0,0 +1,484 @@ +import unittest + +from . import dummy_tween_factory +from . import dummy_tween_factory2 + +from pyramid.exceptions import ConfigurationConflictError + + +class TestTweensConfiguratorMixin(unittest.TestCase): + def _makeOne(self, *arg, **kw): + from pyramid.config import Configurator + + config = Configurator(*arg, **kw) + return config + + def test_add_tweens_names_distinct(self): + from pyramid.interfaces import ITweens + from pyramid.tweens import excview_tween_factory + + def factory1(handler, registry): # pragma: no cover + return handler + + def factory2(handler, registry): # pragma: no cover + return handler + + config = self._makeOne() + config.add_tween('tests.test_config.dummy_tween_factory') + config.add_tween('tests.test_config.dummy_tween_factory2') + config.commit() + tweens = config.registry.queryUtility(ITweens) + implicit = tweens.implicit() + self.assertEqual( + implicit, + [ + ( + 'tests.test_config.dummy_tween_factory2', + dummy_tween_factory2, + ), + ('tests.test_config.dummy_tween_factory', dummy_tween_factory), + ( + 'pyramid.tweens.excview_tween_factory', + excview_tween_factory, + ), + ], + ) + + def test_add_tweens_names_with_underover(self): + from pyramid.interfaces import ITweens + from pyramid.tweens import excview_tween_factory + from pyramid.tweens import MAIN + + config = self._makeOne() + config.add_tween('tests.test_config.dummy_tween_factory', over=MAIN) + config.add_tween( + 'tests.test_config.dummy_tween_factory2', + over=MAIN, + under='tests.test_config.dummy_tween_factory', + ) + config.commit() + tweens = config.registry.queryUtility(ITweens) + implicit = tweens.implicit() + self.assertEqual( + implicit, + [ + ( + 'pyramid.tweens.excview_tween_factory', + excview_tween_factory, + ), + ('tests.test_config.dummy_tween_factory', dummy_tween_factory), + ( + 'tests.test_config.dummy_tween_factory2', + dummy_tween_factory2, + ), + ], + ) + + def test_add_tweens_names_with_under_nonstringoriter(self): + from pyramid.exceptions import ConfigurationError + + config = self._makeOne() + self.assertRaises( + ConfigurationError, + config.add_tween, + 'tests.test_config.dummy_tween_factory', + under=False, + ) + + def test_add_tweens_names_with_over_nonstringoriter(self): + from pyramid.exceptions import ConfigurationError + + config = self._makeOne() + self.assertRaises( + ConfigurationError, + config.add_tween, + 'tests.test_config.dummy_tween_factory', + over=False, + ) + + def test_add_tween_dottedname(self): + from pyramid.interfaces import ITweens + from pyramid.tweens import excview_tween_factory + + config = self._makeOne() + config.add_tween('tests.test_config.dummy_tween_factory') + config.commit() + tweens = config.registry.queryUtility(ITweens) + self.assertEqual( + tweens.implicit(), + [ + ('tests.test_config.dummy_tween_factory', dummy_tween_factory), + ( + 'pyramid.tweens.excview_tween_factory', + excview_tween_factory, + ), + ], + ) + + def test_add_tween_instance(self): + from pyramid.exceptions import ConfigurationError + + class ATween(object): + pass + + atween = ATween() + config = self._makeOne() + self.assertRaises(ConfigurationError, config.add_tween, atween) + + def test_add_tween_unsuitable(self): + from pyramid.exceptions import ConfigurationError + import tests.test_config + + config = self._makeOne() + self.assertRaises( + ConfigurationError, config.add_tween, tests.test_config + ) + + def test_add_tween_name_ingress(self): + from pyramid.exceptions import ConfigurationError + from pyramid.tweens import INGRESS + + config = self._makeOne() + self.assertRaises(ConfigurationError, config.add_tween, INGRESS) + + def test_add_tween_name_main(self): + from pyramid.exceptions import ConfigurationError + from pyramid.tweens import MAIN + + config = self._makeOne() + self.assertRaises(ConfigurationError, config.add_tween, MAIN) + + def test_add_tweens_conflict(self): + config = self._makeOne() + config.add_tween('tests.test_config.dummy_tween_factory') + config.add_tween('tests.test_config.dummy_tween_factory') + self.assertRaises(ConfigurationConflictError, config.commit) + + def test_add_tween_over_ingress(self): + from pyramid.exceptions import ConfigurationError + from pyramid.tweens import INGRESS + + config = self._makeOne() + self.assertRaises( + ConfigurationError, + config.add_tween, + 'tests.test_config.dummy_tween_factory', + over=INGRESS, + ) + + def test_add_tween_over_ingress_iterable(self): + from pyramid.exceptions import ConfigurationError + from pyramid.tweens import INGRESS + + config = self._makeOne() + self.assertRaises( + ConfigurationError, + config.add_tween, + 'tests.test_config.dummy_tween_factory', + over=('a', INGRESS), + ) + + def test_add_tween_under_main(self): + from pyramid.exceptions import ConfigurationError + from pyramid.tweens import MAIN + + config = self._makeOne() + self.assertRaises( + ConfigurationError, + config.add_tween, + 'tests.test_config.dummy_tween_factory', + under=MAIN, + ) + + def test_add_tween_under_main_iterable(self): + from pyramid.exceptions import ConfigurationError + from pyramid.tweens import MAIN + + config = self._makeOne() + self.assertRaises( + ConfigurationError, + config.add_tween, + 'tests.test_config.dummy_tween_factory', + under=('a', MAIN), + ) + + +class TestTweens(unittest.TestCase): + def _makeOne(self): + from pyramid.config.tweens import Tweens + + return Tweens() + + def test_add_explicit(self): + tweens = self._makeOne() + tweens.add_explicit('name', 'factory') + self.assertEqual(tweens.explicit, [('name', 'factory')]) + tweens.add_explicit('name2', 'factory2') + self.assertEqual( + tweens.explicit, [('name', 'factory'), ('name2', 'factory2')] + ) + + def test_add_implicit(self): + tweens = self._makeOne() + tweens.add_implicit('name', 'factory') + tweens.add_implicit('name2', 'factory2') + self.assertEqual( + tweens.sorter.sorted(), + [('name2', 'factory2'), ('name', 'factory')], + ) + + def test___call___explicit(self): + tweens = self._makeOne() + + def factory1(handler, registry): + return handler + + def factory2(handler, registry): + return '123' + + tweens.explicit = [('name', factory1), ('name', factory2)] + self.assertEqual(tweens(None, None), '123') + + def test___call___implicit(self): + tweens = self._makeOne() + + def factory1(handler, registry): + return handler + + def factory2(handler, registry): + return '123' + + tweens.add_implicit('name2', factory2) + tweens.add_implicit('name1', factory1) + self.assertEqual(tweens(None, None), '123') + + def test_implicit_ordering_1(self): + tweens = self._makeOne() + tweens.add_implicit('name1', 'factory1') + tweens.add_implicit('name2', 'factory2') + self.assertEqual( + tweens.implicit(), [('name2', 'factory2'), ('name1', 'factory1')] + ) + + def test_implicit_ordering_2(self): + from pyramid.tweens import MAIN + + tweens = self._makeOne() + tweens.add_implicit('name1', 'factory1') + tweens.add_implicit('name2', 'factory2', over=MAIN) + self.assertEqual( + tweens.implicit(), [('name1', 'factory1'), ('name2', 'factory2')] + ) + + def test_implicit_ordering_3(self): + from pyramid.tweens import MAIN + + tweens = self._makeOne() + add = tweens.add_implicit + add('auth', 'auth_factory', under='browserid') + add('dbt', 'dbt_factory') + add('retry', 'retry_factory', over='txnmgr', under='exceptionview') + add('browserid', 'browserid_factory') + add('txnmgr', 'txnmgr_factory', under='exceptionview') + add('exceptionview', 'excview_factory', over=MAIN) + self.assertEqual( + tweens.implicit(), + [ + ('browserid', 'browserid_factory'), + ('auth', 'auth_factory'), + ('dbt', 'dbt_factory'), + ('exceptionview', 'excview_factory'), + ('retry', 'retry_factory'), + ('txnmgr', 'txnmgr_factory'), + ], + ) + + def test_implicit_ordering_4(self): + from pyramid.tweens import MAIN + + tweens = self._makeOne() + add = tweens.add_implicit + add('exceptionview', 'excview_factory', over=MAIN) + add('auth', 'auth_factory', under='browserid') + add('retry', 'retry_factory', over='txnmgr', under='exceptionview') + add('browserid', 'browserid_factory') + add('txnmgr', 'txnmgr_factory', under='exceptionview') + add('dbt', 'dbt_factory') + self.assertEqual( + tweens.implicit(), + [ + ('dbt', 'dbt_factory'), + ('browserid', 'browserid_factory'), + ('auth', 'auth_factory'), + ('exceptionview', 'excview_factory'), + ('retry', 'retry_factory'), + ('txnmgr', 'txnmgr_factory'), + ], + ) + + def test_implicit_ordering_5(self): + from pyramid.tweens import MAIN, INGRESS + + tweens = self._makeOne() + add = tweens.add_implicit + add('exceptionview', 'excview_factory', over=MAIN) + add('auth', 'auth_factory', under=INGRESS) + add('retry', 'retry_factory', over='txnmgr', under='exceptionview') + add('browserid', 'browserid_factory', under=INGRESS) + add('txnmgr', 'txnmgr_factory', under='exceptionview', over=MAIN) + add('dbt', 'dbt_factory') + self.assertEqual( + tweens.implicit(), + [ + ('dbt', 'dbt_factory'), + ('browserid', 'browserid_factory'), + ('auth', 'auth_factory'), + ('exceptionview', 'excview_factory'), + ('retry', 'retry_factory'), + ('txnmgr', 'txnmgr_factory'), + ], + ) + + def test_implicit_ordering_missing_over_partial(self): + from pyramid.exceptions import ConfigurationError + + tweens = self._makeOne() + add = tweens.add_implicit + add('dbt', 'dbt_factory') + add('auth', 'auth_factory', under='browserid') + add('retry', 'retry_factory', over='txnmgr', under='exceptionview') + add('browserid', 'browserid_factory') + self.assertRaises(ConfigurationError, tweens.implicit) + + def test_implicit_ordering_missing_under_partial(self): + from pyramid.exceptions import ConfigurationError + + tweens = self._makeOne() + add = tweens.add_implicit + add('dbt', 'dbt_factory') + add('auth', 'auth_factory', under='txnmgr') + add('retry', 'retry_factory', over='dbt', under='exceptionview') + add('browserid', 'browserid_factory') + self.assertRaises(ConfigurationError, tweens.implicit) + + def test_implicit_ordering_missing_over_and_under_partials(self): + from pyramid.exceptions import ConfigurationError + + tweens = self._makeOne() + add = tweens.add_implicit + add('dbt', 'dbt_factory') + add('auth', 'auth_factory', under='browserid') + add('retry', 'retry_factory', over='foo', under='txnmgr') + add('browserid', 'browserid_factory') + self.assertRaises(ConfigurationError, tweens.implicit) + + def test_implicit_ordering_missing_over_partial_with_fallback(self): + from pyramid.tweens import MAIN + + tweens = self._makeOne() + add = tweens.add_implicit + add('exceptionview', 'excview_factory', over=MAIN) + add('auth', 'auth_factory', under='browserid') + add( + 'retry', + 'retry_factory', + over=('txnmgr', MAIN), + under='exceptionview', + ) + add('browserid', 'browserid_factory') + add('dbt', 'dbt_factory') + self.assertEqual( + tweens.implicit(), + [ + ('dbt', 'dbt_factory'), + ('browserid', 'browserid_factory'), + ('auth', 'auth_factory'), + ('exceptionview', 'excview_factory'), + ('retry', 'retry_factory'), + ], + ) + + def test_implicit_ordering_missing_under_partial_with_fallback(self): + from pyramid.tweens import MAIN + + tweens = self._makeOne() + add = tweens.add_implicit + add('exceptionview', 'excview_factory', over=MAIN) + add('auth', 'auth_factory', under=('txnmgr', 'browserid')) + add('retry', 'retry_factory', under='exceptionview') + add('browserid', 'browserid_factory') + add('dbt', 'dbt_factory') + self.assertEqual( + tweens.implicit(), + [ + ('dbt', 'dbt_factory'), + ('browserid', 'browserid_factory'), + ('auth', 'auth_factory'), + ('exceptionview', 'excview_factory'), + ('retry', 'retry_factory'), + ], + ) + + def test_implicit_ordering_with_partial_fallbacks(self): + from pyramid.tweens import MAIN + + tweens = self._makeOne() + add = tweens.add_implicit + add('exceptionview', 'excview_factory', over=('wontbethere', MAIN)) + add('retry', 'retry_factory', under='exceptionview') + add('browserid', 'browserid_factory', over=('wont2', 'exceptionview')) + self.assertEqual( + tweens.implicit(), + [ + ('browserid', 'browserid_factory'), + ('exceptionview', 'excview_factory'), + ('retry', 'retry_factory'), + ], + ) + + def test_implicit_ordering_with_multiple_matching_fallbacks(self): + from pyramid.tweens import MAIN + + tweens = self._makeOne() + add = tweens.add_implicit + add('exceptionview', 'excview_factory', over=MAIN) + add('retry', 'retry_factory', under='exceptionview') + add('browserid', 'browserid_factory', over=('retry', 'exceptionview')) + self.assertEqual( + tweens.implicit(), + [ + ('browserid', 'browserid_factory'), + ('exceptionview', 'excview_factory'), + ('retry', 'retry_factory'), + ], + ) + + def test_implicit_ordering_with_missing_fallbacks(self): + from pyramid.exceptions import ConfigurationError + from pyramid.tweens import MAIN + + tweens = self._makeOne() + add = tweens.add_implicit + add('exceptionview', 'excview_factory', over=MAIN) + add('retry', 'retry_factory', under='exceptionview') + add('browserid', 'browserid_factory', over=('txnmgr', 'auth')) + self.assertRaises(ConfigurationError, tweens.implicit) + + def test_implicit_ordering_conflict_direct(self): + from pyramid.exceptions import CyclicDependencyError + + tweens = self._makeOne() + add = tweens.add_implicit + add('browserid', 'browserid_factory') + add('auth', 'auth_factory', over='browserid', under='browserid') + self.assertRaises(CyclicDependencyError, tweens.implicit) + + def test_implicit_ordering_conflict_indirect(self): + from pyramid.exceptions import CyclicDependencyError + + tweens = self._makeOne() + add = tweens.add_implicit + add('browserid', 'browserid_factory') + add('auth', 'auth_factory', over='browserid') + add('dbt', 'dbt_factory', under='browserid', over='auth') + self.assertRaises(CyclicDependencyError, tweens.implicit) diff --git a/tests/test_config/test_views.py b/tests/test_config/test_views.py new file mode 100644 index 000000000..b72b9b36a --- /dev/null +++ b/tests/test_config/test_views.py @@ -0,0 +1,4360 @@ +import os +import unittest +from zope.interface import implementer + +from pyramid import testing +from pyramid.compat import im_func, text_ +from pyramid.exceptions import ConfigurationError +from pyramid.exceptions import ConfigurationExecutionError +from pyramid.exceptions import ConfigurationConflictError +from pyramid.interfaces import IResponse, IRequest, IMultiView + +from . import IDummy +from . import dummy_view + + +class TestViewsConfigurationMixin(unittest.TestCase): + def _makeOne(self, *arg, **kw): + from pyramid.config import Configurator + + config = Configurator(*arg, **kw) + config.set_default_csrf_options(require_csrf=False) + return config + + def _getViewCallable( + self, + config, + ctx_iface=None, + exc_iface=None, + request_iface=None, + name='', + ): + from zope.interface import Interface + from pyramid.interfaces import IRequest + from pyramid.interfaces import IView + from pyramid.interfaces import IViewClassifier + from pyramid.interfaces import IExceptionViewClassifier + + if exc_iface: + classifier = IExceptionViewClassifier + ctx_iface = exc_iface + else: + classifier = IViewClassifier + if ctx_iface is None: + ctx_iface = Interface + if request_iface is None: + request_iface = IRequest + return config.registry.adapters.lookup( + (classifier, request_iface, ctx_iface), + IView, + name=name, + default=None, + ) + + def _registerRenderer(self, config, name='.txt'): + from pyramid.interfaces import IRendererFactory + + class Renderer: + def __init__(self, info): + self.__class__.info = info + + def __call__(self, *arg): + return b'Hello!' + + config.registry.registerUtility(Renderer, IRendererFactory, name=name) + return Renderer + + def _makeRequest(self, config): + request = DummyRequest() + request.registry = config.registry + return request + + def _assertNotFound(self, wrapper, *arg): + from pyramid.httpexceptions import HTTPNotFound + + self.assertRaises(HTTPNotFound, wrapper, *arg) + + def _getRouteRequestIface(self, config, name): + from pyramid.interfaces import IRouteRequest + + iface = config.registry.getUtility(IRouteRequest, name) + return iface + + def _assertRoute(self, config, name, path, num_predicates=0): + from pyramid.interfaces import IRoutesMapper + + mapper = config.registry.getUtility(IRoutesMapper) + routes = mapper.get_routes() + route = routes[0] + self.assertEqual(len(routes), 1) + self.assertEqual(route.name, name) + self.assertEqual(route.path, path) + self.assertEqual(len(routes[0].predicates), num_predicates) + return route + + def test_add_view_view_callable_None_no_renderer(self): + config = self._makeOne(autocommit=True) + self.assertRaises(ConfigurationError, config.add_view) + + def test_add_view_with_request_type_and_route_name(self): + config = self._makeOne(autocommit=True) + view = lambda *arg: 'OK' + self.assertRaises( + ConfigurationError, + config.add_view, + view, + '', + None, + None, + True, + True, + ) + + def test_add_view_with_request_type(self): + from pyramid.renderers import null_renderer + from zope.interface import directlyProvides + from pyramid.interfaces import IRequest + + view = lambda *arg: 'OK' + config = self._makeOne(autocommit=True) + config.add_view( + view=view, + request_type='pyramid.interfaces.IRequest', + renderer=null_renderer, + ) + wrapper = self._getViewCallable(config) + request = DummyRequest() + self._assertNotFound(wrapper, None, request) + directlyProvides(request, IRequest) + result = wrapper(None, request) + self.assertEqual(result, 'OK') + + def test_add_view_view_callable_None_with_renderer(self): + config = self._makeOne(autocommit=True) + self._registerRenderer(config, name='dummy') + config.add_view(renderer='dummy') + view = self._getViewCallable(config) + self.assertTrue(b'Hello!' in view(None, None).body) + + def test_add_view_with_tmpl_renderer_factory_introspector_missing(self): + config = self._makeOne(autocommit=True) + config.introspection = False + config.introspector = None + config.add_view(renderer='dummy.pt') + view = self._getViewCallable(config) + self.assertRaises(ValueError, view, None, None) + + def test_add_view_with_tmpl_renderer_factory_no_renderer_factory(self): + config = self._makeOne(autocommit=True) + introspector = DummyIntrospector() + config.introspector = introspector + config.add_view(renderer='dummy.pt') + self.assertFalse( + ('renderer factories', '.pt') in introspector.related[-1] + ) + view = self._getViewCallable(config) + self.assertRaises(ValueError, view, None, None) + + def test_add_view_with_tmpl_renderer_factory_with_renderer_factory(self): + config = self._makeOne(autocommit=True) + introspector = DummyIntrospector(True) + config.introspector = introspector + + def dummy_factory(helper): + return lambda val, system_vals: 'Hello!' + + config.add_renderer('.pt', dummy_factory) + config.add_view(renderer='dummy.pt') + self.assertTrue( + ('renderer factories', '.pt') in introspector.related[-1] + ) + view = self._getViewCallable(config) + self.assertTrue(b'Hello!' in view(None, None).body) + + def test_add_view_wrapped_view_is_decorated(self): + def view(request): # request-only wrapper + """ """ + + config = self._makeOne(autocommit=True) + config.add_view(view=view) + wrapper = self._getViewCallable(config) + self.assertEqual(wrapper.__module__, view.__module__) + self.assertEqual(wrapper.__name__, view.__name__) + self.assertEqual(wrapper.__doc__, view.__doc__) + self.assertEqual( + wrapper.__discriminator__(None, None).resolve()[0], 'view' + ) + + def test_add_view_view_callable_dottedname(self): + from pyramid.renderers import null_renderer + + config = self._makeOne(autocommit=True) + config.add_view( + view='tests.test_config.dummy_view', renderer=null_renderer + ) + wrapper = self._getViewCallable(config) + self.assertEqual(wrapper(None, None), 'OK') + + def test_add_view_with_function_callable(self): + from pyramid.renderers import null_renderer + + view = lambda *arg: 'OK' + config = self._makeOne(autocommit=True) + config.add_view(view=view, renderer=null_renderer) + wrapper = self._getViewCallable(config) + result = wrapper(None, None) + self.assertEqual(result, 'OK') + + def test_add_view_with_function_callable_requestonly(self): + from pyramid.renderers import null_renderer + + def view(request): + return 'OK' + + config = self._makeOne(autocommit=True) + config.add_view(view=view, renderer=null_renderer) + wrapper = self._getViewCallable(config) + result = wrapper(None, None) + self.assertEqual(result, 'OK') + + def test_add_view_with_name(self): + from pyramid.renderers import null_renderer + + view = lambda *arg: 'OK' + config = self._makeOne(autocommit=True) + config.add_view(view=view, name='abc', renderer=null_renderer) + wrapper = self._getViewCallable(config, name='abc') + result = wrapper(None, None) + self.assertEqual(result, 'OK') + + def test_add_view_with_name_unicode(self): + from pyramid.renderers import null_renderer + + view = lambda *arg: 'OK' + config = self._makeOne(autocommit=True) + name = text_(b'La Pe\xc3\xb1a', 'utf-8') + config.add_view(view=view, name=name, renderer=null_renderer) + wrapper = self._getViewCallable(config, name=name) + result = wrapper(None, None) + self.assertEqual(result, 'OK') + + def test_add_view_with_decorator(self): + from pyramid.renderers import null_renderer + + def view(request): + """ ABC """ + return 'OK' + + def view_wrapper(fn): + def inner(context, request): + return fn(context, request) + + return inner + + config = self._makeOne(autocommit=True) + config.add_view( + view=view, decorator=view_wrapper, renderer=null_renderer + ) + wrapper = self._getViewCallable(config) + self.assertFalse(wrapper is view) + self.assertEqual(wrapper.__doc__, view.__doc__) + result = wrapper(None, None) + self.assertEqual(result, 'OK') + + def test_add_view_with_decorator_tuple(self): + from pyramid.renderers import null_renderer + + def view(request): + """ ABC """ + return 'OK' + + def view_wrapper1(fn): + def inner(context, request): + return 'wrapped1' + fn(context, request) + + return inner + + def view_wrapper2(fn): + def inner(context, request): + return 'wrapped2' + fn(context, request) + + return inner + + config = self._makeOne(autocommit=True) + config.add_view( + view=view, + decorator=(view_wrapper2, view_wrapper1), + renderer=null_renderer, + ) + wrapper = self._getViewCallable(config) + self.assertFalse(wrapper is view) + self.assertEqual(wrapper.__doc__, view.__doc__) + result = wrapper(None, None) + self.assertEqual(result, 'wrapped2wrapped1OK') + + def test_add_view_with_http_cache(self): + import datetime + from pyramid.response import Response + + response = Response('OK') + + def view(request): + """ ABC """ + return response + + config = self._makeOne(autocommit=True) + config.add_view(view=view, http_cache=(86400, {'public': True})) + wrapper = self._getViewCallable(config) + self.assertFalse(wrapper is view) + self.assertEqual(wrapper.__doc__, view.__doc__) + request = testing.DummyRequest() + when = datetime.datetime.utcnow() + datetime.timedelta(days=1) + result = wrapper(None, request) + self.assertEqual(result, response) + headers = dict(response.headerlist) + self.assertEqual(headers['Cache-Control'], 'max-age=86400, public') + expires = parse_httpdate(headers['Expires']) + assert_similar_datetime(expires, when) + + def test_add_view_as_instance(self): + from pyramid.renderers import null_renderer + + class AView: + def __call__(self, context, request): + """ """ + return 'OK' + + view = AView() + config = self._makeOne(autocommit=True) + config.add_view(view=view, renderer=null_renderer) + wrapper = self._getViewCallable(config) + result = wrapper(None, None) + self.assertEqual(result, 'OK') + + def test_add_view_as_instancemethod(self): + from pyramid.renderers import null_renderer + + class View: + def index(self, context, request): + return 'OK' + + view = View() + config = self._makeOne(autocommit=True) + config.add_view(view=view.index, renderer=null_renderer) + wrapper = self._getViewCallable(config) + result = wrapper(None, None) + self.assertEqual(result, 'OK') + + def test_add_view_as_instancemethod_requestonly(self): + from pyramid.renderers import null_renderer + + class View: + def index(self, request): + return 'OK' + + view = View() + config = self._makeOne(autocommit=True) + config.add_view(view=view.index, renderer=null_renderer) + wrapper = self._getViewCallable(config) + result = wrapper(None, None) + self.assertEqual(result, 'OK') + + def test_add_view_as_instance_requestonly(self): + from pyramid.renderers import null_renderer + + class AView: + def __call__(self, request): + """ """ + return 'OK' + + view = AView() + config = self._makeOne(autocommit=True) + config.add_view(view=view, renderer=null_renderer) + wrapper = self._getViewCallable(config) + result = wrapper(None, None) + self.assertEqual(result, 'OK') + + def test_add_view_as_oldstyle_class(self): + from pyramid.renderers import null_renderer + + class view: + def __init__(self, context, request): + self.context = context + self.request = request + + def __call__(self): + return 'OK' + + config = self._makeOne(autocommit=True) + config.add_view(view=view, renderer=null_renderer) + wrapper = self._getViewCallable(config) + request = self._makeRequest(config) + result = wrapper(None, request) + self.assertEqual(result, 'OK') + self.assertEqual(request.__view__.__class__, view) + + def test_add_view_as_oldstyle_class_requestonly(self): + from pyramid.renderers import null_renderer + + class view: + def __init__(self, request): + self.request = request + + def __call__(self): + return 'OK' + + config = self._makeOne(autocommit=True) + config.add_view(view=view, renderer=null_renderer) + wrapper = self._getViewCallable(config) + + request = self._makeRequest(config) + result = wrapper(None, request) + self.assertEqual(result, 'OK') + self.assertEqual(request.__view__.__class__, view) + + def test_add_view_context_as_class(self): + from pyramid.renderers import null_renderer + from zope.interface import implementedBy + + view = lambda *arg: 'OK' + + class Foo: + pass + + config = self._makeOne(autocommit=True) + config.add_view(context=Foo, view=view, renderer=null_renderer) + foo = implementedBy(Foo) + wrapper = self._getViewCallable(config, foo) + self.assertEqual(wrapper, view) + + def test_add_view_context_as_iface(self): + from pyramid.renderers import null_renderer + + view = lambda *arg: 'OK' + config = self._makeOne(autocommit=True) + config.add_view(context=IDummy, view=view, renderer=null_renderer) + wrapper = self._getViewCallable(config, IDummy) + self.assertEqual(wrapper, view) + + def test_add_view_context_as_dottedname(self): + from pyramid.renderers import null_renderer + + view = lambda *arg: 'OK' + config = self._makeOne(autocommit=True) + config.add_view( + context='tests.test_config.IDummy', + view=view, + renderer=null_renderer, + ) + wrapper = self._getViewCallable(config, IDummy) + self.assertEqual(wrapper, view) + + def test_add_view_for__as_dottedname(self): + from pyramid.renderers import null_renderer + + view = lambda *arg: 'OK' + config = self._makeOne(autocommit=True) + config.add_view( + for_='tests.test_config.IDummy', view=view, renderer=null_renderer + ) + wrapper = self._getViewCallable(config, IDummy) + self.assertEqual(wrapper, view) + + def test_add_view_for_as_class(self): + # ``for_`` is older spelling for ``context`` + from pyramid.renderers import null_renderer + from zope.interface import implementedBy + + view = lambda *arg: 'OK' + + class Foo: + pass + + config = self._makeOne(autocommit=True) + config.add_view(for_=Foo, view=view, renderer=null_renderer) + foo = implementedBy(Foo) + wrapper = self._getViewCallable(config, foo) + self.assertEqual(wrapper, view) + + def test_add_view_for_as_iface(self): + # ``for_`` is older spelling for ``context`` + from pyramid.renderers import null_renderer + + view = lambda *arg: 'OK' + config = self._makeOne(autocommit=True) + config.add_view(for_=IDummy, view=view, renderer=null_renderer) + wrapper = self._getViewCallable(config, IDummy) + self.assertEqual(wrapper, view) + + def test_add_view_context_trumps_for(self): + # ``for_`` is older spelling for ``context`` + from pyramid.renderers import null_renderer + + view = lambda *arg: 'OK' + config = self._makeOne(autocommit=True) + + class Foo: + pass + + config.add_view( + context=IDummy, for_=Foo, view=view, renderer=null_renderer + ) + wrapper = self._getViewCallable(config, IDummy) + self.assertEqual(wrapper, view) + + def test_add_view_register_secured_view(self): + from pyramid.renderers import null_renderer + from zope.interface import Interface + from pyramid.interfaces import IRequest + from pyramid.interfaces import ISecuredView + from pyramid.interfaces import IViewClassifier + + view = lambda *arg: 'OK' + view.__call_permissive__ = view + config = self._makeOne(autocommit=True) + config.add_view(view=view, renderer=null_renderer) + wrapper = config.registry.adapters.lookup( + (IViewClassifier, IRequest, Interface), + ISecuredView, + name='', + default=None, + ) + self.assertEqual(wrapper, view) + + def test_add_view_exception_register_secured_view(self): + from pyramid.renderers import null_renderer + from zope.interface import implementedBy + from pyramid.interfaces import IRequest + from pyramid.interfaces import IView + from pyramid.interfaces import IExceptionViewClassifier + + view = lambda *arg: 'OK' + view.__call_permissive__ = view + config = self._makeOne(autocommit=True) + config.add_view( + view=view, context=RuntimeError, renderer=null_renderer + ) + wrapper = config.registry.adapters.lookup( + (IExceptionViewClassifier, IRequest, implementedBy(RuntimeError)), + IView, + name='', + default=None, + ) + self.assertEqual(wrapper, view) + + def test_add_view_same_phash_overrides_existing_single_view(self): + from pyramid.renderers import null_renderer + from hashlib import md5 + from zope.interface import Interface + from pyramid.interfaces import IRequest + from pyramid.interfaces import IView + from pyramid.interfaces import IViewClassifier + from pyramid.interfaces import IMultiView + + phash = md5() + phash.update(b'xhr = True') + view = lambda *arg: 'NOT OK' + view.__phash__ = phash.hexdigest() + config = self._makeOne(autocommit=True) + config.registry.registerAdapter( + view, (IViewClassifier, IRequest, Interface), IView, name='' + ) + + def newview(context, request): + return 'OK' + + config.add_view(view=newview, xhr=True, renderer=null_renderer) + wrapper = self._getViewCallable(config) + self.assertFalse(IMultiView.providedBy(wrapper)) + request = DummyRequest() + request.is_xhr = True + self.assertEqual(wrapper(None, request), 'OK') + + def test_add_view_exc_same_phash_overrides_existing_single_view(self): + from pyramid.renderers import null_renderer + from hashlib import md5 + from zope.interface import implementedBy + from pyramid.interfaces import IRequest + from pyramid.interfaces import IView + from pyramid.interfaces import IExceptionViewClassifier + from pyramid.interfaces import IMultiView + + phash = md5() + phash.update(b'xhr = True') + view = lambda *arg: 'NOT OK' + view.__phash__ = phash.hexdigest() + config = self._makeOne(autocommit=True) + config.registry.registerAdapter( + view, + (IExceptionViewClassifier, IRequest, implementedBy(RuntimeError)), + IView, + name='', + ) + + def newview(context, request): + return 'OK' + + config.add_view( + view=newview, + xhr=True, + context=RuntimeError, + renderer=null_renderer, + ) + wrapper = self._getViewCallable( + config, exc_iface=implementedBy(RuntimeError) + ) + self.assertFalse(IMultiView.providedBy(wrapper)) + request = DummyRequest() + request.is_xhr = True + self.assertEqual(wrapper(None, request), 'OK') + + def test_add_view_default_phash_overrides_no_phash(self): + from pyramid.renderers import null_renderer + from zope.interface import Interface + from pyramid.interfaces import IRequest + from pyramid.interfaces import IView + from pyramid.interfaces import IViewClassifier + from pyramid.interfaces import IMultiView + + view = lambda *arg: 'NOT OK' + config = self._makeOne(autocommit=True) + config.registry.registerAdapter( + view, (IViewClassifier, IRequest, Interface), IView, name='' + ) + + def newview(context, request): + return 'OK' + + config.add_view(view=newview, renderer=null_renderer) + wrapper = self._getViewCallable(config) + self.assertFalse(IMultiView.providedBy(wrapper)) + request = DummyRequest() + request.is_xhr = True + self.assertEqual(wrapper(None, request), 'OK') + + def test_add_view_exc_default_phash_overrides_no_phash(self): + from pyramid.renderers import null_renderer + from zope.interface import implementedBy + from pyramid.interfaces import IRequest + from pyramid.interfaces import IView + from pyramid.interfaces import IExceptionViewClassifier + from pyramid.interfaces import IMultiView + + view = lambda *arg: 'NOT OK' + config = self._makeOne(autocommit=True) + config.registry.registerAdapter( + view, + (IExceptionViewClassifier, IRequest, implementedBy(RuntimeError)), + IView, + name='', + ) + + def newview(context, request): + return 'OK' + + config.add_view( + view=newview, context=RuntimeError, renderer=null_renderer + ) + wrapper = self._getViewCallable( + config, exc_iface=implementedBy(RuntimeError) + ) + self.assertFalse(IMultiView.providedBy(wrapper)) + request = DummyRequest() + request.is_xhr = True + self.assertEqual(wrapper(None, request), 'OK') + + def test_add_view_default_phash_overrides_default_phash(self): + from pyramid.config.predicates import DEFAULT_PHASH + from pyramid.renderers import null_renderer + from zope.interface import Interface + from pyramid.interfaces import IRequest + from pyramid.interfaces import IView + from pyramid.interfaces import IViewClassifier + from pyramid.interfaces import IMultiView + + view = lambda *arg: 'NOT OK' + view.__phash__ = DEFAULT_PHASH + config = self._makeOne(autocommit=True) + config.registry.registerAdapter( + view, (IViewClassifier, IRequest, Interface), IView, name='' + ) + + def newview(context, request): + return 'OK' + + config.add_view(view=newview, renderer=null_renderer) + wrapper = self._getViewCallable(config) + self.assertFalse(IMultiView.providedBy(wrapper)) + request = DummyRequest() + request.is_xhr = True + self.assertEqual(wrapper(None, request), 'OK') + + def test_add_view_exc_default_phash_overrides_default_phash(self): + from pyramid.config.predicates import DEFAULT_PHASH + from pyramid.renderers import null_renderer + from zope.interface import implementedBy + from pyramid.interfaces import IRequest + from pyramid.interfaces import IView + from pyramid.interfaces import IExceptionViewClassifier + from pyramid.interfaces import IMultiView + + view = lambda *arg: 'NOT OK' + view.__phash__ = DEFAULT_PHASH + config = self._makeOne(autocommit=True) + config.registry.registerAdapter( + view, + (IExceptionViewClassifier, IRequest, implementedBy(RuntimeError)), + IView, + name='', + ) + + def newview(context, request): + return 'OK' + + config.add_view( + view=newview, context=RuntimeError, renderer=null_renderer + ) + wrapper = self._getViewCallable( + config, exc_iface=implementedBy(RuntimeError) + ) + self.assertFalse(IMultiView.providedBy(wrapper)) + request = DummyRequest() + request.is_xhr = True + self.assertEqual(wrapper(None, request), 'OK') + + def test_add_view_multiview_replaces_existing_view(self): + from pyramid.renderers import null_renderer + from zope.interface import Interface + from pyramid.interfaces import IRequest + from pyramid.interfaces import IView + from pyramid.interfaces import IViewClassifier + from pyramid.interfaces import IMultiView + + view = lambda *arg: 'OK' + view.__phash__ = 'abc' + config = self._makeOne(autocommit=True) + config.registry.registerAdapter( + view, (IViewClassifier, IRequest, Interface), IView, name='' + ) + config.add_view(view=view, renderer=null_renderer) + wrapper = self._getViewCallable(config) + self.assertTrue(IMultiView.providedBy(wrapper)) + self.assertEqual(wrapper(None, None), 'OK') + + def test_add_view_exc_multiview_replaces_existing_view(self): + from pyramid.renderers import null_renderer + from zope.interface import implementedBy + from pyramid.interfaces import IRequest + from pyramid.interfaces import IView + from pyramid.interfaces import IExceptionViewClassifier + from pyramid.interfaces import IViewClassifier + from pyramid.interfaces import IMultiView + + view = lambda *arg: 'OK' + view.__phash__ = 'abc' + config = self._makeOne(autocommit=True) + config.registry.registerAdapter( + view, + (IViewClassifier, IRequest, implementedBy(RuntimeError)), + IView, + name='', + ) + config.registry.registerAdapter( + view, + (IExceptionViewClassifier, IRequest, implementedBy(RuntimeError)), + IView, + name='', + ) + config.add_view( + view=view, context=RuntimeError, renderer=null_renderer + ) + wrapper = self._getViewCallable( + config, exc_iface=implementedBy(RuntimeError) + ) + self.assertTrue(IMultiView.providedBy(wrapper)) + self.assertEqual(wrapper(None, None), 'OK') + + def test_add_view_multiview_replaces_existing_securedview(self): + from pyramid.renderers import null_renderer + from zope.interface import Interface + from pyramid.interfaces import IRequest + from pyramid.interfaces import ISecuredView + from pyramid.interfaces import IMultiView + from pyramid.interfaces import IViewClassifier + + view = lambda *arg: 'OK' + view.__phash__ = 'abc' + config = self._makeOne(autocommit=True) + config.registry.registerAdapter( + view, (IViewClassifier, IRequest, Interface), ISecuredView, name='' + ) + config.add_view(view=view, renderer=null_renderer) + wrapper = self._getViewCallable(config) + self.assertTrue(IMultiView.providedBy(wrapper)) + self.assertEqual(wrapper(None, None), 'OK') + + def test_add_view_exc_multiview_replaces_existing_securedview(self): + from pyramid.renderers import null_renderer + from zope.interface import implementedBy + from pyramid.interfaces import IRequest + from pyramid.interfaces import ISecuredView + from pyramid.interfaces import IMultiView + from pyramid.interfaces import IViewClassifier + from pyramid.interfaces import IExceptionViewClassifier + + view = lambda *arg: 'OK' + view.__phash__ = 'abc' + config = self._makeOne(autocommit=True) + config.registry.registerAdapter( + view, + (IViewClassifier, IRequest, implementedBy(RuntimeError)), + ISecuredView, + name='', + ) + config.registry.registerAdapter( + view, + (IExceptionViewClassifier, IRequest, implementedBy(RuntimeError)), + ISecuredView, + name='', + ) + config.add_view( + view=view, context=RuntimeError, renderer=null_renderer + ) + wrapper = self._getViewCallable( + config, exc_iface=implementedBy(RuntimeError) + ) + self.assertTrue(IMultiView.providedBy(wrapper)) + self.assertEqual(wrapper(None, None), 'OK') + + def test_add_view_with_accept_multiview_replaces_existing_view(self): + from pyramid.renderers import null_renderer + from zope.interface import Interface + from pyramid.interfaces import IRequest + from pyramid.interfaces import IView + from pyramid.interfaces import IMultiView + from pyramid.interfaces import IViewClassifier + + def view(context, request): + return 'OK' + + def view2(context, request): + return 'OK2' + + config = self._makeOne(autocommit=True) + config.registry.registerAdapter( + view, (IViewClassifier, IRequest, Interface), IView, name='' + ) + config.add_view(view=view2, accept='text/html', renderer=null_renderer) + wrapper = self._getViewCallable(config) + self.assertTrue(IMultiView.providedBy(wrapper)) + self.assertEqual(len(wrapper.views), 1) + self.assertEqual(len(wrapper.media_views), 1) + self.assertEqual(wrapper(None, None), 'OK') + request = DummyRequest() + request.accept = DummyAccept('text/html', 'text/html') + self.assertEqual(wrapper(None, request), 'OK2') + + def test_add_view_mixed_case_replaces_existing_view(self): + from pyramid.renderers import null_renderer + + def view(context, request): + return 'OK' + + def view2(context, request): # pragma: no cover + return 'OK2' + + def view3(context, request): + return 'OK3' + + config = self._makeOne(autocommit=True) + config.add_view(view=view, renderer=null_renderer) + config.add_view(view=view2, accept='text/html', renderer=null_renderer) + config.add_view(view=view3, accept='text/HTML', renderer=null_renderer) + wrapper = self._getViewCallable(config) + self.assertTrue(IMultiView.providedBy(wrapper)) + self.assertEqual(len(wrapper.media_views.items()), 1) + self.assertFalse('text/HTML' in wrapper.media_views) + self.assertEqual(wrapper(None, None), 'OK') + request = DummyRequest() + request.accept = DummyAccept('text/html', 'text/html') + self.assertEqual(wrapper(None, request), 'OK3') + + def test_add_views_with_accept_multiview_replaces_existing(self): + from pyramid.renderers import null_renderer + + def view(context, request): + return 'OK' + + def view2(context, request): # pragma: no cover + return 'OK2' + + def view3(context, request): + return 'OK3' + + config = self._makeOne(autocommit=True) + config.add_view(view=view, renderer=null_renderer) + config.add_view(view=view2, accept='text/html', renderer=null_renderer) + config.add_view(view=view3, accept='text/html', renderer=null_renderer) + wrapper = self._getViewCallable(config) + self.assertEqual(len(wrapper.media_views['text/html']), 1) + self.assertEqual(wrapper(None, None), 'OK') + request = DummyRequest() + request.accept = DummyAccept('text/html', 'text/html') + self.assertEqual(wrapper(None, request), 'OK3') + + def test_add_view_exc_with_accept_multiview_replaces_existing_view(self): + from pyramid.renderers import null_renderer + from zope.interface import implementedBy + from pyramid.interfaces import IRequest + from pyramid.interfaces import IView + from pyramid.interfaces import IMultiView + from pyramid.interfaces import IViewClassifier + from pyramid.interfaces import IExceptionViewClassifier + + def view(context, request): + return 'OK' + + def view2(context, request): + return 'OK2' + + config = self._makeOne(autocommit=True) + config.registry.registerAdapter( + view, + (IViewClassifier, IRequest, implementedBy(RuntimeError)), + IView, + name='', + ) + config.registry.registerAdapter( + view, + (IExceptionViewClassifier, IRequest, implementedBy(RuntimeError)), + IView, + name='', + ) + config.add_view( + view=view2, + accept='text/html', + context=RuntimeError, + renderer=null_renderer, + ) + wrapper = self._getViewCallable( + config, exc_iface=implementedBy(RuntimeError) + ) + self.assertTrue(IMultiView.providedBy(wrapper)) + self.assertEqual(len(wrapper.views), 1) + self.assertEqual(len(wrapper.media_views), 1) + self.assertEqual(wrapper(None, None), 'OK') + request = DummyRequest() + request.accept = DummyAccept('text/html', 'text/html') + self.assertEqual(wrapper(None, request), 'OK2') + + def test_add_view_multiview_replaces_existing_view_with___accept__(self): + from pyramid.renderers import null_renderer + from zope.interface import Interface + from pyramid.interfaces import IRequest + from pyramid.interfaces import IView + from pyramid.interfaces import IMultiView + from pyramid.interfaces import IViewClassifier + + def view(context, request): + return 'OK' + + def view2(context, request): + return 'OK2' + + view.__accept__ = 'text/html' + view.__phash__ = 'abc' + config = self._makeOne(autocommit=True) + config.registry.registerAdapter( + view, (IViewClassifier, IRequest, Interface), IView, name='' + ) + config.add_view(view=view2, renderer=null_renderer) + wrapper = self._getViewCallable(config) + self.assertTrue(IMultiView.providedBy(wrapper)) + self.assertEqual(len(wrapper.views), 1) + self.assertEqual(len(wrapper.media_views), 1) + self.assertEqual(wrapper(None, None), 'OK2') + request = DummyRequest() + request.accept = DummyAccept('text/html') + self.assertEqual(wrapper(None, request), 'OK') + + def test_add_view_exc_mulview_replaces_existing_view_with___accept__(self): + from pyramid.renderers import null_renderer + from zope.interface import implementedBy + from pyramid.interfaces import IRequest + from pyramid.interfaces import IView + from pyramid.interfaces import IMultiView + from pyramid.interfaces import IViewClassifier + from pyramid.interfaces import IExceptionViewClassifier + + def view(context, request): + return 'OK' + + def view2(context, request): + return 'OK2' + + view.__accept__ = 'text/html' + view.__phash__ = 'abc' + config = self._makeOne(autocommit=True) + config.registry.registerAdapter( + view, + (IViewClassifier, IRequest, implementedBy(RuntimeError)), + IView, + name='', + ) + config.registry.registerAdapter( + view, + (IExceptionViewClassifier, IRequest, implementedBy(RuntimeError)), + IView, + name='', + ) + config.add_view( + view=view2, context=RuntimeError, renderer=null_renderer + ) + wrapper = self._getViewCallable( + config, exc_iface=implementedBy(RuntimeError) + ) + self.assertTrue(IMultiView.providedBy(wrapper)) + self.assertEqual(len(wrapper.views), 1) + self.assertEqual(len(wrapper.media_views), 1) + self.assertEqual(wrapper(None, None), 'OK2') + request = DummyRequest() + request.accept = DummyAccept('text/html') + self.assertEqual(wrapper(None, request), 'OK') + + def test_add_view_multiview_replaces_multiview(self): + from pyramid.renderers import null_renderer + from zope.interface import Interface + from pyramid.interfaces import IRequest + from pyramid.interfaces import IMultiView + from pyramid.interfaces import IViewClassifier + + view = DummyMultiView() + config = self._makeOne(autocommit=True) + config.registry.registerAdapter( + view, (IViewClassifier, IRequest, Interface), IMultiView, name='' + ) + view2 = lambda *arg: 'OK2' + config.add_view(view=view2, renderer=null_renderer) + wrapper = self._getViewCallable(config) + self.assertTrue(IMultiView.providedBy(wrapper)) + self.assertEqual( + [(x[0], x[2]) for x in wrapper.views], [(view2, None)] + ) + self.assertEqual(wrapper(None, None), 'OK1') + + def test_add_view_exc_multiview_replaces_multiviews(self): + from pyramid.renderers import null_renderer + from zope.interface import implementedBy + from pyramid.interfaces import IRequest + from pyramid.interfaces import IMultiView + from pyramid.interfaces import IViewClassifier + from pyramid.interfaces import IExceptionViewClassifier + + hot_view = DummyMultiView() + exc_view = DummyMultiView() + config = self._makeOne(autocommit=True) + config.registry.registerAdapter( + hot_view, + (IViewClassifier, IRequest, implementedBy(RuntimeError)), + IMultiView, + name='', + ) + config.registry.registerAdapter( + exc_view, + (IExceptionViewClassifier, IRequest, implementedBy(RuntimeError)), + IMultiView, + name='', + ) + view2 = lambda *arg: 'OK2' + config.add_view( + view=view2, context=RuntimeError, renderer=null_renderer + ) + hot_wrapper = self._getViewCallable( + config, ctx_iface=implementedBy(RuntimeError) + ) + self.assertTrue(IMultiView.providedBy(hot_wrapper)) + self.assertEqual( + [(x[0], x[2]) for x in hot_wrapper.views], [(view2, None)] + ) + self.assertEqual(hot_wrapper(None, None), 'OK1') + + exc_wrapper = self._getViewCallable( + config, exc_iface=implementedBy(RuntimeError) + ) + self.assertTrue(IMultiView.providedBy(exc_wrapper)) + self.assertEqual( + [(x[0], x[2]) for x in exc_wrapper.views], [(view2, None)] + ) + self.assertEqual(exc_wrapper(None, None), 'OK1') + + def test_add_view_exc_multiview_replaces_only_exc_multiview(self): + from pyramid.renderers import null_renderer + from zope.interface import implementedBy + from pyramid.interfaces import IRequest + from pyramid.interfaces import IMultiView + from pyramid.interfaces import IViewClassifier + from pyramid.interfaces import IExceptionViewClassifier + + hot_view = DummyMultiView() + exc_view = DummyMultiView() + config = self._makeOne(autocommit=True) + config.registry.registerAdapter( + hot_view, + (IViewClassifier, IRequest, implementedBy(RuntimeError)), + IMultiView, + name='', + ) + config.registry.registerAdapter( + exc_view, + (IExceptionViewClassifier, IRequest, implementedBy(RuntimeError)), + IMultiView, + name='', + ) + view2 = lambda *arg: 'OK2' + config.add_view( + view=view2, + context=RuntimeError, + exception_only=True, + renderer=null_renderer, + ) + hot_wrapper = self._getViewCallable( + config, ctx_iface=implementedBy(RuntimeError) + ) + self.assertTrue(IMultiView.providedBy(hot_wrapper)) + self.assertEqual(len(hot_wrapper.views), 0) + self.assertEqual(hot_wrapper(None, None), 'OK1') + + exc_wrapper = self._getViewCallable( + config, exc_iface=implementedBy(RuntimeError) + ) + self.assertTrue(IMultiView.providedBy(exc_wrapper)) + self.assertEqual( + [(x[0], x[2]) for x in exc_wrapper.views], [(view2, None)] + ) + self.assertEqual(exc_wrapper(None, None), 'OK1') + + def test_add_view_multiview_context_superclass_then_subclass(self): + from pyramid.renderers import null_renderer + from zope.interface import Interface + from pyramid.interfaces import IRequest + from pyramid.interfaces import IView + from pyramid.interfaces import IMultiView + from pyramid.interfaces import IViewClassifier + + class ISuper(Interface): + pass + + class ISub(ISuper): + pass + + view = lambda *arg: 'OK' + view2 = lambda *arg: 'OK2' + config = self._makeOne(autocommit=True) + config.registry.registerAdapter( + view, (IViewClassifier, IRequest, ISuper), IView, name='' + ) + config.add_view(view=view2, for_=ISub, renderer=null_renderer) + wrapper = self._getViewCallable( + config, ctx_iface=ISuper, request_iface=IRequest + ) + self.assertFalse(IMultiView.providedBy(wrapper)) + self.assertEqual(wrapper(None, None), 'OK') + wrapper = self._getViewCallable( + config, ctx_iface=ISub, request_iface=IRequest + ) + self.assertFalse(IMultiView.providedBy(wrapper)) + self.assertEqual(wrapper(None, None), 'OK2') + + def test_add_view_multiview_exception_superclass_then_subclass(self): + from pyramid.renderers import null_renderer + from zope.interface import implementedBy + from pyramid.interfaces import IRequest + from pyramid.interfaces import IView + from pyramid.interfaces import IMultiView + from pyramid.interfaces import IViewClassifier + from pyramid.interfaces import IExceptionViewClassifier + + class Super(Exception): + pass + + class Sub(Super): + pass + + view = lambda *arg: 'OK' + view2 = lambda *arg: 'OK2' + config = self._makeOne(autocommit=True) + config.registry.registerAdapter( + view, (IViewClassifier, IRequest, Super), IView, name='' + ) + config.registry.registerAdapter( + view, (IExceptionViewClassifier, IRequest, Super), IView, name='' + ) + config.add_view(view=view2, for_=Sub, renderer=null_renderer) + wrapper = self._getViewCallable( + config, ctx_iface=implementedBy(Super), request_iface=IRequest + ) + wrapper_exc_view = self._getViewCallable( + config, exc_iface=implementedBy(Super), request_iface=IRequest + ) + self.assertEqual(wrapper_exc_view, wrapper) + self.assertFalse(IMultiView.providedBy(wrapper_exc_view)) + self.assertEqual(wrapper_exc_view(None, None), 'OK') + wrapper = self._getViewCallable( + config, ctx_iface=implementedBy(Sub), request_iface=IRequest + ) + wrapper_exc_view = self._getViewCallable( + config, exc_iface=implementedBy(Sub), request_iface=IRequest + ) + self.assertEqual(wrapper_exc_view, wrapper) + self.assertFalse(IMultiView.providedBy(wrapper_exc_view)) + self.assertEqual(wrapper_exc_view(None, None), 'OK2') + + def test_add_view_multiview_call_ordering(self): + from pyramid.renderers import null_renderer as nr + from zope.interface import directlyProvides + + def view1(context, request): + return 'view1' + + def view2(context, request): + return 'view2' + + def view3(context, request): + return 'view3' + + def view4(context, request): + return 'view4' + + def view5(context, request): + return 'view5' + + def view6(context, request): + return 'view6' + + def view7(context, request): + return 'view7' + + def view8(context, request): + return 'view8' + + config = self._makeOne(autocommit=True) + config.add_view(view=view1, renderer=nr) + config.add_view(view=view2, request_method='POST', renderer=nr) + config.add_view(view=view3, request_param='param', renderer=nr) + config.add_view(view=view4, containment=IDummy, renderer=nr) + config.add_view( + view=view5, + request_method='POST', + request_param='param', + renderer=nr, + ) + config.add_view( + view=view6, request_method='POST', containment=IDummy, renderer=nr + ) + config.add_view( + view=view7, request_param='param', containment=IDummy, renderer=nr + ) + config.add_view( + view=view8, + request_method='POST', + request_param='param', + containment=IDummy, + renderer=nr, + ) + + wrapper = self._getViewCallable(config) + + ctx = DummyContext() + request = self._makeRequest(config) + request.method = 'GET' + request.params = {} + self.assertEqual(wrapper(ctx, request), 'view1') + + ctx = DummyContext() + request = self._makeRequest(config) + request.params = {} + request.method = 'POST' + self.assertEqual(wrapper(ctx, request), 'view2') + + ctx = DummyContext() + request = self._makeRequest(config) + request.params = {'param': '1'} + request.method = 'GET' + self.assertEqual(wrapper(ctx, request), 'view3') + + ctx = DummyContext() + directlyProvides(ctx, IDummy) + request = self._makeRequest(config) + request.method = 'GET' + request.params = {} + self.assertEqual(wrapper(ctx, request), 'view4') + + ctx = DummyContext() + request = self._makeRequest(config) + request.method = 'POST' + request.params = {'param': '1'} + self.assertEqual(wrapper(ctx, request), 'view5') + + ctx = DummyContext() + directlyProvides(ctx, IDummy) + request = self._makeRequest(config) + request.params = {} + request.method = 'POST' + self.assertEqual(wrapper(ctx, request), 'view6') + + ctx = DummyContext() + directlyProvides(ctx, IDummy) + request = self._makeRequest(config) + request.method = 'GET' + request.params = {'param': '1'} + self.assertEqual(wrapper(ctx, request), 'view7') + + ctx = DummyContext() + directlyProvides(ctx, IDummy) + request = self._makeRequest(config) + request.method = 'POST' + request.params = {'param': '1'} + self.assertEqual(wrapper(ctx, request), 'view8') + + def test_view_with_most_specific_predicate(self): + from pyramid.renderers import null_renderer as nr + from pyramid.router import Router + + class OtherBase(object): + pass + + class Int1(object): + pass + + class Int2(object): + pass + + class Resource(OtherBase, Int1, Int2): + def __init__(self, request): + pass + + def unknown(context, request): # pragma: no cover + return 'unknown' + + def view(context, request): + return 'hello' + + config = self._makeOne(autocommit=True) + config.add_route('root', '/', factory=Resource) + config.add_view(unknown, route_name='root', renderer=nr) + config.add_view( + view, + renderer=nr, + route_name='root', + context=Int1, + request_method='GET', + ) + config.add_view( + view=view, + renderer=nr, + route_name='root', + context=Int2, + request_method='POST', + ) + request = self._makeRequest(config) + request.method = 'POST' + request.params = {} + router = Router(config.registry) + response = router.handle_request(request) + self.assertEqual(response, 'hello') + + def test_view_with_most_specific_predicate_with_mismatch(self): + from pyramid.renderers import null_renderer as nr + from pyramid.router import Router + + class OtherBase(object): + pass + + class Int1(object): + pass + + class Int2(object): + pass + + class Resource(OtherBase, Int1, Int2): + def __init__(self, request): + pass + + def unknown(context, request): # pragma: no cover + return 'unknown' + + def view(context, request): + return 'hello' + + config = self._makeOne(autocommit=True) + config.add_route('root', '/', factory=Resource) + + config.add_view( + unknown, + route_name='root', + renderer=nr, + request_method=('POST',), + xhr=True, + ) + + config.add_view( + view, + renderer=nr, + route_name='root', + context=Int1, + request_method='GET', + ) + config.add_view( + view=view, + renderer=nr, + route_name='root', + context=Int2, + request_method='POST', + ) + request = self._makeRequest(config) + request.method = 'POST' + request.params = {} + router = Router(config.registry) + response = router.handle_request(request) + self.assertEqual(response, 'hello') + + def test_add_view_multiview___discriminator__(self): + from pyramid.renderers import null_renderer + from zope.interface import Interface + + class IFoo(Interface): + pass + + class IBar(Interface): + pass + + @implementer(IFoo) + class Foo(object): + pass + + @implementer(IBar) + class Bar(object): + pass + + foo = Foo() + bar = Bar() + + from pyramid.interfaces import IRequest + from pyramid.interfaces import IView + from pyramid.interfaces import IViewClassifier + from pyramid.interfaces import IMultiView + + view = lambda *arg: 'OK' + view.__phash__ = 'abc' + config = self._makeOne(autocommit=True) + config.registry.registerAdapter( + view, (IViewClassifier, IRequest, Interface), IView, name='' + ) + config.add_view(view=view, renderer=null_renderer, containment=IFoo) + config.add_view(view=view, renderer=null_renderer, containment=IBar) + wrapper = self._getViewCallable(config) + self.assertTrue(IMultiView.providedBy(wrapper)) + request = self._makeRequest(config) + self.assertNotEqual( + wrapper.__discriminator__(foo, request), + wrapper.__discriminator__(bar, request), + ) + + def test_add_view_with_template_renderer(self): + from tests import test_config + from pyramid.interfaces import ISettings + + class view(object): + def __init__(self, context, request): + self.request = request + self.context = context + + def __call__(self): + return {'a': '1'} + + config = self._makeOne(autocommit=True) + renderer = self._registerRenderer(config) + fixture = 'tests.test_config:files/minimal.txt' + config.introspection = False + config.add_view(view=view, renderer=fixture) + wrapper = self._getViewCallable(config) + request = self._makeRequest(config) + result = wrapper(None, request) + self.assertEqual(result.body, b'Hello!') + settings = config.registry.queryUtility(ISettings) + result = renderer.info + self.assertEqual(result.registry, config.registry) + self.assertEqual(result.type, '.txt') + self.assertEqual(result.package, test_config) + self.assertEqual(result.name, fixture) + self.assertEqual(result.settings, settings) + + def test_add_view_with_default_renderer(self): + class view(object): + def __init__(self, context, request): + self.request = request + self.context = context + + def __call__(self): + return {'a': '1'} + + config = self._makeOne(autocommit=True) + + class moo(object): + def __init__(self, *arg, **kw): + pass + + def __call__(self, *arg, **kw): + return b'moo' + + config.add_renderer(None, moo) + config.add_view(view=view) + wrapper = self._getViewCallable(config) + request = self._makeRequest(config) + result = wrapper(None, request) + self.assertEqual(result.body, b'moo') + + def test_add_view_with_template_renderer_no_callable(self): + from tests import test_config + from pyramid.interfaces import ISettings + + config = self._makeOne(autocommit=True) + renderer = self._registerRenderer(config) + fixture = 'tests.test_config:files/minimal.txt' + config.introspection = False + config.add_view(view=None, renderer=fixture) + wrapper = self._getViewCallable(config) + request = self._makeRequest(config) + result = wrapper(None, request) + self.assertEqual(result.body, b'Hello!') + settings = config.registry.queryUtility(ISettings) + result = renderer.info + self.assertEqual(result.registry, config.registry) + self.assertEqual(result.type, '.txt') + self.assertEqual(result.package, test_config) + self.assertEqual(result.name, fixture) + self.assertEqual(result.settings, settings) + + def test_add_view_with_request_type_as_iface(self): + from pyramid.renderers import null_renderer + from zope.interface import directlyProvides + + def view(context, request): + return 'OK' + + config = self._makeOne(autocommit=True) + config.add_view(request_type=IDummy, view=view, renderer=null_renderer) + wrapper = self._getViewCallable(config, None) + request = self._makeRequest(config) + directlyProvides(request, IDummy) + result = wrapper(None, request) + self.assertEqual(result, 'OK') + + def test_add_view_with_request_type_as_noniface(self): + view = lambda *arg: 'OK' + config = self._makeOne() + self.assertRaises( + ConfigurationError, config.add_view, view, '', None, None, object + ) + + def test_add_view_with_route_name(self): + from pyramid.renderers import null_renderer + + view = lambda *arg: 'OK' + config = self._makeOne(autocommit=True) + config.add_route('foo', '/a/b') + config.add_view(view=view, route_name='foo', renderer=null_renderer) + request_iface = self._getRouteRequestIface(config, 'foo') + self.assertNotEqual(request_iface, None) + wrapper = self._getViewCallable(config, request_iface=request_iface) + self.assertNotEqual(wrapper, None) + self.assertEqual(wrapper(None, None), 'OK') + + def test_add_view_with_nonexistant_route_name(self): + from pyramid.renderers import null_renderer + + view = lambda *arg: 'OK' + config = self._makeOne() + config.add_view(view=view, route_name='foo', renderer=null_renderer) + self.assertRaises(ConfigurationExecutionError, config.commit) + + def test_add_view_with_route_name_exception(self): + from pyramid.renderers import null_renderer + from zope.interface import implementedBy + + view = lambda *arg: 'OK' + config = self._makeOne(autocommit=True) + config.add_route('foo', '/a/b') + config.add_view( + view=view, + route_name='foo', + context=RuntimeError, + renderer=null_renderer, + ) + request_iface = self._getRouteRequestIface(config, 'foo') + wrapper_exc_view = self._getViewCallable( + config, + exc_iface=implementedBy(RuntimeError), + request_iface=request_iface, + ) + self.assertNotEqual(wrapper_exc_view, None) + wrapper = self._getViewCallable( + config, + ctx_iface=implementedBy(RuntimeError), + request_iface=request_iface, + ) + self.assertEqual(wrapper_exc_view, wrapper) + self.assertEqual(wrapper_exc_view(None, None), 'OK') + + def test_add_view_with_request_method_true(self): + from pyramid.renderers import null_renderer + + view = lambda *arg: 'OK' + config = self._makeOne(autocommit=True) + config.add_view( + view=view, request_method='POST', renderer=null_renderer + ) + wrapper = self._getViewCallable(config) + request = self._makeRequest(config) + request.method = 'POST' + self.assertEqual(wrapper(None, request), 'OK') + + def test_add_view_with_request_method_false(self): + view = lambda *arg: 'OK' + config = self._makeOne(autocommit=True) + config.add_view(view=view, request_method='POST') + wrapper = self._getViewCallable(config) + request = self._makeRequest(config) + request.method = 'GET' + self._assertNotFound(wrapper, None, request) + + def test_add_view_with_request_method_sequence_true(self): + from pyramid.renderers import null_renderer + + view = lambda *arg: 'OK' + config = self._makeOne(autocommit=True) + config.add_view( + view=view, request_method=('POST', 'GET'), renderer=null_renderer + ) + wrapper = self._getViewCallable(config) + request = self._makeRequest(config) + request.method = 'POST' + self.assertEqual(wrapper(None, request), 'OK') + + def test_add_view_with_request_method_sequence_conflict(self): + from pyramid.renderers import null_renderer + + view = lambda *arg: 'OK' + config = self._makeOne() + config.add_view( + view=view, request_method=('POST', 'GET'), renderer=null_renderer + ) + config.add_view( + view=view, request_method=('GET', 'POST'), renderer=null_renderer + ) + self.assertRaises(ConfigurationConflictError, config.commit) + + def test_add_view_with_request_method_sequence_false(self): + view = lambda *arg: 'OK' + config = self._makeOne(autocommit=True) + config.add_view(view=view, request_method=('POST', 'HEAD')) + wrapper = self._getViewCallable(config) + request = self._makeRequest(config) + request.method = 'GET' + self._assertNotFound(wrapper, None, request) + + def test_add_view_with_request_method_get_implies_head(self): + from pyramid.renderers import null_renderer + + view = lambda *arg: 'OK' + config = self._makeOne(autocommit=True) + config.add_view( + view=view, request_method='GET', renderer=null_renderer + ) + wrapper = self._getViewCallable(config) + request = self._makeRequest(config) + request.method = 'HEAD' + self.assertEqual(wrapper(None, request), 'OK') + + def test_add_view_with_request_param_noval_true(self): + from pyramid.renderers import null_renderer + + view = lambda *arg: 'OK' + config = self._makeOne(autocommit=True) + config.add_view(view=view, request_param='abc', renderer=null_renderer) + wrapper = self._getViewCallable(config) + request = self._makeRequest(config) + request.params = {'abc': ''} + self.assertEqual(wrapper(None, request), 'OK') + + def test_add_view_with_request_param_noval_false(self): + view = lambda *arg: 'OK' + config = self._makeOne(autocommit=True) + config.add_view(view=view, request_param='abc') + wrapper = self._getViewCallable(config) + request = self._makeRequest(config) + request.params = {} + self._assertNotFound(wrapper, None, request) + + def test_add_view_with_request_param_val_true(self): + from pyramid.renderers import null_renderer + + view = lambda *arg: 'OK' + config = self._makeOne(autocommit=True) + config.add_view( + view=view, request_param='abc=123', renderer=null_renderer + ) + wrapper = self._getViewCallable(config) + request = self._makeRequest(config) + request.params = {'abc': '123'} + self.assertEqual(wrapper(None, request), 'OK') + + def test_add_view_with_request_param_val_false(self): + view = lambda *arg: 'OK' + config = self._makeOne(autocommit=True) + config.add_view(view=view, request_param='abc=123') + wrapper = self._getViewCallable(config) + request = self._makeRequest(config) + request.params = {'abc': ''} + self._assertNotFound(wrapper, None, request) + + def test_add_view_with_xhr_true(self): + from pyramid.renderers import null_renderer + + view = lambda *arg: 'OK' + config = self._makeOne(autocommit=True) + config.add_view(view=view, xhr=True, renderer=null_renderer) + wrapper = self._getViewCallable(config) + request = self._makeRequest(config) + request.is_xhr = True + self.assertEqual(wrapper(None, request), 'OK') + + def test_add_view_with_xhr_false(self): + view = lambda *arg: 'OK' + config = self._makeOne(autocommit=True) + config.add_view(view=view, xhr=True) + wrapper = self._getViewCallable(config) + request = self._makeRequest(config) + request.is_xhr = False + self._assertNotFound(wrapper, None, request) + + def test_add_view_with_header_badregex(self): + view = lambda *arg: 'OK' + config = self._makeOne() + config.add_view(view, header='Host:a\\') + self.assertRaises(ConfigurationError, config.commit) + + def test_add_view_with_header_noval_match(self): + from pyramid.renderers import null_renderer + + view = lambda *arg: 'OK' + config = self._makeOne(autocommit=True) + config.add_view(view=view, header='Host', renderer=null_renderer) + wrapper = self._getViewCallable(config) + request = self._makeRequest(config) + request.headers = {'Host': 'whatever'} + self.assertEqual(wrapper(None, request), 'OK') + + def test_add_view_with_header_noval_nomatch(self): + view = lambda *arg: 'OK' + config = self._makeOne(autocommit=True) + config.add_view(view=view, header='Host') + wrapper = self._getViewCallable(config) + request = self._makeRequest(config) + request.headers = {'NotHost': 'whatever'} + self._assertNotFound(wrapper, None, request) + + def test_add_view_with_header_val_match(self): + from pyramid.renderers import null_renderer + + view = lambda *arg: 'OK' + config = self._makeOne(autocommit=True) + config.add_view(view=view, header=r'Host:\d', renderer=null_renderer) + wrapper = self._getViewCallable(config) + request = self._makeRequest(config) + request.headers = {'Host': '1'} + self.assertEqual(wrapper(None, request), 'OK') + + def test_add_view_with_header_val_nomatch(self): + view = lambda *arg: 'OK' + config = self._makeOne(autocommit=True) + config.add_view(view=view, header=r'Host:\d') + wrapper = self._getViewCallable(config) + request = self._makeRequest(config) + request.headers = {'Host': 'abc'} + self._assertNotFound(wrapper, None, request) + + def test_add_view_with_header_val_missing(self): + from pyramid.httpexceptions import HTTPNotFound + + view = lambda *arg: 'OK' + config = self._makeOne(autocommit=True) + config.add_view(view=view, header=r'Host:\d') + wrapper = self._getViewCallable(config) + request = self._makeRequest(config) + request.headers = {'NoHost': '1'} + self.assertRaises(HTTPNotFound, wrapper, None, request) + + def test_add_view_with_accept_match(self): + from pyramid.renderers import null_renderer + + view = lambda *arg: 'OK' + config = self._makeOne(autocommit=True) + config.add_view(view=view, accept='text/xml', renderer=null_renderer) + wrapper = self._getViewCallable(config) + request = self._makeRequest(config) + request.accept = DummyAccept('text/xml') + self.assertEqual(wrapper(None, request), 'OK') + + def test_add_view_with_accept_nomatch(self): + view = lambda *arg: 'OK' + config = self._makeOne(autocommit=True) + config.add_view(view=view, accept='text/xml') + wrapper = self._getViewCallable(config) + request = self._makeRequest(config) + request.accept = DummyAccept('text/html') + self._assertNotFound(wrapper, None, request) + + def test_add_view_with_wildcard_accept_raises(self): + view = lambda *arg: 'OK' + config = self._makeOne(autocommit=True) + self.assertRaises( + ValueError, lambda: config.add_view(view=view, accept='text/*') + ) + + def test_add_view_with_containment_true(self): + from pyramid.renderers import null_renderer + from zope.interface import directlyProvides + + view = lambda *arg: 'OK' + config = self._makeOne(autocommit=True) + config.add_view(view=view, containment=IDummy, renderer=null_renderer) + wrapper = self._getViewCallable(config) + context = DummyContext() + directlyProvides(context, IDummy) + self.assertEqual(wrapper(context, None), 'OK') + + def test_add_view_with_containment_false(self): + view = lambda *arg: 'OK' + config = self._makeOne(autocommit=True) + config.add_view(view=view, containment=IDummy) + wrapper = self._getViewCallable(config) + context = DummyContext() + self._assertNotFound(wrapper, context, None) + + def test_add_view_with_containment_dottedname(self): + from pyramid.renderers import null_renderer + from zope.interface import directlyProvides + + view = lambda *arg: 'OK' + config = self._makeOne(autocommit=True) + config.add_view( + view=view, + containment='tests.test_config.IDummy', + renderer=null_renderer, + ) + wrapper = self._getViewCallable(config) + context = DummyContext() + directlyProvides(context, IDummy) + self.assertEqual(wrapper(context, None), 'OK') + + def test_add_view_with_path_info_badregex(self): + view = lambda *arg: 'OK' + config = self._makeOne() + config.add_view(view, path_info='\\') + self.assertRaises(ConfigurationError, config.commit) + + def test_add_view_with_path_info_match(self): + from pyramid.renderers import null_renderer + + view = lambda *arg: 'OK' + config = self._makeOne(autocommit=True) + config.add_view(view=view, path_info='/foo', renderer=null_renderer) + wrapper = self._getViewCallable(config) + request = self._makeRequest(config) + request.upath_info = text_(b'/foo') + self.assertEqual(wrapper(None, request), 'OK') + + def test_add_view_with_path_info_nomatch(self): + view = lambda *arg: 'OK' + config = self._makeOne(autocommit=True) + config.add_view(view=view, path_info='/foo') + wrapper = self._getViewCallable(config) + request = self._makeRequest(config) + request.upath_info = text_('/') + self._assertNotFound(wrapper, None, request) + + def test_add_view_with_check_csrf_predicates_match(self): + import warnings + from pyramid.renderers import null_renderer + + view = lambda *arg: 'OK' + config = self._makeOne(autocommit=True) + with warnings.catch_warnings(record=True) as w: + warnings.filterwarnings('always') + config.add_view(view=view, check_csrf=True, renderer=null_renderer) + self.assertEqual(len(w), 1) + wrapper = self._getViewCallable(config) + request = self._makeRequest(config) + request.method = "POST" + request.session = DummySession({'csrf_token': 'foo'}) + request.POST = {'csrf_token': 'foo'} + request.headers = {} + self.assertEqual(wrapper(None, request), 'OK') + + def test_add_view_with_custom_predicates_match(self): + import warnings + from pyramid.renderers import null_renderer + + view = lambda *arg: 'OK' + config = self._makeOne(autocommit=True) + + def pred1(context, request): + return True + + def pred2(context, request): + return True + + predicates = (pred1, pred2) + with warnings.catch_warnings(record=True) as w: + warnings.filterwarnings('always') + config.add_view( + view=view, custom_predicates=predicates, renderer=null_renderer + ) + self.assertEqual(len(w), 1) + wrapper = self._getViewCallable(config) + request = self._makeRequest(config) + self.assertEqual(wrapper(None, request), 'OK') + + def test_add_view_with_custom_predicates_nomatch(self): + import warnings + + view = lambda *arg: 'OK' + config = self._makeOne(autocommit=True) + + def pred1(context, request): + return True + + def pred2(context, request): + return False + + predicates = (pred1, pred2) + with warnings.catch_warnings(record=True) as w: + warnings.filterwarnings('always') + config.add_view(view=view, custom_predicates=predicates) + self.assertEqual(len(w), 1) + wrapper = self._getViewCallable(config) + request = self._makeRequest(config) + self._assertNotFound(wrapper, None, request) + + def test_add_view_custom_predicate_bests_standard_predicate(self): + import warnings + from pyramid.renderers import null_renderer + + view = lambda *arg: 'OK' + view2 = lambda *arg: 'NOT OK' + config = self._makeOne(autocommit=True) + + def pred1(context, request): + return True + + with warnings.catch_warnings(record=True) as w: + warnings.filterwarnings('always') + config.add_view( + view=view, custom_predicates=(pred1,), renderer=null_renderer + ) + config.add_view( + view=view2, request_method='GET', renderer=null_renderer + ) + self.assertEqual(len(w), 1) + wrapper = self._getViewCallable(config) + request = self._makeRequest(config) + request.method = 'GET' + self.assertEqual(wrapper(None, request), 'OK') + + def test_add_view_custom_more_preds_first_bests_fewer_preds_last(self): + from pyramid.renderers import null_renderer + + view = lambda *arg: 'OK' + view2 = lambda *arg: 'NOT OK' + config = self._makeOne(autocommit=True) + config.add_view( + view=view, request_method='GET', xhr=True, renderer=null_renderer + ) + config.add_view( + view=view2, request_method='GET', renderer=null_renderer + ) + wrapper = self._getViewCallable(config) + request = self._makeRequest(config) + request.method = 'GET' + request.is_xhr = True + self.assertEqual(wrapper(None, request), 'OK') + + def test_add_view_same_predicates(self): + view2 = lambda *arg: 'second' + view1 = lambda *arg: 'first' + config = self._makeOne() + config.add_view(view=view1) + config.add_view(view=view2) + self.assertRaises(ConfigurationConflictError, config.commit) + + def test_add_view_with_csrf_param(self): + from pyramid.renderers import null_renderer + + def view(request): + return 'OK' + + config = self._makeOne(autocommit=True) + config.add_view(view, require_csrf='st', renderer=null_renderer) + view = self._getViewCallable(config) + request = self._makeRequest(config) + request.scheme = "http" + request.method = 'POST' + request.POST = {'st': 'foo'} + request.headers = {} + request.session = DummySession({'csrf_token': 'foo'}) + self.assertEqual(view(None, request), 'OK') + + def test_add_view_with_csrf_header(self): + from pyramid.renderers import null_renderer + + def view(request): + return 'OK' + + config = self._makeOne(autocommit=True) + config.add_view(view, require_csrf=True, renderer=null_renderer) + view = self._getViewCallable(config) + request = self._makeRequest(config) + request.scheme = "http" + request.method = 'POST' + request.POST = {} + request.headers = {'X-CSRF-Token': 'foo'} + request.session = DummySession({'csrf_token': 'foo'}) + self.assertEqual(view(None, request), 'OK') + + def test_add_view_with_missing_csrf_header(self): + from pyramid.exceptions import BadCSRFToken + from pyramid.renderers import null_renderer + + def view(request): # pragma: no cover + return 'OK' + + config = self._makeOne(autocommit=True) + config.add_view(view, require_csrf=True, renderer=null_renderer) + view = self._getViewCallable(config) + request = self._makeRequest(config) + request.scheme = "http" + request.method = 'POST' + request.POST = {} + request.headers = {} + request.session = DummySession({'csrf_token': 'foo'}) + self.assertRaises(BadCSRFToken, lambda: view(None, request)) + + def test_add_view_with_permission(self): + from pyramid.renderers import null_renderer + + view1 = lambda *arg: 'OK' + outerself = self + + class DummyPolicy(object): + def effective_principals(self, r): + outerself.assertEqual(r, request) + return ['abc'] + + def permits(self, context, principals, permission): + outerself.assertEqual(context, None) + outerself.assertEqual(principals, ['abc']) + outerself.assertEqual(permission, 'view') + return True + + policy = DummyPolicy() + config = self._makeOne( + authorization_policy=policy, + authentication_policy=policy, + autocommit=True, + ) + config.add_view(view=view1, permission='view', renderer=null_renderer) + view = self._getViewCallable(config) + request = self._makeRequest(config) + self.assertEqual(view(None, request), 'OK') + + def test_add_view_with_default_permission_no_explicit_permission(self): + from pyramid.renderers import null_renderer + + view1 = lambda *arg: 'OK' + outerself = self + + class DummyPolicy(object): + def effective_principals(self, r): + outerself.assertEqual(r, request) + return ['abc'] + + def permits(self, context, principals, permission): + outerself.assertEqual(context, None) + outerself.assertEqual(principals, ['abc']) + outerself.assertEqual(permission, 'view') + return True + + policy = DummyPolicy() + config = self._makeOne( + authorization_policy=policy, + authentication_policy=policy, + default_permission='view', + autocommit=True, + ) + config.add_view(view=view1, renderer=null_renderer) + view = self._getViewCallable(config) + request = self._makeRequest(config) + self.assertEqual(view(None, request), 'OK') + + def test_add_view_with_no_default_permission_no_explicit_permission(self): + from pyramid.renderers import null_renderer + + view1 = lambda *arg: 'OK' + + class DummyPolicy(object): + pass # wont be called + + policy = DummyPolicy() + config = self._makeOne( + authorization_policy=policy, + authentication_policy=policy, + autocommit=True, + ) + config.add_view(view=view1, renderer=null_renderer) + view = self._getViewCallable(config) + request = self._makeRequest(config) + self.assertEqual(view(None, request), 'OK') + + def test_add_view_with_mapper(self): + from pyramid.renderers import null_renderer + + class Mapper(object): + def __init__(self, **kw): + self.__class__.kw = kw + + def __call__(self, view): + return view + + config = self._makeOne(autocommit=True) + + def view(context, request): + return 'OK' + + config.add_view(view=view, mapper=Mapper, renderer=null_renderer) + view = self._getViewCallable(config) + self.assertEqual(view(None, None), 'OK') + self.assertEqual(Mapper.kw['mapper'], Mapper) + + def test_add_view_with_view_defaults(self): + from pyramid.renderers import null_renderer + from pyramid.exceptions import PredicateMismatch + from zope.interface import directlyProvides + + class view(object): + __view_defaults__ = {'containment': 'tests.test_config.IDummy'} + + def __init__(self, request): + pass + + def __call__(self): + return 'OK' + + config = self._makeOne(autocommit=True) + config.add_view(view=view, renderer=null_renderer) + wrapper = self._getViewCallable(config) + context = DummyContext() + directlyProvides(context, IDummy) + request = self._makeRequest(config) + self.assertEqual(wrapper(context, request), 'OK') + context = DummyContext() + request = self._makeRequest(config) + self.assertRaises(PredicateMismatch, wrapper, context, request) + + def test_add_view_with_view_defaults_viewname_is_dottedname_kwarg(self): + from pyramid.renderers import null_renderer + from pyramid.exceptions import PredicateMismatch + from zope.interface import directlyProvides + + config = self._makeOne(autocommit=True) + config.add_view( + view='tests.test_config.test_views.DummyViewDefaultsClass', + renderer=null_renderer, + ) + wrapper = self._getViewCallable(config) + context = DummyContext() + directlyProvides(context, IDummy) + request = self._makeRequest(config) + self.assertEqual(wrapper(context, request), 'OK') + context = DummyContext() + request = self._makeRequest(config) + self.assertRaises(PredicateMismatch, wrapper, context, request) + + def test_add_view_with_view_defaults_viewname_is_dottedname_nonkwarg(self): + from pyramid.renderers import null_renderer + from pyramid.exceptions import PredicateMismatch + from zope.interface import directlyProvides + + config = self._makeOne(autocommit=True) + config.add_view( + 'tests.test_config.test_views.DummyViewDefaultsClass', + renderer=null_renderer, + ) + wrapper = self._getViewCallable(config) + context = DummyContext() + directlyProvides(context, IDummy) + request = self._makeRequest(config) + self.assertEqual(wrapper(context, request), 'OK') + context = DummyContext() + request = self._makeRequest(config) + self.assertRaises(PredicateMismatch, wrapper, context, request) + + def test_add_view_with_view_config_and_view_defaults_doesnt_conflict(self): + from pyramid.renderers import null_renderer + + class view(object): + __view_defaults__ = {'containment': 'tests.test_config.IDummy'} + + class view2(object): + __view_defaults__ = {'containment': 'tests.test_config.IFactory'} + + config = self._makeOne(autocommit=False) + config.add_view(view=view, renderer=null_renderer) + config.add_view(view=view2, renderer=null_renderer) + config.commit() # does not raise + + def test_add_view_with_view_config_and_view_defaults_conflicts(self): + from pyramid.renderers import null_renderer + + class view(object): + __view_defaults__ = {'containment': 'tests.test_config.IDummy'} + + class view2(object): + __view_defaults__ = {'containment': 'tests.test_config.IDummy'} + + config = self._makeOne(autocommit=False) + config.add_view(view=view, renderer=null_renderer) + config.add_view(view=view2, renderer=null_renderer) + self.assertRaises(ConfigurationConflictError, config.commit) + + def test_add_view_class_method_no_attr(self): + from pyramid.renderers import null_renderer + from pyramid.exceptions import ConfigurationError + + config = self._makeOne(autocommit=True) + + class DummyViewClass(object): + def run(self): # pragma: no cover + pass + + def configure_view(): + config.add_view(view=DummyViewClass.run, renderer=null_renderer) + + self.assertRaises(ConfigurationError, configure_view) + + def test_add_view_exception_only_no_regular_view(self): + from zope.interface import implementedBy + from pyramid.renderers import null_renderer + + view1 = lambda *arg: 'OK' + config = self._makeOne(autocommit=True) + config.add_view( + view=view1, + context=Exception, + exception_only=True, + renderer=null_renderer, + ) + view = self._getViewCallable( + config, ctx_iface=implementedBy(Exception) + ) + self.assertTrue(view is None) + + def test_add_view_exception_only(self): + from zope.interface import implementedBy + from pyramid.renderers import null_renderer + + view1 = lambda *arg: 'OK' + config = self._makeOne(autocommit=True) + config.add_view( + view=view1, + context=Exception, + exception_only=True, + renderer=null_renderer, + ) + view = self._getViewCallable( + config, exc_iface=implementedBy(Exception) + ) + self.assertEqual(view1, view) + + def test_add_view_exception_only_misconfiguration(self): + view = lambda *arg: 'OK' + config = self._makeOne(autocommit=True) + + class NotAnException(object): + pass + + self.assertRaises( + ConfigurationError, + config.add_view, + view, + context=NotAnException, + exception_only=True, + ) + + def test_add_exception_view(self): + from zope.interface import implementedBy + from pyramid.renderers import null_renderer + + view1 = lambda *arg: 'OK' + config = self._makeOne(autocommit=True) + config.add_exception_view(view=view1, renderer=null_renderer) + wrapper = self._getViewCallable( + config, exc_iface=implementedBy(Exception) + ) + context = Exception() + request = self._makeRequest(config) + self.assertEqual(wrapper(context, request), 'OK') + + def test_add_exception_view_with_subclass(self): + from zope.interface import implementedBy + from pyramid.renderers import null_renderer + + view1 = lambda *arg: 'OK' + config = self._makeOne(autocommit=True) + config.add_exception_view( + view=view1, context=ValueError, renderer=null_renderer + ) + wrapper = self._getViewCallable( + config, exc_iface=implementedBy(ValueError) + ) + context = ValueError() + request = self._makeRequest(config) + self.assertEqual(wrapper(context, request), 'OK') + + def test_add_exception_view_disallows_name(self): + config = self._makeOne(autocommit=True) + self.assertRaises( + ConfigurationError, + config.add_exception_view, + context=Exception(), + name='foo', + ) + + def test_add_exception_view_disallows_permission(self): + config = self._makeOne(autocommit=True) + self.assertRaises( + ConfigurationError, + config.add_exception_view, + context=Exception(), + permission='foo', + ) + + def test_add_exception_view_disallows_require_csrf(self): + config = self._makeOne(autocommit=True) + self.assertRaises( + ConfigurationError, + config.add_exception_view, + context=Exception(), + require_csrf=True, + ) + + def test_add_exception_view_disallows_for_(self): + config = self._makeOne(autocommit=True) + self.assertRaises( + ConfigurationError, + config.add_exception_view, + context=Exception(), + for_='foo', + ) + + def test_add_exception_view_disallows_exception_only(self): + config = self._makeOne(autocommit=True) + self.assertRaises( + ConfigurationError, + config.add_exception_view, + context=Exception(), + exception_only=True, + ) + + def test_add_exception_view_with_view_defaults(self): + from pyramid.renderers import null_renderer + from pyramid.exceptions import PredicateMismatch + from zope.interface import directlyProvides + from zope.interface import implementedBy + + class view(object): + __view_defaults__ = {'containment': 'tests.test_config.IDummy'} + + def __init__(self, request): + pass + + def __call__(self): + return 'OK' + + config = self._makeOne(autocommit=True) + config.add_exception_view( + view=view, context=Exception, renderer=null_renderer + ) + wrapper = self._getViewCallable( + config, exc_iface=implementedBy(Exception) + ) + context = DummyContext() + directlyProvides(context, IDummy) + request = self._makeRequest(config) + self.assertEqual(wrapper(context, request), 'OK') + context = DummyContext() + request = self._makeRequest(config) + self.assertRaises(PredicateMismatch, wrapper, context, request) + + def test_derive_view_function(self): + from pyramid.renderers import null_renderer + + def view(request): + return 'OK' + + config = self._makeOne() + result = config.derive_view(view, renderer=null_renderer) + self.assertFalse(result is view) + self.assertEqual(result(None, None), 'OK') + + def test_derive_view_dottedname(self): + from pyramid.renderers import null_renderer + + config = self._makeOne() + result = config.derive_view( + 'tests.test_config.dummy_view', renderer=null_renderer + ) + self.assertFalse(result is dummy_view) + self.assertEqual(result(None, None), 'OK') + + def test_derive_view_with_default_renderer_no_explicit_renderer(self): + config = self._makeOne() + + class moo(object): + def __init__(self, view): + pass + + def __call__(self, *arg, **kw): + return 'moo' + + config.add_renderer(None, moo) + config.commit() + + def view(request): + return 'OK' + + result = config.derive_view(view) + self.assertFalse(result is view) + self.assertEqual(result(None, None).body, b'moo') + + def test_derive_view_with_default_renderer_with_explicit_renderer(self): + class moo(object): + pass + + class foo(object): + def __init__(self, view): + pass + + def __call__(self, *arg, **kw): + return b'foo' + + def view(request): + return 'OK' + + config = self._makeOne() + config.add_renderer(None, moo) + config.add_renderer('foo', foo) + config.commit() + result = config.derive_view(view, renderer='foo') + self.assertFalse(result is view) + request = self._makeRequest(config) + self.assertEqual(result(None, request).body, b'foo') + + def test_add_static_view_here_no_utility_registered(self): + from pyramid.renderers import null_renderer + from zope.interface import Interface + from pyramid.interfaces import IView + from pyramid.interfaces import IViewClassifier + + config = self._makeOne(autocommit=True) + config.add_static_view('static', 'files', renderer=null_renderer) + request_type = self._getRouteRequestIface(config, '__static/') + self._assertRoute(config, '__static/', 'static/*subpath') + wrapped = config.registry.adapters.lookup( + (IViewClassifier, request_type, Interface), IView, name='' + ) + from pyramid.request import Request + + request = Request.blank('/static/minimal.txt') + request.subpath = ('minimal.txt',) + result = wrapped(None, request) + self.assertEqual(result.status, '200 OK') + self.assertTrue(result.body.startswith(b'<div')) + + def test_add_static_view_package_relative(self): + from pyramid.interfaces import IStaticURLInfo + + info = DummyStaticURLInfo() + config = self._makeOne(autocommit=True) + config.registry.registerUtility(info, IStaticURLInfo) + config.add_static_view('static', 'tests.test_config:files') + self.assertEqual( + info.added, [(config, 'static', 'tests.test_config:files', {})] + ) + + def test_add_static_view_package_here_relative(self): + from pyramid.interfaces import IStaticURLInfo + + info = DummyStaticURLInfo() + config = self._makeOne(autocommit=True) + config.registry.registerUtility(info, IStaticURLInfo) + config.add_static_view('static', 'files') + self.assertEqual( + info.added, [(config, 'static', 'tests.test_config:files', {})] + ) + + def test_add_static_view_absolute(self): + import os + from pyramid.interfaces import IStaticURLInfo + + info = DummyStaticURLInfo() + config = self._makeOne(autocommit=True) + config.registry.registerUtility(info, IStaticURLInfo) + here = os.path.dirname(__file__) + static_path = os.path.join(here, 'files') + config.add_static_view('static', static_path) + self.assertEqual(info.added, [(config, 'static', static_path, {})]) + + def test_add_forbidden_view(self): + from pyramid.renderers import null_renderer + from zope.interface import implementedBy + from pyramid.interfaces import IRequest + from pyramid.httpexceptions import HTTPForbidden + + config = self._makeOne(autocommit=True) + view = lambda *arg: 'OK' + config.add_forbidden_view(view, renderer=null_renderer) + request = self._makeRequest(config) + view = self._getViewCallable( + config, + exc_iface=implementedBy(HTTPForbidden), + request_iface=IRequest, + ) + result = view(None, request) + self.assertEqual(result, 'OK') + + def test_add_forbidden_view_no_view_argument(self): + from zope.interface import implementedBy + from pyramid.interfaces import IRequest + from pyramid.httpexceptions import HTTPForbidden + + config = self._makeOne(autocommit=True) + config.setup_registry() + config.add_forbidden_view() + request = self._makeRequest(config) + view = self._getViewCallable( + config, + exc_iface=implementedBy(HTTPForbidden), + request_iface=IRequest, + ) + context = HTTPForbidden() + result = view(context, request) + self.assertEqual(result, context) + + def test_add_forbidden_view_allows_other_predicates(self): + from pyramid.renderers import null_renderer + + config = self._makeOne(autocommit=True) + # doesnt blow up + config.add_view_predicate('dummy', DummyPredicate) + config.add_forbidden_view(renderer=null_renderer, dummy='abc') + + def test_add_forbidden_view_disallows_name(self): + config = self._makeOne(autocommit=True) + self.assertRaises( + ConfigurationError, config.add_forbidden_view, name='foo' + ) + + def test_add_forbidden_view_disallows_permission(self): + config = self._makeOne(autocommit=True) + self.assertRaises( + ConfigurationError, config.add_forbidden_view, permission='foo' + ) + + def test_add_forbidden_view_disallows_require_csrf(self): + config = self._makeOne(autocommit=True) + self.assertRaises( + ConfigurationError, config.add_forbidden_view, require_csrf=True + ) + + def test_add_forbidden_view_disallows_context(self): + config = self._makeOne(autocommit=True) + self.assertRaises( + ConfigurationError, config.add_forbidden_view, context='foo' + ) + + def test_add_forbidden_view_disallows_for_(self): + config = self._makeOne(autocommit=True) + self.assertRaises( + ConfigurationError, config.add_forbidden_view, for_='foo' + ) + + def test_add_forbidden_view_with_view_defaults(self): + from pyramid.interfaces import IRequest + from pyramid.renderers import null_renderer + from pyramid.exceptions import PredicateMismatch + from pyramid.httpexceptions import HTTPForbidden + from zope.interface import directlyProvides + from zope.interface import implementedBy + + class view(object): + __view_defaults__ = {'containment': 'tests.test_config.IDummy'} + + def __init__(self, request): + pass + + def __call__(self): + return 'OK' + + config = self._makeOne(autocommit=True) + config.add_forbidden_view(view=view, renderer=null_renderer) + wrapper = self._getViewCallable( + config, + exc_iface=implementedBy(HTTPForbidden), + request_iface=IRequest, + ) + context = DummyContext() + directlyProvides(context, IDummy) + request = self._makeRequest(config) + self.assertEqual(wrapper(context, request), 'OK') + context = DummyContext() + request = self._makeRequest(config) + self.assertRaises(PredicateMismatch, wrapper, context, request) + + def test_add_notfound_view(self): + from pyramid.renderers import null_renderer + from zope.interface import implementedBy + from pyramid.interfaces import IRequest + from pyramid.httpexceptions import HTTPNotFound + + config = self._makeOne(autocommit=True) + view = lambda *arg: arg + config.add_notfound_view(view, renderer=null_renderer) + request = self._makeRequest(config) + view = self._getViewCallable( + config, + exc_iface=implementedBy(HTTPNotFound), + request_iface=IRequest, + ) + result = view(None, request) + self.assertEqual(result, (None, request)) + + def test_add_notfound_view_no_view_argument(self): + from zope.interface import implementedBy + from pyramid.interfaces import IRequest + from pyramid.httpexceptions import HTTPNotFound + + config = self._makeOne(autocommit=True) + config.setup_registry() + config.add_notfound_view() + request = self._makeRequest(config) + view = self._getViewCallable( + config, + exc_iface=implementedBy(HTTPNotFound), + request_iface=IRequest, + ) + context = HTTPNotFound() + result = view(context, request) + self.assertEqual(result, context) + + def test_add_notfound_view_allows_other_predicates(self): + from pyramid.renderers import null_renderer + + config = self._makeOne(autocommit=True) + # doesnt blow up + config.add_view_predicate('dummy', DummyPredicate) + config.add_notfound_view(renderer=null_renderer, dummy='abc') + + def test_add_notfound_view_disallows_name(self): + config = self._makeOne(autocommit=True) + self.assertRaises( + ConfigurationError, config.add_notfound_view, name='foo' + ) + + def test_add_notfound_view_disallows_permission(self): + config = self._makeOne(autocommit=True) + self.assertRaises( + ConfigurationError, config.add_notfound_view, permission='foo' + ) + + def test_add_notfound_view_disallows_require_csrf(self): + config = self._makeOne(autocommit=True) + self.assertRaises( + ConfigurationError, config.add_notfound_view, require_csrf=True + ) + + def test_add_notfound_view_disallows_context(self): + config = self._makeOne(autocommit=True) + self.assertRaises( + ConfigurationError, config.add_notfound_view, context='foo' + ) + + def test_add_notfound_view_disallows_for_(self): + config = self._makeOne(autocommit=True) + self.assertRaises( + ConfigurationError, config.add_notfound_view, for_='foo' + ) + + def test_add_notfound_view_append_slash(self): + from pyramid.response import Response + from pyramid.renderers import null_renderer + from zope.interface import implementedBy + from pyramid.interfaces import IRequest + from pyramid.httpexceptions import HTTPTemporaryRedirect, HTTPNotFound + + config = self._makeOne(autocommit=True) + config.add_route('foo', '/foo/') + + def view(request): # pragma: no cover + return Response('OK') + + config.add_notfound_view( + view, renderer=null_renderer, append_slash=True + ) + request = self._makeRequest(config) + request.environ['PATH_INFO'] = '/foo' + request.query_string = 'a=1&b=2' + request.path = '/scriptname/foo' + view = self._getViewCallable( + config, + exc_iface=implementedBy(HTTPNotFound), + request_iface=IRequest, + ) + result = view(None, request) + self.assertTrue(isinstance(result, HTTPTemporaryRedirect)) + self.assertEqual(result.location, '/scriptname/foo/?a=1&b=2') + + def test_add_notfound_view_append_slash_custom_response(self): + from pyramid.response import Response + from pyramid.renderers import null_renderer + from zope.interface import implementedBy + from pyramid.interfaces import IRequest + from pyramid.httpexceptions import HTTPMovedPermanently, HTTPNotFound + + config = self._makeOne(autocommit=True) + config.add_route('foo', '/foo/') + + def view(request): # pragma: no cover + return Response('OK') + + config.add_notfound_view( + view, renderer=null_renderer, append_slash=HTTPMovedPermanently + ) + request = self._makeRequest(config) + request.environ['PATH_INFO'] = '/foo' + request.query_string = 'a=1&b=2' + request.path = '/scriptname/foo' + view = self._getViewCallable( + config, + exc_iface=implementedBy(HTTPNotFound), + request_iface=IRequest, + ) + result = view(None, request) + self.assertTrue(isinstance(result, HTTPMovedPermanently)) + self.assertEqual(result.location, '/scriptname/foo/?a=1&b=2') + + def test_add_notfound_view_with_view_defaults(self): + from pyramid.interfaces import IRequest + from pyramid.renderers import null_renderer + from pyramid.exceptions import PredicateMismatch + from pyramid.httpexceptions import HTTPNotFound + from zope.interface import directlyProvides + from zope.interface import implementedBy + + class view(object): + __view_defaults__ = {'containment': 'tests.test_config.IDummy'} + + def __init__(self, request): + pass + + def __call__(self): + return 'OK' + + config = self._makeOne(autocommit=True) + config.add_notfound_view(view=view, renderer=null_renderer) + wrapper = self._getViewCallable( + config, + exc_iface=implementedBy(HTTPNotFound), + request_iface=IRequest, + ) + context = DummyContext() + directlyProvides(context, IDummy) + request = self._makeRequest(config) + self.assertEqual(wrapper(context, request), 'OK') + context = DummyContext() + request = self._makeRequest(config) + self.assertRaises(PredicateMismatch, wrapper, context, request) + + # Since Python 3 has to be all cool and fancy and different... + def _assertBody(self, response, value): + from pyramid.compat import text_type + + if isinstance(value, text_type): # pragma: no cover + self.assertEqual(response.text, value) + else: # pragma: no cover + self.assertEqual(response.body, value) + + def test_add_notfound_view_with_renderer(self): + from zope.interface import implementedBy + from pyramid.interfaces import IRequest + from pyramid.httpexceptions import HTTPNotFound + + config = self._makeOne(autocommit=True) + view = lambda *arg: {} + config.introspection = False + config.add_notfound_view(view, renderer='json') + request = self._makeRequest(config) + view = self._getViewCallable( + config, + exc_iface=implementedBy(HTTPNotFound), + request_iface=IRequest, + ) + result = view(None, request) + self._assertBody(result, '{}') + + def test_add_forbidden_view_with_renderer(self): + from zope.interface import implementedBy + from pyramid.interfaces import IRequest + from pyramid.httpexceptions import HTTPForbidden + + config = self._makeOne(autocommit=True) + view = lambda *arg: {} + config.introspection = False + config.add_forbidden_view(view, renderer='json') + request = self._makeRequest(config) + view = self._getViewCallable( + config, + exc_iface=implementedBy(HTTPForbidden), + request_iface=IRequest, + ) + result = view(None, request) + self._assertBody(result, '{}') + + def test_set_view_mapper(self): + from pyramid.interfaces import IViewMapperFactory + + config = self._makeOne(autocommit=True) + mapper = object() + config.set_view_mapper(mapper) + result = config.registry.getUtility(IViewMapperFactory) + self.assertEqual(result, mapper) + + def test_set_view_mapper_dottedname(self): + from pyramid.interfaces import IViewMapperFactory + + config = self._makeOne(autocommit=True) + config.set_view_mapper('tests.test_config') + result = config.registry.getUtility(IViewMapperFactory) + from tests import test_config + + self.assertEqual(result, test_config) + + def test_add_normal_and_exception_view_intr_derived_callable(self): + from pyramid.renderers import null_renderer + from pyramid.exceptions import BadCSRFToken + + config = self._makeOne(autocommit=True) + introspector = DummyIntrospector() + config.introspector = introspector + view = lambda r: 'OK' + config.set_default_csrf_options(require_csrf=True) + config.add_view(view, context=Exception, renderer=null_renderer) + view_intr = introspector.introspectables[-1] + self.assertTrue(view_intr.type_name, 'view') + self.assertEqual(view_intr['callable'], view) + derived_view = view_intr['derived_callable'] + + request = self._makeRequest(config) + request.method = 'POST' + request.scheme = 'http' + request.POST = {} + request.headers = {} + request.session = DummySession({'csrf_token': 'foo'}) + self.assertRaises(BadCSRFToken, lambda: derived_view(None, request)) + request.exception = Exception() + self.assertEqual(derived_view(None, request), 'OK') + + def test_add_view_does_not_accept_iterable_accept(self): + from pyramid.exceptions import ConfigurationError + + config = self._makeOne(autocommit=True) + self.assertRaises( + ConfigurationError, config.add_view, accept=['image/*', 'text/*'] + ) + + def test_default_accept_view_order(self): + from pyramid.interfaces import IAcceptOrder + + config = self._makeOne(autocommit=True) + order = config.registry.getUtility(IAcceptOrder) + result = [v for _, v in order.sorted()] + self.assertEqual( + result, + [ + 'text/html', + 'application/xhtml+xml', + 'application/xml', + 'text/xml', + 'text/plain', + 'application/json', + ], + ) + + def test_add_accept_view_order_override(self): + from pyramid.interfaces import IAcceptOrder + + config = self._makeOne(autocommit=False) + config.add_accept_view_order( + 'text/html', + weighs_more_than='text/xml', + weighs_less_than='application/xml', + ) + config.commit() + order = config.registry.getUtility(IAcceptOrder) + result = [v for _, v in order.sorted()] + self.assertEqual( + result, + [ + 'application/xhtml+xml', + 'application/xml', + 'text/html', + 'text/xml', + 'text/plain', + 'application/json', + ], + ) + + def test_add_accept_view_order_throws_on_wildcard(self): + config = self._makeOne(autocommit=True) + self.assertRaises(ValueError, config.add_accept_view_order, '*/*') + + def test_add_accept_view_order_throws_on_type_mismatch(self): + config = self._makeOne(autocommit=True) + self.assertRaises( + ValueError, + config.add_accept_view_order, + 'text/*', + weighs_more_than='text/html', + ) + self.assertRaises( + ValueError, + config.add_accept_view_order, + 'text/html', + weighs_less_than='application/*', + ) + self.assertRaises( + ConfigurationError, + config.add_accept_view_order, + 'text/html', + weighs_more_than='text/html;charset=utf8', + ) + self.assertRaises( + ConfigurationError, + config.add_accept_view_order, + 'text/html;charset=utf8', + weighs_more_than='text/plain;charset=utf8', + ) + + +class Test_runtime_exc_view(unittest.TestCase): + def _makeOne(self, view1, view2): + from pyramid.config.views import runtime_exc_view + + return runtime_exc_view(view1, view2) + + def test_call(self): + def view1(context, request): + return 'OK' + + def view2(context, request): # pragma: no cover + raise AssertionError + + result_view = self._makeOne(view1, view2) + request = DummyRequest() + result = result_view(None, request) + self.assertEqual(result, 'OK') + + def test_call_dispatches_on_exception(self): + def view1(context, request): # pragma: no cover + raise AssertionError + + def view2(context, request): + return 'OK' + + result_view = self._makeOne(view1, view2) + request = DummyRequest() + request.exception = Exception() + result = result_view(None, request) + self.assertEqual(result, 'OK') + + def test_permitted(self): + def errfn(context, request): # pragma: no cover + raise AssertionError + + def view1(context, request): # pragma: no cover + raise AssertionError + + view1.__permitted__ = lambda c, r: 'OK' + + def view2(context, request): # pragma: no cover + raise AssertionError + + view2.__permitted__ = errfn + result_view = self._makeOne(view1, view2) + request = DummyRequest() + result = result_view.__permitted__(None, request) + self.assertEqual(result, 'OK') + + def test_permitted_dispatches_on_exception(self): + def errfn(context, request): # pragma: no cover + raise AssertionError + + def view1(context, request): # pragma: no cover + raise AssertionError + + view1.__permitted__ = errfn + + def view2(context, request): # pragma: no cover + raise AssertionError + + view2.__permitted__ = lambda c, r: 'OK' + result_view = self._makeOne(view1, view2) + request = DummyRequest() + request.exception = Exception() + result = result_view.__permitted__(None, request) + self.assertEqual(result, 'OK') + + +class Test_requestonly(unittest.TestCase): + def _callFUT(self, view, attr=None): + from pyramid.config.views import requestonly + + return requestonly(view, attr=attr) + + def test_defaults(self): + def aview(request, a=1, b=2): # pragma: no cover + pass + + self.assertTrue(self._callFUT(aview)) + + def test_otherattr(self): + class AView(object): + def __init__(self, request, a=1, b=2): # pragma: no cover + pass + + def bleh(self): # pragma: no cover + pass + + self.assertTrue(self._callFUT(AView, 'bleh')) + + +class Test_isexception(unittest.TestCase): + def _callFUT(self, ob): + from pyramid.config.views import isexception + + return isexception(ob) + + def test_is_exception_instance(self): + class E(Exception): + pass + + e = E() + self.assertEqual(self._callFUT(e), True) + + def test_is_exception_class(self): + class E(Exception): + pass + + self.assertEqual(self._callFUT(E), True) + + def test_is_IException(self): + from pyramid.interfaces import IException + + self.assertEqual(self._callFUT(IException), True) + + def test_is_IException_subinterface(self): + from pyramid.interfaces import IException + + class ISubException(IException): + pass + + self.assertEqual(self._callFUT(ISubException), True) + + +class TestMultiView(unittest.TestCase): + def _getTargetClass(self): + from pyramid.config.views import MultiView + + return MultiView + + def _makeOne(self, name='name'): + return self._getTargetClass()(name) + + def test_class_implements_ISecuredView(self): + from zope.interface.verify import verifyClass + from pyramid.interfaces import ISecuredView + + verifyClass(ISecuredView, self._getTargetClass()) + + def test_instance_implements_ISecuredView(self): + from zope.interface.verify import verifyObject + from pyramid.interfaces import ISecuredView + + verifyObject(ISecuredView, self._makeOne()) + + def test_add(self): + mv = self._makeOne() + mv.add('view', 100) + self.assertEqual(mv.views, [(100, 'view', None)]) + mv.add('view2', 99) + self.assertEqual(mv.views, [(99, 'view2', None), (100, 'view', None)]) + mv.add('view3', 100, accept='text/html') + self.assertEqual(mv.media_views['text/html'], [(100, 'view3', None)]) + mv.add('view4', 99, 'abc', accept='text/html') + self.assertEqual( + mv.media_views['text/html'], + [(99, 'view4', 'abc'), (100, 'view3', None)], + ) + mv.add('view5', 100, accept='text/xml') + self.assertEqual(mv.media_views['text/xml'], [(100, 'view5', None)]) + self.assertEqual(set(mv.accepts), set(['text/xml', 'text/html'])) + self.assertEqual(mv.views, [(99, 'view2', None), (100, 'view', None)]) + + def test_add_with_phash(self): + mv = self._makeOne() + mv.add('view', 100, phash='abc') + self.assertEqual(mv.views, [(100, 'view', 'abc')]) + mv.add('view', 100, phash='abc') + self.assertEqual(mv.views, [(100, 'view', 'abc')]) + mv.add('view', 100, phash='def') + self.assertEqual( + mv.views, [(100, 'view', 'abc'), (100, 'view', 'def')] + ) + mv.add('view', 100, phash='abc') + self.assertEqual( + mv.views, [(100, 'view', 'abc'), (100, 'view', 'def')] + ) + + def test_add_with_phash_override_accept(self): + mv = self._makeOne() + + def view1(): # pragma: no cover + pass + + def view2(): # pragma: no cover + pass + + def view3(): # pragma: no cover + pass + + mv.add(view1, 100, accept='text/html', phash='abc') + mv.add(view2, 100, accept='text/html', phash='abc') + mv.add(view3, 99, accept='text/html', phash='def') + self.assertEqual( + mv.media_views['text/html'], + [(99, view3, 'def'), (100, view2, 'abc')], + ) + + def test_add_with_phash_override_accept2(self): + mv = self._makeOne() + + def view1(): # pragma: no cover + pass + + def view2(): # pragma: no cover + pass + + def view3(): # pragma: no cover + pass + + mv.add(view1, 100, accept='text/html', phash='abc') + mv.add(view2, 100, accept='text/html', phash='def') + mv.add(view3, 99, accept='text/html', phash='ghi') + self.assertEqual( + mv.media_views['text/html'], + [(99, view3, 'ghi'), (100, view1, 'abc'), (100, view2, 'def')], + ) + + def test_multiple_with_functions_as_views(self): + # this failed on py3 at one point, because functions aren't orderable + # and we were sorting the views via a plain sort() rather than + # sort(key=itemgetter(0)). + def view1(request): # pragma: no cover + pass + + def view2(request): # pragma: no cover + pass + + mv = self._makeOne() + mv.add(view1, 100, None) + self.assertEqual(mv.views, [(100, view1, None)]) + mv.add(view2, 100, None) + self.assertEqual(mv.views, [(100, view1, None), (100, view2, None)]) + + def test_get_views_request_has_no_accept(self): + request = DummyRequest() + mv = self._makeOne() + mv.views = [(99, lambda *arg: None)] + self.assertEqual(mv.get_views(request), mv.views) + + def test_get_views_no_self_accepts(self): + request = DummyRequest() + request.accept = True + mv = self._makeOne() + mv.accepts = [] + mv.views = [(99, lambda *arg: None)] + self.assertEqual(mv.get_views(request), mv.views) + + def test_get_views(self): + request = DummyRequest() + request.accept = DummyAccept('text/html') + mv = self._makeOne() + mv.accepts = ['text/html'] + mv.views = [(99, lambda *arg: None)] + html_views = [(98, lambda *arg: None)] + mv.media_views['text/html'] = html_views + self.assertEqual(mv.get_views(request), html_views + mv.views) + + def test_get_views_best_match_returns_None(self): + request = DummyRequest() + request.accept = DummyAccept(None) + mv = self._makeOne() + mv.accepts = ['text/html'] + mv.views = [(99, lambda *arg: None)] + self.assertEqual(mv.get_views(request), mv.views) + + def test_match_not_found(self): + from pyramid.httpexceptions import HTTPNotFound + + mv = self._makeOne() + context = DummyContext() + request = DummyRequest() + self.assertRaises(HTTPNotFound, mv.match, context, request) + + def test_match_predicate_fails(self): + from pyramid.httpexceptions import HTTPNotFound + + mv = self._makeOne() + + def view(context, request): + """ """ + + view.__predicated__ = lambda *arg: False + mv.views = [(100, view, None)] + context = DummyContext() + request = DummyRequest() + self.assertRaises(HTTPNotFound, mv.match, context, request) + + def test_match_predicate_succeeds(self): + mv = self._makeOne() + + def view(context, request): + """ """ + + view.__predicated__ = lambda *arg: True + mv.views = [(100, view, None)] + context = DummyContext() + request = DummyRequest() + result = mv.match(context, request) + self.assertEqual(result, view) + + def test_permitted_no_views(self): + from pyramid.httpexceptions import HTTPNotFound + + mv = self._makeOne() + context = DummyContext() + request = DummyRequest() + self.assertRaises(HTTPNotFound, mv.__permitted__, context, request) + + def test_permitted_no_match_with__permitted__(self): + mv = self._makeOne() + + def view(context, request): + """ """ + + mv.views = [(100, view, None)] + self.assertEqual(mv.__permitted__(None, None), True) + + def test_permitted(self): + mv = self._makeOne() + + def view(context, request): + """ """ + + def permitted(context, request): + return False + + view.__permitted__ = permitted + mv.views = [(100, view, None)] + context = DummyContext() + request = DummyRequest() + result = mv.__permitted__(context, request) + self.assertEqual(result, False) + + def test__call__not_found(self): + from pyramid.httpexceptions import HTTPNotFound + + mv = self._makeOne() + context = DummyContext() + request = DummyRequest() + self.assertRaises(HTTPNotFound, mv, context, request) + + def test___call__intermediate_not_found(self): + from pyramid.exceptions import PredicateMismatch + + mv = self._makeOne() + context = DummyContext() + request = DummyRequest() + request.view_name = '' + expected_response = DummyResponse() + + def view1(context, request): + raise PredicateMismatch + + def view2(context, request): + return expected_response + + mv.views = [(100, view1, None), (99, view2, None)] + response = mv(context, request) + self.assertEqual(response, expected_response) + + def test___call__raise_not_found_isnt_interpreted_as_pred_mismatch(self): + from pyramid.httpexceptions import HTTPNotFound + + mv = self._makeOne() + context = DummyContext() + request = DummyRequest() + request.view_name = '' + + def view1(context, request): + raise HTTPNotFound + + def view2(context, request): + """ """ + + mv.views = [(100, view1, None), (99, view2, None)] + self.assertRaises(HTTPNotFound, mv, context, request) + + def test___call__(self): + mv = self._makeOne() + context = DummyContext() + request = DummyRequest() + request.view_name = '' + expected_response = DummyResponse() + + def view(context, request): + return expected_response + + mv.views = [(100, view, None)] + response = mv(context, request) + self.assertEqual(response, expected_response) + + def test__call_permissive__not_found(self): + from pyramid.httpexceptions import HTTPNotFound + + mv = self._makeOne() + context = DummyContext() + request = DummyRequest() + self.assertRaises(HTTPNotFound, mv, context, request) + + def test___call_permissive_has_call_permissive(self): + mv = self._makeOne() + context = DummyContext() + request = DummyRequest() + request.view_name = '' + expected_response = DummyResponse() + + def view(context, request): + """ """ + + def permissive(context, request): + return expected_response + + view.__call_permissive__ = permissive + mv.views = [(100, view, None)] + response = mv.__call_permissive__(context, request) + self.assertEqual(response, expected_response) + + def test___call_permissive_has_no_call_permissive(self): + mv = self._makeOne() + context = DummyContext() + request = DummyRequest() + request.view_name = '' + expected_response = DummyResponse() + + def view(context, request): + return expected_response + + mv.views = [(100, view, None)] + response = mv.__call_permissive__(context, request) + self.assertEqual(response, expected_response) + + def test__call__with_accept_match(self): + mv = self._makeOne() + context = DummyContext() + request = DummyRequest() + request.accept = DummyAccept('text/html', 'text/xml') + expected_response = DummyResponse() + + def view(context, request): + return expected_response + + mv.views = [(100, None)] + mv.media_views['text/xml'] = [(100, view, None)] + mv.accepts = ['text/xml'] + response = mv(context, request) + self.assertEqual(response, expected_response) + + def test__call__with_accept_miss(self): + mv = self._makeOne() + context = DummyContext() + request = DummyRequest() + request.accept = DummyAccept('text/plain', 'text/html') + expected_response = DummyResponse() + + def view(context, request): + return expected_response + + mv.views = [(100, view, None)] + mv.media_views['text/xml'] = [(100, None, None)] + mv.accepts = ['text/xml'] + response = mv(context, request) + self.assertEqual(response, expected_response) + + +class TestDefaultViewMapper(unittest.TestCase): + def setUp(self): + self.config = testing.setUp() + self.registry = self.config.registry + + def tearDown(self): + del self.registry + testing.tearDown() + + def _makeOne(self, **kw): + from pyramid.config.views import DefaultViewMapper + + kw['registry'] = self.registry + return DefaultViewMapper(**kw) + + def _makeRequest(self): + request = DummyRequest() + request.registry = self.registry + return request + + def test_view_as_function_context_and_request(self): + def view(context, request): + return 'OK' + + mapper = self._makeOne() + result = mapper(view) + self.assertTrue(result is view) + request = self._makeRequest() + self.assertEqual(result(None, request), 'OK') + + def test__view_as_function_with_attr(self): + def view(context, request): + """ """ + + mapper = self._makeOne(attr='__name__') + result = mapper(view) + self.assertFalse(result is view) + request = self._makeRequest() + self.assertRaises(TypeError, result, None, request) + + def test_view_as_function_requestonly(self): + def view(request): + return 'OK' + + mapper = self._makeOne() + result = mapper(view) + self.assertFalse(result is view) + request = self._makeRequest() + self.assertEqual(result(None, request), 'OK') + + def test_view_as_function_requestonly_with_attr(self): + def view(request): + """ """ + + mapper = self._makeOne(attr='__name__') + result = mapper(view) + self.assertFalse(result is view) + request = self._makeRequest() + self.assertRaises(TypeError, result, None, request) + + def test_view_as_newstyle_class_context_and_request(self): + class view(object): + def __init__(self, context, request): + pass + + def __call__(self): + return 'OK' + + mapper = self._makeOne() + result = mapper(view) + self.assertFalse(result is view) + request = self._makeRequest() + self.assertEqual(result(None, request), 'OK') + + def test_view_as_newstyle_class_context_and_request_with_attr(self): + class view(object): + def __init__(self, context, request): + pass + + def index(self): + return 'OK' + + mapper = self._makeOne(attr='index') + result = mapper(view) + self.assertFalse(result is view) + request = self._makeRequest() + self.assertEqual(result(None, request), 'OK') + + def test_view_as_newstyle_class_requestonly(self): + class view(object): + def __init__(self, request): + pass + + def __call__(self): + return 'OK' + + mapper = self._makeOne() + result = mapper(view) + self.assertFalse(result is view) + request = self._makeRequest() + self.assertEqual(result(None, request), 'OK') + + def test_view_as_newstyle_class_requestonly_with_attr(self): + class view(object): + def __init__(self, request): + pass + + def index(self): + return 'OK' + + mapper = self._makeOne(attr='index') + result = mapper(view) + self.assertFalse(result is view) + request = self._makeRequest() + self.assertEqual(result(None, request), 'OK') + + def test_view_as_oldstyle_class_context_and_request(self): + class view: + def __init__(self, context, request): + pass + + def __call__(self): + return 'OK' + + mapper = self._makeOne() + result = mapper(view) + self.assertFalse(result is view) + request = self._makeRequest() + self.assertEqual(result(None, request), 'OK') + + def test_view_as_oldstyle_class_context_and_request_with_attr(self): + class view: + def __init__(self, context, request): + pass + + def index(self): + return 'OK' + + mapper = self._makeOne(attr='index') + result = mapper(view) + self.assertFalse(result is view) + request = self._makeRequest() + self.assertEqual(result(None, request), 'OK') + + def test_view_as_oldstyle_class_requestonly(self): + class view: + def __init__(self, request): + pass + + def __call__(self): + return 'OK' + + mapper = self._makeOne() + result = mapper(view) + self.assertFalse(result is view) + request = self._makeRequest() + self.assertEqual(result(None, request), 'OK') + + def test_view_as_oldstyle_class_requestonly_with_attr(self): + class view: + def __init__(self, request): + pass + + def index(self): + return 'OK' + + mapper = self._makeOne(attr='index') + result = mapper(view) + self.assertFalse(result is view) + request = self._makeRequest() + self.assertEqual(result(None, request), 'OK') + + def test_view_as_instance_context_and_request(self): + class View: + def __call__(self, context, request): + return 'OK' + + view = View() + mapper = self._makeOne() + result = mapper(view) + self.assertTrue(result is view) + request = self._makeRequest() + self.assertEqual(result(None, request), 'OK') + + def test_view_as_instance_context_and_request_and_attr(self): + class View: + def index(self, context, request): + return 'OK' + + view = View() + mapper = self._makeOne(attr='index') + result = mapper(view) + self.assertFalse(result is view) + request = self._makeRequest() + self.assertEqual(result(None, request), 'OK') + + def test_view_as_instance_requestonly(self): + class View: + def __call__(self, request): + return 'OK' + + view = View() + mapper = self._makeOne() + result = mapper(view) + self.assertFalse(result is view) + request = self._makeRequest() + self.assertEqual(result(None, request), 'OK') + + def test_view_as_instance_requestonly_with_attr(self): + class View: + def index(self, request): + return 'OK' + + view = View() + mapper = self._makeOne(attr='index') + result = mapper(view) + self.assertFalse(result is view) + request = self._makeRequest() + self.assertEqual(result(None, request), 'OK') + + +class Test_preserve_view_attrs(unittest.TestCase): + def _callFUT(self, view, wrapped_view): + from pyramid.config.views import preserve_view_attrs + + return preserve_view_attrs(view, wrapped_view) + + def test_it_same(self): + def view(context, request): + """ """ + + result = self._callFUT(view, view) + self.assertTrue(result is view) + + def test_it_view_is_None(self): + def view(context, request): + """ """ + + result = self._callFUT(None, view) + self.assertTrue(result is view) + + def test_it_different_with_existing_original_view(self): + def view1(context, request): # pragma: no cover + pass + + view1.__original_view__ = 'abc' + + def view2(context, request): # pragma: no cover + pass + + result = self._callFUT(view1, view2) + self.assertEqual(result.__original_view__, 'abc') + self.assertFalse(result is view1) + + def test_it_different(self): + class DummyView1: + """ 1 """ + + __name__ = '1' + __module__ = '1' + + def __call__(self, context, request): + """ """ + + def __call_permissive__(self, context, request): + """ """ + + def __predicated__(self, context, request): + """ """ + + def __permitted__(self, context, request): + """ """ + + class DummyView2: + """ 2 """ + + __name__ = '2' + __module__ = '2' + + def __call__(self, context, request): + """ """ + + def __call_permissive__(self, context, request): + """ """ + + def __predicated__(self, context, request): + """ """ + + def __permitted__(self, context, request): + """ """ + + view1 = DummyView1() + view2 = DummyView2() + result = self._callFUT(view2, view1) + self.assertEqual(result, view1) + self.assertTrue(view1.__original_view__ is view2) + self.assertTrue(view1.__doc__ is view2.__doc__) + self.assertTrue(view1.__module__ is view2.__module__) + self.assertTrue(view1.__name__ is view2.__name__) + self.assertTrue( + getattr(view1.__call_permissive__, im_func) + is getattr(view2.__call_permissive__, im_func) + ) + self.assertTrue( + getattr(view1.__permitted__, im_func) + is getattr(view2.__permitted__, im_func) + ) + self.assertTrue( + getattr(view1.__predicated__, im_func) + is getattr(view2.__predicated__, im_func) + ) + + +class TestStaticURLInfo(unittest.TestCase): + def _getTargetClass(self): + from pyramid.config.views import StaticURLInfo + + return StaticURLInfo + + def _makeOne(self): + return self._getTargetClass()() + + def _makeRequest(self): + request = DummyRequest() + request.registry = DummyRegistry() + return request + + def test_verifyClass(self): + from pyramid.interfaces import IStaticURLInfo + from zope.interface.verify import verifyClass + + verifyClass(IStaticURLInfo, self._getTargetClass()) + + def test_verifyObject(self): + from pyramid.interfaces import IStaticURLInfo + from zope.interface.verify import verifyObject + + verifyObject(IStaticURLInfo, self._makeOne()) + + def test_generate_missing(self): + inst = self._makeOne() + request = self._makeRequest() + self.assertRaises(ValueError, inst.generate, 'path', request) + + def test_generate_registration_miss(self): + inst = self._makeOne() + inst.registrations = [ + (None, 'spec', 'route_name'), + ('http://example.com/foo/', 'package:path/', None), + ] + request = self._makeRequest() + result = inst.generate('package:path/abc', request) + self.assertEqual(result, 'http://example.com/foo/abc') + + def test_generate_slash_in_name1(self): + inst = self._makeOne() + inst.registrations = [ + ('http://example.com/foo/', 'package:path/', None) + ] + request = self._makeRequest() + result = inst.generate('package:path/abc', request) + self.assertEqual(result, 'http://example.com/foo/abc') + + def test_generate_slash_in_name2(self): + inst = self._makeOne() + inst.registrations = [ + ('http://example.com/foo/', 'package:path/', None) + ] + request = self._makeRequest() + result = inst.generate('package:path/', request) + self.assertEqual(result, 'http://example.com/foo/') + + def test_generate_quoting(self): + from pyramid.interfaces import IStaticURLInfo + + config = testing.setUp() + try: + config.add_static_view('images', path='mypkg:templates') + request = testing.DummyRequest() + request.registry = config.registry + inst = config.registry.getUtility(IStaticURLInfo) + result = inst.generate('mypkg:templates/foo%2Fbar', request) + self.assertEqual(result, 'http://example.com/images/foo%252Fbar') + finally: + testing.tearDown() + + def test_generate_route_url(self): + inst = self._makeOne() + inst.registrations = [(None, 'package:path/', '__viewname/')] + + def route_url(n, **kw): + self.assertEqual(n, '__viewname/') + self.assertEqual(kw, {'subpath': 'abc', 'a': 1}) + return 'url' + + request = self._makeRequest() + request.route_url = route_url + result = inst.generate('package:path/abc', request, a=1) + self.assertEqual(result, 'url') + + def test_generate_url_unquoted_local(self): + inst = self._makeOne() + inst.registrations = [(None, 'package:path/', '__viewname/')] + + def route_url(n, **kw): + self.assertEqual(n, '__viewname/') + self.assertEqual(kw, {'subpath': 'abc def', 'a': 1}) + return 'url' + + request = self._makeRequest() + request.route_url = route_url + result = inst.generate('package:path/abc def', request, a=1) + self.assertEqual(result, 'url') + + def test_generate_url_quoted_remote(self): + inst = self._makeOne() + inst.registrations = [('http://example.com/', 'package:path/', None)] + request = self._makeRequest() + result = inst.generate('package:path/abc def', request, a=1) + self.assertEqual(result, 'http://example.com/abc%20def') + + def test_generate_url_with_custom_query(self): + inst = self._makeOne() + registrations = [('http://example.com/', 'package:path/', None)] + inst.registrations = registrations + request = self._makeRequest() + result = inst.generate( + 'package:path/abc def', request, a=1, _query='(openlayers)' + ) + self.assertEqual(result, 'http://example.com/abc%20def?(openlayers)') + + def test_generate_url_with_custom_anchor(self): + inst = self._makeOne() + inst.registrations = [('http://example.com/', 'package:path/', None)] + request = self._makeRequest() + uc = text_(b'La Pe\xc3\xb1a', 'utf-8') + result = inst.generate( + 'package:path/abc def', request, a=1, _anchor=uc + ) + self.assertEqual(result, 'http://example.com/abc%20def#La%20Pe%C3%B1a') + + def test_generate_url_cachebust(self): + def cachebust(request, subpath, kw): + kw['foo'] = 'bar' + return 'foo' + '/' + subpath, kw + + inst = self._makeOne() + inst.registrations = [(None, 'package:path/', '__viewname')] + inst.cache_busters = [('package:path/', cachebust, False)] + request = self._makeRequest() + called = [False] + + def route_url(n, **kw): + called[0] = True + self.assertEqual(n, '__viewname') + self.assertEqual( + kw, + { + 'subpath': 'foo/abc', + 'foo': 'bar', + 'pathspec': 'package:path/abc', + 'rawspec': 'package:path/abc', + }, + ) + + request.route_url = route_url + inst.generate('package:path/abc', request) + self.assertTrue(called[0]) + + def test_generate_url_cachebust_abspath(self): + here = os.path.dirname(__file__) + os.sep + + def cachebust(pathspec, subpath, kw): + kw['foo'] = 'bar' + return 'foo' + '/' + subpath, kw + + inst = self._makeOne() + inst.registrations = [(None, here, '__viewname')] + inst.cache_busters = [(here, cachebust, False)] + request = self._makeRequest() + called = [False] + + def route_url(n, **kw): + called[0] = True + self.assertEqual(n, '__viewname') + self.assertEqual( + kw, + { + 'subpath': 'foo/abc', + 'foo': 'bar', + 'pathspec': here + 'abc', + 'rawspec': here + 'abc', + }, + ) + + request.route_url = route_url + inst.generate(here + 'abc', request) + self.assertTrue(called[0]) + + def test_generate_url_cachebust_nomatch(self): + def fake_cb(*a, **kw): # pragma: no cover + raise AssertionError + + inst = self._makeOne() + inst.registrations = [(None, 'package:path/', '__viewname')] + inst.cache_busters = [('package:path2/', fake_cb, False)] + request = self._makeRequest() + called = [False] + + def route_url(n, **kw): + called[0] = True + self.assertEqual(n, '__viewname') + self.assertEqual( + kw, + { + 'subpath': 'abc', + 'pathspec': 'package:path/abc', + 'rawspec': 'package:path/abc', + }, + ) + + request.route_url = route_url + inst.generate('package:path/abc', request) + self.assertTrue(called[0]) + + def test_generate_url_cachebust_with_overrides(self): + config = testing.setUp() + try: + request = testing.DummyRequest() + config.add_static_view('static', 'path') + config.override_asset( + 'tests.test_config:path/', 'tests.test_config:other_path/' + ) + + def cb(val): + def cb_(request, subpath, kw): + kw['_query'] = {'x': val} + return subpath, kw + + return cb_ + + config.add_cache_buster('path', cb('foo')) + result = request.static_url('path/foo.png') + self.assertEqual(result, 'http://example.com/static/foo.png?x=foo') + config.add_cache_buster('other_path', cb('bar'), explicit=True) + result = request.static_url('path/foo.png') + self.assertEqual(result, 'http://example.com/static/foo.png?x=bar') + finally: + testing.tearDown() + + def test_add_already_exists(self): + config = DummyConfig() + inst = self._makeOne() + inst.registrations = [('http://example.com/', 'package:path/', None)] + inst.add(config, 'http://example.com', 'anotherpackage:path') + expected = [('http://example.com/', 'anotherpackage:path/', None)] + self.assertEqual(inst.registrations, expected) + + def test_add_package_root(self): + config = DummyConfig() + inst = self._makeOne() + inst.add(config, 'http://example.com', 'package:') + expected = [('http://example.com/', 'package:', None)] + self.assertEqual(inst.registrations, expected) + + def test_add_url_withendslash(self): + config = DummyConfig() + inst = self._makeOne() + inst.add(config, 'http://example.com/', 'anotherpackage:path') + expected = [('http://example.com/', 'anotherpackage:path/', None)] + self.assertEqual(inst.registrations, expected) + + def test_add_url_noendslash(self): + config = DummyConfig() + inst = self._makeOne() + inst.add(config, 'http://example.com', 'anotherpackage:path') + expected = [('http://example.com/', 'anotherpackage:path/', None)] + self.assertEqual(inst.registrations, expected) + + def test_add_url_noscheme(self): + config = DummyConfig() + inst = self._makeOne() + inst.add(config, '//example.com', 'anotherpackage:path') + expected = [('//example.com/', 'anotherpackage:path/', None)] + self.assertEqual(inst.registrations, expected) + + def test_add_viewname(self): + from pyramid.security import NO_PERMISSION_REQUIRED + from pyramid.static import static_view + + config = DummyConfig() + inst = self._makeOne() + inst.add(config, 'view', 'anotherpackage:path', cache_max_age=1) + expected = [(None, 'anotherpackage:path/', '__view/')] + self.assertEqual(inst.registrations, expected) + self.assertEqual(config.route_args, ('__view/', 'view/*subpath')) + self.assertEqual(config.view_kw['permission'], NO_PERMISSION_REQUIRED) + self.assertEqual(config.view_kw['view'].__class__, static_view) + + def test_add_viewname_with_route_prefix(self): + config = DummyConfig() + config.route_prefix = '/abc' + inst = self._makeOne() + inst.add(config, 'view', 'anotherpackage:path') + expected = [(None, 'anotherpackage:path/', '__/abc/view/')] + self.assertEqual(inst.registrations, expected) + self.assertEqual(config.route_args, ('__/abc/view/', 'view/*subpath')) + + def test_add_viewname_with_permission(self): + config = DummyConfig() + inst = self._makeOne() + inst.add( + config, + 'view', + 'anotherpackage:path', + cache_max_age=1, + permission='abc', + ) + self.assertEqual(config.view_kw['permission'], 'abc') + + def test_add_viewname_with_context(self): + config = DummyConfig() + inst = self._makeOne() + inst.add( + config, + 'view', + 'anotherpackage:path', + cache_max_age=1, + context=DummyContext, + ) + self.assertEqual(config.view_kw['context'], DummyContext) + + def test_add_viewname_with_for_(self): + config = DummyConfig() + inst = self._makeOne() + inst.add( + config, + 'view', + 'anotherpackage:path', + cache_max_age=1, + for_=DummyContext, + ) + self.assertEqual(config.view_kw['context'], DummyContext) + + def test_add_viewname_with_renderer(self): + config = DummyConfig() + inst = self._makeOne() + inst.add( + config, + 'view', + 'anotherpackage:path', + cache_max_age=1, + renderer='mypackage:templates/index.pt', + ) + self.assertEqual( + config.view_kw['renderer'], 'mypackage:templates/index.pt' + ) + + def test_add_cachebust_prevented(self): + config = DummyConfig() + config.registry.settings['pyramid.prevent_cachebust'] = True + inst = self._makeOne() + cachebust = DummyCacheBuster('foo') + inst.add_cache_buster(config, 'mypackage:path', cachebust) + self.assertEqual(inst.cache_busters, []) + + def test_add_cachebuster(self): + config = DummyConfig() + inst = self._makeOne() + inst.add_cache_buster( + config, 'mypackage:path', DummyCacheBuster('foo') + ) + cachebust = inst.cache_busters[-1][1] + subpath, kw = cachebust(None, 'some/path', {}) + self.assertEqual(subpath, 'some/path') + self.assertEqual(kw['x'], 'foo') + + def test_add_cachebuster_abspath(self): + here = os.path.dirname(__file__) + config = DummyConfig() + inst = self._makeOne() + cb = DummyCacheBuster('foo') + inst.add_cache_buster(config, here, cb) + self.assertEqual(inst.cache_busters, [(here + os.sep, cb, False)]) + + def test_add_cachebuster_overwrite(self): + config = DummyConfig() + inst = self._makeOne() + cb1 = DummyCacheBuster('foo') + cb2 = DummyCacheBuster('bar') + inst.add_cache_buster(config, 'mypackage:path/', cb1) + inst.add_cache_buster(config, 'mypackage:path', cb2) + self.assertEqual(inst.cache_busters, [('mypackage:path/', cb2, False)]) + + def test_add_cachebuster_overwrite_explicit(self): + config = DummyConfig() + inst = self._makeOne() + cb1 = DummyCacheBuster('foo') + cb2 = DummyCacheBuster('bar') + inst.add_cache_buster(config, 'mypackage:path/', cb1) + inst.add_cache_buster(config, 'mypackage:path', cb2, True) + self.assertEqual( + inst.cache_busters, + [('mypackage:path/', cb1, False), ('mypackage:path/', cb2, True)], + ) + + def test_add_cachebuster_for_more_specific_path(self): + config = DummyConfig() + inst = self._makeOne() + cb1 = DummyCacheBuster('foo') + cb2 = DummyCacheBuster('bar') + cb3 = DummyCacheBuster('baz') + cb4 = DummyCacheBuster('xyz') + cb5 = DummyCacheBuster('w') + inst.add_cache_buster(config, 'mypackage:path', cb1) + inst.add_cache_buster(config, 'mypackage:path/sub', cb2, True) + inst.add_cache_buster(config, 'mypackage:path/sub/other', cb3) + inst.add_cache_buster(config, 'mypackage:path/sub/other', cb4, True) + inst.add_cache_buster(config, 'mypackage:path/sub/less', cb5, True) + self.assertEqual( + inst.cache_busters, + [ + ('mypackage:path/', cb1, False), + ('mypackage:path/sub/other/', cb3, False), + ('mypackage:path/sub/', cb2, True), + ('mypackage:path/sub/less/', cb5, True), + ('mypackage:path/sub/other/', cb4, True), + ], + ) + + +class Test_view_description(unittest.TestCase): + def _callFUT(self, view): + from pyramid.config.views import view_description + + return view_description(view) + + def test_with_text(self): + def view(): # pragma: no cover + pass + + view.__text__ = 'some text' + result = self._callFUT(view) + self.assertEqual(result, 'some text') + + def test_without_text(self): + def view(): # pragma: no cover + pass + + result = self._callFUT(view) + self.assertEqual(result, 'function tests.test_config.test_views.view') + + +class Test_viewdefaults(unittest.TestCase): + def _makeOne(self, wrapped): + from pyramid.decorator import reify + + return reify(wrapped) + + def test_dunder_attrs_copied(self): + from pyramid.config.views import viewdefaults + + decorator = self._makeOne(viewdefaults) + self.assertEqual(decorator.__doc__, viewdefaults.__doc__) + self.assertEqual(decorator.__name__, viewdefaults.__name__) + self.assertEqual(decorator.__module__, viewdefaults.__module__) + + +class DummyRegistry: + utility = None + + def __init__(self): + self.settings = {} + + def queryUtility(self, type_or_iface, name=None, default=None): + return self.utility or default + + +@implementer(IResponse) +class DummyResponse(object): + content_type = None + default_content_type = None + body = None + + +class DummyRequest: + subpath = () + matchdict = None + request_iface = IRequest + application_url = 'http://example.com/foo' + + def __init__(self, environ=None): + if environ is None: + environ = {} + self.environ = environ + self.params = {} + self.cookies = {} + self.response = DummyResponse() + + +class DummyContext: + pass + + +class DummyAccept(object): + def __init__(self, *matches, **kw): + self.matches = list(matches) + self.contains = kw.pop('contains', False) + + def acceptable_offers(self, offers): + results = [] + for match in self.matches: + if match in offers: + results.append((match, 1.0)) + return results + + +class DummyConfig: + def __init__(self): + self.registry = DummyRegistry() + + route_prefix = '' + + def add_route(self, *args, **kw): + self.route_args = args + self.route_kw = kw + + def add_view(self, *args, **kw): + self.view_args = args + self.view_kw = kw + + def action(self, discriminator, callable, introspectables=()): + callable() + + def introspectable(self, *arg): + return {} + + +@implementer(IMultiView) +class DummyMultiView: + def __init__(self): + self.views = [] + self.name = 'name' + + def add(self, view, order, phash=None, accept=None, accept_order=None): + self.views.append((view, phash, accept, accept_order)) + + def __call__(self, context, request): + return 'OK1' + + def __permitted__(self, context, request): + """ """ + + +class DummyCacheBuster(object): + def __init__(self, token): + self.token = token + + def __call__(self, request, subpath, kw): + kw['x'] = self.token + return subpath, kw + + +def parse_httpdate(s): + import datetime + + # cannot use %Z, must use literal GMT; Jython honors timezone + # but CPython does not + return datetime.datetime.strptime(s, "%a, %d %b %Y %H:%M:%S GMT") + + +def assert_similar_datetime(one, two): + for attr in ('year', 'month', 'day', 'hour', 'minute'): + one_attr = getattr(one, attr) + two_attr = getattr(two, attr) + if not one_attr == two_attr: # pragma: no cover + raise AssertionError('%r != %r in %s' % (one_attr, two_attr, attr)) + + +class DummyStaticURLInfo: + def __init__(self): + self.added = [] + + def add(self, config, name, spec, **kw): + self.added.append((config, name, spec, kw)) + + +class DummyViewDefaultsClass(object): + __view_defaults__ = {'containment': 'tests.test_config.IDummy'} + + def __init__(self, request): + pass + + def __call__(self): + return 'OK' + + +class DummyPredicate(object): + def __init__(self, val, config): + self.val = val + + def text(self): + return 'dummy' + + phash = text + + +class DummyIntrospector(object): + def __init__(self, getval=None): + self.related = [] + self.introspectables = [] + self.getval = getval + + def add(self, introspectable): + self.introspectables.append(introspectable) + + def get(self, name, discrim): + return self.getval + + def relate(self, a, b): + self.related.append((a, b)) + + +class DummySession(dict): + def get_csrf_token(self): + return self['csrf_token'] |
