diff options
author | Jaehoon Hwang <jaehoonhwang@users.noreply.github.com> | 2021-10-17 00:31:34 -0700 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-10-17 09:31:34 +0200 |
commit | 59d2b545b557a7ac47955c65935889e296da941a (patch) | |
tree | a07b8d66954e630e5b8181d175fff60c423b93c7 /tests/functional | |
parent | 9098c6078551e2d3028fe65537d3b0e407c85724 (diff) | |
download | pylint-git-59d2b545b557a7ac47955c65935889e296da941a.tar.gz |
Add a warning ``use-implicit-booleaness-not-comparison`` for comparison with collection literals (#5120)
* Create a new checker; use-implicit-booleanness checker where it looks
for boolean evaluatiion with collection literals such as `()`, `[]`,
or `{}`
* Fixed invalid usage of comparison within pylint package
This closes #4774
* Ignore tuples when checking for `literal-comparison`
Closes #3031
* Merge len_checker with empty_literal checker
Moving empty literal checker with len_checker to avoid class without
iterators without boolean expressions (false positive on pandas)
Reference: https://github.com/PyCQA/pylint/pull/3821/files
* Update `len_checker` and its class `LenChecker` to `ComparisonChecker`
to reflect better usage after merging between `len_checker` and
`empty_literal_checker` and its tests.
* Fixed `consider_using_in` and `consider_iterating_dictionary` tests
that were failing due to new empty literal checkers.
Co-authored-by: Pierre Sassoulas <pierre.sassoulas@gmail.com>
Diffstat (limited to 'tests/functional')
7 files changed, 202 insertions, 30 deletions
diff --git a/tests/functional/c/consider/consider_iterating_dictionary.py b/tests/functional/c/consider/consider_iterating_dictionary.py index 996fa5429..d3cc75f4d 100644 --- a/tests/functional/c/consider/consider_iterating_dictionary.py +++ b/tests/functional/c/consider/consider_iterating_dictionary.py @@ -1,6 +1,6 @@ # pylint: disable=missing-docstring, expression-not-assigned, too-few-public-methods # pylint: disable=no-member, import-error, no-self-use, line-too-long, useless-object-inheritance -# pylint: disable=unnecessary-comprehension, use-dict-literal +# pylint: disable=unnecessary-comprehension, use-dict-literal, use-implicit-booleaness-not-comparison from unknown import Unknown diff --git a/tests/functional/c/consider/consider_using_in.py b/tests/functional/c/consider/consider_using_in.py index 8d23bb093..7ce5dd0b6 100644 --- a/tests/functional/c/consider/consider_using_in.py +++ b/tests/functional/c/consider/consider_using_in.py @@ -1,4 +1,4 @@ -# pylint: disable=missing-docstring, invalid-name, pointless-statement, misplaced-comparison-constant, undefined-variable, literal-comparison, line-too-long, unneeded-not, too-few-public-methods +# pylint: disable=missing-docstring, invalid-name, pointless-statement, misplaced-comparison-constant, undefined-variable, literal-comparison, line-too-long, unneeded-not, too-few-public-methods, use-implicit-booleaness-not-comparison value = value1 = 1 value2 = 2 diff --git a/tests/functional/c/consider/consider_using_in.txt b/tests/functional/c/consider/consider_using_in.txt index 72c8e389d..427c0ee04 100644 --- a/tests/functional/c/consider/consider_using_in.txt +++ b/tests/functional/c/consider/consider_using_in.txt @@ -1,14 +1,14 @@ -consider-using-in:10:0::"Consider merging these comparisons with ""in"" to 'value in (1,)'" -consider-using-in:11:0::"Consider merging these comparisons with ""in"" to 'value in (1, 2)'" -consider-using-in:12:0::"Consider merging these comparisons with ""in"" to ""value in ('value',)""" -consider-using-in:13:0::"Consider merging these comparisons with ""in"" to 'value in (1, undef_value)'" -consider-using-in:14:0::"Consider merging these comparisons with ""in"" to 'value in (1, 2, 3)'" -consider-using-in:15:0::"Consider merging these comparisons with ""in"" to ""value in ('2', 1)""" -consider-using-in:16:0::"Consider merging these comparisons with ""in"" to 'value in (1, 2)'" -consider-using-in:17:0::"Consider merging these comparisons with ""in"" to 'value in (1, 2)'" -consider-using-in:18:0::"Consider merging these comparisons with ""in"" to 'value in (1, a_list)'" -consider-using-in:19:0::"Consider merging these comparisons with ""in"" to 'value in (a_set, a_list, a_str)'" -consider-using-in:20:0::"Consider merging these comparisons with ""in"" to 'value not in (1, 2)'" -consider-using-in:21:0::"Consider merging these comparisons with ""in"" to 'value1 in (value2,)'" -consider-using-in:22:0::"Consider merging these comparisons with ""in"" to 'a_list in ([1, 2, 3], [])'" -consider-using-in:53:0::"Consider merging these comparisons with ""in"" to 'A.value in (1, 2)'" +consider-using-in:10:0::"Consider merging these comparisons with ""in"" to 'value in (1,)'":HIGH +consider-using-in:11:0::"Consider merging these comparisons with ""in"" to 'value in (1, 2)'":HIGH +consider-using-in:12:0::"Consider merging these comparisons with ""in"" to ""value in ('value',)""":HIGH +consider-using-in:13:0::"Consider merging these comparisons with ""in"" to 'value in (1, undef_value)'":HIGH +consider-using-in:14:0::"Consider merging these comparisons with ""in"" to 'value in (1, 2, 3)'":HIGH +consider-using-in:15:0::"Consider merging these comparisons with ""in"" to ""value in ('2', 1)""":HIGH +consider-using-in:16:0::"Consider merging these comparisons with ""in"" to 'value in (1, 2)'":HIGH +consider-using-in:17:0::"Consider merging these comparisons with ""in"" to 'value in (1, 2)'":HIGH +consider-using-in:18:0::"Consider merging these comparisons with ""in"" to 'value in (1, a_list)'":HIGH +consider-using-in:19:0::"Consider merging these comparisons with ""in"" to 'value in (a_set, a_list, a_str)'":HIGH +consider-using-in:20:0::"Consider merging these comparisons with ""in"" to 'value not in (1, 2)'":HIGH +consider-using-in:21:0::"Consider merging these comparisons with ""in"" to 'value1 in (value2,)'":HIGH +consider-using-in:22:0::"Consider merging these comparisons with ""in"" to 'a_list in ([1, 2, 3], [])'":HIGH +consider-using-in:53:0::"Consider merging these comparisons with ""in"" to 'A.value in (1, 2)'":HIGH diff --git a/tests/functional/l/literal_comparison.py b/tests/functional/l/literal_comparison.py index 646e57eec..4e41caaa4 100644 --- a/tests/functional/l/literal_comparison.py +++ b/tests/functional/l/literal_comparison.py @@ -10,7 +10,7 @@ if "a" is b"a": # [literal-comparison] if 2.0 is 3.0: # [literal-comparison] pass -if () is (1, 2, 3): # [literal-comparison] +if () is (1, 2, 3): pass if () is {1:2, 2:3}: # [literal-comparison] @@ -48,3 +48,10 @@ if CONST is 42: # [literal-comparison] # object might be used as a sentinel. if () is CONST: pass + +def github_issue_3031(arg=()): + if arg is (): + pass + + if arg is not (): + pass diff --git a/tests/functional/l/literal_comparison.txt b/tests/functional/l/literal_comparison.txt index 541bfe515..30d54a285 100644 --- a/tests/functional/l/literal_comparison.txt +++ b/tests/functional/l/literal_comparison.txt @@ -1,13 +1,12 @@ -literal-comparison:4:3::Comparison to literal -literal-comparison:7:3::Comparison to literal -literal-comparison:10:3::Comparison to literal -literal-comparison:13:3::Comparison to literal -literal-comparison:16:3::Comparison to literal -literal-comparison:19:3::Comparison to literal -literal-comparison:22:3::Comparison to literal -literal-comparison:25:3::Comparison to literal -literal-comparison:28:3::Comparison to literal -literal-comparison:31:3::Comparison to literal -literal-comparison:38:3::Comparison to literal -literal-comparison:41:3::Comparison to literal -literal-comparison:44:3::Comparison to literal +literal-comparison:4:3::Comparison to literal:HIGH +literal-comparison:7:3::Comparison to literal:HIGH +literal-comparison:10:3::Comparison to literal:HIGH +literal-comparison:16:3::Comparison to literal:HIGH +literal-comparison:19:3::Comparison to literal:HIGH +literal-comparison:22:3::Comparison to literal:HIGH +literal-comparison:25:3::Comparison to literal:HIGH +literal-comparison:28:3::Comparison to literal:HIGH +literal-comparison:31:3::Comparison to literal:HIGH +literal-comparison:38:3::Comparison to literal:HIGH +literal-comparison:41:3::Comparison to literal:HIGH +literal-comparison:44:3::Comparison to literal:HIGH diff --git a/tests/functional/u/use/use_implicit_booleaness_not_comparison.py b/tests/functional/u/use/use_implicit_booleaness_not_comparison.py new file mode 100644 index 000000000..18ca9c370 --- /dev/null +++ b/tests/functional/u/use/use_implicit_booleaness_not_comparison.py @@ -0,0 +1,142 @@ +# pylint: disable=missing-docstring, missing-module-docstring, invalid-name +# pylint: disable=too-few-public-methods, line-too-long, dangerous-default-value +# https://github.com/PyCQA/pylint/issues/4774 + +def github_issue_4774(): + # Test literals + # https://github.com/PyCQA/pylint/issues/4774 + good_list = [] + if not good_list: + pass + + bad_list = [] + if bad_list == []: # [use-implicit-booleaness-not-comparison] + pass + +# Testing for empty literals +empty_tuple = () +empty_list = [] +empty_dict = {} + +if empty_tuple == (): # [use-implicit-booleaness-not-comparison] + pass + +if empty_list == []: # [use-implicit-booleaness-not-comparison] + pass + +if empty_dict == {}: # [use-implicit-booleaness-not-comparison] + pass + +if () == empty_tuple: # [use-implicit-booleaness-not-comparison] + pass + +if [] == empty_list: # [use-implicit-booleaness-not-comparison] + pass + +if {} == empty_dict: # [use-implicit-booleaness-not-comparison] + pass + +def bad_tuple_return(): + t = (1, ) + return t == () # [use-implicit-booleaness-not-comparison] + +def bad_list_return(): + b = [1] + return b == [] # [use-implicit-booleaness-not-comparison] + +def bad_dict_return(): + c = {1: 1} + return c == {} # [use-implicit-booleaness-not-comparison] + +assert () == empty_tuple # [use-implicit-booleaness-not-comparison] +assert [] == empty_list # [use-implicit-booleaness-not-comparison] +assert {} != empty_dict # [use-implicit-booleaness-not-comparison] +assert () < empty_tuple # [use-implicit-booleaness-not-comparison] +assert [] <= empty_list # [use-implicit-booleaness-not-comparison] +assert () > empty_tuple # [use-implicit-booleaness-not-comparison] +assert [] >= empty_list # [use-implicit-booleaness-not-comparison] + +assert [] == [] +assert {} != {} +assert () == () + +d = {} + +if d in {}: + pass + +class NoBool: + def __init__(self): + self.a = 2 + +class YesBool: + def __init__(self): + self.a = True + + def __bool__(self): + return self.a + + +# Should be triggered +a = NoBool() +if [] == a: # [use-implicit-booleaness-not-comparison] + pass + +a = YesBool() +if a == []: + pass + +# compound test cases + +e = [] +f = {} + +if e == [] and f == {}: # [use-implicit-booleaness-not-comparison, use-implicit-booleaness-not-comparison] + pass + + +named_fields = [0, "", "42", "forty two"] +empty = any(field == "" for field in named_fields) + +something_else = NoBool() +empty_literals = [[], {}, ()] +is_empty = any(field == something_else for field in empty_literals) + +# this should work, but it doesn't since, input parameter only get the latest one, not all when inferred() +h, i, j = 1, None, [1,2,3] + +def test(k): + print(k == {}) + +def test_with_default(k={}): + print(k == {}) # [use-implicit-booleaness-not-comparison] + print(k == 1) + +test(h) +test(i) +test(j) + +test_with_default(h) +test_with_default(i) +test_with_default(j) + +# pylint: disable=import-outside-toplevel, wrong-import-position, import-error +# Numpy has its own implementation of __bool__, but base class has list, that's why the comparison check is happening +import numpy +numpy_array = numpy.array([0]) +if numpy_array == []: # [use-implicit-booleaness-not-comparison] + print('numpy_array') +if numpy_array != []: # [use-implicit-booleaness-not-comparison] + print('numpy_array') +if numpy_array >= (): # [use-implicit-booleaness-not-comparison] + print('b') + +# pandas has its own implementations of __bool__ and is not subclass of list, dict, or tuple; that's why comparison check is not happening +import pandas as pd +pandas_df = pd.DataFrame() +if pandas_df == []: + pass +if pandas_df != (): + pass +if pandas_df <= []: + print("truth value of a dataframe is ambiguous") diff --git a/tests/functional/u/use/use_implicit_booleaness_not_comparison.txt b/tests/functional/u/use/use_implicit_booleaness_not_comparison.txt new file mode 100644 index 000000000..1baca0b42 --- /dev/null +++ b/tests/functional/u/use/use_implicit_booleaness_not_comparison.txt @@ -0,0 +1,24 @@ +use-implicit-booleaness-not-comparison:13:7:github_issue_4774:'bad_list == []' can be simplified to 'bad_list' as an empty sequence is falsey:HIGH +use-implicit-booleaness-not-comparison:21:3::'empty_tuple == ()' can be simplified to 'empty_tuple' as an empty sequence is falsey:HIGH +use-implicit-booleaness-not-comparison:24:3::'empty_list == []' can be simplified to 'empty_list' as an empty sequence is falsey:HIGH +use-implicit-booleaness-not-comparison:27:3::'empty_dict == {}' can be simplified to 'empty_dict' as an empty sequence is falsey:HIGH +use-implicit-booleaness-not-comparison:30:3::'empty_tuple == ()' can be simplified to 'empty_tuple' as an empty sequence is falsey:HIGH +use-implicit-booleaness-not-comparison:33:3::'empty_list == []' can be simplified to 'empty_list' as an empty sequence is falsey:HIGH +use-implicit-booleaness-not-comparison:36:3::'empty_dict == {}' can be simplified to 'empty_dict' as an empty sequence is falsey:HIGH +use-implicit-booleaness-not-comparison:41:11:bad_tuple_return:'t == ()' can be simplified to 't' as an empty sequence is falsey:HIGH +use-implicit-booleaness-not-comparison:45:11:bad_list_return:'b == []' can be simplified to 'b' as an empty sequence is falsey:HIGH +use-implicit-booleaness-not-comparison:49:11:bad_dict_return:'c == {}' can be simplified to 'c' as an empty sequence is falsey:HIGH +use-implicit-booleaness-not-comparison:51:7::'empty_tuple == ()' can be simplified to 'empty_tuple' as an empty sequence is falsey:HIGH +use-implicit-booleaness-not-comparison:52:7::'empty_list == []' can be simplified to 'empty_list' as an empty sequence is falsey:HIGH +use-implicit-booleaness-not-comparison:53:7::'empty_dict != {}' can be simplified to 'not empty_dict' as an empty sequence is falsey:HIGH +use-implicit-booleaness-not-comparison:54:7::'empty_tuple < ()' can be simplified to 'empty_tuple' as an empty sequence is falsey:HIGH +use-implicit-booleaness-not-comparison:55:7::'empty_list <= []' can be simplified to 'empty_list' as an empty sequence is falsey:HIGH +use-implicit-booleaness-not-comparison:56:7::'empty_tuple > ()' can be simplified to 'empty_tuple' as an empty sequence is falsey:HIGH +use-implicit-booleaness-not-comparison:57:7::'empty_list >= []' can be simplified to 'empty_list' as an empty sequence is falsey:HIGH +use-implicit-booleaness-not-comparison:82:3::'a == []' can be simplified to 'a' as an empty sequence is falsey:HIGH +use-implicit-booleaness-not-comparison:94:3::'e == []' can be simplified to 'e' as an empty sequence is falsey:HIGH +use-implicit-booleaness-not-comparison:94:15::'f == {}' can be simplified to 'f' as an empty sequence is falsey:HIGH +use-implicit-booleaness-not-comparison:112:10:test_with_default:'k == {}' can be simplified to 'k' as an empty sequence is falsey:HIGH +use-implicit-booleaness-not-comparison:127:3::'numpy_array == []' can be simplified to 'numpy_array' as an empty sequence is falsey:HIGH +use-implicit-booleaness-not-comparison:129:3::'numpy_array != []' can be simplified to 'not numpy_array' as an empty sequence is falsey:HIGH +use-implicit-booleaness-not-comparison:131:3::'numpy_array >= ()' can be simplified to 'numpy_array' as an empty sequence is falsey:HIGH |