ruff icon indicating copy to clipboard operation
ruff copied to clipboard

False positive for F821

Open olliemath opened this issue 2 years ago • 12 comments

It seems that using dict as a parameter name in a function (which I'd consider bad style) breaks ruff's parsing in unexpected ways. In particular the following gives 6:31: F821 Undefined name 'name', when it shouldn't.

def unimportant(name):
    pass


def dang(dict):
    return unimportant(name=dict["name"])

Here is my pyproject.toml if that's needed to reproduce:

[tool.ruff]
ignore = [
    'B007',
    'E741',
    'E501',
]
line-length = 88
select = [
    'B',
    'E',
    'F',
    'W',
]

olliemath avatar Nov 16 '22 22:11 olliemath

Thanks! Yeah, definitely a legit bug. We need to verify that dict corresponds to the built-in and hasn't been shadowed.

charliermarsh avatar Nov 16 '22 23:11 charliermarsh

Appreciate the clear test case.

charliermarsh avatar Nov 16 '22 23:11 charliermarsh

(I'll fix this tomorrow most likely, probably not tonight.)

charliermarsh avatar Nov 16 '22 23:11 charliermarsh

Tangentially, I guess I'd argue that Flake8 erroneously doesn't catch this:

# Flake8 allows this
x = dict["foo"]

# Flake8 raises F821 here
x: dict["foo"]

Both should raise an undefined error on foo.

charliermarsh avatar Nov 17 '22 00:11 charliermarsh

The reason I mention it is because both Flake8 and Ruff accidentally raise F821 here:

def f(dict):
    x: dict["foo"] = 1

charliermarsh avatar Nov 17 '22 00:11 charliermarsh

But I will fix this in Ruff :)

charliermarsh avatar Nov 17 '22 00:11 charliermarsh

Thanks for the quick response! Yeah interesting that flake8 has that issue too - I guess it's a bit more niche, so as-yet undiscovered (or unfixed) by them.

olliemath avatar Nov 17 '22 09:11 olliemath

Well, I've also let the pyflakes team know about this edge case https://github.com/PyCQA/pyflakes/issues/738 I assume they'll want to fix it!

olliemath avatar Nov 17 '22 10:11 olliemath

The reason I mention it is because both Flake8 and Ruff accidentally raise F821 here:

def f(dict):
    x: dict["foo"] = 1

So pyflakes adopt the attitude of "this is a bad type annotation - won't fix". In fact this also gives F821 with flake8 but not ruff:

def f(noshadow):
    x: noshadow["foo"] = 1

Either way, having consistent behavior in ruff with or without shadowing is good (whether or not that differs from flake8 slightly).

olliemath avatar Nov 17 '22 13:11 olliemath

I'm behind on this, it'll come soon :)

charliermarsh avatar Nov 18 '22 17:11 charliermarsh

@charliermarsh, I could work on it if it is ok with you.

JonathanPlasse avatar Nov 19 '22 06:11 JonathanPlasse

That'd be great @JonathanPlasse! I know it's relevant to the sys.exit stuff too.

charliermarsh avatar Nov 20 '22 15:11 charliermarsh