From 8a1905e6ee85c508f93de08301140d078fa18c19 Mon Sep 17 00:00:00 2001 From: Mikhail Korobov Date: Wed, 5 Feb 2014 02:28:51 +0600 Subject: [PATCH 1/2] Handle cases when inspect.stack() fails --- scrapy/utils/deprecate.py | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/scrapy/utils/deprecate.py b/scrapy/utils/deprecate.py index edaecc3d3..767059476 100644 --- a/scrapy/utils/deprecate.py +++ b/scrapy/utils/deprecate.py @@ -95,10 +95,18 @@ def create_deprecated_class(name, new_class, clsdict=None, return super(DeprecatedClass, cls).__call__(*args, **kwargs) deprecated_cls = DeprecatedClass(name, (new_class,), clsdict or {}) - frm = inspect.stack()[1] - parent_module = inspect.getmodule(frm[0]) - if parent_module is not None: - deprecated_cls.__module__ = parent_module.__name__ + + try: + frm = inspect.stack()[1] + parent_module = inspect.getmodule(frm[0]) + if parent_module is not None: + deprecated_cls.__module__ = parent_module.__name__ + except Exception as e: + # Sometimes inspect.stack() fails (e.g. when the first import of + # deprecated class is in jinja2 template). __module__ attribute is not + # important enough to raise an exception as users may be unable + # to fix inspect.stack() errors. + warnings.warn("Error detecting parent module: %r" % e) return deprecated_cls From 9e95b36a09751e97b9844c6bf00f01a2d32ad61b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Gra=C3=B1a?= Date: Fri, 7 Feb 2014 01:36:43 -0200 Subject: [PATCH 2/2] test inspect.stack failure --- scrapy/tests/test_utils_deprecate.py | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/scrapy/tests/test_utils_deprecate.py b/scrapy/tests/test_utils_deprecate.py index 07b9a3dd5..dfecc6d2a 100644 --- a/scrapy/tests/test_utils_deprecate.py +++ b/scrapy/tests/test_utils_deprecate.py @@ -3,14 +3,18 @@ from __future__ import absolute_import import inspect import unittest import warnings +import mock from scrapy.utils.deprecate import create_deprecated_class + class MyWarning(UserWarning): pass + class SomeBaseClass(object): pass + class NewName(SomeBaseClass): pass @@ -223,3 +227,12 @@ class WarnWhenSubclassedTest(unittest.TestCase): self.assertIn('foo.Bar', str(w[0].message)) self.assertIn('AlsoDeprecated', str(w[1].message)) self.assertIn('foo.Bar', str(w[1].message)) + + def test_inspect_stack(self): + with mock.patch('inspect.stack', side_effect=IndexError): + with warnings.catch_warnings(record=True) as w: + DeprecatedName = create_deprecated_class('DeprecatedName', NewName) + class SubClass(DeprecatedName): + pass + + self.assertIn("Error detecting parent module", str(w[0].message))