Merge pull request #2707 from cybergrind/fix_baseexception
Catch BaseException in safe_getattr
This commit is contained in:
commit
b770a32dc8
|
@ -11,6 +11,7 @@ import functools
|
||||||
import py
|
import py
|
||||||
|
|
||||||
import _pytest
|
import _pytest
|
||||||
|
from _pytest.outcomes import TEST_OUTCOME
|
||||||
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
@ -221,14 +222,16 @@ def getimfunc(func):
|
||||||
|
|
||||||
|
|
||||||
def safe_getattr(object, name, default):
|
def safe_getattr(object, name, default):
|
||||||
""" Like getattr but return default upon any Exception.
|
""" Like getattr but return default upon any Exception or any OutcomeException.
|
||||||
|
|
||||||
Attribute access can potentially fail for 'evil' Python objects.
|
Attribute access can potentially fail for 'evil' Python objects.
|
||||||
See issue #214.
|
See issue #214.
|
||||||
|
It catches OutcomeException because of #2490 (issue #580), new outcomes are derived from BaseException
|
||||||
|
instead of Exception (for more details check #2707)
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
return getattr(object, name, default)
|
return getattr(object, name, default)
|
||||||
except Exception:
|
except TEST_OUTCOME:
|
||||||
return default
|
return default
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
Fixed edge-case during collection: attributes which raised ``pytest.fail`` when accessed would abort the entire collection.
|
|
@ -2,7 +2,8 @@ from __future__ import absolute_import, division, print_function
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
from _pytest.compat import is_generator, get_real_func
|
from _pytest.compat import is_generator, get_real_func, safe_getattr
|
||||||
|
from _pytest.outcomes import OutcomeException
|
||||||
|
|
||||||
|
|
||||||
def test_is_generator():
|
def test_is_generator():
|
||||||
|
@ -74,3 +75,27 @@ def test_is_generator_async_syntax(testdir):
|
||||||
""")
|
""")
|
||||||
result = testdir.runpytest()
|
result = testdir.runpytest()
|
||||||
result.stdout.fnmatch_lines(['*1 passed*'])
|
result.stdout.fnmatch_lines(['*1 passed*'])
|
||||||
|
|
||||||
|
|
||||||
|
class ErrorsHelper(object):
|
||||||
|
@property
|
||||||
|
def raise_exception(self):
|
||||||
|
raise Exception('exception should be catched')
|
||||||
|
|
||||||
|
@property
|
||||||
|
def raise_fail(self):
|
||||||
|
pytest.fail('fail should be catched')
|
||||||
|
|
||||||
|
|
||||||
|
def test_helper_failures():
|
||||||
|
helper = ErrorsHelper()
|
||||||
|
with pytest.raises(Exception):
|
||||||
|
helper.raise_exception
|
||||||
|
with pytest.raises(OutcomeException):
|
||||||
|
helper.raise_fail
|
||||||
|
|
||||||
|
|
||||||
|
def test_safe_getattr():
|
||||||
|
helper = ErrorsHelper()
|
||||||
|
assert safe_getattr(helper, 'raise_exception', 'default') == 'default'
|
||||||
|
assert safe_getattr(helper, 'raise_fail', 'default') == 'default'
|
||||||
|
|
Loading…
Reference in New Issue