parent
d99ceb1218
commit
53a0e2b118
|
@ -4,7 +4,9 @@
|
||||||
* Fix regression when ``importorskip`` is used at module level (`#1822`_).
|
* Fix regression when ``importorskip`` is used at module level (`#1822`_).
|
||||||
Thanks `@jaraco`_ and `@The-Compiler`_ for the report and `@nicoddemus`_ for the PR.
|
Thanks `@jaraco`_ and `@The-Compiler`_ for the report and `@nicoddemus`_ for the PR.
|
||||||
|
|
||||||
*
|
* Fix parametrization scope when session fixtures are used in conjunction
|
||||||
|
with normal parameters in the same call (`#1832`_).
|
||||||
|
Thanks `@The-Compiler`_ for the report, `@Kingdread`_ and `@nicoddemus`_ for the PR.
|
||||||
|
|
||||||
* Fix loader error when running ``pytest`` embedded in a zipfile.
|
* Fix loader error when running ``pytest`` embedded in a zipfile.
|
||||||
Thanks `@mbachry`_ for the PR.
|
Thanks `@mbachry`_ for the PR.
|
||||||
|
@ -13,10 +15,15 @@
|
||||||
|
|
||||||
*
|
*
|
||||||
|
|
||||||
|
*
|
||||||
|
|
||||||
|
*
|
||||||
|
|
||||||
|
.. _@Kingdread: https://github.com/Kingdread
|
||||||
.. _@mbachry: https://github.com/mbachry
|
.. _@mbachry: https://github.com/mbachry
|
||||||
|
|
||||||
.. _#1822: https://github.com/pytest-dev/pytest/issues/1822
|
.. _#1822: https://github.com/pytest-dev/pytest/issues/1822
|
||||||
|
.. _#1832: https://github.com/pytest-dev/pytest/issues/1832
|
||||||
|
|
||||||
|
|
||||||
3.0.0
|
3.0.0
|
||||||
|
|
|
@ -802,14 +802,8 @@ class Metafunc(fixtures.FuncargnamesCompatAttr):
|
||||||
newkeywords = [{newmark.markname: newmark}]
|
newkeywords = [{newmark.markname: newmark}]
|
||||||
|
|
||||||
if scope is None:
|
if scope is None:
|
||||||
if self._arg2fixturedefs:
|
scope = _find_parametrized_scope(argnames, self._arg2fixturedefs, indirect)
|
||||||
# Takes the most narrow scope from used fixtures
|
|
||||||
fixtures_scopes = [fixturedef[0].scope for fixturedef in self._arg2fixturedefs.values()]
|
|
||||||
for scope in reversed(scopes):
|
|
||||||
if scope in fixtures_scopes:
|
|
||||||
break
|
|
||||||
else:
|
|
||||||
scope = 'function'
|
|
||||||
scopenum = scopes.index(scope)
|
scopenum = scopes.index(scope)
|
||||||
valtypes = {}
|
valtypes = {}
|
||||||
for arg in argnames:
|
for arg in argnames:
|
||||||
|
@ -889,6 +883,30 @@ class Metafunc(fixtures.FuncargnamesCompatAttr):
|
||||||
self._calls.append(cs)
|
self._calls.append(cs)
|
||||||
|
|
||||||
|
|
||||||
|
def _find_parametrized_scope(argnames, arg2fixturedefs, indirect):
|
||||||
|
"""Find the most appropriate scope for a parametrized call based on its arguments.
|
||||||
|
|
||||||
|
When there's at least one direct argument, always use "function" scope.
|
||||||
|
|
||||||
|
When a test function is parametrized and all its arguments are indirect
|
||||||
|
(e.g. fixtures), return the most narrow scope based on the fixtures used.
|
||||||
|
|
||||||
|
Related to issue #1832, based on code posted by @Kingdread.
|
||||||
|
"""
|
||||||
|
from _pytest.fixtures import scopes
|
||||||
|
indirect_as_list = isinstance(indirect, (list, tuple))
|
||||||
|
all_arguments_are_fixtures = indirect is True or \
|
||||||
|
indirect_as_list and len(indirect) == argnames
|
||||||
|
if all_arguments_are_fixtures:
|
||||||
|
fixturedefs = arg2fixturedefs or {}
|
||||||
|
used_scopes = [fixturedef[0].scope for name, fixturedef in fixturedefs.items()]
|
||||||
|
if used_scopes:
|
||||||
|
# Takes the most narrow scope from used fixtures
|
||||||
|
for scope in reversed(scopes):
|
||||||
|
if scope in used_scopes:
|
||||||
|
return scope
|
||||||
|
|
||||||
|
return 'function'
|
||||||
|
|
||||||
|
|
||||||
def _idval(val, argname, idx, idfn, config=None):
|
def _idval(val, argname, idx, idfn, config=None):
|
||||||
|
|
|
@ -930,43 +930,6 @@ class TestMetafuncFunctional:
|
||||||
reprec = testdir.inline_run()
|
reprec = testdir.inline_run()
|
||||||
reprec.assertoutcome(passed=5)
|
reprec.assertoutcome(passed=5)
|
||||||
|
|
||||||
def test_parametrize_issue634(self, testdir):
|
|
||||||
testdir.makepyfile('''
|
|
||||||
import pytest
|
|
||||||
|
|
||||||
@pytest.fixture(scope='module')
|
|
||||||
def foo(request):
|
|
||||||
print('preparing foo-%d' % request.param)
|
|
||||||
return 'foo-%d' % request.param
|
|
||||||
|
|
||||||
|
|
||||||
def test_one(foo):
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
def test_two(foo):
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
test_two.test_with = (2, 3)
|
|
||||||
|
|
||||||
|
|
||||||
def pytest_generate_tests(metafunc):
|
|
||||||
params = (1, 2, 3, 4)
|
|
||||||
if not 'foo' in metafunc.fixturenames:
|
|
||||||
return
|
|
||||||
|
|
||||||
test_with = getattr(metafunc.function, 'test_with', None)
|
|
||||||
if test_with:
|
|
||||||
params = test_with
|
|
||||||
metafunc.parametrize('foo', params, indirect=True)
|
|
||||||
|
|
||||||
''')
|
|
||||||
result = testdir.runpytest("-s")
|
|
||||||
output = result.stdout.str()
|
|
||||||
assert output.count('preparing foo-2') == 1
|
|
||||||
assert output.count('preparing foo-3') == 1
|
|
||||||
|
|
||||||
def test_parametrize_issue323(self, testdir):
|
def test_parametrize_issue323(self, testdir):
|
||||||
testdir.makepyfile("""
|
testdir.makepyfile("""
|
||||||
import pytest
|
import pytest
|
||||||
|
@ -1047,6 +1010,125 @@ class TestMetafuncFunctional:
|
||||||
assert expectederror in failures[0].longrepr.reprcrash.message
|
assert expectederror in failures[0].longrepr.reprcrash.message
|
||||||
|
|
||||||
|
|
||||||
|
class TestMetafuncFunctionalAuto:
|
||||||
|
"""
|
||||||
|
Tests related to automatically find out the correct scope for parametrized tests (#1832).
|
||||||
|
"""
|
||||||
|
|
||||||
|
def test_parametrize_auto_scope(self, testdir):
|
||||||
|
testdir.makepyfile('''
|
||||||
|
import pytest
|
||||||
|
|
||||||
|
@pytest.fixture(scope='session', autouse=True)
|
||||||
|
def fixture():
|
||||||
|
return 1
|
||||||
|
|
||||||
|
@pytest.mark.parametrize('animal', ["dog", "cat"])
|
||||||
|
def test_1(animal):
|
||||||
|
assert animal in ('dog', 'cat')
|
||||||
|
|
||||||
|
@pytest.mark.parametrize('animal', ['fish'])
|
||||||
|
def test_2(animal):
|
||||||
|
assert animal == 'fish'
|
||||||
|
|
||||||
|
''')
|
||||||
|
result = testdir.runpytest()
|
||||||
|
result.stdout.fnmatch_lines(['* 3 passed *'])
|
||||||
|
|
||||||
|
def test_parametrize_auto_scope_indirect(self, testdir):
|
||||||
|
testdir.makepyfile('''
|
||||||
|
import pytest
|
||||||
|
|
||||||
|
@pytest.fixture(scope='session')
|
||||||
|
def echo(request):
|
||||||
|
return request.param
|
||||||
|
|
||||||
|
@pytest.mark.parametrize('animal, echo', [("dog", 1), ("cat", 2)], indirect=['echo'])
|
||||||
|
def test_1(animal, echo):
|
||||||
|
assert animal in ('dog', 'cat')
|
||||||
|
assert echo in (1, 2, 3)
|
||||||
|
|
||||||
|
@pytest.mark.parametrize('animal, echo', [('fish', 3)], indirect=['echo'])
|
||||||
|
def test_2(animal, echo):
|
||||||
|
assert animal == 'fish'
|
||||||
|
assert echo in (1, 2, 3)
|
||||||
|
''')
|
||||||
|
result = testdir.runpytest()
|
||||||
|
result.stdout.fnmatch_lines(['* 3 passed *'])
|
||||||
|
|
||||||
|
def test_parametrize_auto_scope_override_fixture(self, testdir):
|
||||||
|
testdir.makepyfile('''
|
||||||
|
import pytest
|
||||||
|
|
||||||
|
@pytest.fixture(scope='session', autouse=True)
|
||||||
|
def animal():
|
||||||
|
return 'fox'
|
||||||
|
|
||||||
|
@pytest.mark.parametrize('animal', ["dog", "cat"])
|
||||||
|
def test_1(animal):
|
||||||
|
assert animal in ('dog', 'cat')
|
||||||
|
''')
|
||||||
|
result = testdir.runpytest()
|
||||||
|
result.stdout.fnmatch_lines(['* 2 passed *'])
|
||||||
|
|
||||||
|
def test_parametrize_all_indirects(self, testdir):
|
||||||
|
testdir.makepyfile('''
|
||||||
|
import pytest
|
||||||
|
|
||||||
|
@pytest.fixture()
|
||||||
|
def animal(request):
|
||||||
|
return request.param
|
||||||
|
|
||||||
|
@pytest.fixture(scope='session')
|
||||||
|
def echo(request):
|
||||||
|
return request.param
|
||||||
|
|
||||||
|
@pytest.mark.parametrize('animal, echo', [("dog", 1), ("cat", 2)], indirect=True)
|
||||||
|
def test_1(animal, echo):
|
||||||
|
assert animal in ('dog', 'cat')
|
||||||
|
assert echo in (1, 2, 3)
|
||||||
|
|
||||||
|
@pytest.mark.parametrize('animal, echo', [("fish", 3)], indirect=True)
|
||||||
|
def test_2(animal, echo):
|
||||||
|
assert animal == 'fish'
|
||||||
|
assert echo in (1, 2, 3)
|
||||||
|
''')
|
||||||
|
result = testdir.runpytest()
|
||||||
|
result.stdout.fnmatch_lines(['* 3 passed *'])
|
||||||
|
|
||||||
|
def test_parametrize_issue634(self, testdir):
|
||||||
|
testdir.makepyfile('''
|
||||||
|
import pytest
|
||||||
|
|
||||||
|
@pytest.fixture(scope='module')
|
||||||
|
def foo(request):
|
||||||
|
print('preparing foo-%d' % request.param)
|
||||||
|
return 'foo-%d' % request.param
|
||||||
|
|
||||||
|
def test_one(foo):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def test_two(foo):
|
||||||
|
pass
|
||||||
|
|
||||||
|
test_two.test_with = (2, 3)
|
||||||
|
|
||||||
|
def pytest_generate_tests(metafunc):
|
||||||
|
params = (1, 2, 3, 4)
|
||||||
|
if not 'foo' in metafunc.fixturenames:
|
||||||
|
return
|
||||||
|
|
||||||
|
test_with = getattr(metafunc.function, 'test_with', None)
|
||||||
|
if test_with:
|
||||||
|
params = test_with
|
||||||
|
metafunc.parametrize('foo', params, indirect=True)
|
||||||
|
''')
|
||||||
|
result = testdir.runpytest("-s")
|
||||||
|
output = result.stdout.str()
|
||||||
|
assert output.count('preparing foo-2') == 1
|
||||||
|
assert output.count('preparing foo-3') == 1
|
||||||
|
|
||||||
|
|
||||||
class TestMarkersWithParametrization:
|
class TestMarkersWithParametrization:
|
||||||
pytestmark = pytest.mark.issue308
|
pytestmark = pytest.mark.issue308
|
||||||
def test_simple_mark(self, testdir):
|
def test_simple_mark(self, testdir):
|
||||||
|
|
Loading…
Reference in New Issue