Allow custom fixture names for fixtures
When defining a fixture in the same module as where it is used, the function argument shadows the fixture name, which a) annoys pylint and b) can lead to bugs where you forget to request a fixture into a test method. This allows one to define fixtures with a different name than the name of the function, bypassing that problem.
This commit is contained in:
parent
c2b9196a7c
commit
9577120592
1
AUTHORS
1
AUTHORS
|
@ -63,6 +63,7 @@ Matt Williams
|
||||||
Michael Aquilina
|
Michael Aquilina
|
||||||
Michael Birtwell
|
Michael Birtwell
|
||||||
Michael Droettboom
|
Michael Droettboom
|
||||||
|
Mike Lundy
|
||||||
Nicolas Delaby
|
Nicolas Delaby
|
||||||
Pieter Mulder
|
Pieter Mulder
|
||||||
Piotr Banaszkiewicz
|
Piotr Banaszkiewicz
|
||||||
|
|
|
@ -7,6 +7,10 @@
|
||||||
namespace in which your doctests run.
|
namespace in which your doctests run.
|
||||||
Thanks `@milliams`_ for the complete PR (`#1428`_).
|
Thanks `@milliams`_ for the complete PR (`#1428`_).
|
||||||
|
|
||||||
|
* New ``name`` argument to ``pytest.fixture`` mark, which allows a custom name
|
||||||
|
for a fixture (to solve the funcarg-shadowing-fixture problem).
|
||||||
|
Thanks `@novas0x2a`_ for the complete PR (`#1444`_).
|
||||||
|
|
||||||
*
|
*
|
||||||
|
|
||||||
*
|
*
|
||||||
|
@ -21,8 +25,10 @@
|
||||||
*
|
*
|
||||||
|
|
||||||
.. _@milliams: https://github.com/milliams
|
.. _@milliams: https://github.com/milliams
|
||||||
|
.. _@novas0x2a: https://github.com/novas0x2a
|
||||||
|
|
||||||
.. _#1428: https://github.com/pytest-dev/pytest/pull/1428
|
.. _#1428: https://github.com/pytest-dev/pytest/pull/1428
|
||||||
|
.. _#1444: https://github.com/pytest-dev/pytest/pull/1444
|
||||||
|
|
||||||
|
|
||||||
2.9.1.dev1
|
2.9.1.dev1
|
||||||
|
|
|
@ -114,12 +114,13 @@ def safe_getattr(object, name, default):
|
||||||
|
|
||||||
class FixtureFunctionMarker:
|
class FixtureFunctionMarker:
|
||||||
def __init__(self, scope, params,
|
def __init__(self, scope, params,
|
||||||
autouse=False, yieldctx=False, ids=None):
|
autouse=False, yieldctx=False, ids=None, name=None):
|
||||||
self.scope = scope
|
self.scope = scope
|
||||||
self.params = params
|
self.params = params
|
||||||
self.autouse = autouse
|
self.autouse = autouse
|
||||||
self.yieldctx = yieldctx
|
self.yieldctx = yieldctx
|
||||||
self.ids = ids
|
self.ids = ids
|
||||||
|
self.name = name
|
||||||
|
|
||||||
def __call__(self, function):
|
def __call__(self, function):
|
||||||
if isclass(function):
|
if isclass(function):
|
||||||
|
@ -129,7 +130,7 @@ class FixtureFunctionMarker:
|
||||||
return function
|
return function
|
||||||
|
|
||||||
|
|
||||||
def fixture(scope="function", params=None, autouse=False, ids=None):
|
def fixture(scope="function", params=None, autouse=False, ids=None, name=None):
|
||||||
""" (return a) decorator to mark a fixture factory function.
|
""" (return a) decorator to mark a fixture factory function.
|
||||||
|
|
||||||
This decorator can be used (with or or without parameters) to define
|
This decorator can be used (with or or without parameters) to define
|
||||||
|
@ -155,14 +156,21 @@ def fixture(scope="function", params=None, autouse=False, ids=None):
|
||||||
so that they are part of the test id. If no ids are provided
|
so that they are part of the test id. If no ids are provided
|
||||||
they will be generated automatically from the params.
|
they will be generated automatically from the params.
|
||||||
|
|
||||||
|
:arg name: the name of the fixture. This defaults to the name of the
|
||||||
|
decorated function. If a fixture is used in the same module in
|
||||||
|
which it is defined, the function name of the fixture will be
|
||||||
|
shadowed by the function arg that requests the fixture; one way
|
||||||
|
to resolve this is to name the decorated function
|
||||||
|
``fixture_<fixturename>`` and then use
|
||||||
|
``@pytest.fixture(name='<fixturename>')``.
|
||||||
"""
|
"""
|
||||||
if callable(scope) and params is None and autouse == False:
|
if callable(scope) and params is None and autouse == False:
|
||||||
# direct decoration
|
# direct decoration
|
||||||
return FixtureFunctionMarker(
|
return FixtureFunctionMarker(
|
||||||
"function", params, autouse)(scope)
|
"function", params, autouse, name=name)(scope)
|
||||||
if params is not None and not isinstance(params, (list, tuple)):
|
if params is not None and not isinstance(params, (list, tuple)):
|
||||||
params = list(params)
|
params = list(params)
|
||||||
return FixtureFunctionMarker(scope, params, autouse, ids=ids)
|
return FixtureFunctionMarker(scope, params, autouse, ids=ids, name=name)
|
||||||
|
|
||||||
def yield_fixture(scope="function", params=None, autouse=False, ids=None):
|
def yield_fixture(scope="function", params=None, autouse=False, ids=None):
|
||||||
""" (return a) decorator to mark a yield-fixture factory function
|
""" (return a) decorator to mark a yield-fixture factory function
|
||||||
|
@ -1989,6 +1997,8 @@ class FixtureManager:
|
||||||
# fixture attribute
|
# fixture attribute
|
||||||
continue
|
continue
|
||||||
else:
|
else:
|
||||||
|
if marker.name:
|
||||||
|
name = marker.name
|
||||||
assert not name.startswith(self._argprefix)
|
assert not name.startswith(self._argprefix)
|
||||||
fixturedef = FixtureDef(self, nodeid, name, obj,
|
fixturedef = FixtureDef(self, nodeid, name, obj,
|
||||||
marker.scope, marker.params,
|
marker.scope, marker.params,
|
||||||
|
|
|
@ -2691,3 +2691,14 @@ class TestContextManagerFixtureFuncs:
|
||||||
*def arg1*
|
*def arg1*
|
||||||
""")
|
""")
|
||||||
|
|
||||||
|
def test_custom_name(self, testdir):
|
||||||
|
testdir.makepyfile("""
|
||||||
|
import pytest
|
||||||
|
@pytest.fixture(name='meow')
|
||||||
|
def arg1():
|
||||||
|
return 'mew'
|
||||||
|
def test_1(meow):
|
||||||
|
print(meow)
|
||||||
|
""")
|
||||||
|
result = testdir.runpytest("-s")
|
||||||
|
result.stdout.fnmatch_lines("*mew*")
|
||||||
|
|
Loading…
Reference in New Issue