From e51069db045ccc648435e3535723f3ac4a24b168 Mon Sep 17 00:00:00 2001 From: Theron Luhn Date: Mon, 1 Apr 2019 17:42:22 -0700 Subject: Improve debugging info from view_config decorator. Grab a frame when instanciating view_config, rather than pulling info from venusian's AttachInfo. See discussion at https://github.com/Pylons/pyramid/issues/3471 This fixes the build for Python 3.8. --- src/pyramid/view.py | 17 +++++++++++++---- tests/test_view.py | 12 ++++++++---- 2 files changed, 21 insertions(+), 8 deletions(-) diff --git a/src/pyramid/view.py b/src/pyramid/view.py index 944ad93ea..524e06fb2 100644 --- a/src/pyramid/view.py +++ b/src/pyramid/view.py @@ -1,5 +1,6 @@ import itertools import sys +import inspect import venusian @@ -216,6 +217,13 @@ class view_config(object): if settings.get('context') is None: settings['context'] = settings['for_'] self.__dict__.update(settings) + self._get_info() + + def _get_info(self): + frame = sys._getframe(2) + frameinfo = inspect.getframeinfo(frame) + sourceline = frameinfo[3][0].strip() + self._info = frameinfo[0], frameinfo[1], frameinfo[2], sourceline def __call__(self, wrapped): settings = self.__dict__.copy() @@ -237,14 +245,13 @@ class view_config(object): if settings.get('attr') is None: settings['attr'] = wrapped.__name__ - settings['_info'] = info.codeinfo # fbo "action_method" return wrapped bfg_view = view_config # bw compat (forever) -class view_defaults(view_config): +def view_defaults(**settings): """ A class :term:`decorator` which, when applied to a class, will provide defaults for all view configurations that use the class. This decorator accepts all the arguments accepted by @@ -253,10 +260,12 @@ class view_defaults(view_config): See :ref:`view_defaults` for more information. """ - def __call__(self, wrapped): - wrapped.__view_defaults__ = self.__dict__.copy() + def wrap(wrapped): + wrapped.__view_defaults__ = settings return wrapped + return wrap + class AppendSlashNotFoundViewFactory(object): """ There can only be one :term:`Not Found view` in any diff --git a/tests/test_view.py b/tests/test_view.py index de40df1d5..e182c28ad 100644 --- a/tests/test_view.py +++ b/tests/test_view.py @@ -507,7 +507,14 @@ class TestViewConfigDecorator(unittest.TestCase): def test_create_defaults(self): decorator = self._makeOne() - self.assertEqual(decorator.__dict__, {}) + self.assertEqual(list(decorator.__dict__.keys()), ['_info']) + + def test_create_info(self): + target = self._getTargetClass() + decorator = target() + info = decorator._info + self.assertEqual(info[2], 'test_create_info') + self.assertEqual(info[3], 'decorator = target()') def test_create_context_trumps_for(self): decorator = self._makeOne(context='123', for_='456') @@ -560,7 +567,6 @@ class TestViewConfigDecorator(unittest.TestCase): self.assertEqual(len(settings[0]), 3) self.assertEqual(settings[0]['venusian'], venusian) self.assertEqual(settings[0]['view'], None) # comes from call_venusian - self.assertEqual(settings[0]['_info'], 'codeinfo') def test_call_class(self): decorator = self._makeOne() @@ -580,7 +586,6 @@ class TestViewConfigDecorator(unittest.TestCase): self.assertEqual(settings[0]['venusian'], venusian) self.assertEqual(settings[0]['view'], None) # comes from call_venusian self.assertEqual(settings[0]['attr'], 'foo') - self.assertEqual(settings[0]['_info'], 'codeinfo') def test_call_class_attr_already_set(self): decorator = self._makeOne(attr='abc') @@ -600,7 +605,6 @@ class TestViewConfigDecorator(unittest.TestCase): self.assertEqual(settings[0]['venusian'], venusian) self.assertEqual(settings[0]['view'], None) # comes from call_venusian self.assertEqual(settings[0]['attr'], 'abc') - self.assertEqual(settings[0]['_info'], 'codeinfo') def test_stacking(self): decorator1 = self._makeOne(name='1') -- cgit v1.2.3 From fbf4d51e0f6ae8b12c1e718e551794196f6cc286 Mon Sep 17 00:00:00 2001 From: Theron Luhn Date: Mon, 1 Apr 2019 22:50:08 -0700 Subject: Fix docs build. --- docs/api/view.rst | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/docs/api/view.rst b/docs/api/view.rst index e41212012..fe4b80acb 100644 --- a/docs/api/view.rst +++ b/docs/api/view.rst @@ -14,8 +14,7 @@ .. autoclass:: view_config :members: - .. autoclass:: view_defaults - :members: + .. autofunction:: view_defaults .. autoclass:: notfound_view_config :members: -- cgit v1.2.3 From b1c366a5921969254d87ffc2417d39046cffebe3 Mon Sep 17 00:00:00 2001 From: Theron Luhn Date: Mon, 1 Apr 2019 22:59:07 -0700 Subject: Use inspect.stack() instead of sys._getframe() --- src/pyramid/view.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/pyramid/view.py b/src/pyramid/view.py index 524e06fb2..51e6c3c1b 100644 --- a/src/pyramid/view.py +++ b/src/pyramid/view.py @@ -220,10 +220,9 @@ class view_config(object): self._get_info() def _get_info(self): - frame = sys._getframe(2) - frameinfo = inspect.getframeinfo(frame) - sourceline = frameinfo[3][0].strip() - self._info = frameinfo[0], frameinfo[1], frameinfo[2], sourceline + frameinfo = inspect.stack()[2] + sourceline = frameinfo[4][0].strip() + self._info = frameinfo[1], frameinfo[2], frameinfo[3], sourceline def __call__(self, wrapped): settings = self.__dict__.copy() -- cgit v1.2.3 From bd51b6c3afb8bd46d37bbf77e208f2e91401b1db Mon Sep 17 00:00:00 2001 From: Theron Luhn Date: Thu, 4 Apr 2019 20:16:21 -0700 Subject: Use depth argument for view_config info. --- CHANGES.rst | 3 +++ src/pyramid/view.py | 3 ++- tests/test_view.py | 11 +++++++++++ 3 files changed, 16 insertions(+), 1 deletion(-) diff --git a/CHANGES.rst b/CHANGES.rst index afac078b0..5ebd0e81e 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -35,6 +35,9 @@ Features provided by WebOb. This allows the attribute to now be settable. See https://github.com/Pylons/pyramid/pull/3447 +- Improve debugging info from ``pyramid.view.view_config`` decorator. + See https://github.com/Pylons/pyramid/pull/3483 + Deprecations ------------ diff --git a/src/pyramid/view.py b/src/pyramid/view.py index 51e6c3c1b..b856c309a 100644 --- a/src/pyramid/view.py +++ b/src/pyramid/view.py @@ -220,7 +220,8 @@ class view_config(object): self._get_info() def _get_info(self): - frameinfo = inspect.stack()[2] + depth = self.__dict__.get('_depth', 0) + frameinfo = inspect.stack()[depth + 2] sourceline = frameinfo[4][0].strip() self._info = frameinfo[1], frameinfo[2], frameinfo[3], sourceline diff --git a/tests/test_view.py b/tests/test_view.py index e182c28ad..5411e57c0 100644 --- a/tests/test_view.py +++ b/tests/test_view.py @@ -516,6 +516,17 @@ class TestViewConfigDecorator(unittest.TestCase): self.assertEqual(info[2], 'test_create_info') self.assertEqual(info[3], 'decorator = target()') + def test_create_info_depth(self): + target = self._getTargetClass() + + def make(): + return target(_depth=1) + + decorator = make() + info = decorator._info + self.assertEqual(info[2], 'test_create_info_depth') + self.assertEqual(info[3], 'decorator = make()') + def test_create_context_trumps_for(self): decorator = self._makeOne(context='123', for_='456') self.assertEqual(decorator.context, '123') -- cgit v1.2.3