Merge pull request #2209 from RonnyPfannschmidt/bugfix-2208/get_real_func_loop_limit
fixes #2208 by introducing a iteration limit
This commit is contained in:
commit
88f7befabb
|
@ -41,6 +41,10 @@ Changes
|
|||
* fix `#2013`_: turn RecordedWarning into namedtupe,
|
||||
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
|
||||
.. _@fushi: https://github.com/fushi
|
||||
.. _@mattduck: https://github.com/mattduck
|
||||
|
@ -57,6 +61,7 @@ Changes
|
|||
.. _#2101: https://github.com/pytest-dev/pytest/pull/2101
|
||||
.. _#2166: https://github.com/pytest-dev/pytest/pull/2166
|
||||
.. _#2147: https://github.com/pytest-dev/pytest/issues/2147
|
||||
.. _#2208: https://github.com/pytest-dev/pytest/issues/2208
|
||||
|
||||
3.0.6.dev0 (unreleased)
|
||||
=======================
|
||||
|
|
|
@ -180,8 +180,18 @@ def get_real_func(obj):
|
|||
""" gets the real function object of the (possibly) wrapped object by
|
||||
functools.wraps or functools.partial.
|
||||
"""
|
||||
while hasattr(obj, "__wrapped__"):
|
||||
obj = obj.__wrapped__
|
||||
start_obj = obj
|
||||
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=py.io.saferepr(start_obj),
|
||||
current=py.io.saferepr(obj)))
|
||||
if isinstance(obj, functools.partial):
|
||||
obj = obj.func
|
||||
return obj
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import sys
|
||||
|
||||
import pytest
|
||||
from _pytest.compat import is_generator
|
||||
from _pytest.compat import is_generator, get_real_func
|
||||
|
||||
|
||||
def test_is_generator():
|
||||
|
@ -15,7 +15,30 @@ def test_is_generator():
|
|||
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):
|
||||
testdir.makepyfile("""
|
||||
from _pytest.compat import is_generator
|
||||
|
@ -27,12 +50,14 @@ def test_is_generator_asyncio(testdir):
|
|||
def test_is_generator_asyncio():
|
||||
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.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):
|
||||
testdir.makepyfile("""
|
||||
from _pytest.compat import is_generator
|
||||
|
|
Loading…
Reference in New Issue