Commits

holger krekel committed a751a14

extended - fix issue214 - ignore attribute-access errors with objects in test modules that can blow up (for example flask's request object)

Comments (0)

Files changed (6)

 Changes between 2.3.2 and 2.3.3.dev
 -----------------------------------
 
-- fix issue 214: gracefully handle proxy objects that
-  look like fixtures but raise exceptions on introspection
+- fix issue214 - parse modules that contain special objects like e. g.
+  flask's request object which blows up on getattr access if no request
+  is active.
 - fix issue213 - allow to parametrize with values like numpy arrays that
-  do not support an __eq__ operator 
+  do not support an __eq__ operator
+
 
 Changes between 2.3.1 and 2.3.2
 -----------------------------------

_pytest/__init__.py

 #
-__version__ = '2.3.2'
+__version__ = '2.3.3.dev1'

_pytest/python.py

             # fixture functions have a pytest_funcarg__ prefix (pre-2.3 style)
             # or are "@pytest.fixture" marked
             try:
-                marker = getattr(obj, "_pytestfixturefunction", None)
-            except RuntimeError:
-                # some proxy objects raise RuntimeError
-                # flasks request globals are one example
-                # those aren't fixture functions, so we can ignore
-                # XXX: maybe trace it when it happens?
+                marker = obj._pytestfixturefunction
+            except KeyboardInterrupt:
+                raise
+            except Exception:
+                # some objects raise errors like request (from flask import request)
+                # we don't expect them to be fixture functions
                 marker = None
 
             if marker is None:

doc/en/example/nonpython/conftest.py

 
 import pytest
 
-def pytest_collect_file(path, parent):
+def pytest_collect_file(parent, path):
     if path.ext == ".yml" and path.basename.startswith("test"):
         return YamlFile(path, parent)
-            
+
 class YamlFile(pytest.File):
     def collect(self):
         import yaml # we need a yaml parser, e.g. PyYAML
     def __init__(self, name, parent, spec):
         super(YamlItem, self).__init__(name, parent)
         self.spec = spec
-    
+
     def runtest(self):
         for name, value in self.spec.items():
             # some custom test execution (dumb example follows)
         name='pytest',
         description='py.test: simple powerful testing with Python',
         long_description = long_description,
-        version='2.3.2',
+        version='2.3.3.dev1',
         url='http://pytest.org',
         license='MIT license',
         platforms=['unix', 'linux', 'osx', 'cygwin', 'win32'],

testing/test_python.py

     assert "INTERNAL" not in result.stdout.str()
 
 
-def test_funcarg_fixture_discovery_failure_issue214(testdir):
-    # some proxy objects raise RuntimeError on getattr
-    # for example flask.request
-    p = testdir.makepyfile("""
-
-        class EvilObject(object):
-            def __call__(self): 
-                #needed to trick discovery
-                pass
-            def __getattr__(self, arg):
-                raise RuntimeError('uhm ' + arg)
-
-
-        fixture = EvilObject()
-        
-        def test_1():
-            pass
-    """)
-    result = testdir.runpytest('--fulltrace')
-    result.stdout.fnmatch_lines([
-        '*1 passed*'
-    ])
-    assert "INTERNAL" not in result.stdout.str()
-    assert "ERROR" not in result.stdout.str()
-        
-
-
 class TestReportInfo:
     def test_itemreport_reportinfo(self, testdir, linecomp):
         testdir.makeconftest("""
         """)
         return testdir
 
+    def test_parsefactories_evil_objects_issue214(self, testdir):
+        testdir.makepyfile("""
+            class A:
+                def __call__(self):
+                    pass
+                def __getattr__(self, name):
+                    raise RuntimeError()
+            a = A()
+            def test_hello():
+                pass
+        """)
+        reprec = testdir.inline_run()
+        reprec.assertoutcome(passed=1, failed=0)
+
     def test_parsefactories_conftest(self, testdir):
         testdir.makepyfile("""
             def test_hello(item, fm):