diff options
| -rw-r--r-- | pyramid/config/__init__.py | 18 | ||||
| -rw-r--r-- | pyramid/interfaces.py | 13 | ||||
| -rw-r--r-- | pyramid/tests/test_config/test_init.py | 205 | ||||
| -rw-r--r-- | pyramid/tests/test_config/test_util.py | 10 | ||||
| -rw-r--r-- | pyramid/tests/test_util.py | 4 |
5 files changed, 221 insertions, 29 deletions
diff --git a/pyramid/config/__init__.py b/pyramid/config/__init__.py index d4dc0247f..31f35e5ff 100644 --- a/pyramid/config/__init__.py +++ b/pyramid/config/__init__.py @@ -69,7 +69,10 @@ from pyramid.config.security import SecurityConfiguratorMixin from pyramid.config.settings import SettingsConfiguratorMixin from pyramid.config.testing import TestingConfiguratorMixin from pyramid.config.tweens import TweensConfiguratorMixin -from pyramid.config.util import action_method +from pyramid.config.util import ( + action_method, + ActionInfo, + ) from pyramid.config.views import ViewsConfiguratorMixin from pyramid.config.zca import ZCAConfiguratorMixin @@ -491,7 +494,7 @@ class Configurator( if self._ainfo: info = self._ainfo[0] else: - info = '' + info = ActionInfo('<unknown>', 0, '<unknown>', '<unknown>') return info def action(self, discriminator, callable=None, args=(), kw=None, order=None, @@ -918,7 +921,7 @@ class ActionState(object): return True def action(self, discriminator, callable=None, args=(), kw=None, order=None, - includepath=(), info='', introspectables=()): + includepath=(), info=None, introspectables=()): """Add an action with the given discriminator, callable and arguments """ if kw is None: @@ -976,13 +979,11 @@ class ActionState(object): in: oops - Note that actions executed before the error still have an effect: >>> output [('f', (1,), {}), ('f', (2,), {})] - """ try: @@ -992,10 +993,9 @@ class ActionState(object): kw = action['kw'] info = action['info'] introspectables = action['introspectables'] - if callable is None: - continue try: - callable(*args, **kw) + if callable is not None: + callable(*args, **kw) except (KeyboardInterrupt, SystemExit): # pragma: no cover raise except: @@ -1073,7 +1073,7 @@ def resolveConflicts(actions): return output def expand_action(discriminator, callable=None, args=(), kw=None, - includepath=(), info='', order=None, introspectables=()): + includepath=(), info=None, order=None, introspectables=()): if kw is None: kw = {} return dict( diff --git a/pyramid/interfaces.py b/pyramid/interfaces.py index 2576b4e35..05881571e 100644 --- a/pyramid/interfaces.py +++ b/pyramid/interfaces.py @@ -996,12 +996,13 @@ class IIntrospectable(Interface): """ class IActionInfo(Interface): - filename = Attribute('filename as a string') - lineno = Attribute('line number in file as an integer') - function = Attribute('a string representing the function or method ' - 'that was executing') - linerepr = Attribute('a string representing the call site ' - 'which caused the action to be executed') + filename = Attribute('filename of action-invoking code as a string') + lineno = Attribute('line number in file (as an integer) of action-invoking ' + 'code') + function = Attribute('a string representing the module, function or method ' + 'that enclosed the line which invoked the action') + linerepr = Attribute('a string representing the source code line ' + 'which invoked the action') # configuration phases: a lower phase number means the actions associated # with this phase will be executed earlier than those with later phase diff --git a/pyramid/tests/test_config/test_init.py b/pyramid/tests/test_config/test_init.py index e80557096..86dace822 100644 --- a/pyramid/tests/test_config/test_init.py +++ b/pyramid/tests/test_config/test_init.py @@ -228,6 +228,12 @@ class ConfiguratorTests(unittest.TestCase): request_iface=IRequest) self.assertTrue(view.__wraps__ is exceptionresponse_view) + def test_ctor_with_introspector(self): + introspector = DummyIntrospector() + config = self._makeOne(introspector=introspector) + self.assertEqual(config.introspector, introspector) + self.assertEqual(config.registry.introspector, introspector) + def test_with_package_module(self): from pyramid.tests.test_config import test_init import pyramid.tests @@ -637,6 +643,21 @@ pyramid.tests.test_config.dummy_include2""", [('pyramid.tests.test_config.dummy_tween_factory', dummy_tween_factory)]) + def test_introspector_decorator(self): + inst = self._makeOne() + default = inst.introspector + self.failUnless(hasattr(default, 'add')) + self.assertEqual(inst.introspector, inst.registry.introspector) + introspector = DummyIntrospector() + inst.introspector = introspector + new = inst.introspector + self.failUnless(new is introspector) + self.assertEqual(inst.introspector, inst.registry.introspector) + del inst.introspector + default = inst.introspector + self.failIf(default is new) + self.failUnless(hasattr(default, 'add')) + def test_make_wsgi_app(self): import pyramid.config from pyramid.router import Router @@ -740,6 +761,15 @@ pyramid.tests.test_config.dummy_include2""", config = self._makeOne(autocommit=True) self.assertEqual(config.action('discrim', kw={'a':1}), None) + def test_action_autocommit_with_introspectables(self): + from pyramid.config.util 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_branching_nonautocommit_with_config_info(self): config = self._makeOne(autocommit=False) config.info = 'abc' @@ -779,6 +809,18 @@ pyramid.tests.test_config.dummy_include2""", 'kw': {'a': 1}, 'order': None})]) + 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_scan_integration(self): from zope.interface import alsoProvides from pyramid.interfaces import IRequest @@ -1398,7 +1440,7 @@ class TestActionState(unittest.TestCase): 'callable': f, 'discriminator': 1, 'includepath': (), - 'info': '', + 'info': None, 'introspectables': (), 'kw': {'x': 1}, 'order': None}]) @@ -1409,7 +1451,7 @@ class TestActionState(unittest.TestCase): 'callable': f, 'discriminator': 1, 'includepath': (), - 'info': '', + 'info': None, 'introspectables': (), 'kw': {'x': 1}, 'order': None}, @@ -1418,7 +1460,7 @@ class TestActionState(unittest.TestCase): 'callable': None, 'discriminator': None, 'includepath': (), - 'info': '', + 'info': None, 'introspectables': (), 'kw': {}, 'order': None},]) @@ -1433,7 +1475,7 @@ class TestActionState(unittest.TestCase): 'callable': None, 'discriminator': None, 'includepath': ('abc',), - 'info': '', + 'info': None, 'introspectables': (), 'kw': {}, 'order': None}]) @@ -1476,20 +1518,36 @@ class TestActionState(unittest.TestCase): 'callable': None, 'discriminator': None, 'includepath': (), - 'info': '', + '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': None}]) + def test_processSpec(self): c = self._makeOne() self.assertTrue(c.processSpec('spec')) self.assertFalse(c.processSpec('spec')) - def test_execute_actions_simple(self): + def test_execute_actions_tuples(self): output = [] def f(*a, **k): - output.append(('f', a, k)) + output.append((a, k)) c = self._makeOne() c.actions = [ (1, f, (1,)), @@ -1498,7 +1556,57 @@ class TestActionState(unittest.TestCase): (None, None), ] c.execute_actions() - self.assertEqual(output, [('f', (1,), {}), ('f', (2,), {})]) + 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':None, 'includepath':(), 'info':None, + 'introspectables':()}, + {'discriminator':1, 'callable':f, 'args':(11,), 'kw':{}, + 'includepath':('x',), 'order': None, 'info':None, + 'introspectables':()}, + {'discriminator':2, 'callable':f, 'args':(2,), 'kw':{}, + 'order':None, 'includepath':(), 'info':None, + 'introspectables':()}, + {'discriminator':None, 'callable':None, 'args':(), 'kw':{}, + 'order':None, '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':None, 'includepath':(), 'info':None, + 'introspectables':(intr,)}, + ] + introspector = DummyIntrospector() + 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':None, 'includepath':(), 'info':None, + 'introspectables':(intr,)}, + ] + introspector = DummyIntrospector() + c.execute_actions(introspector=introspector) + self.assertEqual(intr.registered, [(introspector, None)]) def test_execute_actions_error(self): output = [] @@ -1521,7 +1629,7 @@ class Test_resolveConflicts(unittest.TestCase): from pyramid.config import resolveConflicts return resolveConflicts(actions) - def test_it_success(self): + def test_it_success_tuples(self): from pyramid.tests.test_config import dummyfactory as f result = self._callFUT([ (None, f), @@ -1534,7 +1642,68 @@ class Test_resolveConflicts(unittest.TestCase): ]) self.assertEqual( result, - [{'info': '', + [{'info': None, + 'args': (), + 'callable': f, + 'introspectables': (), + 'kw': {}, + 'discriminator': None, + 'includepath': (), + 'order': 0}, + + {'info': 'first', + 'args': (1,), + 'callable': f, + 'introspectables': (), + 'kw': {}, + 'discriminator': 1, + 'includepath': (), + 'order': 1}, + + {'info': None, + 'args': (3,), + 'callable': f, + 'introspectables': (), + 'kw': {}, + 'discriminator': 3, + 'includepath': ('y',), + 'order': 5}, + + {'info': None, + 'args': (5,), + 'callable': f, + 'introspectables': (), + 'kw': {}, + 'discriminator': None, + 'includepath': ('y',), + 'order': 6}, + + {'info': 'should be last', + 'args': (4,), + 'callable': f, + 'introspectables': (), + 'kw': {}, + 'discriminator': 4, + 'includepath': ('y',), + 'order': 99999} + ] + ) + + def test_it_success_dicts(self): + from pyramid.tests.test_config import dummyfactory as f + from pyramid.config import expand_action + result = self._callFUT([ + expand_action(None, f), + expand_action(1, f, (1,), {}, (), 'first'), + expand_action(1, f, (2,), {}, ('x',), 'second'), + expand_action(1, f, (3,), {}, ('y',), 'third'), + expand_action(4, f, (4,), {}, ('y',), 'should be last', 99999), + expand_action(3, f, (3,), {}, ('y',)), + expand_action(None, f, (5,), {}, ('y',)), + ]) + self.assertEqual( + result, + [{'info': None, 'args': (), 'callable': f, 'introspectables': (), @@ -1552,7 +1721,7 @@ class Test_resolveConflicts(unittest.TestCase): 'includepath': (), 'order': 1}, - {'info': '', + {'info': None, 'args': (3,), 'callable': f, 'introspectables': (), @@ -1561,7 +1730,7 @@ class Test_resolveConflicts(unittest.TestCase): 'includepath': ('y',), 'order': 5}, - {'info': '', + {'info': None, 'args': (5,), 'callable': f, 'introspectables': (), @@ -1700,3 +1869,15 @@ class DummyZCMLContext(object): includepath = () info = '' +class DummyIntrospector(object): + def __init__(self): + self.intrs = [] + def add(self, intr): + self.intrs.append(intr) + +class DummyIntrospectable(object): + def __init__(self): + self.registered = [] + def register(self, introspector, action_info): + self.registered.append((introspector, action_info)) + diff --git a/pyramid/tests/test_config/test_util.py b/pyramid/tests/test_config/test_util.py index bc7cf0a82..1225b3e21 100644 --- a/pyramid/tests/test_config/test_util.py +++ b/pyramid/tests/test_config/test_util.py @@ -312,6 +312,16 @@ class Test__make_predicates(unittest.TestCase): hash2, _, __= self._callFUT(request_method='GET') self.assertEqual(hash1, hash2) +class TestActionInfo(unittest.TestCase): + def _makeOne(self, filename, lineno, function, linerepr): + from pyramid.config.util import ActionInfo + return ActionInfo(filename, lineno, function, linerepr) + + def test___str__(self): + inst = self._makeOne('filename', 'lineno', 'function', 'linerepr') + self.assertEqual(str(inst), + "Line lineno of file filename in function: 'linerepr'") + class DummyCustomPredicate(object): def __init__(self): self.__text__ = 'custom predicate' diff --git a/pyramid/tests/test_util.py b/pyramid/tests/test_util.py index d010e6653..61e372417 100644 --- a/pyramid/tests/test_util.py +++ b/pyramid/tests/test_util.py @@ -279,9 +279,9 @@ class Test_object_description(unittest.TestCase): self.assertEqual(self._callFUT(('a', 'b')), "('a', 'b')") def test_set(self): - if PY3: + if PY3: # pragma: no cover self.assertEqual(self._callFUT(set(['a'])), "{'a'}") - else: + else: # pragma: no cover self.assertEqual(self._callFUT(set(['a'])), "set(['a'])") def test_list(self): |
