pytest fixtures Redefining name from outer scope [pylint]
Asked Answered
D

4

99

I'm learning pytest and I lint my code with pylint. But pylint still complaints about:
W0621: Redefining name %r from outer scope (line %s)

for the following example from pytest:

# test_wallet.py

@pytest.fixture
def my_wallet():
    '''Returns a Wallet instance with a zero balance'''
    return Wallet()

@pytest.mark.parametrize("earned,spent,expected", [
    (30, 10, 20),
    (20, 2, 18),
])
def test_transactions(my_wallet, earned, spent, expected):
    my_wallet.add_cash(earned)
    my_wallet.spend_cash(spent)
    assert my_wallet.balance == expected

Redefining name my_wallet from outer scope.

I found workaround to add _ prefix to the fixture name: _my_wallet.

What would be the best practice if I want to keep fixtures in same file as functions?

  1. Prepend all fixtures with _?
  2. Disable this pylint check for tests?
  3. Better suggestion?
Dorise answered 7/9, 2017 at 6:39 Comment(0)
R
47

I just disabled that rule in my test files:

# pylint: disable=redefined-outer-name
# ^^^ this
import pytest

@pytest.fixture
def my_wallet():
    '''Returns a Wallet instance with a zero balance'''
    return Wallet()

@pytest.mark.parametrize("earned,spent,expected", [
    (30, 10, 20),
    (20, 2, 18),
])
def test_transactions(my_wallet, earned, spent, expected):
    my_wallet.add_cash(earned)
    my_wallet.spend_cash(spent)
    assert my_wallet.balance == expected
Rosol answered 4/1, 2019 at 20:39 Comment(2)
This is sad. The lint rule is there for a good reason. I blame pylint for this.Hearing
@Hearing I am a Pylint contributor, I opened a bug issue regarding this False Positive message. github.com/PyCQA/pylint/issues/6531Poodle
D
177

The pytest docs for @pytest.fixture say this:

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>').

So this solution is similar to your option 1, except that the pytest author suggests a slightly more descriptive name for the fixture function. So replace these two lines

@pytest.fixture
def my_wallet():

with:

@pytest.fixture(name="my_wallet")
def fixture_my_wallet():

The description in the docs also hints at another solution which is to move the fixtures into conftest.py so they are not in the same module as the test code using the fixtures. This location is also useful for sharing fixtures among test modules.

Dumpcart answered 13/7, 2019 at 0:35 Comment(4)
This should be the valid answer.Lizalizabeth
Here's an updated link to the relevant pytest docsPolly
This works. But you still get pylint errors if you are using mocker. For example: from pytest_mock import mocker followed by def test_my_thing(mocker): gives you a pylint error. I think this is why so many people voted for the other answer which suggests disabling this pylint rule for the WHOLE file. This is BAD imo. It seems to me that pylint stomps all over good linting rules.Hearing
funny thing, now I get "unused argument 'name'"Vadnais
R
47

I just disabled that rule in my test files:

# pylint: disable=redefined-outer-name
# ^^^ this
import pytest

@pytest.fixture
def my_wallet():
    '''Returns a Wallet instance with a zero balance'''
    return Wallet()

@pytest.mark.parametrize("earned,spent,expected", [
    (30, 10, 20),
    (20, 2, 18),
])
def test_transactions(my_wallet, earned, spent, expected):
    my_wallet.add_cash(earned)
    my_wallet.spend_cash(spent)
    assert my_wallet.balance == expected
Rosol answered 4/1, 2019 at 20:39 Comment(2)
This is sad. The lint rule is there for a good reason. I blame pylint for this.Hearing
@Hearing I am a Pylint contributor, I opened a bug issue regarding this False Positive message. github.com/PyCQA/pylint/issues/6531Poodle
F
9

Add name parameter for fixture and fixture_ prefix in def.

@pytest.fixture(name="my_wallet")
def fixture_wallet():
    '''Returns a Wallet instance with a zero balance.'''
    return Wallet()

@pytest.mark.parametrize("earned, spent, expected", [
    (30, 10, 20),
    (20, 2, 18),
])
def test_transactions(my_wallet, earned, spent, expected):
    my_wallet.add_cash(earned)
    my_wallet.spend_cash(spent)
    assert my_wallet.balance == expected
Franckot answered 14/10, 2020 at 5:45 Comment(0)
L
6

It's usually disabled (1, 2).

There is a pylint-pytest plugin that tried to fix some problems, but the error W0621 is not fixed yet.

Leo answered 8/9, 2017 at 19:16 Comment(3)
Doesn't this plugin error out during pytest on pylint warnings, instead of suppressing pylint warnings in tests code?Segovia
yes, the pluging @insysion is linking to runs pylint as part pytest, and has nothing to do with fixing pylint error messages on common pytest fixture usage.Sex
this plugin doesn't seem to work properly when using the "enable" pytest configuration. Any flag that is "enabled" takes precedence over what pylint-pytest is trying to do.Fahy

© 2022 - 2024 — McMap. All rights reserved.