From d4f04a79219c4ea12f013ff19cd7a98c215ea53e Mon Sep 17 00:00:00 2001 From: Mark Byrne Date: Mon, 10 Jan 2022 00:00:04 +0100 Subject: [PATCH] Fixed false positive for ``global-variable-not-assigned`` when the `del` statement is used Closes #5333 --- ChangeLog | 4 ++++ doc/whatsnew/2.13.rst | 4 ++++ pylint/checkers/utils.py | 9 +++++++++ pylint/checkers/variables.py | 1 + tests/functional/g/globals.py | 7 +++++++ tests/functional/g/globals.txt | 9 +++++---- 6 files changed, 30 insertions(+), 4 deletions(-) diff --git a/ChangeLog b/ChangeLog index 2bf37a089a..79d0f7b3bf 100644 --- a/ChangeLog +++ b/ChangeLog @@ -47,6 +47,10 @@ Release date: TBA Closes #5499 +* Fixed false positive for ``global-variable-not-assigned`` when the ``del`` statement is used + + Closes #5333 + * By default, pylint does no longer take files starting with ``.#`` into account. Those are considered `emacs file locks`. See https://www.gnu.org/software/emacs/manual/html_node/elisp/File-Locks.html. diff --git a/doc/whatsnew/2.13.rst b/doc/whatsnew/2.13.rst index c1b5922378..284d68f292 100644 --- a/doc/whatsnew/2.13.rst +++ b/doc/whatsnew/2.13.rst @@ -180,3 +180,7 @@ Other Changes raise ValueError Closes #4955 + +* Fixed false positive for ``global-variable-not-assigned`` when the ``del`` statement is used + + Closes #5333 diff --git a/pylint/checkers/utils.py b/pylint/checkers/utils.py index c20342c82e..105a39bb39 100644 --- a/pylint/checkers/utils.py +++ b/pylint/checkers/utils.py @@ -1672,6 +1672,15 @@ def is_reassigned_after_current(node: nodes.NodeNG, varname: str) -> bool: ) +def is_deleted_after_current(node: nodes.NodeNG, varname: str) -> bool: + """Check if the given variable name is deleted in the same scope after the current node""" + return any( + getattr(target, "name", None) == varname and target.lineno > node.lineno + for del_node in node.scope().nodes_of_class(nodes.Delete) + for target in del_node.targets + ) + + def is_function_body_ellipsis(node: nodes.FunctionDef) -> bool: """Checks whether a function body only consists of a single Ellipsis""" return ( diff --git a/pylint/checkers/variables.py b/pylint/checkers/variables.py index ae01a65d18..584a5cc4fe 100644 --- a/pylint/checkers/variables.py +++ b/pylint/checkers/variables.py @@ -1083,6 +1083,7 @@ def visit_global(self, node: nodes.Global) -> None: ) if ( not utils.is_reassigned_after_current(node, name) + and not utils.is_deleted_after_current(node, name) and not_defined_locally_by_import ): self.add_message("global-variable-not-assigned", args=name, node=node) diff --git a/tests/functional/g/globals.py b/tests/functional/g/globals.py index a5e4b4bffc..56c852d8a6 100644 --- a/tests/functional/g/globals.py +++ b/tests/functional/g/globals.py @@ -40,6 +40,13 @@ def global_no_assign(): print(CONSTANT) +def global_del(): + """Deleting the global name prevents `global-variable-not-assigned`""" + global CONSTANT # [global-statement] + print(CONSTANT) + del CONSTANT + + def global_operator_assign(): """Operator assigns should only throw a global statement error""" global CONSTANT # [global-statement] diff --git a/tests/functional/g/globals.txt b/tests/functional/g/globals.txt index 0559eea213..4e3f6dca43 100644 --- a/tests/functional/g/globals.txt +++ b/tests/functional/g/globals.txt @@ -6,7 +6,8 @@ undefined-variable:22:10:22:13:other:Undefined variable 'HOP':UNDEFINED global-variable-undefined:27:4:27:18:define_constant:Global variable 'SOMEVAR' undefined at the module level:UNDEFINED global-statement:33:4:33:14:global_with_import:Using the global statement:UNDEFINED global-variable-not-assigned:39:4:39:19:global_no_assign:Using global for 'CONSTANT' but no assignment is done:UNDEFINED -global-statement:45:4:45:19:global_operator_assign:Using the global statement:UNDEFINED -global-statement:52:4:52:19:global_function_assign:Using the global statement:UNDEFINED -global-statement:62:4:62:15:override_func:Using the global statement:UNDEFINED -global-statement:71:4:71:14:func:Using the global statement:UNDEFINED +global-statement:45:4:45:19:global_del:Using the global statement:UNDEFINED +global-statement:52:4:52:19:global_operator_assign:Using the global statement:UNDEFINED +global-statement:59:4:59:19:global_function_assign:Using the global statement:UNDEFINED +global-statement:69:4:69:15:override_func:Using the global statement:UNDEFINED +global-statement:78:4:78:14:func:Using the global statement:UNDEFINED