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
|
||||
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
|
||||
.. _#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)
|
||||
==================
|
||||
|
|
|
@ -19,6 +19,7 @@ except ImportError: # pragma: no cover
|
|||
# Only available in Python 3.4+ or as a backport
|
||||
enum = None
|
||||
|
||||
|
||||
_PY3 = sys.version_info > (3, 0)
|
||||
_PY2 = not _PY3
|
||||
|
||||
|
@ -42,11 +43,18 @@ REGEX_TYPE = type(re.compile(''))
|
|||
|
||||
|
||||
def is_generator(func):
|
||||
try:
|
||||
return _pytest._code.getrawcode(func).co_flags & 32 # generator function
|
||||
except AttributeError: # builtin functions have no bytecode
|
||||
# assume them to not be generators
|
||||
return False
|
||||
genfunc = inspect.isgeneratorfunction(func)
|
||||
return genfunc and not iscoroutinefunction(func)
|
||||
|
||||
|
||||
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):
|
||||
|
|
|
@ -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