fixes #2208 by introducing a iteration limit

This commit is contained in:
Ronny Pfannschmidt 2017-01-19 11:38:15 +01:00
parent 6c011f43e9
commit 123289a88e
3 changed files with 44 additions and 6 deletions

View File

@ -41,6 +41,10 @@ Changes
* fix `#2013`_: turn RecordedWarning into namedtupe, * fix `#2013`_: turn RecordedWarning into namedtupe,
to give it a comprehensible repr while preventing unwarranted modification to give it a comprehensible repr while preventing unwarranted modification
* fix `#2208`_: ensure a iteration limit for _pytest.compat.get_real_func.
Thanks `@RonnyPfannschmidt`_ for the Report and PR
.. _@davidszotten: https://github.com/davidszotten .. _@davidszotten: https://github.com/davidszotten
.. _@fushi: https://github.com/fushi .. _@fushi: https://github.com/fushi
.. _@mattduck: https://github.com/mattduck .. _@mattduck: https://github.com/mattduck
@ -57,6 +61,7 @@ Changes
.. _#2101: https://github.com/pytest-dev/pytest/pull/2101 .. _#2101: https://github.com/pytest-dev/pytest/pull/2101
.. _#2166: https://github.com/pytest-dev/pytest/pull/2166 .. _#2166: https://github.com/pytest-dev/pytest/pull/2166
.. _#2147: https://github.com/pytest-dev/pytest/issues/2147 .. _#2147: https://github.com/pytest-dev/pytest/issues/2147
.. _#2208: https://github.com/pytest-dev/pytest/issues/2208
3.0.6.dev0 (unreleased) 3.0.6.dev0 (unreleased)
======================= =======================

View File

@ -180,8 +180,16 @@ def get_real_func(obj):
""" gets the real function object of the (possibly) wrapped object by """ gets the real function object of the (possibly) wrapped object by
functools.wraps or functools.partial. functools.wraps or functools.partial.
""" """
while hasattr(obj, "__wrapped__"): start_obj = obj
obj = obj.__wrapped__ for i in range(100):
new_obj = getattr(obj, '__wrapped__', None)
if new_obj is None:
break
obj = new_obj
else:
raise ValueError(
("could not find real function of {start}"
"\nstopped at {current}").format(start=start_obj, current=obj))
if isinstance(obj, functools.partial): if isinstance(obj, functools.partial):
obj = obj.func obj = obj.func
return obj return obj

View File

@ -1,7 +1,7 @@
import sys import sys
import pytest import pytest
from _pytest.compat import is_generator from _pytest.compat import is_generator, get_real_func
def test_is_generator(): def test_is_generator():
@ -15,7 +15,30 @@ def test_is_generator():
assert not is_generator(foo) assert not is_generator(foo)
@pytest.mark.skipif(sys.version_info < (3, 4), reason='asyncio available in Python 3.4+') def test_real_func_loop_limit():
class Evil(object):
def __init__(self):
self.left = 1000
def __repr__(self):
return "<Evil left={left}>".format(left=self.left)
def __getattr__(self, attr):
if not self.left:
raise RuntimeError('its over')
self.left -= 1
return self
evil = Evil()
with pytest.raises(ValueError):
res = get_real_func(evil)
print(res)
@pytest.mark.skipif(sys.version_info < (3, 4),
reason='asyncio available in Python 3.4+')
def test_is_generator_asyncio(testdir): def test_is_generator_asyncio(testdir):
testdir.makepyfile(""" testdir.makepyfile("""
from _pytest.compat import is_generator from _pytest.compat import is_generator
@ -27,12 +50,14 @@ def test_is_generator_asyncio(testdir):
def test_is_generator_asyncio(): def test_is_generator_asyncio():
assert not is_generator(baz) assert not is_generator(baz)
""") """)
# avoid importing asyncio into pytest's own process, which in turn imports logging (#8) # avoid importing asyncio into pytest's own process,
# which in turn imports logging (#8)
result = testdir.runpytest_subprocess() result = testdir.runpytest_subprocess()
result.stdout.fnmatch_lines(['*1 passed*']) result.stdout.fnmatch_lines(['*1 passed*'])
@pytest.mark.skipif(sys.version_info < (3, 5), reason='async syntax available in Python 3.5+') @pytest.mark.skipif(sys.version_info < (3, 5),
reason='async syntax available in Python 3.5+')
def test_is_generator_async_syntax(testdir): def test_is_generator_async_syntax(testdir):
testdir.makepyfile(""" testdir.makepyfile("""
from _pytest.compat import is_generator from _pytest.compat import is_generator