From 6e32e007f739e2e80ca912bdf36b306d8e94965e Mon Sep 17 00:00:00 2001 From: Konstantina Saketou Date: Wed, 16 Mar 2022 15:55:30 +0200 Subject: [PATCH 01/10] Add duplicate value check for sets This commit adds some new functionality which checks for duplicate values inside sets. For that reason, we create a new message called duplicate-value. --- pylint/checkers/base.py | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/pylint/checkers/base.py b/pylint/checkers/base.py index e2a3ece496..a143056e12 100644 --- a/pylint/checkers/base.py +++ b/pylint/checkers/base.py @@ -1080,6 +1080,11 @@ class BasicChecker(_BasicChecker): "Used when an assert statement has a string literal as its first argument, which will " "cause the assert to always pass.", ), + "W0130": ( + "Duplicate value %r in set", + "duplicate-value", + "Used when a set contains the same value multiple times.", + ), } reports = (("RP0101", "Statistics by type", report_by_type_stats),) @@ -1467,6 +1472,19 @@ def visit_dict(self, node: nodes.Dict) -> None: self.add_message("duplicate-key", node=node, args=key) keys.add(key) + @utils.check_messages("duplicate-value") + def visit_set(self, node: nodes.Set) -> None: + """Check duplicate value in set.""" + values = set() + for v in node.elts: + if isinstance(v, nodes.Const): + value = v.value + else: + continue + if value in values: + self.add_message("duplicate-value", node=node, args=value) + values.add(value) + def visit_tryfinally(self, node: nodes.TryFinally) -> None: """Update try...finally flag.""" self._tryfinallys.append(node) From 656f7c105594f131cd94f876794224b099c5e066 Mon Sep 17 00:00:00 2001 From: Konstantina Saketou Date: Wed, 16 Mar 2022 15:57:03 +0200 Subject: [PATCH 02/10] Add new tests for duplicate-value message This commit adds new functional tests for the new message duplicate-value. --- tests/functional/d/duplicate_value.py | 18 ++++++++++++++++++ tests/functional/d/duplicate_value.txt | 10 ++++++++++ 2 files changed, 28 insertions(+) create mode 100644 tests/functional/d/duplicate_value.py create mode 100644 tests/functional/d/duplicate_value.txt diff --git a/tests/functional/d/duplicate_value.py b/tests/functional/d/duplicate_value.py new file mode 100644 index 0000000000..291353c862 --- /dev/null +++ b/tests/functional/d/duplicate_value.py @@ -0,0 +1,18 @@ +# pylint: disable = invalid-name, line-too-long +"""Simple test sets for checking duplicate values""" + +set1 = {1, 2, 3, 4} +set2 = {1, 1, 2} # [duplicate-value] +set3 = {1, 2, 2} # [duplicate-value] + +set4 = {'one', 'two', 'three'} +set5 = {'one', 'two', 'one'} # [duplicate-value] +set6 = {'one', 'two', 'two'} # [duplicate-value] + +wrong_set = {12, 23, True, 6, True, 0, 12} # [duplicate-value, duplicate-value] +correct_set = {12, 13, 23, 24, 89} + +wrong_set_mixed = {1, 2, 'value', 1} # [duplicate-value] +wrong_set = {'arg1', 'arg2', False, 'arg1', True} # [duplicate-value] + +another_wrong_set = {2, 3, 'arg1', True, 'arg1', False, True} # [duplicate-value, duplicate-value] diff --git a/tests/functional/d/duplicate_value.txt b/tests/functional/d/duplicate_value.txt new file mode 100644 index 0000000000..89ad78f574 --- /dev/null +++ b/tests/functional/d/duplicate_value.txt @@ -0,0 +1,10 @@ +duplicate-value:5:7:5:16::Duplicate value 1 in set:UNDEFINED +duplicate-value:6:7:6:16::Duplicate value 2 in set:UNDEFINED +duplicate-value:9:7:9:28::Duplicate value 'one' in set:UNDEFINED +duplicate-value:10:7:10:28::Duplicate value 'two' in set:UNDEFINED +duplicate-value:12:12:12:42::Duplicate value 12 in set:UNDEFINED +duplicate-value:12:12:12:42::Duplicate value True in set:UNDEFINED +duplicate-value:15:18:15:36::Duplicate value 1 in set:UNDEFINED +duplicate-value:16:12:16:49::Duplicate value 'arg1' in set:UNDEFINED +duplicate-value:18:20:18:61::Duplicate value 'arg1' in set:UNDEFINED +duplicate-value:18:20:18:61::Duplicate value True in set:UNDEFINED From 5a4b7e6e31fbfa666b6a593d9364e0cb4ff84027 Mon Sep 17 00:00:00 2001 From: Konstantina Saketou Date: Wed, 16 Mar 2022 16:13:02 +0200 Subject: [PATCH 03/10] Add duplicate-value message in Changelog and whats new --- ChangeLog | 4 ++++ doc/whatsnew/2.13.rst | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/ChangeLog b/ChangeLog index 6e3a338e12..1a5ca41428 100644 --- a/ChangeLog +++ b/ChangeLog @@ -11,6 +11,10 @@ Release date: TBA * Fix pyreverse diagrams type hinting for classmethods and staticmethods. +* Add new message ``duplicate-value`` for identifying duplicate values inside sets. + + Closes #5880 + * Fix matching ``--notes`` options that end in a non-word character. Closes #5840 diff --git a/doc/whatsnew/2.13.rst b/doc/whatsnew/2.13.rst index 1aa94d4aff..6b6342e128 100644 --- a/doc/whatsnew/2.13.rst +++ b/doc/whatsnew/2.13.rst @@ -62,6 +62,10 @@ New checkers Closes #5670 +* Added new message called ``duplicate-value`` which identifies duplicate values inside sets. + + Closes #5880 + Removed checkers ================ From 1fbf4baca183b942fbae4de1c5d1a70742e1d7c4 Mon Sep 17 00:00:00 2001 From: Konstantina Saketou Date: Mon, 21 Mar 2022 22:41:29 +0200 Subject: [PATCH 04/10] Modify escape sequences clarification This commit changes the unsplit_ends set by keeping only the unicode sequences and noting their synonyms in comments in order to avoid duplicate-value error triggering. --- pylint/checkers/format.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/pylint/checkers/format.py b/pylint/checkers/format.py index 799d97cbc5..f5eedb6d73 100644 --- a/pylint/checkers/format.py +++ b/pylint/checkers/format.py @@ -717,10 +717,8 @@ def is_line_length_check_activated(pylint_pattern_match_object) -> bool: def specific_splitlines(lines: str) -> List[str]: """Split lines according to universal newlines except those in a specific sets.""" unsplit_ends = { - "\v", - "\x0b", - "\f", - "\x0c", + "\x0b", # synonym of \v + "\x0c", # synonym of \f "\x1c", "\x1d", "\x1e", From a73f3254ee2defef190b76bb9464579518cf117b Mon Sep 17 00:00:00 2001 From: Konstantina Saketou Date: Thu, 31 Mar 2022 17:53:06 +0300 Subject: [PATCH 05/10] Move doc to 2.14 --- ChangeLog | 4 ++++ doc/whatsnew/2.13.rst | 3 --- doc/whatsnew/2.14.rst | 4 ++++ 3 files changed, 8 insertions(+), 3 deletions(-) diff --git a/ChangeLog b/ChangeLog index e8cadf7f26..f1b3ae3976 100644 --- a/ChangeLog +++ b/ChangeLog @@ -28,6 +28,10 @@ Release date: TBA * Fix bug where specifically enabling just ``await-outside-async`` was not possible. +* Added new message called ``duplicate-value`` which identifies duplicate values inside sets. + + Closes #5880 + .. Insert your changelog randomly, it will reduce merge conflicts (Ie. not necessarily at the end) diff --git a/doc/whatsnew/2.13.rst b/doc/whatsnew/2.13.rst index 7ed2cdd33b..706416e0c4 100644 --- a/doc/whatsnew/2.13.rst +++ b/doc/whatsnew/2.13.rst @@ -84,9 +84,6 @@ New checkers Closes #5670 -* Added new message called ``duplicate-value`` which identifies duplicate values inside sets. - - Closes #5880 Removed checkers ================ diff --git a/doc/whatsnew/2.14.rst b/doc/whatsnew/2.14.rst index ad38200e7f..04dd35a661 100644 --- a/doc/whatsnew/2.14.rst +++ b/doc/whatsnew/2.14.rst @@ -23,6 +23,10 @@ New checkers Closes #4525 +* Added new message called ``duplicate-value`` which identifies duplicate values inside sets. + + Closes #5880 + Removed checkers ================ From ddd23e66875a1dcff4accfc81521d7a6fea4f542 Mon Sep 17 00:00:00 2001 From: Konstantina Saketou Date: Thu, 31 Mar 2022 18:01:51 +0300 Subject: [PATCH 06/10] Move error to new file and change confidence to HIGH --- pylint/checkers/base/basic_checker.py | 22 +++++++++++++++++++++- tests/functional/d/duplicate_value.txt | 20 ++++++++++---------- 2 files changed, 31 insertions(+), 11 deletions(-) diff --git a/pylint/checkers/base/basic_checker.py b/pylint/checkers/base/basic_checker.py index 1e5a2a15bb..d26ceaab2d 100644 --- a/pylint/checkers/base/basic_checker.py +++ b/pylint/checkers/base/basic_checker.py @@ -15,7 +15,7 @@ from pylint import interfaces from pylint import utils as lint_utils from pylint.checkers import BaseChecker, utils -from pylint.interfaces import IAstroidChecker +from pylint.interfaces import HIGH, IAstroidChecker from pylint.reporters.ureports import nodes as reporter_nodes from pylint.utils import LinterStats from pylint.utils.utils import get_global_option @@ -246,6 +246,11 @@ class BasicChecker(_BasicChecker): "Used when an assert statement has a string literal as its first argument, which will " "cause the assert to always pass.", ), + "W0130": ( + "Duplicate value %r in set", + "duplicate-value", + "Used when a set contains the same value multiple times.", + ), } reports = (("RP0101", "Statistics by type", report_by_type_stats),) @@ -637,6 +642,21 @@ def visit_dict(self, node: nodes.Dict) -> None: self.add_message("duplicate-key", node=node, args=key) keys.add(key) + @utils.check_messages("duplicate-value") + def visit_set(self, node: nodes.Set) -> None: + """Check duplicate value in set.""" + values = set() + for v in node.elts: + if isinstance(v, nodes.Const): + value = v.value + else: + continue + if value in values: + self.add_message( + "duplicate-value", node=node, args=value, confidence=HIGH + ) + values.add(value) + def visit_tryfinally(self, node: nodes.TryFinally) -> None: """Update try...finally flag.""" self._tryfinallys.append(node) diff --git a/tests/functional/d/duplicate_value.txt b/tests/functional/d/duplicate_value.txt index 89ad78f574..25c154086e 100644 --- a/tests/functional/d/duplicate_value.txt +++ b/tests/functional/d/duplicate_value.txt @@ -1,10 +1,10 @@ -duplicate-value:5:7:5:16::Duplicate value 1 in set:UNDEFINED -duplicate-value:6:7:6:16::Duplicate value 2 in set:UNDEFINED -duplicate-value:9:7:9:28::Duplicate value 'one' in set:UNDEFINED -duplicate-value:10:7:10:28::Duplicate value 'two' in set:UNDEFINED -duplicate-value:12:12:12:42::Duplicate value 12 in set:UNDEFINED -duplicate-value:12:12:12:42::Duplicate value True in set:UNDEFINED -duplicate-value:15:18:15:36::Duplicate value 1 in set:UNDEFINED -duplicate-value:16:12:16:49::Duplicate value 'arg1' in set:UNDEFINED -duplicate-value:18:20:18:61::Duplicate value 'arg1' in set:UNDEFINED -duplicate-value:18:20:18:61::Duplicate value True in set:UNDEFINED +duplicate-value:5:7:5:16::Duplicate value 1 in set:HIGH +duplicate-value:6:7:6:16::Duplicate value 2 in set:HIGH +duplicate-value:9:7:9:28::Duplicate value 'one' in set:HIGH +duplicate-value:10:7:10:28::Duplicate value 'two' in set:HIGH +duplicate-value:12:12:12:42::Duplicate value 12 in set:HIGH +duplicate-value:12:12:12:42::Duplicate value True in set:HIGH +duplicate-value:15:18:15:36::Duplicate value 1 in set:HIGH +duplicate-value:16:12:16:49::Duplicate value 'arg1' in set:HIGH +duplicate-value:18:20:18:61::Duplicate value 'arg1' in set:HIGH +duplicate-value:18:20:18:61::Duplicate value True in set:HIGH From 46a608587e2ea6aede303cc63beb1c58cd9e7df1 Mon Sep 17 00:00:00 2001 From: Konstantina Saketou Date: Thu, 31 Mar 2022 18:02:53 +0300 Subject: [PATCH 07/10] Add documentation for the new error --- doc/data/messages/d/duplicate-value/bad.py | 1 + doc/data/messages/d/duplicate-value/details.rst | 2 ++ doc/data/messages/d/duplicate-value/good.py | 1 + 3 files changed, 4 insertions(+) create mode 100644 doc/data/messages/d/duplicate-value/bad.py create mode 100644 doc/data/messages/d/duplicate-value/details.rst create mode 100644 doc/data/messages/d/duplicate-value/good.py diff --git a/doc/data/messages/d/duplicate-value/bad.py b/doc/data/messages/d/duplicate-value/bad.py new file mode 100644 index 0000000000..bf6f8ad005 --- /dev/null +++ b/doc/data/messages/d/duplicate-value/bad.py @@ -0,0 +1 @@ +incorrect_set = {'value1', 23, 5, 'value1'} # [duplicate-value] diff --git a/doc/data/messages/d/duplicate-value/details.rst b/doc/data/messages/d/duplicate-value/details.rst new file mode 100644 index 0000000000..69207d01d2 --- /dev/null +++ b/doc/data/messages/d/duplicate-value/details.rst @@ -0,0 +1,2 @@ +This error message is emitted when a set contains the same value two or more times. +It aims to reduce duplication of values inside sets. diff --git a/doc/data/messages/d/duplicate-value/good.py b/doc/data/messages/d/duplicate-value/good.py new file mode 100644 index 0000000000..9a12133712 --- /dev/null +++ b/doc/data/messages/d/duplicate-value/good.py @@ -0,0 +1 @@ +correct_set = {1, 2, 'value', 'arg'} From 5ddddcb9e5b984d2b3c0e18b1b17a211ad214b1e Mon Sep 17 00:00:00 2001 From: Pierre Sassoulas Date: Fri, 1 Apr 2022 19:08:11 +0200 Subject: [PATCH 08/10] Apply suggestions from code review MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Daniƫl van Noord <13665637+DanielNoord@users.noreply.github.com> --- ChangeLog | 3 --- doc/data/messages/d/duplicate-value/good.py | 2 +- doc/whatsnew/2.13.rst | 1 - 3 files changed, 1 insertion(+), 5 deletions(-) diff --git a/ChangeLog b/ChangeLog index a1b021167c..4117d95607 100644 --- a/ChangeLog +++ b/ChangeLog @@ -165,9 +165,6 @@ Release date: 2022-03-24 * Fix pyreverse diagrams type hinting for classmethods and staticmethods. -* Add new message ``duplicate-value`` for identifying duplicate values inside sets. - - Closes #5880 * Fix pyreverse diagrams type hinting for methods returning None. * Fix matching ``--notes`` options that end in a non-word character. diff --git a/doc/data/messages/d/duplicate-value/good.py b/doc/data/messages/d/duplicate-value/good.py index 9a12133712..c30cd78213 100644 --- a/doc/data/messages/d/duplicate-value/good.py +++ b/doc/data/messages/d/duplicate-value/good.py @@ -1 +1 @@ -correct_set = {1, 2, 'value', 'arg'} +correct_set = {'value1', 23, 5} diff --git a/doc/whatsnew/2.13.rst b/doc/whatsnew/2.13.rst index 706416e0c4..4bbf48ee7f 100644 --- a/doc/whatsnew/2.13.rst +++ b/doc/whatsnew/2.13.rst @@ -84,7 +84,6 @@ New checkers Closes #5670 - Removed checkers ================ From 1798d36dad1ea63f3e68876361bccf8c96854b40 Mon Sep 17 00:00:00 2001 From: Konstantina Saketou Date: Fri, 1 Apr 2022 21:15:53 +0300 Subject: [PATCH 09/10] Modify message description --- pylint/checkers/base/basic_checker.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pylint/checkers/base/basic_checker.py b/pylint/checkers/base/basic_checker.py index d26ceaab2d..55ce39d900 100644 --- a/pylint/checkers/base/basic_checker.py +++ b/pylint/checkers/base/basic_checker.py @@ -249,7 +249,7 @@ class BasicChecker(_BasicChecker): "W0130": ( "Duplicate value %r in set", "duplicate-value", - "Used when a set contains the same value multiple times.", + "This message is emitted when a set contains the same value two or more times.", ), } From e9103b16a21c9cc03c766cb1e405b3b6e01dba6e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dani=C3=ABl=20van=20Noord?= <13665637+DanielNoord@users.noreply.github.com> Date: Fri, 1 Apr 2022 20:33:02 +0200 Subject: [PATCH 10/10] Remove file --- doc/data/messages/d/duplicate-value/details.rst | 2 -- 1 file changed, 2 deletions(-) delete mode 100644 doc/data/messages/d/duplicate-value/details.rst diff --git a/doc/data/messages/d/duplicate-value/details.rst b/doc/data/messages/d/duplicate-value/details.rst deleted file mode 100644 index 69207d01d2..0000000000 --- a/doc/data/messages/d/duplicate-value/details.rst +++ /dev/null @@ -1,2 +0,0 @@ -This error message is emitted when a set contains the same value two or more times. -It aims to reduce duplication of values inside sets.