Permalink
Browse files

Refactor add_handler, add test for bug in explicit action name not being

a method.
  • Loading branch information...
1 parent c848ef7 commit c0fb94007b7c24b409bb1734dfa75cc24364a4e0 @bbangert bbangert committed Mar 22, 2011
Showing with 91 additions and 58 deletions.
  1. +70 −53 pyramid_handlers/__init__.py
  2. +21 −5 pyramid_handlers/tests.py
@@ -79,62 +79,79 @@ def add_handler(self, route_name, pattern, handler, action=None, **kw):
'path %r' % (action, pattern))
if path_has_action:
- autoexpose = getattr(handler, '__autoexpose__', r'[A-Za-z]+')
- if autoexpose:
- try:
- autoexpose = re.compile(autoexpose).match
- except (re.error, TypeError), why:
- raise ConfigurationError(why[0])
- for method_name, method in inspect.getmembers(
- handler, inspect.ismethod):
- configs = getattr(method, '__exposed__', [])
- if autoexpose and not configs:
- if autoexpose(method_name):
- configs = [{}]
- for expose_config in configs:
- # we don't want to mutate any dict in __exposed__,
- # so we copy each
- view_args = expose_config.copy()
- action = view_args.pop('name', method_name)
- preds = list(view_args.pop('custom_predicates', []))
- preds.append(ActionPredicate(action))
- view_args['custom_predicates'] = preds
- self.add_view(view=handler, attr=method_name,
- route_name=route_name,
- decorator=action_decorator, **view_args)
+ scan_handler(self, handler, route_name, action_decorator)
else:
- method_name = action
- if method_name is None:
- method_name = '__call__'
-
- # Scan the controller for any other methods with this action name
- for meth_name, method in inspect.getmembers(
- handler, inspect.ismethod):
- configs = getattr(method, '__exposed__', [{}])
- for expose_config in configs:
- # Don't re-register the same view if this method name is
- # the action name
- if meth_name == action:
- continue
- # We only reg a view if the name matches the action
- if expose_config.get('name') != method_name:
- continue
- # we don't want to mutate any dict in __exposed__,
- # so we copy each
- view_args = expose_config.copy()
- del view_args['name']
- self.add_view(view=handler, attr=meth_name,
- route_name=route_name,
- decorator=action_decorator, **view_args)
-
- # Now register the method itself
- method = getattr(handler, method_name, None)
+ locate_view_by_name(
+ config=self,
+ handler=handler,
+ route_name=route_name,
+ action_decorator=action_decorator,
+ name=action
+ )
+ return route
+
+
+def scan_handler(config, handler, route_name, action_decorator):
+ """Scan a handler for automatically exposed views to register"""
+ autoexpose = getattr(handler, '__autoexpose__', r'[A-Za-z]+')
+ if autoexpose:
+ try:
+ autoexpose = re.compile(autoexpose).match
+ except (re.error, TypeError), why:
+ raise ConfigurationError(why[0])
+ for method_name, method in inspect.getmembers(
+ handler, inspect.ismethod):
+ configs = getattr(method, '__exposed__', [])
+ if autoexpose and not configs:
+ if autoexpose(method_name):
+ configs = [{}]
+ for expose_config in configs:
+ # we don't want to mutate any dict in __exposed__,
+ # so we copy each
+ view_args = expose_config.copy()
+ action = view_args.pop('name', method_name)
+ preds = list(view_args.pop('custom_predicates', []))
+ preds.append(ActionPredicate(action))
+ view_args['custom_predicates'] = preds
+ config.add_view(view=handler, attr=method_name,
+ route_name=route_name,
+ decorator=action_decorator, **view_args)
+
+
+def locate_view_by_name(config, handler, route_name, action_decorator, name):
+ """Locate and add all the views in a handler with the matching name, or
+ the method itself if it exists."""
+ method_name = name
+ if method_name is None:
+ method_name = '__call__'
+
+ # Scan the controller for any other methods with this action name
+ for meth_name, method in inspect.getmembers(
+ handler, inspect.ismethod):
configs = getattr(method, '__exposed__', [{}])
for expose_config in configs:
- self.add_view(view=handler, attr=action, route_name=route_name,
- decorator=action_decorator, **expose_config)
-
- return route
+ # Don't re-register the same view if this method name is
+ # the action name
+ if meth_name == name:
+ continue
+ # We only reg a view if the name matches the action
+ if expose_config.get('name') != method_name:
+ continue
+ # we don't want to mutate any dict in __exposed__,
+ # so we copy each
+ view_args = expose_config.copy()
+ del view_args['name']
+ config.add_view(view=handler, attr=meth_name,
+ route_name=route_name,
+ decorator=action_decorator, **view_args)
+
+ # Now register the method itself
+ method = getattr(handler, method_name, None)
+ if method:
+ configs = getattr(method, '__exposed__', [{}])
+ for expose_config in configs:
+ config.add_view(view=handler, attr=name, route_name=route_name,
+ decorator=action_decorator, **expose_config)
class ActionPredicate(object):
View
@@ -254,11 +254,13 @@ def test_add_handler_string(self):
config = self._makeOne()
def dummy_add_view(**kw):
views.append(kw)
+ class DummyHandler(object):
+ def one(self): pass
config.add_view = dummy_add_view
- config.add_handler('name', '/abc', 'pyramid')
+ config.add_handler('name', '/abc', DummyHandler)
self.assertEqual(len(views), 1)
view = views[0]
- self.assertEqual(view['view'], pyramid)
+ self.assertEqual(view['view'], DummyHandler)
def test_add_handler_pattern_None_no_previous_route(self):
from pyramid.exceptions import ConfigurationError
@@ -273,13 +275,27 @@ def test_add_handler_pattern_None_with_previous_route(self):
views = []
def dummy_add_view(**kw):
views.append(kw)
+ class DummyHandler(object):
+ def one(self): pass
config.add_view = dummy_add_view
config.add_route = None # shouldn't be called
- config.add_handler('name', None, 'pyramid')
+ config.add_handler('name', None, DummyHandler)
self.assertEqual(len(views), 1)
view = views[0]
- self.assertEqual(view['view'], pyramid)
-
+ self.assertEqual(view['view'], DummyHandler)
+
+ def test_add_handler_explicit_action_lacking(self):
+ import pyramid
+ config = self._makeOne()
+ config.add_route('name', ':def')
+ views = []
+ def dummy_add_view(**kw): views.append(kw)
+ class DummyHandler(object):
+ def one(self): pass
+ config.add_view = dummy_add_view # shouldn't be called
+ config.add_route = None # shouldn't be called
+ config.add_handler('name', None, DummyHandler, action='two')
+ self.assertEqual(len(views), 0)
def _assertRoute(self, config, name, path, num_predicates=0):
from pyramid.interfaces import IRoutesMapper

0 comments on commit c0fb940

Please sign in to comment.