CHANGES.txt | ●●●●● patch | view | raw | blame | history | |
pyramid/compat.py | ●●●●● patch | view | raw | blame | history | |
pyramid/config/views.py | ●●●●● patch | view | raw | blame | history | |
pyramid/tests/test_config/test_views.py | ●●●●● patch | view | raw | blame | history |
CHANGES.txt
@@ -11,6 +11,11 @@ because it mistakenly detects that a route was matched when, in fact, it was not. - The fix for issue https://github.com/Pylons/pyramid/issues/461 (which made it possible for instance methods to be used as view callables) introduced a backwards incompatibility when methods that declared only a request argument were used. See https://github.com/Pylons/pyramid/issues/503 1.3b3 (2012-03-17) ================== pyramid/compat.py
@@ -1,3 +1,4 @@ import inspect import platform import sys import types @@ -185,8 +186,10 @@ if PY3: # pragma: no cover im_func = '__func__' im_self = '__self__' else: im_func = 'im_func' im_self = 'im_self' try: # pragma: no cover import configparser @@ -237,3 +240,7 @@ from urlparse import unquote as unquote_to_bytes def unquote_bytes_to_wsgi(bytestring): return unquote_to_bytes(bytestring) def is_bound_method(ob): return inspect.ismethod(ob) and getattr(ob, im_self, None) is not None pyramid/config/views.py
@@ -41,6 +41,7 @@ im_func, url_quote, WIN, is_bound_method, ) from pyramid.exceptions import ( @@ -140,18 +141,7 @@ self.decorated_view( self.rendered_view( self.mapped_view( self.text_wrapped_view( view)))))))))) @wraps_view def text_wrapped_view(self, view): # if the method is an instance method, we need to wrap it in order # to be able to assign a __text__ value to it later. see #461. if inspect.ismethod(view): def text_wrapper(context, request): return view(context, request) return text_wrapper return view view))))))))) @wraps_view def mapped_view(self, view): @@ -428,9 +418,16 @@ elif self.attr: mapped_view = self.map_nonclass_attr(view) if inspect.isroutine(mapped_view): # we potentially mutate an unwrapped view here if it's a function; # we do this to avoid function call overhead of injecting another # wrapper # This branch will be true if the view is a function or a method. # We potentially mutate an unwrapped object here if it's a # function. We do this to avoid function call overhead of # injecting another wrapper. However, we must wrap if the # function is a bound method because we can't set attributes on a # bound method. if is_bound_method(view): _mapped_view = mapped_view def mapped_view(context, request): return _mapped_view(context, request) if self.attr is not None: mapped_view.__text__ = 'attr %s of %s' % ( self.attr, object_description(view)) pyramid/tests/test_config/test_views.py
@@ -230,6 +230,18 @@ 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: