fixes #2208 by introducing a iteration limit
This commit is contained in:
parent
6c011f43e9
commit
123289a88e
|
@ -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)
|
||||||
=======================
|
=======================
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
Loading…
Reference in New Issue