Merge pull request #2130 from malinoff/fix-2129
Use inspect to properly detect generators. Fixes #2129
This commit is contained in:
commit
718f0b0255
|
@ -3,7 +3,8 @@
|
||||||
|
|
||||||
*
|
*
|
||||||
|
|
||||||
*
|
* pytest no longer recognizes coroutine functions as yield tests (`#2129`_).
|
||||||
|
Thanks to `@malinoff`_ for the PR.
|
||||||
|
|
||||||
* Improve error message when pytest.warns fails (`#2150`_). The type(s) of the
|
* Improve error message when pytest.warns fails (`#2150`_). The type(s) of the
|
||||||
expected warnings and the list of caught warnings is added to the
|
expected warnings and the list of caught warnings is added to the
|
||||||
|
@ -21,6 +22,9 @@
|
||||||
.. _#2150: https://github.com/pytest-dev/pytest/issues/2150
|
.. _#2150: https://github.com/pytest-dev/pytest/issues/2150
|
||||||
.. _#2148: https://github.com/pytest-dev/pytest/issues/2148
|
.. _#2148: https://github.com/pytest-dev/pytest/issues/2148
|
||||||
|
|
||||||
|
.. _@malinoff: https://github.com/malinoff
|
||||||
|
|
||||||
|
.. _#2129: https://github.com/pytest-dev/pytest/issues/2129
|
||||||
|
|
||||||
3.0.5 (2016-12-05)
|
3.0.5 (2016-12-05)
|
||||||
==================
|
==================
|
||||||
|
|
|
@ -19,6 +19,7 @@ except ImportError: # pragma: no cover
|
||||||
# Only available in Python 3.4+ or as a backport
|
# Only available in Python 3.4+ or as a backport
|
||||||
enum = None
|
enum = None
|
||||||
|
|
||||||
|
|
||||||
_PY3 = sys.version_info > (3, 0)
|
_PY3 = sys.version_info > (3, 0)
|
||||||
_PY2 = not _PY3
|
_PY2 = not _PY3
|
||||||
|
|
||||||
|
@ -42,11 +43,18 @@ REGEX_TYPE = type(re.compile(''))
|
||||||
|
|
||||||
|
|
||||||
def is_generator(func):
|
def is_generator(func):
|
||||||
try:
|
genfunc = inspect.isgeneratorfunction(func)
|
||||||
return _pytest._code.getrawcode(func).co_flags & 32 # generator function
|
return genfunc and not iscoroutinefunction(func)
|
||||||
except AttributeError: # builtin functions have no bytecode
|
|
||||||
# assume them to not be generators
|
|
||||||
return False
|
def iscoroutinefunction(func):
|
||||||
|
"""Return True if func is a decorated coroutine function.
|
||||||
|
|
||||||
|
Note: copied and modified from Python 3.5's builtin couroutines.py to avoid import asyncio directly,
|
||||||
|
which in turns also initializes the "logging" module as side-effect (see issue #8).
|
||||||
|
"""
|
||||||
|
return (getattr(func, '_is_coroutine', False) or
|
||||||
|
(hasattr(inspect, 'iscoroutinefunction') and inspect.iscoroutinefunction(func)))
|
||||||
|
|
||||||
|
|
||||||
def getlocation(function, curdir):
|
def getlocation(function, curdir):
|
||||||
|
|
|
@ -0,0 +1,50 @@
|
||||||
|
import sys
|
||||||
|
|
||||||
|
import pytest
|
||||||
|
from _pytest.compat import is_generator
|
||||||
|
|
||||||
|
|
||||||
|
def test_is_generator():
|
||||||
|
def zap():
|
||||||
|
yield
|
||||||
|
|
||||||
|
def foo():
|
||||||
|
pass
|
||||||
|
|
||||||
|
assert is_generator(zap)
|
||||||
|
assert not is_generator(foo)
|
||||||
|
|
||||||
|
|
||||||
|
@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
|
||||||
|
import asyncio
|
||||||
|
@asyncio.coroutine
|
||||||
|
def baz():
|
||||||
|
yield from [1,2,3]
|
||||||
|
|
||||||
|
def test_is_generator_asyncio():
|
||||||
|
assert not is_generator(baz)
|
||||||
|
""")
|
||||||
|
# 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+')
|
||||||
|
def test_is_generator_async_syntax(testdir):
|
||||||
|
testdir.makepyfile("""
|
||||||
|
from _pytest.compat import is_generator
|
||||||
|
def test_is_generator_py35():
|
||||||
|
async def foo():
|
||||||
|
await foo()
|
||||||
|
|
||||||
|
async def bar():
|
||||||
|
pass
|
||||||
|
|
||||||
|
assert not is_generator(foo)
|
||||||
|
assert not is_generator(bar)
|
||||||
|
""")
|
||||||
|
result = testdir.runpytest()
|
||||||
|
result.stdout.fnmatch_lines(['*1 passed*'])
|
Loading…
Reference in New Issue