Merge pull request #3123 from mmerickel/backport-3122-to-1.9-branch
add _depth and _category arguments to all decorators
| | |
| | | unreleased |
| | | ========== |
| | | |
| | | - Add a ``_category`` argument to the ``pyramid.view.view_config`` decorator. |
| | | This argument will be forwarded to venusian and can be used to affect |
| | | what items are picked up by ``config.scan(..., category=...)``. |
| | | See https://github.com/Pylons/pyramid/pull/3121 |
| | | - Add a ``_depth`` and ``_category`` arguments to all of the venusian |
| | | decorators. The ``_category`` argument can be used to affect which actions |
| | | are registered when performing a ``config.scan(..., category=...)`` with a |
| | | specific category. The ``_depth`` argument should be used when wrapping |
| | | the decorator in your own. This change affects ``pyramid.view.view_config``, |
| | | ``pyramid.view.exception_view_config``, |
| | | ``pyramid.view.forbidden_view_config``, ``pyramid.view.notfound_view_config``, |
| | | ``pyramid.events.subscriber`` and ``pyramid.response.response_adapter`` |
| | | decorators. See https://github.com/Pylons/pyramid/pull/3121 and |
| | | https://github.com/Pylons/pyramid/pull/3123 |
| | | |
| | | 1.9 (2017-06-26) |
| | | ================ |
| | |
| | | :ref:`subscriber_predicates` for a description of how predicates can |
| | | narrow the set of circumstances in which a subscriber will be called. |
| | | |
| | | Two additional keyword arguments which will be passed to the |
| | | :term:`venusian` ``attach`` function are ``_depth`` and ``_category``. |
| | | |
| | | ``_depth`` is provided for people who wish to reuse this class from another |
| | | decorator. The default value is ``0`` and should be specified relative to |
| | | the ``subscriber`` invocation. It will be passed in to the |
| | | :term:`venusian` ``attach`` function as the depth of the callstack when |
| | | Venusian checks if the decorator is being used in a class or module |
| | | context. It's not often used, but it can be useful in this circumstance. |
| | | |
| | | ``_category`` sets the decorator category name. It can be useful in |
| | | combination with the ``category`` argument of ``scan`` to control which |
| | | views should be processed. |
| | | |
| | | See the :py:func:`venusian.attach` function in Venusian for more |
| | | information about the ``_depth`` and ``_category`` arguments. |
| | | |
| | | .. versionchanged:: 1.9.1 |
| | | Added the ``_depth`` and ``_category`` arguments. |
| | | |
| | | """ |
| | | venusian = venusian # for unit testing |
| | | |
| | | def __init__(self, *ifaces, **predicates): |
| | | self.ifaces = ifaces |
| | | self.predicates = predicates |
| | | self.depth = predicates.pop('_depth', 0) |
| | | self.category = predicates.pop('_category', 'pyramid') |
| | | |
| | | def register(self, scanner, name, wrapped): |
| | | config = scanner.config |
| | |
| | | config.add_subscriber(wrapped, iface, **self.predicates) |
| | | |
| | | def __call__(self, wrapped): |
| | | self.venusian.attach(wrapped, self.register, category='pyramid') |
| | | self.venusian.attach(wrapped, self.register, category=self.category, |
| | | depth=self.depth + 1) |
| | | return wrapped |
| | | |
| | | @implementer(INewRequest) |
| | |
| | | config = Configurator() |
| | | config.scan('somepackage_containing_adapters') |
| | | |
| | | Two additional keyword arguments which will be passed to the |
| | | :term:`venusian` ``attach`` function are ``_depth`` and ``_category``. |
| | | |
| | | ``_depth`` is provided for people who wish to reuse this class from another |
| | | decorator. The default value is ``0`` and should be specified relative to |
| | | the ``response_adapter`` invocation. It will be passed in to the |
| | | :term:`venusian` ``attach`` function as the depth of the callstack when |
| | | Venusian checks if the decorator is being used in a class or module |
| | | context. It's not often used, but it can be useful in this circumstance. |
| | | |
| | | ``_category`` sets the decorator category name. It can be useful in |
| | | combination with the ``category`` argument of ``scan`` to control which |
| | | views should be processed. |
| | | |
| | | See the :py:func:`venusian.attach` function in Venusian for more |
| | | information about the ``_depth`` and ``_category`` arguments. |
| | | |
| | | .. versionchanged:: 1.9.1 |
| | | Added the ``_depth`` and ``_category`` arguments. |
| | | |
| | | """ |
| | | venusian = venusian # for unit testing |
| | | |
| | | def __init__(self, *types_or_ifaces): |
| | | def __init__(self, *types_or_ifaces, **kwargs): |
| | | self.types_or_ifaces = types_or_ifaces |
| | | self.depth = kwargs.pop('_depth', 0) |
| | | self.category = kwargs.pop('_category', 'pyramid') |
| | | self.kwargs = kwargs |
| | | |
| | | def register(self, scanner, name, wrapped): |
| | | config = scanner.config |
| | | for type_or_iface in self.types_or_ifaces: |
| | | config.add_response_adapter(wrapped, type_or_iface) |
| | | config.add_response_adapter(wrapped, type_or_iface, **self.kwargs) |
| | | |
| | | def __call__(self, wrapped): |
| | | self.venusian.attach(wrapped, self.register, category='pyramid') |
| | | self.venusian.attach(wrapped, self.register, category=self.category, |
| | | depth=self.depth + 1) |
| | | return wrapped |
| | | |
| | | |
| | |
| | | def foo(): pass |
| | | dec(foo) |
| | | self.assertEqual(dummy_venusian.attached, |
| | | [(foo, dec.register, 'pyramid')]) |
| | | [(foo, dec.register, 'pyramid', 1)]) |
| | | |
| | | def test___call___with_venusian_args(self): |
| | | dec = self._makeOne(_category='foo', _depth=1) |
| | | dummy_venusian = DummyVenusian() |
| | | dec.venusian = dummy_venusian |
| | | def foo(): pass |
| | | dec(foo) |
| | | self.assertEqual(dummy_venusian.attached, |
| | | [(foo, dec.register, 'foo', 2)]) |
| | | |
| | | def test_regsister_with_predicates(self): |
| | | from zope.interface import Interface |
| | |
| | | def __init__(self): |
| | | self.attached = [] |
| | | |
| | | def attach(self, wrapped, fn, category=None): |
| | | self.attached.append((wrapped, fn, category)) |
| | | def attach(self, wrapped, fn, category=None, depth=None): |
| | | self.attached.append((wrapped, fn, category, depth)) |
| | | |
| | | class Dummy: |
| | | pass |
| | |
| | | def tearDown(self): |
| | | self.config.end() |
| | | |
| | | def _makeOne(self, *types_or_ifaces): |
| | | def _makeOne(self, *types_or_ifaces, **kw): |
| | | from pyramid.response import response_adapter |
| | | return response_adapter(*types_or_ifaces) |
| | | return response_adapter(*types_or_ifaces, **kw) |
| | | |
| | | def test_register_single(self): |
| | | from zope.interface import Interface |
| | |
| | | def foo(): pass |
| | | dec(foo) |
| | | self.assertEqual(dummy_venusian.attached, |
| | | [(foo, dec.register, 'pyramid')]) |
| | | [(foo, dec.register, 'pyramid', 1)]) |
| | | |
| | | def test___call___with_venusian_args(self): |
| | | from zope.interface import Interface |
| | | class IFoo(Interface): pass |
| | | dec = self._makeOne(IFoo, _category='foo', _depth=1) |
| | | dummy_venusian = DummyVenusian() |
| | | dec.venusian = dummy_venusian |
| | | def foo(): pass |
| | | dec(foo) |
| | | self.assertEqual(dummy_venusian.attached, |
| | | [(foo, dec.register, 'foo', 2)]) |
| | | |
| | | |
| | | class TestGetResponseFactory(unittest.TestCase): |
| | |
| | | def __init__(self): |
| | | self.attached = [] |
| | | |
| | | def attach(self, wrapped, fn, category=None): |
| | | self.attached.append((wrapped, fn, category)) |
| | | def attach(self, wrapped, fn, category=None, depth=None): |
| | | self.attached.append((wrapped, fn, category, depth)) |
| | |
| | | self.assertEqual(settings[0]['attr'], 'view') |
| | | self.assertEqual(settings[0]['_info'], 'codeinfo') |
| | | |
| | | def test_call_with_venusian_args(self): |
| | | decorator = self._makeOne(_depth=1, _category='foo') |
| | | venusian = DummyVenusian() |
| | | decorator.venusian = venusian |
| | | def foo(): pass |
| | | decorator(foo) |
| | | attachments = venusian.attachments |
| | | category = attachments[0][2] |
| | | depth = attachments[0][3] |
| | | self.assertEqual(depth, 2) |
| | | self.assertEqual(category, 'foo') |
| | | |
| | | class Test_forbidden_view_config(BaseTest, unittest.TestCase): |
| | | def _makeOne(self, **kw): |
| | | from pyramid.view import forbidden_view_config |
| | |
| | | self.assertEqual(settings[0]['view'], None) # comes from call_venusian |
| | | self.assertEqual(settings[0]['attr'], 'view') |
| | | self.assertEqual(settings[0]['_info'], 'codeinfo') |
| | | |
| | | def test_call_with_venusian_args(self): |
| | | decorator = self._makeOne(_depth=1, _category='foo') |
| | | venusian = DummyVenusian() |
| | | decorator.venusian = venusian |
| | | def foo(): pass |
| | | decorator(foo) |
| | | attachments = venusian.attachments |
| | | category = attachments[0][2] |
| | | depth = attachments[0][3] |
| | | self.assertEqual(depth, 2) |
| | | self.assertEqual(category, 'foo') |
| | | |
| | | class Test_exception_view_config(BaseTest, unittest.TestCase): |
| | | def _makeOne(self, *args, **kw): |
| | |
| | | self.assertEqual(settings[0]['view'], None) # comes from call_venusian |
| | | self.assertEqual(settings[0]['attr'], 'view') |
| | | self.assertEqual(settings[0]['_info'], 'codeinfo') |
| | | |
| | | def test_call_with_venusian_args(self): |
| | | decorator = self._makeOne(_depth=1, _category='foo') |
| | | venusian = DummyVenusian() |
| | | decorator.venusian = venusian |
| | | def foo(): pass |
| | | decorator(foo) |
| | | attachments = venusian.attachments |
| | | category = attachments[0][2] |
| | | depth = attachments[0][3] |
| | | self.assertEqual(depth, 2) |
| | | self.assertEqual(category, 'foo') |
| | | |
| | | class RenderViewToResponseTests(BaseTest, unittest.TestCase): |
| | | def _callFUT(self, *arg, **kw): |
| | |
| | | decorator.venusian = venusian |
| | | def foo(): pass |
| | | decorator(foo) |
| | | self.assertEqual(venusian.depth, 2) |
| | | attachments = venusian.attachments |
| | | depth = attachments[0][3] |
| | | self.assertEqual(depth, 2) |
| | | |
| | | def test_call_withoutcategory(self): |
| | | decorator = self._makeOne() |
| | |
| | | self.attachments = [] |
| | | |
| | | def attach(self, wrapped, callback, category=None, depth=1): |
| | | self.attachments.append((wrapped, callback, category)) |
| | | self.depth = depth |
| | | self.attachments.append((wrapped, callback, category, depth)) |
| | | return self.info |
| | | |
| | | class DummyRegistry(object): |
| | |
| | | def call_venusian(venusian, context=None): |
| | | if context is None: |
| | | context = DummyVenusianContext() |
| | | for wrapped, callback, category in venusian.attachments: |
| | | for wrapped, callback, category, depth in venusian.attachments: |
| | | callback(context, None, None) |
| | | return context.config |
| | | |
| | |
| | | combination with the ``category`` argument of ``scan`` to control which |
| | | views should be processed. |
| | | |
| | | See the :py:func:`venusian.attach` function in Venusian for more information. |
| | | See the :py:func:`venusian.attach` function in Venusian for more |
| | | information about the ``_depth`` and ``_category`` arguments. |
| | | |
| | | .. seealso:: |
| | | |
| | |
| | | being used, :class:`~pyramid.httpexceptions.HTTPMovedPermanently will |
| | | be used` for the redirect response if a slash-appended route is found. |
| | | |
| | | .. versionchanged:: 1.6 |
| | | |
| | | See :ref:`changing_the_notfound_view` for detailed usage information. |
| | | |
| | | .. versionchanged:: 1.9.1 |
| | | Added the ``_depth`` and ``_category`` arguments. |
| | | |
| | | """ |
| | | |
| | |
| | | |
| | | def __call__(self, wrapped): |
| | | settings = self.__dict__.copy() |
| | | depth = settings.pop('_depth', 0) |
| | | category = settings.pop('_category', 'pyramid') |
| | | |
| | | def callback(context, name, ob): |
| | | config = context.config.with_package(info.module) |
| | | config.add_notfound_view(view=ob, **settings) |
| | | |
| | | info = self.venusian.attach(wrapped, callback, category='pyramid') |
| | | info = self.venusian.attach(wrapped, callback, category=category, |
| | | depth=depth + 1) |
| | | |
| | | if info.scope == 'class': |
| | | # if the decorator was attached to a method in a class, or |
| | |
| | | |
| | | See :ref:`changing_the_forbidden_view` for detailed usage information. |
| | | |
| | | .. versionchanged:: 1.9.1 |
| | | Added the ``_depth`` and ``_category`` arguments. |
| | | |
| | | """ |
| | | |
| | | venusian = venusian |
| | |
| | | |
| | | def __call__(self, wrapped): |
| | | settings = self.__dict__.copy() |
| | | depth = settings.pop('_depth', 0) |
| | | category = settings.pop('_category', 'pyramid') |
| | | |
| | | def callback(context, name, ob): |
| | | config = context.config.with_package(info.module) |
| | | config.add_forbidden_view(view=ob, **settings) |
| | | |
| | | info = self.venusian.attach(wrapped, callback, category='pyramid') |
| | | info = self.venusian.attach(wrapped, callback, category=category, |
| | | depth=depth + 1) |
| | | |
| | | if info.scope == 'class': |
| | | # if the decorator was attached to a method in a class, or |
| | |
| | | :meth:`pyramid.view.view_config`, and each predicate argument restricts |
| | | the set of circumstances under which this exception view will be invoked. |
| | | |
| | | .. versionchanged:: 1.9.1 |
| | | Added the ``_depth`` and ``_category`` arguments. |
| | | |
| | | """ |
| | | venusian = venusian |
| | | |
| | |
| | | |
| | | def __call__(self, wrapped): |
| | | settings = self.__dict__.copy() |
| | | depth = settings.pop('_depth', 0) |
| | | category = settings.pop('_category', 'pyramid') |
| | | |
| | | def callback(context, name, ob): |
| | | config = context.config.with_package(info.module) |
| | | config.add_exception_view(view=ob, **settings) |
| | | |
| | | info = self.venusian.attach(wrapped, callback, category='pyramid') |
| | | info = self.venusian.attach(wrapped, callback, category=category, |
| | | depth=depth + 1) |
| | | |
| | | if info.scope == 'class': |
| | | # if the decorator was attached to a method in a class, or |