Short Answer: It's a bug in Pylint 2.4.4 (and older). I've submitted a patch, which has been merged into master, and will be included in the next release of Pylint.
Details (for the curious):
When Python parses the code into Abstract Syntax Tree (AST) nodes, decorator nodes (e.g @dec...
) are attached to the decorator_list
of the node for the function definition (e.g. def g...
):
stmt = FunctionDef(identifier name, arguments args,
stmt* body, expr* decorator_list, expr? returns,
string? type_comment)
Pylint had a special case for function arguments (args
), but forgot to check the decorator_list
and the returns
annotation. This was causing Pylint to incorrectly treat the decorators as if they were inside the function, and thus in function scope rather than class scope.
Workaround:
As a static code checker, Pylint can only go so far. It currently has 500 open issues, so expect a few false positives. For now, you can follow @chepner's suggestion to disable the Pylint warning, just for that line:
@dec([i + 5 for i in x]) # pylint: disable=undefined-variable
But I want it now! (for those who want a 10/10 code rating without cheating)
git clone https://github.com/PyCQA/astroid.git
git clone https://github.com/PyCQA/pylint.git
pip install ./astroid/
pip install ./pylint/
pylint --version
pylint 2.5.0-dev1
astroid 2.4.0
With the development version of Pylint (and Astroid, the library Pylint uses for parsing), the code in the question shouldn't give any undefined-variable
complaints (though it will give some style warnings). If this ever changes, please reopen the bug report!