From 7905ec1f35d35aedb0a299598eebc9c98fe73f8a Mon Sep 17 00:00:00 2001 From: Marc Mueller <30130371+cdce8p@users.noreply.github.com> Date: Sat, 6 Mar 2021 03:31:34 +0100 Subject: [PATCH] Fix false-positive for unused-import on class keyword arguments --- ChangeLog | 4 ++ pylint/checkers/variables.py | 8 ++++ .../unused/unused_import_class_def_keyword.py | 38 +++++++++++++++++++ 3 files changed, 50 insertions(+) create mode 100644 tests/functional/u/unused/unused_import_class_def_keyword.py diff --git a/ChangeLog b/ChangeLog index bc00604068..56262f3be0 100644 --- a/ChangeLog +++ b/ChangeLog @@ -77,6 +77,10 @@ Release date: TBA * Improve check if class is subscriptable PEP585 +* Fix false-positive for ``unused-import`` on class keyword arguments + + Closes #3202 + What's New in Pylint 2.7.2? =========================== diff --git a/pylint/checkers/variables.py b/pylint/checkers/variables.py index 875257155f..9fc5235763 100644 --- a/pylint/checkers/variables.py +++ b/pylint/checkers/variables.py @@ -976,6 +976,14 @@ def visit_name(self, node): ): continue + # Ignore inner class scope for keywords in class definition + if ( + current_consumer.scope_type == "class" + and isinstance(node.parent, astroid.Keyword) + and isinstance(node.parent.parent, astroid.ClassDef) + ): + continue + # if the name node is used as a function default argument's value or as # a decorator, then start from the parent frame of the function instead # of the function frame - and thus open an inner class scope diff --git a/tests/functional/u/unused/unused_import_class_def_keyword.py b/tests/functional/u/unused/unused_import_class_def_keyword.py new file mode 100644 index 0000000000..0d6b599873 --- /dev/null +++ b/tests/functional/u/unused/unused_import_class_def_keyword.py @@ -0,0 +1,38 @@ +""" +Test false-positive for unused-import on class keyword arguments + + https://github.com/PyCQA/pylint/issues/3202 +""" +# pylint: disable=missing-docstring,too-few-public-methods,invalid-name,import-error + +# Imports don't exist! Only check `unused-import` +from const import DOMAIN +from const import DOMAIN_2 +from const import DOMAIN_3 + + +class Child: + def __init_subclass__(cls, **kwargs): + pass + +class Parent(Child, domain=DOMAIN): + pass + + +# Alternative 1 +class Parent_2(Child, domain=DOMAIN_2): + DOMAIN_2 = DOMAIN_2 + + +# Alternative 2 +class A: + def __init__(self, arg): + pass + +class B: + CONF = "Hello World" + SCHEMA = A(arg=CONF) + + +# Test normal instantiation +A(arg=DOMAIN_3)