Merge pull request #4420 from blueyed/merge-master
Merge master into features
This commit is contained in:
commit
6e85febf20
|
@ -0,0 +1 @@
|
||||||
|
Rearrange warning handling for the yield test errors so the opt-out in 4.0.x correctly works.
|
|
@ -0,0 +1 @@
|
||||||
|
Fix collection of testpaths with ``--pyargs``.
|
|
@ -0,0 +1 @@
|
||||||
|
Fix assertion rewriting involving ``Starred`` + side-effects.
|
10
setup.py
10
setup.py
|
@ -29,6 +29,16 @@ def main():
|
||||||
use_scm_version={"write_to": "src/_pytest/_version.py"},
|
use_scm_version={"write_to": "src/_pytest/_version.py"},
|
||||||
setup_requires=["setuptools-scm", "setuptools>=40.0"],
|
setup_requires=["setuptools-scm", "setuptools>=40.0"],
|
||||||
package_dir={"": "src"},
|
package_dir={"": "src"},
|
||||||
|
# fmt: off
|
||||||
|
extras_require={
|
||||||
|
"testing": [
|
||||||
|
"hypothesis>=3.56",
|
||||||
|
"nose",
|
||||||
|
"requests",
|
||||||
|
"mock;python_version=='2.7'",
|
||||||
|
],
|
||||||
|
},
|
||||||
|
# fmt: on
|
||||||
install_requires=INSTALL_REQUIRES,
|
install_requires=INSTALL_REQUIRES,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -946,7 +946,8 @@ class AssertionRewriter(ast.NodeVisitor):
|
||||||
def visit_Starred(self, starred):
|
def visit_Starred(self, starred):
|
||||||
# From Python 3.5, a Starred node can appear in a function call
|
# From Python 3.5, a Starred node can appear in a function call
|
||||||
res, expl = self.visit(starred.value)
|
res, expl = self.visit(starred.value)
|
||||||
return starred, "*" + expl
|
new_starred = ast.Starred(res, starred.ctx)
|
||||||
|
return new_starred, "*" + expl
|
||||||
|
|
||||||
def visit_Call_legacy(self, call):
|
def visit_Call_legacy(self, call):
|
||||||
"""
|
"""
|
||||||
|
|
|
@ -852,10 +852,7 @@ class Config(object):
|
||||||
)
|
)
|
||||||
if not args:
|
if not args:
|
||||||
if self.invocation_dir == self.rootdir:
|
if self.invocation_dir == self.rootdir:
|
||||||
args = [
|
args = self.getini("testpaths")
|
||||||
str(self.invocation_dir.join(x, abs=True))
|
|
||||||
for x in self.getini("testpaths")
|
|
||||||
]
|
|
||||||
if not args:
|
if not args:
|
||||||
args = [str(self.invocation_dir)]
|
args = [str(self.invocation_dir)]
|
||||||
self.args = args
|
self.args = args
|
||||||
|
|
|
@ -518,6 +518,9 @@ class Testdir(object):
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return "<Testdir %r>" % (self.tmpdir,)
|
return "<Testdir %r>" % (self.tmpdir,)
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return str(self.tmpdir)
|
||||||
|
|
||||||
def finalize(self):
|
def finalize(self):
|
||||||
"""Clean up global state artifacts.
|
"""Clean up global state artifacts.
|
||||||
|
|
||||||
|
|
|
@ -741,16 +741,20 @@ class FunctionMixin(PyobjMixin):
|
||||||
|
|
||||||
class Generator(FunctionMixin, PyCollector):
|
class Generator(FunctionMixin, PyCollector):
|
||||||
def collect(self):
|
def collect(self):
|
||||||
|
|
||||||
# test generators are seen as collectors but they also
|
# test generators are seen as collectors but they also
|
||||||
# invoke setup/teardown on popular request
|
# invoke setup/teardown on popular request
|
||||||
# (induced by the common "test_*" naming shared with normal tests)
|
# (induced by the common "test_*" naming shared with normal tests)
|
||||||
from _pytest import deprecated
|
from _pytest import deprecated
|
||||||
|
|
||||||
|
self.warn(deprecated.YIELD_TESTS)
|
||||||
|
|
||||||
self.session._setupstate.prepare(self)
|
self.session._setupstate.prepare(self)
|
||||||
# see FunctionMixin.setup and test_setupstate_is_preserved_134
|
# see FunctionMixin.setup and test_setupstate_is_preserved_134
|
||||||
self._preservedparent = self.parent.obj
|
self._preservedparent = self.parent.obj
|
||||||
values = []
|
values = []
|
||||||
seen = {}
|
seen = {}
|
||||||
|
_Function = self._getcustomclass("Function")
|
||||||
for i, x in enumerate(self.obj()):
|
for i, x in enumerate(self.obj()):
|
||||||
name, call, args = self.getcallargs(x)
|
name, call, args = self.getcallargs(x)
|
||||||
if not callable(call):
|
if not callable(call):
|
||||||
|
@ -764,11 +768,7 @@ class Generator(FunctionMixin, PyCollector):
|
||||||
"%r generated tests with non-unique name %r" % (self, name)
|
"%r generated tests with non-unique name %r" % (self, name)
|
||||||
)
|
)
|
||||||
seen[name] = True
|
seen[name] = True
|
||||||
with warnings.catch_warnings():
|
values.append(_Function(name, self, args=args, callobj=call))
|
||||||
# ignore our own deprecation warning
|
|
||||||
function_class = self.Function
|
|
||||||
values.append(function_class(name, self, args=args, callobj=call))
|
|
||||||
self.warn(deprecated.YIELD_TESTS)
|
|
||||||
return values
|
return values
|
||||||
|
|
||||||
def getcallargs(self, obj):
|
def getcallargs(self, obj):
|
||||||
|
|
|
@ -413,6 +413,19 @@ class TestAssertionRewrite(object):
|
||||||
)
|
)
|
||||||
testdir.runpytest().assert_outcomes(passed=1)
|
testdir.runpytest().assert_outcomes(passed=1)
|
||||||
|
|
||||||
|
@pytest.mark.skipif("sys.version_info < (3,5)")
|
||||||
|
def test_starred_with_side_effect(self, testdir):
|
||||||
|
"""See #4412"""
|
||||||
|
testdir.makepyfile(
|
||||||
|
"""\
|
||||||
|
def test():
|
||||||
|
f = lambda x: x
|
||||||
|
x = iter([1, 2, 3])
|
||||||
|
assert 2 * next(x) == f(*[next(x)])
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
testdir.runpytest().assert_outcomes(passed=1)
|
||||||
|
|
||||||
def test_call(self):
|
def test_call(self):
|
||||||
def g(a=42, *args, **kwargs):
|
def g(a=42, *args, **kwargs):
|
||||||
return False
|
return False
|
||||||
|
|
|
@ -1086,6 +1086,28 @@ def test_collect_with_chdir_during_import(testdir):
|
||||||
result.stdout.fnmatch_lines(["collected 1 item"])
|
result.stdout.fnmatch_lines(["collected 1 item"])
|
||||||
|
|
||||||
|
|
||||||
|
def test_collect_pyargs_with_testpaths(testdir, monkeypatch):
|
||||||
|
testmod = testdir.mkdir("testmod")
|
||||||
|
# NOTE: __init__.py is not collected since it does not match python_files.
|
||||||
|
testmod.ensure("__init__.py").write("def test_func(): pass")
|
||||||
|
testmod.ensure("test_file.py").write("def test_func(): pass")
|
||||||
|
|
||||||
|
root = testdir.mkdir("root")
|
||||||
|
root.ensure("pytest.ini").write(
|
||||||
|
textwrap.dedent(
|
||||||
|
"""
|
||||||
|
[pytest]
|
||||||
|
addopts = --pyargs
|
||||||
|
testpaths = testmod
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
)
|
||||||
|
monkeypatch.setenv("PYTHONPATH", str(testdir.tmpdir))
|
||||||
|
with root.as_cwd():
|
||||||
|
result = testdir.runpytest_subprocess()
|
||||||
|
result.stdout.fnmatch_lines(["*1 passed in*"])
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.skipif(
|
@pytest.mark.skipif(
|
||||||
not hasattr(py.path.local, "mksymlinkto"),
|
not hasattr(py.path.local, "mksymlinkto"),
|
||||||
reason="symlink not available on this platform",
|
reason="symlink not available on this platform",
|
||||||
|
|
|
@ -4,6 +4,7 @@ from __future__ import print_function
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
from _pytest.main import EXIT_NOTESTSCOLLECTED
|
from _pytest.main import EXIT_NOTESTSCOLLECTED
|
||||||
|
from _pytest.warnings import SHOW_PYTEST_WARNINGS_ARG
|
||||||
|
|
||||||
|
|
||||||
class SessionTests(object):
|
class SessionTests(object):
|
||||||
|
@ -77,7 +78,8 @@ class SessionTests(object):
|
||||||
"""
|
"""
|
||||||
def test_1():
|
def test_1():
|
||||||
yield None
|
yield None
|
||||||
"""
|
""",
|
||||||
|
SHOW_PYTEST_WARNINGS_ARG,
|
||||||
)
|
)
|
||||||
failures = reprec.getfailedcollections()
|
failures = reprec.getfailedcollections()
|
||||||
out = failures[0].longrepr.reprcrash.message
|
out = failures[0].longrepr.reprcrash.message
|
||||||
|
|
20
tox.ini
20
tox.ini
|
@ -28,11 +28,8 @@ setenv =
|
||||||
coverage: _PYTEST_TOX_EXTRA_DEP=coverage-enable-subprocess
|
coverage: _PYTEST_TOX_EXTRA_DEP=coverage-enable-subprocess
|
||||||
coverage: COVERAGE_FILE={toxinidir}/.coverage
|
coverage: COVERAGE_FILE={toxinidir}/.coverage
|
||||||
coverage: COVERAGE_PROCESS_START={toxinidir}/.coveragerc
|
coverage: COVERAGE_PROCESS_START={toxinidir}/.coveragerc
|
||||||
|
extras = testing
|
||||||
deps =
|
deps =
|
||||||
hypothesis>=3.56
|
|
||||||
nose
|
|
||||||
{py27,pypy}: mock
|
|
||||||
requests
|
|
||||||
{env:_PYTEST_TOX_EXTRA_DEP:}
|
{env:_PYTEST_TOX_EXTRA_DEP:}
|
||||||
|
|
||||||
[testenv:py27-subprocess]
|
[testenv:py27-subprocess]
|
||||||
|
@ -51,22 +48,18 @@ deps = pre-commit>=1.11.0
|
||||||
commands = pre-commit run --all-files --show-diff-on-failure
|
commands = pre-commit run --all-files --show-diff-on-failure
|
||||||
|
|
||||||
[testenv:py27-xdist]
|
[testenv:py27-xdist]
|
||||||
|
extras = testing
|
||||||
deps =
|
deps =
|
||||||
pytest-xdist>=1.13
|
pytest-xdist>=1.13
|
||||||
{py27,pypy}: mock
|
|
||||||
nose
|
|
||||||
hypothesis>=3.56
|
|
||||||
{env:_PYTEST_TOX_EXTRA_DEP:}
|
{env:_PYTEST_TOX_EXTRA_DEP:}
|
||||||
commands =
|
commands =
|
||||||
{env:_PYTEST_TOX_COVERAGE_RUN:} pytest -n auto {posargs}
|
{env:_PYTEST_TOX_COVERAGE_RUN:} pytest -n auto {posargs}
|
||||||
|
|
||||||
[testenv:py37-xdist]
|
[testenv:py37-xdist]
|
||||||
# NOTE: copied from above due to https://github.com/tox-dev/tox/issues/706.
|
# NOTE: copied from above due to https://github.com/tox-dev/tox/issues/706.
|
||||||
|
extras = testing
|
||||||
deps =
|
deps =
|
||||||
pytest-xdist>=1.13
|
pytest-xdist>=1.13
|
||||||
{py27,pypy}: mock
|
|
||||||
nose
|
|
||||||
hypothesis>=3.56
|
|
||||||
{env:_PYTEST_TOX_EXTRA_DEP:}
|
{env:_PYTEST_TOX_EXTRA_DEP:}
|
||||||
commands = {[testenv:py27-xdist]commands}
|
commands = {[testenv:py27-xdist]commands}
|
||||||
|
|
||||||
|
@ -76,7 +69,7 @@ deps =
|
||||||
pexpect
|
pexpect
|
||||||
{env:_PYTEST_TOX_EXTRA_DEP:}
|
{env:_PYTEST_TOX_EXTRA_DEP:}
|
||||||
commands =
|
commands =
|
||||||
{env:_PYTEST_TOX_COVERAGE_RUN:} pytest testing/test_pdb.py testing/test_terminal.py testing/test_unittest.py {posargs}
|
{env:_PYTEST_TOX_COVERAGE_RUN:} pytest {posargs:testing/test_pdb.py testing/test_terminal.py testing/test_unittest.py}
|
||||||
|
|
||||||
[testenv:py37-pexpect]
|
[testenv:py37-pexpect]
|
||||||
platform = {[testenv:py27-pexpect]platform}
|
platform = {[testenv:py27-pexpect]platform}
|
||||||
|
@ -84,10 +77,9 @@ deps = {[testenv:py27-pexpect]deps}
|
||||||
commands = {[testenv:py27-pexpect]commands}
|
commands = {[testenv:py27-pexpect]commands}
|
||||||
|
|
||||||
[testenv:py27-nobyte]
|
[testenv:py27-nobyte]
|
||||||
|
extras = testing
|
||||||
deps =
|
deps =
|
||||||
pytest-xdist>=1.13
|
pytest-xdist>=1.13
|
||||||
hypothesis>=3.56
|
|
||||||
py27: mock
|
|
||||||
{env:_PYTEST_TOX_EXTRA_DEP:}
|
{env:_PYTEST_TOX_EXTRA_DEP:}
|
||||||
distribute = true
|
distribute = true
|
||||||
setenv =
|
setenv =
|
||||||
|
@ -219,6 +211,8 @@ filterwarnings =
|
||||||
ignore:.*inspect.getargspec.*deprecated, use inspect.signature.*:DeprecationWarning
|
ignore:.*inspect.getargspec.*deprecated, use inspect.signature.*:DeprecationWarning
|
||||||
# pytest's own futurewarnings
|
# pytest's own futurewarnings
|
||||||
ignore::pytest.PytestExperimentalApiWarning
|
ignore::pytest.PytestExperimentalApiWarning
|
||||||
|
# Do not cause SyntaxError for invalid escape sequences in py37.
|
||||||
|
default:invalid escape sequence:DeprecationWarning
|
||||||
pytester_example_dir = testing/example_scripts
|
pytester_example_dir = testing/example_scripts
|
||||||
[flake8]
|
[flake8]
|
||||||
max-line-length = 120
|
max-line-length = 120
|
||||||
|
|
Loading…
Reference in New Issue