From 91c399d5a0ea7bb87ea02eb3af071359207a0817 Mon Sep 17 00:00:00 2001 From: Jacob Walls Date: Sat, 1 Feb 2025 12:51:54 -0500 Subject: [PATCH 01/13] Apply variable name regex to module-level names that are reassigned --- doc/whatsnew/fragments/3585.false_negative | 7 + pylint/checkers/base/name_checker/checker.py | 28 +++- pylint/checkers/utils.py | 12 ++ tests/functional/a/arguments.py | 12 +- tests/functional/a/arguments.txt | 2 +- .../assignment/assignment_from_no_return_2.py | 2 +- .../c/condition_evals_to_constant.py | 2 +- .../consider/consider_iterating_dictionary.py | 44 +++--- .../c/consider/consider_using_dict_items.py | 64 ++++---- .../c/consider/consider_using_enumerate.py | 2 +- .../d/dataclass/dataclass_typecheck.py | 96 ++++++------ .../d/dataclass/dataclass_typecheck.txt | 16 +- .../d/defined_and_used_on_same_line.py | 6 +- .../d/disabled_msgid_in_pylintrc.py | 2 +- .../d/duplicate/duplicate_dict_literal_key.py | 6 +- .../ext/empty_comment/empty_comment.py | 12 +- .../ext/private_import/private_import.py | 2 +- .../inconsistent_quotes_fstring.py | 4 +- .../inconsistent_quotes_fstring_py312.py | 4 +- .../inconsistent_quotes_fstring_py312_311.py | 4 +- .../invalid_exceptions_caught.py | 2 +- tests/functional/i/invalid/invalid_name.py | 8 +- tests/functional/i/invalid/invalid_name.txt | 12 +- .../invalid_name/invalid_name_module_level.py | 2 +- .../invalid/invalid_star_assignment_target.py | 4 +- tests/functional/m/missing/missing_timeout.py | 8 +- tests/functional/m/modified_iterating.py | 72 ++++----- tests/functional/m/modified_iterating.txt | 20 +-- tests/functional/n/name/name_styles.py | 2 +- tests/functional/n/nested_min_max.py | 22 +-- tests/functional/n/nested_min_max.txt | 8 +- tests/functional/n/no/no_dummy_redefined.py | 2 +- tests/functional/n/no/no_dummy_redefined.txt | 1 - .../non_ascii_import_as_bad.py | 2 +- .../non_ascii_import_from_as.py | 2 +- .../non_ascii_name_dict_kwargs.py | 4 +- .../non_ascii_name_inline_var.py | 2 +- .../non_ascii_name_try_except.py | 2 +- tests/functional/n/not_callable.py | 30 ++-- tests/functional/n/not_callable.txt | 2 +- .../p/positional_only_arguments_expected.py | 16 +- .../p/positional_only_arguments_expected.txt | 8 +- .../regression_4221_object_instanceattr.py | 4 +- .../r/regression/regression_issue_4633.py | 2 +- .../regression_property_no_member_2641.py | 6 +- .../r/regression_02/regression_2567.py | 6 +- .../r/regression_02/regression_4982.py | 2 +- .../r/regression_02/regression_5461.py | 2 +- .../r/regression_02/regression_8067.py | 4 +- .../r/regression_02/regression_8067.txt | 2 +- .../r/renamed_import_logging_not_lazy.py | 8 +- tests/functional/s/shallow_copy_environ.py | 6 +- .../s/simplifiable/simplifiable_condition.py | 6 +- .../s/simplifiable/simplifiable_condition.txt | 2 +- tests/functional/s/slots_checks.py | 4 +- .../t/too/too_many_star_expressions.py | 2 +- tests/functional/t/trailing_comma_tuple.py | 24 +-- .../functional/t/trailing_comma_tuple_9608.py | 16 +- .../unbalanced/unbalanced_tuple_unpacking.py | 8 +- .../u/undefined/undefined_loop_variable.py | 18 +-- .../u/undefined/undefined_variable.py | 2 +- .../u/undefined/undefined_variable_classes.py | 4 +- .../u/undefined/undefined_variable_py38.py | 8 +- tests/functional/u/unexpected_keyword_arg.py | 2 +- tests/functional/u/unhashable_member_py312.py | 2 +- .../u/unicode/unicode_bidi_early_return.py | 4 +- .../unnecessary/unnecessary_comprehension.py | 18 +-- .../unnecessary/unnecessary_comprehension.txt | 8 +- .../unnecessary_dict_index_lookup.py | 44 +++--- .../u/unnecessary/unnecessary_dunder_call.py | 2 +- .../u/unnecessary/unnecessary_lambda.py | 34 ++--- .../unnecessary_lambda_assignment.py | 4 +- .../unnecessary_list_index_lookup.py | 138 +++++++++--------- .../u/unnecessary/unnecessary_pass.py | 4 +- .../unpacking/unpacking_non_sequence_py310.py | 2 +- tests/functional/u/unreachable.py | 2 +- .../functional/u/unspecified_encoding_py38.py | 2 +- tests/functional/u/unsubscriptable_object.py | 4 +- .../u/unused/unused_global_variable4.py | 4 +- .../u/unused/unused_global_variable4.txt | 4 +- tests/functional/u/unused/unused_import.py | 4 +- .../u/use/use_sequence_for_iteration.py | 10 +- .../u/used/used_before_assignment.py | 2 +- ...efore_assignment_comprehension_homonyms.py | 4 +- .../used_before_assignment_conditional.py | 6 +- .../used_before_assignment_conditional.txt | 4 +- .../u/used/used_before_assignment_issue853.py | 12 +- .../functional/u/useless/useless_with_lock.py | 22 +-- tests/functional/w/wrong_import_order.txt | 8 +- tests/functional/w/wrong_import_position.py | 4 +- ...ong_import_position_exclude_dunder_main.py | 4 +- tests/functional/y/yield_from_outside_func.py | 2 +- tests/functional/y/yield_outside_func.py | 2 +- tests/messages/func_w0801.txt | 4 + 94 files changed, 549 insertions(+), 511 deletions(-) create mode 100644 doc/whatsnew/fragments/3585.false_negative diff --git a/doc/whatsnew/fragments/3585.false_negative b/doc/whatsnew/fragments/3585.false_negative new file mode 100644 index 0000000000..e40317c66f --- /dev/null +++ b/doc/whatsnew/fragments/3585.false_negative @@ -0,0 +1,7 @@ +`invalid-name` now distinguishes module-level names that are assigned only once +from those that are reassigned and now applies `--variable-rgx` to the latter. + +Also, `invalid-name` is triggered for module-level names for additional types +(e.g. lists and sets). + +Closes #3585 diff --git a/pylint/checkers/base/name_checker/checker.py b/pylint/checkers/base/name_checker/checker.py index 1d8589a576..3027cf4c16 100644 --- a/pylint/checkers/base/name_checker/checker.py +++ b/pylint/checkers/base/name_checker/checker.py @@ -461,14 +461,28 @@ def visit_assignname( # pylint: disable=too-many-branches elif isinstance(inferred_assign_type, nodes.ClassDef): self._check_name("class", node.name, node) - # Don't emit if the name redefines an import in an ImportError except handler. - elif not _redefines_import(node) and isinstance( - inferred_assign_type, nodes.Const + # Don't emit if the name redefines an import in an ImportError except handler + # nor any other reassignment. + elif ( + not (redefines_import := _redefines_import(node)) + and not isinstance( + inferred_assign_type, (nodes.FunctionDef, nodes.Lambda) + ) + and not utils.is_reassigned_before_current(node, node.name) + and not utils.is_reassigned_after_current(node, node.name) + and not utils.get_node_first_ancestor_of_type( + node, (nodes.For, nodes.While) + ) ): self._check_name("const", node.name, node) - else: + elif inferred_assign_type is not None and not isinstance( + inferred_assign_type, astroid.util.UninferableBase + ): self._check_name( - "variable", node.name, node, disallowed_check_only=True + "variable", + node.name, + node, + disallowed_check_only=redefines_import, ) # Check names defined in AnnAssign nodes @@ -608,11 +622,11 @@ def _assigns_typevar(node: nodes.NodeNG | None) -> bool: def _assigns_typealias(node: nodes.NodeNG | None) -> bool: """Check if a node is assigning a TypeAlias.""" inferred = utils.safe_infer(node) - if isinstance(inferred, nodes.ClassDef): + if isinstance(inferred, (nodes.ClassDef, astroid.bases.UnionType)): qname = inferred.qname() if qname == "typing.TypeAlias": return True - if qname == ".Union": + if qname in {".Union", "builtins.UnionType"}: # Union is a special case because it can be used as a type alias # or as a type annotation. We only want to check the former. assert node is not None diff --git a/pylint/checkers/utils.py b/pylint/checkers/utils.py index 4edd59a0a2..be4c879fe3 100644 --- a/pylint/checkers/utils.py +++ b/pylint/checkers/utils.py @@ -1865,6 +1865,18 @@ def is_sys_guard(node: nodes.If) -> bool: return False +def is_reassigned_before_current(node: nodes.NodeNG, varname: str) -> bool: + """Check if the given variable name is reassigned in the same scope before the + current node. + """ + return any( + a.name == varname and a.lineno < node.lineno + for a in node.scope().nodes_of_class( + (nodes.AssignName, nodes.ClassDef, nodes.FunctionDef) + ) + ) + + def is_reassigned_after_current(node: nodes.NodeNG, varname: str) -> bool: """Check if the given variable name is reassigned in the same scope after the current node. diff --git a/tests/functional/a/arguments.py b/tests/functional/a/arguments.py index 5807916aee..f9b44a361e 100644 --- a/tests/functional/a/arguments.py +++ b/tests/functional/a/arguments.py @@ -62,9 +62,9 @@ def function_default_arg(one=1, two=2): function_default_arg(1, one=5) # [redundant-keyword-arg] # Remaining tests are for coverage of correct names in messages. -LAMBDA = lambda arg: 1 +my_lambda = lambda arg: 1 -LAMBDA() # [no-value-for-parameter] +my_lambda() # [no-value-for-parameter] def method_tests(): """Method invocations.""" @@ -260,7 +260,7 @@ def func(one, two, three): return one + two + three -CALL = lambda *args: func(*args) +call = lambda *args: func(*args) # Ensure `too-many-function-args` is not emitted when a function call is assigned @@ -275,9 +275,9 @@ def _print_selection(self): pick_apple = _pick_fruit("apple") pick_pear = _pick_fruit("pear") -picker = FruitPicker() -picker.pick_apple() -picker.pick_pear() +PICKER = FruitPicker() +PICKER.pick_apple() +PICKER.pick_pear() def name1(apple, /, **kwargs): diff --git a/tests/functional/a/arguments.txt b/tests/functional/a/arguments.txt index 7f20d23d11..bec0ddedaa 100644 --- a/tests/functional/a/arguments.txt +++ b/tests/functional/a/arguments.txt @@ -9,7 +9,7 @@ no-value-for-parameter:59:0:59:21::No value for argument 'first_argument' in fun unexpected-keyword-arg:59:0:59:21::Unexpected keyword argument 'bob' in function call:UNDEFINED unexpected-keyword-arg:60:0:60:40::Unexpected keyword argument 'coin' in function call:UNDEFINED redundant-keyword-arg:62:0:62:30::Argument 'one' passed by position and keyword in function call:UNDEFINED -no-value-for-parameter:67:0:67:8::No value for argument 'arg' in lambda call:UNDEFINED +no-value-for-parameter:67:0:67:11::No value for argument 'arg' in lambda call:UNDEFINED no-value-for-parameter:72:4:72:24:method_tests:No value for argument 'arg' in staticmethod call:UNDEFINED no-value-for-parameter:73:4:73:29:method_tests:No value for argument 'arg' in staticmethod call:UNDEFINED no-value-for-parameter:75:4:75:23:method_tests:No value for argument 'arg' in classmethod call:UNDEFINED diff --git a/tests/functional/a/assignment/assignment_from_no_return_2.py b/tests/functional/a/assignment/assignment_from_no_return_2.py index 8f5dbe779f..aac78e1110 100644 --- a/tests/functional/a/assignment/assignment_from_no_return_2.py +++ b/tests/functional/a/assignment/assignment_from_no_return_2.py @@ -1,4 +1,4 @@ -# pylint: disable=useless-return, condition-evals-to-constant +# pylint: disable=useless-return, condition-evals-to-constant, invalid-name """check assignment to function call where the function doesn't return 'E1111': ('Assigning to function call which doesn\'t return', diff --git a/tests/functional/c/condition_evals_to_constant.py b/tests/functional/c/condition_evals_to_constant.py index 6dfcc0e928..1010fdd8f4 100644 --- a/tests/functional/c/condition_evals_to_constant.py +++ b/tests/functional/c/condition_evals_to_constant.py @@ -20,7 +20,7 @@ def func(_): while CONSTANT and False: # [condition-evals-to-constant] break 1 if CONSTANT or True else 2 # [condition-evals-to-constant] -z = [x for x in range(10) if x or True] # [condition-evals-to-constant] +Z = [x for x in range(10) if x or True] # [condition-evals-to-constant] # Simplifies recursively assert True or CONSTANT or OTHER # [condition-evals-to-constant] diff --git a/tests/functional/c/consider/consider_iterating_dictionary.py b/tests/functional/c/consider/consider_iterating_dictionary.py index 507e7c0c9f..df9b613144 100644 --- a/tests/functional/c/consider/consider_iterating_dictionary.py +++ b/tests/functional/c/consider/consider_iterating_dictionary.py @@ -26,17 +26,17 @@ def keys(self): (key for key in {}.keys()) # [consider-iterating-dictionary] {key for key in {}.keys()} # [consider-iterating-dictionary] {key: key for key in {}.keys()} # [consider-iterating-dictionary] -COMP1 = [key for key in {}.keys()] # [consider-iterating-dictionary] -COMP2 = (key for key in {}.keys()) # [consider-iterating-dictionary] -COMP3 = {key for key in {}.keys()} # [consider-iterating-dictionary] +comp1 = [key for key in {}.keys()] # [consider-iterating-dictionary] +comp2 = (key for key in {}.keys()) # [consider-iterating-dictionary] +comp3 = {key for key in {}.keys()} # [consider-iterating-dictionary] COMP4 = {key: key for key in {}.keys()} # [consider-iterating-dictionary] for key in {}.keys(): # [consider-iterating-dictionary] pass # Issue #1247 DICT = {'a': 1, 'b': 2} -COMP1 = [k * 2 for k in DICT.keys()] + [k * 3 for k in DICT.keys()] # [consider-iterating-dictionary,consider-iterating-dictionary] -COMP2, COMP3 = [k * 2 for k in DICT.keys()], [k * 3 for k in DICT.keys()] # [consider-iterating-dictionary,consider-iterating-dictionary] +comp1 = [k * 2 for k in DICT.keys()] + [k * 3 for k in DICT.keys()] # [consider-iterating-dictionary,consider-iterating-dictionary] +comp2, comp3 = [k * 2 for k in DICT.keys()], [k * 3 for k in DICT.keys()] # [consider-iterating-dictionary,consider-iterating-dictionary] SOME_TUPLE = ([k * 2 for k in DICT.keys()], [k * 3 for k in DICT.keys()]) # [consider-iterating-dictionary,consider-iterating-dictionary] # Checks for membership checks @@ -62,21 +62,21 @@ def keys(self): pass if [1] == dict(): pass -VAR = 1 in {}.keys() # [consider-iterating-dictionary] -VAR = 1 in {} -VAR = 1 in dict() -VAR = [1, 2] == {}.keys() in {False} +var = 1 in {}.keys() # [consider-iterating-dictionary] +var = 1 in {} +var = 1 in dict() +var = [1, 2] == {}.keys() in {False} # Additional membership checks # See: https://github.com/pylint-dev/pylint/issues/5323 -metadata = {} -if "a" not in list(metadata.keys()): # [consider-iterating-dictionary] +METADATA = {} +if "a" not in list(METADATA.keys()): # [consider-iterating-dictionary] print(1) -if "a" not in metadata.keys(): # [consider-iterating-dictionary] +if "a" not in METADATA.keys(): # [consider-iterating-dictionary] print(1) -if "a" in list(metadata.keys()): # [consider-iterating-dictionary] +if "a" in list(METADATA.keys()): # [consider-iterating-dictionary] print(1) -if "a" in metadata.keys(): # [consider-iterating-dictionary] +if "a" in METADATA.keys(): # [consider-iterating-dictionary] print(1) @@ -93,24 +93,24 @@ def inner_function(): return inner_function() return InnerClass().another_function() -a_dict = {"a": 1, "b": 2, "c": 3} -a_set = {"c", "d"} +A_DICT = {"a": 1, "b": 2, "c": 3} +A_SET = {"c", "d"} # Test bitwise operations. These should not raise msg because removing `.keys()` # either gives error or ends in a different result -print(a_dict.keys() | a_set) +print(A_DICT.keys() | A_SET) -if "a" in a_dict.keys() | a_set: +if "a" in A_DICT.keys() | A_SET: pass -if "a" in a_dict.keys() & a_set: +if "a" in A_DICT.keys() & A_SET: pass -if 1 in a_dict.keys() ^ [1, 2]: +if 1 in A_DICT.keys() ^ [1, 2]: pass -if "a" in a_dict.keys() or a_set: # [consider-iterating-dictionary] +if "a" in A_DICT.keys() or A_SET: # [consider-iterating-dictionary] pass -if "a" in a_dict.keys() and a_set: # [consider-iterating-dictionary] +if "a" in A_DICT.keys() and A_SET: # [consider-iterating-dictionary] pass diff --git a/tests/functional/c/consider/consider_using_dict_items.py b/tests/functional/c/consider/consider_using_dict_items.py index 16f73d1dcd..a34a10c8bf 100644 --- a/tests/functional/c/consider/consider_using_dict_items.py +++ b/tests/functional/c/consider/consider_using_dict_items.py @@ -20,39 +20,39 @@ def good(): print(k) -out_of_scope_dict = dict() +OUT_OF_SCOPE_DICT = dict() def another_bad(): - for k in out_of_scope_dict: # [consider-using-dict-items] - print(out_of_scope_dict[k]) + for k in OUT_OF_SCOPE_DICT: # [consider-using-dict-items] + print(OUT_OF_SCOPE_DICT[k]) def another_good(): - for k in out_of_scope_dict: + for k in OUT_OF_SCOPE_DICT: k = 1 k = 2 k = 3 - print(out_of_scope_dict[k]) + print(OUT_OF_SCOPE_DICT[k]) -b_dict = {} -for k2 in b_dict: # Should not emit warning, key access necessary - b_dict[k2] = 2 +B_DICT = {} +for k2 in B_DICT: # Should not emit warning, key access necessary + B_DICT[k2] = 2 -for k2 in b_dict: # Should not emit warning, key access necessary (AugAssign) - b_dict[k2] += 2 +for k2 in B_DICT: # Should not emit warning, key access necessary (AugAssign) + B_DICT[k2] += 2 # Warning should be emitted in this case -for k6 in b_dict: # [consider-using-dict-items] - val = b_dict[k6] - b_dict[k6] = 2 +for k6 in B_DICT: # [consider-using-dict-items] + val = B_DICT[k6] + B_DICT[k6] = 2 -for k3 in b_dict: # [consider-using-dict-items] - val = b_dict[k3] +for k3 in B_DICT: # [consider-using-dict-items] + val = B_DICT[k3] -for k4 in b_dict.keys(): # [consider-iterating-dictionary,consider-using-dict-items] - val = b_dict[k4] +for k4 in B_DICT.keys(): # [consider-iterating-dictionary,consider-using-dict-items] + val = B_DICT[k4] class Foo: @@ -67,25 +67,25 @@ class Foo: # Should NOT emit warning whey key used to access a different dict for k5 in Foo.c_dict: # This is fine - val = b_dict[k5] + val = B_DICT[k5] for k5 in Foo.c_dict: # This is fine val = c_dict[k5] # Should emit warning within a list/dict comprehension -val = {k9: b_dict[k9] for k9 in b_dict} # [consider-using-dict-items] -val = [(k7, b_dict[k7]) for k7 in b_dict] # [consider-using-dict-items] +val = {k9: B_DICT[k9] for k9 in B_DICT} # [consider-using-dict-items] +val = [(k7, B_DICT[k7]) for k7 in B_DICT] # [consider-using-dict-items] # Should emit warning even when using dict attribute of a class within comprehension val = [(k7, Foo.c_dict[k7]) for k7 in Foo.c_dict] # [consider-using-dict-items] val = any(True for k8 in Foo.c_dict if Foo.c_dict[k8]) # [consider-using-dict-items] # Should emit warning when dict access done in ``if`` portion of comprehension -val = any(True for k8 in b_dict if b_dict[k8]) # [consider-using-dict-items] +val = any(True for k8 in B_DICT if B_DICT[k8]) # [consider-using-dict-items] # Should NOT emit warning whey key used to access a different dict -val = [(k7, b_dict[k7]) for k7 in Foo.c_dict] -val = any(True for k8 in Foo.c_dict if b_dict[k8]) +val = [(k7, B_DICT[k7]) for k7 in Foo.c_dict] +val = any(True for k8 in Foo.c_dict if B_DICT[k8]) # Should NOT emit warning, essentially same check as above val = [(k7, c_dict[k7]) for k7 in Foo.c_dict] @@ -97,20 +97,20 @@ class Foo: # Test false positive described in #4630 # (https://github.com/pylint-dev/pylint/issues/4630) -d = {"key": "value"} +D = {"key": "value"} -for k in d: # this is fine, with the reassignment of d[k], d[k] is necessary - d[k] += "123" - if "1" in d[k]: # index lookup necessary here, do not emit error +for k in D: # this is fine, with the reassignment of d[k], d[k] is necessary + D[k] += "123" + if "1" in D[k]: # index lookup necessary here, do not emit error print("found 1") -for k in d: # if this gets rewritten to d.items(), we are back to the above problem - d[k] = d[k] + 1 - if "1" in d[k]: # index lookup necessary here, do not emit error +for k in D: # if this gets rewritten to d.items(), we are back to the above problem + D[k] = D[k] + 1 + if "1" in D[k]: # index lookup necessary here, do not emit error print("found 1") -for k in d: # [consider-using-dict-items] - if "1" in d[k]: # index lookup necessary here, do not emit error +for k in D: # [consider-using-dict-items] + if "1" in D[k]: # index lookup necessary here, do not emit error print("found 1") diff --git a/tests/functional/c/consider/consider_using_enumerate.py b/tests/functional/c/consider/consider_using_enumerate.py index b49ffd9f0b..bffcce6da2 100644 --- a/tests/functional/c/consider/consider_using_enumerate.py +++ b/tests/functional/c/consider/consider_using_enumerate.py @@ -78,7 +78,7 @@ class MyClass: def __init__(self): self.my_list = [] -my_obj = MyClass() +MY_OBJ = MyClass() def my_function(instance: MyClass): for i in range(len(instance.my_list)): # [consider-using-enumerate] var = instance.my_list[i] diff --git a/tests/functional/d/dataclass/dataclass_typecheck.py b/tests/functional/d/dataclass/dataclass_typecheck.py index e667556400..6f9c8d3a3a 100644 --- a/tests/functional/d/dataclass/dataclass_typecheck.py +++ b/tests/functional/d/dataclass/dataclass_typecheck.py @@ -30,48 +30,48 @@ class MyClass: attr5: Dict[str, str] -obj = MyClass(None, 1, 'hi', lambda x: x, [], {}) +OBJ = MyClass(None, 1, 'hi', lambda x: x, [], {}) -lst = [0, 1, 2] -print(lst[obj.attr0]) -print(lst[obj.attr1]) -print(lst[obj.attr2]) # [invalid-sequence-index] +LIST = [0, 1, 2] +print(LIST[OBJ.attr0]) +print(LIST[OBJ.attr1]) +print(LIST[OBJ.attr2]) # [invalid-sequence-index] -print(lst[obj.attr0::]) -print(lst[obj.attr1::]) -print(lst[obj.attr2::]) # [invalid-slice-index] +print(LIST[OBJ.attr0::]) +print(LIST[OBJ.attr1::]) +print(LIST[OBJ.attr2::]) # [invalid-slice-index] -obj.attr0(100) -obj.attr1(100) # [not-callable] -obj.attr3(100) +OBJ.attr0(100) +OBJ.attr1(100) # [not-callable] +OBJ.attr3(100) -print(-obj.attr0) -print(-obj.attr1) -print(-obj.attr2) # [invalid-unary-operand-type] +print(-OBJ.attr0) +print(-OBJ.attr1) +print(-OBJ.attr2) # [invalid-unary-operand-type] -print(1 + obj.attr0) -print(1 + obj.attr1) -print(1 + obj.attr2) # Should be an error here once unsupported-binary-operation is enabled +print(1 + OBJ.attr0) +print(1 + OBJ.attr1) +print(1 + OBJ.attr2) # Should be an error here once unsupported-binary-operation is enabled -print(1 in obj.attr0) -print(1 in obj.attr1) # [unsupported-membership-test] -print(1 in obj.attr4) -print('hi' in obj.attr5) +print(1 in OBJ.attr0) +print(1 in OBJ.attr1) # [unsupported-membership-test] +print(1 in OBJ.attr4) +print('hi' in OBJ.attr5) -print(obj.attr0[1]) -print(obj.attr1[1]) # [unsubscriptable-object] -print(obj.attr4[1]) -print(obj.attr5['hi']) +print(OBJ.attr0[1]) +print(OBJ.attr1[1]) # [unsubscriptable-object] +print(OBJ.attr4[1]) +print(OBJ.attr5['hi']) -obj.attr0[1] = 1 -obj.attr1[1] = 1 # [unsupported-assignment-operation] -obj.attr4[1] = 1 -obj.attr5['hi'] = 'bye' +OBJ.attr0[1] = 1 +OBJ.attr1[1] = 1 # [unsupported-assignment-operation] +OBJ.attr4[1] = 1 +OBJ.attr5['hi'] = 'bye' -del obj.attr0[1] -del obj.attr1[1] # [unsupported-delete-operation] -del obj.attr4[1] -del obj.attr5['hi'] +del OBJ.attr0[1] +del OBJ.attr1[1] # [unsupported-delete-operation] +del OBJ.attr4[1] +del OBJ.attr5['hi'] class Manager: @@ -89,33 +89,33 @@ class MyClass2: attr2: str -obj2 = MyClass2(None, Manager(), 'hi') -with obj2.attr0: +OBJ2 = MyClass2(None, Manager(), 'hi') +with OBJ2.attr0: pass -with obj2.attr1: +with OBJ2.attr1: pass -with obj2.attr2: # [not-context-manager] +with OBJ2.attr2: # [not-context-manager] pass -class Test1(metaclass=obj.attr0): +class Test1(metaclass=OBJ.attr0): pass -class Test2(metaclass=obj.attr1): # [invalid-metaclass] +class Test2(metaclass=OBJ.attr1): # [invalid-metaclass] pass -{}[obj.attr0] = 1 -{}[obj.attr1] = 1 -{}[obj.attr5] = 1 # [unhashable-member] +{}[OBJ.attr0] = 1 +{}[OBJ.attr1] = 1 +{}[OBJ.attr5] = 1 # [unhashable-member] -for k, v in obj.attr5: # TODO: Should be a dict-iter-missing-items error +for k, v in OBJ.attr5: # TODO: Should be a dict-iter-missing-items error print(k, v) -__name__ = obj.attr0 -__name__ = obj.attr1 # TODO: Should be a non-str-assignment-to-dunder-name error -__name__ = obj.attr2 +__name__ = OBJ.attr0 +__name__ = OBJ.attr1 # TODO: Should be a non-str-assignment-to-dunder-name error +__name__ = OBJ.attr2 -print(isinstance(1, obj.attr0)) -print(isinstance(1, obj.attr1)) # [isinstance-second-argument-not-valid-type] +print(isinstance(1, OBJ.attr0)) +print(isinstance(1, OBJ.attr1)) # [isinstance-second-argument-not-valid-type] diff --git a/tests/functional/d/dataclass/dataclass_typecheck.txt b/tests/functional/d/dataclass/dataclass_typecheck.txt index 1873dc1228..2b130f1338 100644 --- a/tests/functional/d/dataclass/dataclass_typecheck.txt +++ b/tests/functional/d/dataclass/dataclass_typecheck.txt @@ -1,12 +1,12 @@ -invalid-sequence-index:38:6:38:20::Sequence index is not an int, slice, or instance with __index__:UNDEFINED -invalid-slice-index:42:10:42:19::Slice index is not an int, None, or instance with __index__:UNDEFINED -not-callable:45:0:45:14::obj.attr1 is not callable:UNDEFINED +invalid-sequence-index:38:6:38:21::Sequence index is not an int, slice, or instance with __index__:UNDEFINED +invalid-slice-index:42:11:42:20::Slice index is not an int, None, or instance with __index__:UNDEFINED +not-callable:45:0:45:14::OBJ.attr1 is not callable:UNDEFINED invalid-unary-operand-type:50:6:50:16::"bad operand type for unary -: str":UNDEFINED -unsupported-membership-test:57:11:57:20::Value 'obj.attr1' doesn't support membership test:UNDEFINED -unsubscriptable-object:62:6:62:15::Value 'obj.attr1' is unsubscriptable:UNDEFINED -unsupported-assignment-operation:67:0:67:9::'obj.attr1' does not support item assignment:UNDEFINED -unsupported-delete-operation:72:4:72:13::'obj.attr1' does not support item deletion:UNDEFINED +unsupported-membership-test:57:11:57:20::Value 'OBJ.attr1' doesn't support membership test:UNDEFINED +unsubscriptable-object:62:6:62:15::Value 'OBJ.attr1' is unsubscriptable:UNDEFINED +unsupported-assignment-operation:67:0:67:9::'OBJ.attr1' does not support item assignment:UNDEFINED +unsupported-delete-operation:72:4:72:13::'OBJ.attr1' does not support item deletion:UNDEFINED not-context-manager:97:0:98:8::Context manager 'str' doesn't implement __enter__ and __exit__.:UNDEFINED invalid-metaclass:105:0:105:11:Test2:Invalid metaclass 'Instance of builtins.int' used:UNDEFINED -unhashable-member:111:0:111:2::'obj.attr5' is unhashable and can't be used as a key in a dict:INFERENCE +unhashable-member:111:0:111:2::'OBJ.attr5' is unhashable and can't be used as a key in a dict:INFERENCE isinstance-second-argument-not-valid-type:121:6:121:30::Second argument of isinstance is not a type:INFERENCE diff --git a/tests/functional/d/defined_and_used_on_same_line.py b/tests/functional/d/defined_and_used_on_same_line.py index bec45419c5..a82ca83a47 100644 --- a/tests/functional/d/defined_and_used_on_same_line.py +++ b/tests/functional/d/defined_and_used_on_same_line.py @@ -7,7 +7,7 @@ print((index for index in range(10))) -FILTER_FUNC = lambda x: not x +filter_func = lambda x: not x def func(xxx): return xxx @@ -17,9 +17,9 @@ def func2(xxx): return xxx + func2(1) for i in range(10): print(i) -j = 4; LAMB = lambda x: x+j +j = 4; lamb = lambda x: x+j -FUNC4 = lambda a, b: a != b +func4 = lambda a, b: a != b # test https://www.logilab.org/ticket/6954: diff --git a/tests/functional/d/disabled_msgid_in_pylintrc.py b/tests/functional/d/disabled_msgid_in_pylintrc.py index 7ad701de96..69a16694e4 100644 --- a/tests/functional/d/disabled_msgid_in_pylintrc.py +++ b/tests/functional/d/disabled_msgid_in_pylintrc.py @@ -1,6 +1,6 @@ """https://github.com/pylint-dev/pylint/issues/4265""" try: - f = open('test', encoding="utf-8") + F = open('test', encoding="utf-8") except Exception: pass diff --git a/tests/functional/d/duplicate/duplicate_dict_literal_key.py b/tests/functional/d/duplicate/duplicate_dict_literal_key.py index 82e98d23ec..2729ce3d9a 100644 --- a/tests/functional/d/duplicate/duplicate_dict_literal_key.py +++ b/tests/functional/d/duplicate/duplicate_dict_literal_key.py @@ -10,17 +10,17 @@ class MyEnum(Enum): -correct_dict = { +CORRECT_DICT = { 'tea': 'for two', 'two': 'for tea', } -wrong_with_enum = { # [duplicate-key] +WRONG_WITH_ENUM = { # [duplicate-key] MyEnum.KEY: "value 1", MyEnum.KEY: "value 2", } -wrong_dict = { # [duplicate-key] +WRONG_DICT = { # [duplicate-key] 'tea': 'for two', 'two': 'for tea', 'tea': 'time', diff --git a/tests/functional/ext/empty_comment/empty_comment.py b/tests/functional/ext/empty_comment/empty_comment.py index 6adaa4fc15..27da50656a 100644 --- a/tests/functional/ext/empty_comment/empty_comment.py +++ b/tests/functional/ext/empty_comment/empty_comment.py @@ -1,13 +1,13 @@ """empty-comment test-case""" # +1:[empty-comment] -A = 5 # +a = 5 # # +1:[empty-comment] # -A = '#' + '1' +a = '#' + '1' # +1:[empty-comment] -print(A) # -print("A=", A) # should not be an error# +print(a) # +print("A=", a) # should not be an error# # +1:[empty-comment] -A = "#pe\0ace#love#" # -A = "peace#love" # \0 peace'#'''' love#peace'''-'#love'-"peace#love"# +a = "#pe\0ace#love#" # +a = "peace#love" # \0 peace'#'''' love#peace'''-'#love'-"peace#love"# ####### diff --git a/tests/functional/ext/private_import/private_import.py b/tests/functional/ext/private_import/private_import.py index a73e69e758..fd5b2bbd93 100644 --- a/tests/functional/ext/private_import/private_import.py +++ b/tests/functional/ext/private_import/private_import.py @@ -139,4 +139,4 @@ def save(self): from ..parent import _private from _private_module_x import some_name # [import-private-name] -var = some_name +VAR = some_name diff --git a/tests/functional/i/inconsistent/inconsistent_quotes_fstring.py b/tests/functional/i/inconsistent/inconsistent_quotes_fstring.py index e6e285341b..fdb5126648 100644 --- a/tests/functional/i/inconsistent/inconsistent_quotes_fstring.py +++ b/tests/functional/i/inconsistent/inconsistent_quotes_fstring.py @@ -1,4 +1,4 @@ # pylint: disable=missing-module-docstring -dictionary = {'0': 0} -F_STRING = f'{dictionary["0"]}' +DICTIONARY = {'0': 0} +F_STRING = f'{DICTIONARY["0"]}' diff --git a/tests/functional/i/inconsistent/inconsistent_quotes_fstring_py312.py b/tests/functional/i/inconsistent/inconsistent_quotes_fstring_py312.py index 323bc6a07b..8c40f28224 100644 --- a/tests/functional/i/inconsistent/inconsistent_quotes_fstring_py312.py +++ b/tests/functional/i/inconsistent/inconsistent_quotes_fstring_py312.py @@ -1,5 +1,5 @@ # pylint: disable=missing-module-docstring -dictionary = {'0': 0} +DICTIONARY = {'0': 0} # quotes are inconsistent when targeting Python 3.12 (use single quotes) -F_STRING = f'{dictionary["0"]}' # [inconsistent-quotes] +F_STRING = f'{DICTIONARY["0"]}' # [inconsistent-quotes] diff --git a/tests/functional/i/inconsistent/inconsistent_quotes_fstring_py312_311.py b/tests/functional/i/inconsistent/inconsistent_quotes_fstring_py312_311.py index c7099e4710..e6cde27eaf 100644 --- a/tests/functional/i/inconsistent/inconsistent_quotes_fstring_py312_311.py +++ b/tests/functional/i/inconsistent/inconsistent_quotes_fstring_py312_311.py @@ -1,5 +1,5 @@ # pylint: disable=missing-module-docstring -dictionary = {'0': 0} +DICTIONARY = {'0': 0} # quotes are consistent when targeting 3.11 and earlier (cannot use single quotes here) -F_STRING = f'{dictionary["0"]}' +F_STRING = f'{DICTIONARY["0"]}' diff --git a/tests/functional/i/invalid/invalid_exceptions/invalid_exceptions_caught.py b/tests/functional/i/invalid/invalid_exceptions/invalid_exceptions_caught.py index 1b513f9724..628942666e 100644 --- a/tests/functional/i/invalid/invalid_exceptions/invalid_exceptions_caught.py +++ b/tests/functional/i/invalid/invalid_exceptions/invalid_exceptions_caught.py @@ -58,7 +58,7 @@ class SecondSkipException(SkipException): except None: # [catching-non-exception] print("caught") -EXCEPTION = None +EXCEPTION = None # pylint: disable=invalid-name EXCEPTION = ZeroDivisionError try: 1 + 46 diff --git a/tests/functional/i/invalid/invalid_name.py b/tests/functional/i/invalid/invalid_name.py index 28638bcb4c..dbf95c763b 100644 --- a/tests/functional/i/invalid/invalid_name.py +++ b/tests/functional/i/invalid/invalid_name.py @@ -45,9 +45,15 @@ def _generate_cmdline_tests(): yield TestCase(''.join(item), True) -# We should emit for the loop variable. +# We should emit for the loop variable using the variable pattern. for i in range(10): Foocapfor = 2 # [invalid-name] + foonocapsfor = 3 + + +# Reassignments outside loops +my_var = 0 +my_var = 1 def dummy_decorator(aaabc, bbbcd): diff --git a/tests/functional/i/invalid/invalid_name.txt b/tests/functional/i/invalid/invalid_name.txt index e8622f864a..7964c852e2 100644 --- a/tests/functional/i/invalid/invalid_name.txt +++ b/tests/functional/i/invalid/invalid_name.txt @@ -1,9 +1,9 @@ invalid-name:12:0:12:3::"Constant name ""aaa"" doesn't conform to UPPER_CASE naming style":HIGH invalid-name:16:4:16:8::"Constant name ""time"" doesn't conform to UPPER_CASE naming style":HIGH invalid-name:36:0:36:5:A:"Function name ""A"" doesn't conform to snake_case naming style":HIGH -invalid-name:50:4:50:13::"Constant name ""Foocapfor"" doesn't conform to UPPER_CASE naming style":HIGH -invalid-name:66:0:66:68:a_very_very_very_long_function_name_WithCamelCase_to_make_it_sad:"Function name ""a_very_very_very_long_function_name_WithCamelCase_to_make_it_sad"" doesn't conform to snake_case naming style":HIGH -invalid-name:74:23:74:29:FooBar.__init__:"Argument name ""fooBar"" doesn't conform to snake_case naming style":HIGH -invalid-name:80:8:80:14:FooBar.func1:"Argument name ""fooBar"" doesn't conform to snake_case naming style":HIGH -invalid-name:100:8:100:15:FooBar.test_disable_mixed:"Argument name ""fooBar2"" doesn't conform to snake_case naming style":HIGH -invalid-name:111:4:111:25:FooBarSubclass:"Class attribute name ""tearDownNotInAncestor"" doesn't conform to snake_case naming style":HIGH +invalid-name:50:4:50:13::"Variable name ""Foocapfor"" doesn't conform to snake_case naming style":HIGH +invalid-name:72:0:72:68:a_very_very_very_long_function_name_WithCamelCase_to_make_it_sad:"Function name ""a_very_very_very_long_function_name_WithCamelCase_to_make_it_sad"" doesn't conform to snake_case naming style":HIGH +invalid-name:80:23:80:29:FooBar.__init__:"Argument name ""fooBar"" doesn't conform to snake_case naming style":HIGH +invalid-name:86:8:86:14:FooBar.func1:"Argument name ""fooBar"" doesn't conform to snake_case naming style":HIGH +invalid-name:106:8:106:15:FooBar.test_disable_mixed:"Argument name ""fooBar2"" doesn't conform to snake_case naming style":HIGH +invalid-name:117:4:117:25:FooBarSubclass:"Class attribute name ""tearDownNotInAncestor"" doesn't conform to snake_case naming style":HIGH diff --git a/tests/functional/i/invalid/invalid_name/invalid_name_module_level.py b/tests/functional/i/invalid/invalid_name/invalid_name_module_level.py index ec2b2769be..e818899d46 100644 --- a/tests/functional/i/invalid/invalid_name/invalid_name_module_level.py +++ b/tests/functional/i/invalid/invalid_name/invalid_name_module_level.py @@ -23,4 +23,4 @@ def A(): # [invalid-name] CONST = "12 34 ".rstrip().split() -assignment_that_crashed_pylint = type(float.__new__.__code__) +ASSIGNMENT_THAT_CRASHED_PYLINT = type(float.__new__.__code__) diff --git a/tests/functional/i/invalid/invalid_star_assignment_target.py b/tests/functional/i/invalid/invalid_star_assignment_target.py index 452f9a7286..346192ebb9 100644 --- a/tests/functional/i/invalid/invalid_star_assignment_target.py +++ b/tests/functional/i/invalid/invalid_star_assignment_target.py @@ -1,4 +1,4 @@ """Test for *a = b """ -*FIRST = [1, 2, 3] # [invalid-star-assignment-target] -(*FIRST, ) = [1, 2, 3] +*first = [1, 2, 3] # [invalid-star-assignment-target] +(*first, ) = [1, 2, 3] diff --git a/tests/functional/m/missing/missing_timeout.py b/tests/functional/m/missing/missing_timeout.py index 13ff35f862..7125798c1c 100644 --- a/tests/functional/m/missing/missing_timeout.py +++ b/tests/functional/m/missing/missing_timeout.py @@ -50,8 +50,8 @@ put("http://localhost") # [missing-timeout] request("call", "http://localhost") # [missing-timeout] -kwargs_wo_timeout = {} -post("http://localhost", **kwargs_wo_timeout) # [missing-timeout] +KWARGS_WO_TIMEOUT = {} +post("http://localhost", **KWARGS_WO_TIMEOUT) # [missing-timeout] # requests valid cases requests.delete("http://localhost", timeout=10) @@ -81,5 +81,5 @@ put("http://localhost", timeout=10) request("call", "http://localhost", timeout=10) -kwargs_timeout = {'timeout': 10} -post("http://localhost", **kwargs_timeout) +KWARGS_TIMEOUT = {'timeout': 10} +post("http://localhost", **KWARGS_TIMEOUT) diff --git a/tests/functional/m/modified_iterating.py b/tests/functional/m/modified_iterating.py index 1fc11f9f5b..bd779dcd5e 100644 --- a/tests/functional/m/modified_iterating.py +++ b/tests/functional/m/modified_iterating.py @@ -4,35 +4,35 @@ import copy from enum import Enum -item_list = [1, 2, 3] -for item in item_list: - item_list.append(item) # [modified-iterating-list] +ITEM_LIST = [1, 2, 3] +for item in ITEM_LIST: + ITEM_LIST.append(item) # [modified-iterating-list] -for item in item_list: - item_list.remove(item) # [modified-iterating-list] +for item in ITEM_LIST: + ITEM_LIST.remove(item) # [modified-iterating-list] -for item in item_list.copy(): - item_list.append(item) - item_list.remove(item) +for item in ITEM_LIST.copy(): + ITEM_LIST.append(item) + ITEM_LIST.remove(item) -for item in copy(item_list): - item_list.append(item) - item_list.remove(item) +for item in copy(ITEM_LIST): + ITEM_LIST.append(item) + ITEM_LIST.remove(item) -for item in [k for k in item_list]: - item_list.append(item) - item_list.remove(item) +for item in [k for k in ITEM_LIST]: + ITEM_LIST.append(item) + ITEM_LIST.remove(item) -my_dict = {"1": 1, "2": 2, "3": 3} +MY_DICT = {"1": 1, "2": 2, "3": 3} i = 1 -for item in my_dict: - item_list[0] = i # for coverage, see reference at /pull/5628#discussion_r792181642 - my_dict[i] = 1 # [modified-iterating-dict] +for item in MY_DICT: + ITEM_LIST[0] = i # for coverage, see reference at /pull/5628#discussion_r792181642 + MY_DICT[i] = 1 # [modified-iterating-dict] i += 1 i = 1 -for item in my_dict.copy(): - my_dict[i] = 1 +for item in MY_DICT.copy(): + MY_DICT[i] = 1 i += 1 item_set = {1, 2, 3} @@ -58,11 +58,11 @@ for item in item_set.copy(): item_set.add(item + 10) -for l in item_list: +for l in ITEM_LIST: for s in item_set: - item_list.append(1) # [modified-iterating-list] + ITEM_LIST.append(1) # [modified-iterating-list] item_set.remove(4) # [modified-iterating-set] - item_list.remove(1) # [modified-iterating-list] + ITEM_LIST.remove(1) # [modified-iterating-list] for item in [1, 2, 3]: del item # [modified-iterating-list] @@ -70,20 +70,20 @@ for inner_first, inner_second in [[1, 2], [1, 2]]: del inner_second # [modified-iterating-list] -for k in my_dict: +for k in MY_DICT: del k # [modified-iterating-dict] for element in item_set: del element # [modified-iterating-set] # Check for nested for loops and changes to iterators -for l in item_list: - item_list.append(1) # [modified-iterating-list] +for l in ITEM_LIST: + ITEM_LIST.append(1) # [modified-iterating-list] for _ in []: for _ in []: - item_list.remove(1) # [modified-iterating-list] + ITEM_LIST.remove(1) # [modified-iterating-list] for _ in []: - item_list.append(1) # [modified-iterating-list] + ITEM_LIST.append(1) # [modified-iterating-list] def format_manifest_serializer_errors(errors): @@ -96,20 +96,20 @@ def format_manifest_serializer_errors(errors): return errors_messages -dict1 = {"1": 1} -dict2 = {"2": 2} -for item in dict1: - dict2[item] = 1 +DICT1 = {"1": 1} +DICT2 = {"2": 2} +for item in DICT1: + DICT2[item] = 1 def update_existing_key(): """No message when updating existing keys""" - for key in my_dict: - my_dict[key] = 1 + for key in MY_DICT: + MY_DICT[key] = 1 - for key in my_dict: + for key in MY_DICT: new_key = key.lower() - my_dict[new_key] = 1 # [modified-iterating-dict] + MY_DICT[new_key] = 1 # [modified-iterating-dict] class MyClass: diff --git a/tests/functional/m/modified_iterating.txt b/tests/functional/m/modified_iterating.txt index ccaec69fe7..0541528493 100644 --- a/tests/functional/m/modified_iterating.txt +++ b/tests/functional/m/modified_iterating.txt @@ -1,21 +1,21 @@ -modified-iterating-list:9:4:9:26::Iterated list 'item_list' is being modified inside for loop body, consider iterating through a copy of it instead.:INFERENCE -modified-iterating-list:12:4:12:26::Iterated list 'item_list' is being modified inside for loop body, consider iterating through a copy of it instead.:INFERENCE -modified-iterating-dict:30:4:30:18::Iterated dict 'my_dict' is being modified inside for loop body, iterate through a copy of it instead.:INFERENCE +modified-iterating-list:9:4:9:26::Iterated list 'ITEM_LIST' is being modified inside for loop body, consider iterating through a copy of it instead.:INFERENCE +modified-iterating-list:12:4:12:26::Iterated list 'ITEM_LIST' is being modified inside for loop body, consider iterating through a copy of it instead.:INFERENCE +modified-iterating-dict:30:4:30:18::Iterated dict 'MY_DICT' is being modified inside for loop body, iterate through a copy of it instead.:INFERENCE modified-iterating-set:40:4:40:27::Iterated set 'item_set' is being modified inside for loop body, iterate through a copy of it instead.:INFERENCE modified-iterating-set:44:4:44:20::Iterated set 'item_set' is being modified inside for loop body, iterate through a copy of it instead.:INFERENCE modified-iterating-set:48:4:48:23::Iterated set 'item_set' is being modified inside for loop body, iterate through a copy of it instead.:INFERENCE modified-iterating-set:52:4:52:18::Iterated set 'item_set' is being modified inside for loop body, iterate through a copy of it instead.:INFERENCE modified-iterating-set:56:4:56:21::Iterated set 'item_set' is being modified inside for loop body, iterate through a copy of it instead.:INFERENCE -modified-iterating-list:63:8:63:27::Iterated list 'item_list' is being modified inside for loop body, consider iterating through a copy of it instead.:INFERENCE +modified-iterating-list:63:8:63:27::Iterated list 'ITEM_LIST' is being modified inside for loop body, consider iterating through a copy of it instead.:INFERENCE modified-iterating-set:64:8:64:26::Iterated set 'item_set' is being modified inside for loop body, iterate through a copy of it instead.:INFERENCE -modified-iterating-list:65:4:65:23::Iterated list 'item_list' is being modified inside for loop body, consider iterating through a copy of it instead.:INFERENCE +modified-iterating-list:65:4:65:23::Iterated list 'ITEM_LIST' is being modified inside for loop body, consider iterating through a copy of it instead.:INFERENCE modified-iterating-list:68:4:68:12::Iterated list 'list' is being modified inside for loop body, consider iterating through a copy of it instead.:INFERENCE modified-iterating-list:71:4:71:20::Iterated list 'list' is being modified inside for loop body, consider iterating through a copy of it instead.:INFERENCE -modified-iterating-dict:74:4:74:9::Iterated dict 'my_dict' is being modified inside for loop body, iterate through a copy of it instead.:INFERENCE +modified-iterating-dict:74:4:74:9::Iterated dict 'MY_DICT' is being modified inside for loop body, iterate through a copy of it instead.:INFERENCE modified-iterating-set:77:4:77:15::Iterated set 'item_set' is being modified inside for loop body, iterate through a copy of it instead.:INFERENCE -modified-iterating-list:81:4:81:23::Iterated list 'item_list' is being modified inside for loop body, consider iterating through a copy of it instead.:INFERENCE -modified-iterating-list:84:12:84:31::Iterated list 'item_list' is being modified inside for loop body, consider iterating through a copy of it instead.:INFERENCE -modified-iterating-list:86:16:86:35::Iterated list 'item_list' is being modified inside for loop body, consider iterating through a copy of it instead.:INFERENCE -modified-iterating-dict:112:8:112:28:update_existing_key:Iterated dict 'my_dict' is being modified inside for loop body, iterate through a copy of it instead.:INFERENCE +modified-iterating-list:81:4:81:23::Iterated list 'ITEM_LIST' is being modified inside for loop body, consider iterating through a copy of it instead.:INFERENCE +modified-iterating-list:84:12:84:31::Iterated list 'ITEM_LIST' is being modified inside for loop body, consider iterating through a copy of it instead.:INFERENCE +modified-iterating-list:86:16:86:35::Iterated list 'ITEM_LIST' is being modified inside for loop body, consider iterating through a copy of it instead.:INFERENCE +modified-iterating-dict:112:8:112:28:update_existing_key:Iterated dict 'MY_DICT' is being modified inside for loop body, iterate through a copy of it instead.:INFERENCE modified-iterating-list:124:12:124:19:MyClass.my_method:Iterated list 'attribute' is being modified inside for loop body, consider iterating through a copy of it instead.:INFERENCE modified-iterating-dict:142:8:142:15:my_call:Iterated dict '' is being modified inside for loop body, iterate through a copy of it instead.:INFERENCE diff --git a/tests/functional/n/name/name_styles.py b/tests/functional/n/name/name_styles.py index 47ad26e797..e7b6654dd6 100644 --- a/tests/functional/n/name/name_styles.py +++ b/tests/functional/n/name/name_styles.py @@ -138,9 +138,9 @@ def _private_scope_function_with_long_descriptive_name(): return 12 LONG_CONSTANT_NAME_IN_PUBLIC_SCOPE_ARE_OKAY = True +GOOD_NAME_FOR_LISTS = [1, 2, 3] # We don't emit for non-const nodes good_name_for_funcs = lambda: None -good_name_for_lists = [1, 2, 3] class _AnExceptionalExceptionThatOccursVeryVeryRarely(Exception): """A very exceptional exception with a nice descriptive name""" diff --git a/tests/functional/n/nested_min_max.py b/tests/functional/n/nested_min_max.py index d4c31bd858..5449c6777e 100644 --- a/tests/functional/n/nested_min_max.py +++ b/tests/functional/n/nested_min_max.py @@ -11,7 +11,7 @@ min(min(1, 2), min(3, 4)) # [nested-min-max] min(len([]), min(len([1]), len([1, 2]))) # [nested-min-max] -orig_min = min +orig_min = min # pylint: disable=invalid-name min = lambda *args: args[0] min(1, min(2, 3)) orig_min(1, orig_min(2, 3)) # [nested-min-max] @@ -21,9 +21,9 @@ max(max(max(i for i in range(10)), 0), 1) # These examples can be improved by splicing -lst = [1, 2] -max(3, max(lst)) # [nested-min-max] -max(3, *lst) +LIST = [1, 2] +max(3, max(LIST)) # [nested-min-max] +max(3, *LIST) nums = (1, 2,) max(3, max(nums)) # [nested-min-max] @@ -40,8 +40,8 @@ max(3, max(nums.values())) # [nested-min-max] max(3, *nums.values()) -lst2 = [3, 7, 10] -max(3, max(nums), max(lst2)) # [nested-min-max] +LIST2 = [3, 7, 10] +max(3, max(nums), max(LIST2)) # [nested-min-max] max(3, max([5] + [6, 7])) # [nested-min-max] max(3, *[5] + [6, 7]) @@ -57,8 +57,8 @@ # Nesting is useful for finding the maximum in a matrix # No message if external call has exactly 1 argument -matrix = [[1, 2, 3], [4, 5, 6]] -max(max(matrix)) -max(max(max(matrix))) -max(3, max(max(matrix))) # [nested-min-max] -max(max(3, max(matrix))) # [nested-min-max] +MATRIX = [[1, 2, 3], [4, 5, 6]] +max(max(MATRIX)) +max(max(max(MATRIX))) +max(3, max(max(MATRIX))) # [nested-min-max] +max(max(3, max(MATRIX))) # [nested-min-max] diff --git a/tests/functional/n/nested_min_max.txt b/tests/functional/n/nested_min_max.txt index 80d6a24d32..dd8729e5b4 100644 --- a/tests/functional/n/nested_min_max.txt +++ b/tests/functional/n/nested_min_max.txt @@ -6,15 +6,15 @@ nested-min-max:8:0:8:25::Do not use nested call of 'min'; it's possible to do 'm nested-min-max:11:0:11:25::Do not use nested call of 'min'; it's possible to do 'min(1, 2, 3, 4)' instead:INFERENCE nested-min-max:12:0:12:40::Do not use nested call of 'min'; it's possible to do 'min(len([]), len([1]), len([1, 2]))' instead:INFERENCE nested-min-max:17:0:17:27::Do not use nested call of 'orig_min'; it's possible to do 'orig_min(1, 2, 3)' instead:INFERENCE -nested-min-max:25:0:25:16::Do not use nested call of 'max'; it's possible to do 'max(3, *lst)' instead:INFERENCE +nested-min-max:25:0:25:17::Do not use nested call of 'max'; it's possible to do 'max(3, *LIST)' instead:INFERENCE nested-min-max:29:0:29:17::Do not use nested call of 'max'; it's possible to do 'max(3, *nums)' instead:INFERENCE nested-min-max:33:0:33:17::Do not use nested call of 'max'; it's possible to do 'max(3, *nums)' instead:INFERENCE nested-min-max:37:0:37:17::Do not use nested call of 'max'; it's possible to do 'max(3, *nums)' instead:INFERENCE nested-min-max:40:0:40:26::Do not use nested call of 'max'; it's possible to do 'max(3, *nums.values())' instead:INFERENCE -nested-min-max:44:0:44:28::Do not use nested call of 'max'; it's possible to do 'max(3, *nums, *lst2)' instead:INFERENCE +nested-min-max:44:0:44:29::Do not use nested call of 'max'; it's possible to do 'max(3, *nums, *LIST2)' instead:INFERENCE nested-min-max:46:0:46:25::Do not use nested call of 'max'; it's possible to do 'max(3, *[5] + [6, 7])' instead:INFERENCE nested-min-max:49:0:49:45::Do not use nested call of 'max'; it's possible to do 'max(3, *[5] + [i for i in range(4) if i])' instead:INFERENCE nested-min-max:52:0:52:33::Do not use nested call of 'max'; it's possible to do 'max(3, *[5] + list(range(4)))' instead:INFERENCE nested-min-max:55:0:55:27::Do not use nested call of 'max'; it's possible to do 'max(3, *list(range(4)))' instead:INFERENCE -nested-min-max:63:0:63:24::Do not use nested call of 'max'; it's possible to do 'max(3, max(matrix))' instead:INFERENCE -nested-min-max:64:4:64:23::Do not use nested call of 'max'; it's possible to do 'max(3, *matrix)' instead:INFERENCE +nested-min-max:63:0:63:24::Do not use nested call of 'max'; it's possible to do 'max(3, max(MATRIX))' instead:INFERENCE +nested-min-max:64:4:64:23::Do not use nested call of 'max'; it's possible to do 'max(3, *MATRIX)' instead:INFERENCE diff --git a/tests/functional/n/no/no_dummy_redefined.py b/tests/functional/n/no/no_dummy_redefined.py index 5a03ed5e46..b902291b7a 100644 --- a/tests/functional/n/no/no_dummy_redefined.py +++ b/tests/functional/n/no/no_dummy_redefined.py @@ -3,7 +3,7 @@ _, INTERESTING = 'a=b'.split('=') -value = 10 # [invalid-name] +value = 10 def clobbering(): diff --git a/tests/functional/n/no/no_dummy_redefined.txt b/tests/functional/n/no/no_dummy_redefined.txt index 467116c160..c469db5b18 100644 --- a/tests/functional/n/no/no_dummy_redefined.txt +++ b/tests/functional/n/no/no_dummy_redefined.txt @@ -1,2 +1 @@ -invalid-name:6:0:6:5::"Constant name ""value"" doesn't conform to UPPER_CASE naming style":HIGH redefined-outer-name:11:4:11:9:clobbering:Redefining name 'value' from outer scope (line 6):UNDEFINED diff --git a/tests/functional/n/non_ascii_import/non_ascii_import_as_bad.py b/tests/functional/n/non_ascii_import/non_ascii_import_as_bad.py index b558c1fe13..a93d2c10a6 100644 --- a/tests/functional/n/non_ascii_import/non_ascii_import_as_bad.py +++ b/tests/functional/n/non_ascii_import/non_ascii_import_as_bad.py @@ -3,4 +3,4 @@ # Usage should not raise a second error -test = łos.join("a", "b") +TEST = łos.join("a", "b") diff --git a/tests/functional/n/non_ascii_import/non_ascii_import_from_as.py b/tests/functional/n/non_ascii_import/non_ascii_import_from_as.py index d5ed1d6f01..b3d2e718dc 100644 --- a/tests/functional/n/non_ascii_import/non_ascii_import_from_as.py +++ b/tests/functional/n/non_ascii_import/non_ascii_import_from_as.py @@ -3,4 +3,4 @@ # Usage should not raise a second error -test = łos("a", "b") +TEST = łos("a", "b") diff --git a/tests/functional/n/non_ascii_name/non_ascii_name_dict_kwargs.py b/tests/functional/n/non_ascii_name/non_ascii_name_dict_kwargs.py index 5d7b4c7f37..e0a692f47d 100644 --- a/tests/functional/n/non_ascii_name/non_ascii_name_dict_kwargs.py +++ b/tests/functional/n/non_ascii_name/non_ascii_name_dict_kwargs.py @@ -8,6 +8,6 @@ def okay(**kwargs): print(kwargs) -keyword_args = {"łol": "this would be hard to check against"} +KEYWORD_ARGS = {"łol": "this would be hard to check against"} -okay(**keyword_args) +okay(**KEYWORD_ARGS) diff --git a/tests/functional/n/non_ascii_name/non_ascii_name_inline_var.py b/tests/functional/n/non_ascii_name/non_ascii_name_inline_var.py index 3e878933d8..da0109c065 100644 --- a/tests/functional/n/non_ascii_name/non_ascii_name_inline_var.py +++ b/tests/functional/n/non_ascii_name/non_ascii_name_inline_var.py @@ -2,7 +2,7 @@ import os -test = [ +TEST = [ f"{łol} " for łol in os.listdir(".") # [non-ascii-name] ] diff --git a/tests/functional/n/non_ascii_name/non_ascii_name_try_except.py b/tests/functional/n/non_ascii_name/non_ascii_name_try_except.py index bf8f041bde..80822379a3 100644 --- a/tests/functional/n/non_ascii_name/non_ascii_name_try_except.py +++ b/tests/functional/n/non_ascii_name/non_ascii_name_try_except.py @@ -8,4 +8,4 @@ # +1: [non-ascii-name] except AttributeError as łol: # Usage should not raise a second error - test = łol + TEST = łol diff --git a/tests/functional/n/not_callable.py b/tests/functional/n/not_callable.py index a0411d39e6..f80ad2f7fc 100644 --- a/tests/functional/n/not_callable.py +++ b/tests/functional/n/not_callable.py @@ -1,14 +1,14 @@ # pylint: disable=missing-docstring,too-few-public-methods,wrong-import-position,use-dict-literal # pylint: disable=wrong-import-order, undefined-variable -REVISION = None +revision = None -REVISION() # [not-callable] +revision() # [not-callable] def correct(): return 1 -REVISION = correct() +revision = correct() class Correct: """callable object""" @@ -21,15 +21,15 @@ def __call__(self): INSTANCE = Correct() CALLABLE_INSTANCE = MetaCorrect() CORRECT = CALLABLE_INSTANCE() -INCORRECT = INSTANCE() # [not-callable] +incorrect = INSTANCE() # [not-callable] LIST = [] -INCORRECT = LIST() # [not-callable] +incorrect = LIST() # [not-callable] DICT = {} -INCORRECT = DICT() # [not-callable] +incorrect = DICT() # [not-callable] TUPLE = () -INCORRECT = TUPLE() # [not-callable] +incorrect = TUPLE() # [not-callable] INT = 1 -INCORRECT = INT() # [not-callable] +incorrect = INT() # [not-callable] # Test calling properties. Pylint can detect when using only the # getter, but it doesn't infer properly when having a getter @@ -141,7 +141,7 @@ def value(self): import typing Named = typing.NamedTuple("Named", [("foo", int), ("bar", int)]) -named = Named(1, 2) +NAMED = Named(1, 2) # NamedTuple is callable, even if it aliased to an attribute @@ -211,8 +211,8 @@ def myproperty(self): self._x = lambda: None return self._x -myobject = Klass() -myobject.myproperty() +MY_OBJECT = Klass() +MY_OBJECT.myproperty() class Klass2: @property @@ -222,16 +222,16 @@ def something(self): return 'abcd' -obj2 = Klass2() -obj2.something() +OBJ_2 = Klass2() +OBJ_2.something() # Regression test for https://github.com/pylint-dev/pylint/issues/7109 instance_or_cls = MyClass # pylint:disable=invalid-name instance_or_cls = MyClass() if not isinstance(instance_or_cls, MyClass): - new = MyClass.__new__(instance_or_cls) - new() + NEW = MyClass.__new__(instance_or_cls) + NEW() # Regression test for https://github.com/pylint-dev/pylint/issues/5113. diff --git a/tests/functional/n/not_callable.txt b/tests/functional/n/not_callable.txt index e8a06b0030..1eff11f1ba 100644 --- a/tests/functional/n/not_callable.txt +++ b/tests/functional/n/not_callable.txt @@ -1,4 +1,4 @@ -not-callable:6:0:6:10::REVISION is not callable:UNDEFINED +not-callable:6:0:6:10::revision is not callable:UNDEFINED not-callable:24:12:24:22::INSTANCE is not callable:UNDEFINED not-callable:26:12:26:18::LIST is not callable:UNDEFINED not-callable:28:12:28:18::DICT is not callable:UNDEFINED diff --git a/tests/functional/p/positional_only_arguments_expected.py b/tests/functional/p/positional_only_arguments_expected.py index dde40f174b..621489b85d 100644 --- a/tests/functional/p/positional_only_arguments_expected.py +++ b/tests/functional/p/positional_only_arguments_expected.py @@ -6,16 +6,16 @@ def nihon(self, a, r, i, /, cheese=False): return f"{a}{r}{i}gateaux" + " au fromage" if cheese else "" -cake = Gateaux() +CAKE = Gateaux() # Should not emit error -cake.nihon(1, 2, 3) -cake.nihon(1, 2, 3, True) -cake.nihon(1, 2, 3, cheese=True) +CAKE.nihon(1, 2, 3) +CAKE.nihon(1, 2, 3, True) +CAKE.nihon(1, 2, 3, cheese=True) # Emits error -cake.nihon(1, 2, i=3) # [positional-only-arguments-expected] -cake.nihon(1, r=2, i=3) # [positional-only-arguments-expected] -cake.nihon(a=1, r=2, i=3) # [positional-only-arguments-expected] -cake.nihon(1, r=2, i=3, cheese=True) # [positional-only-arguments-expected] +CAKE.nihon(1, 2, i=3) # [positional-only-arguments-expected] +CAKE.nihon(1, r=2, i=3) # [positional-only-arguments-expected] +CAKE.nihon(a=1, r=2, i=3) # [positional-only-arguments-expected] +CAKE.nihon(1, r=2, i=3, cheese=True) # [positional-only-arguments-expected] def function_with_kwargs(apple, banana="Yellow banana", /, **kwargs): diff --git a/tests/functional/p/positional_only_arguments_expected.txt b/tests/functional/p/positional_only_arguments_expected.txt index 91e24f87b5..a73455e56c 100644 --- a/tests/functional/p/positional_only_arguments_expected.txt +++ b/tests/functional/p/positional_only_arguments_expected.txt @@ -1,4 +1,4 @@ -positional-only-arguments-expected:15:0:15:21::"`cake.nihon()` got some positional-only arguments passed as keyword arguments: 'i'":INFERENCE -positional-only-arguments-expected:16:0:16:23::"`cake.nihon()` got some positional-only arguments passed as keyword arguments: 'r', 'i'":INFERENCE -positional-only-arguments-expected:17:0:17:25::"`cake.nihon()` got some positional-only arguments passed as keyword arguments: 'a', 'r', 'i'":INFERENCE -positional-only-arguments-expected:18:0:18:36::"`cake.nihon()` got some positional-only arguments passed as keyword arguments: 'r', 'i'":INFERENCE +positional-only-arguments-expected:15:0:15:21::"`CAKE.nihon()` got some positional-only arguments passed as keyword arguments: 'i'":INFERENCE +positional-only-arguments-expected:16:0:16:23::"`CAKE.nihon()` got some positional-only arguments passed as keyword arguments: 'r', 'i'":INFERENCE +positional-only-arguments-expected:17:0:17:25::"`CAKE.nihon()` got some positional-only arguments passed as keyword arguments: 'a', 'r', 'i'":INFERENCE +positional-only-arguments-expected:18:0:18:36::"`CAKE.nihon()` got some positional-only arguments passed as keyword arguments: 'r', 'i'":INFERENCE diff --git a/tests/functional/r/regression/regression_4221_object_instanceattr.py b/tests/functional/r/regression/regression_4221_object_instanceattr.py index 6599bf249d..0053b8dfe0 100644 --- a/tests/functional/r/regression/regression_4221_object_instanceattr.py +++ b/tests/functional/r/regression/regression_4221_object_instanceattr.py @@ -2,7 +2,7 @@ # https://github.com/pylint-dev/pylint/issues/4221 import random -o = object() +O = object() if random.choice([True, False]): - o.count = None + O.count = None "abc".count("a") diff --git a/tests/functional/r/regression/regression_issue_4633.py b/tests/functional/r/regression/regression_issue_4633.py index b2a8f7c907..5d2d08eaff 100644 --- a/tests/functional/r/regression/regression_issue_4633.py +++ b/tests/functional/r/regression/regression_issue_4633.py @@ -7,7 +7,7 @@ from queue import Queue from unittest.mock import MagicMock -mock = MagicMock(name="mock") +mock = MagicMock(name="mock") # pylint: disable=invalid-name class Ham(mock.spam): diff --git a/tests/functional/r/regression/regression_property_no_member_2641.py b/tests/functional/r/regression/regression_property_no_member_2641.py index dd87726e6b..c26bae787a 100644 --- a/tests/functional/r/regression/regression_property_no_member_2641.py +++ b/tests/functional/r/regression/regression_property_no_member_2641.py @@ -34,7 +34,7 @@ def __init__(self, name, age, tel): self.tel = tel -ms = Myself("Matheus Saraiva", 36, "988070350") -wi = Wife("Joice Saraiva", 34, "999923554") +MS = Myself("Matheus Saraiva", 36, "988070350") +WI = Wife("Joice Saraiva", 34, "999923554") -print(wi.name) +print(WI.name) diff --git a/tests/functional/r/regression_02/regression_2567.py b/tests/functional/r/regression_02/regression_2567.py index 7de293bfb7..42b4fcd126 100644 --- a/tests/functional/r/regression_02/regression_2567.py +++ b/tests/functional/r/regression_02/regression_2567.py @@ -16,9 +16,9 @@ def context_manager(): pass -cm = context_manager() -cm.__enter__() -cm.__exit__(None, None, None) +CM = context_manager() +CM.__enter__() +CM.__exit__(None, None, None) @contextlib.contextmanager diff --git a/tests/functional/r/regression_02/regression_4982.py b/tests/functional/r/regression_02/regression_4982.py index 27e8d08a1c..40274dff64 100644 --- a/tests/functional/r/regression_02/regression_4982.py +++ b/tests/functional/r/regression_02/regression_4982.py @@ -11,7 +11,7 @@ def get_first_subclass(cls): return object -subclass = Base.get_first_subclass() +subclass = Base.get_first_subclass() # pylint: disable=invalid-name class Another(subclass): diff --git a/tests/functional/r/regression_02/regression_5461.py b/tests/functional/r/regression_02/regression_5461.py index 9344782c02..6f9ebc25d7 100644 --- a/tests/functional/r/regression_02/regression_5461.py +++ b/tests/functional/r/regression_02/regression_5461.py @@ -3,4 +3,4 @@ See: https://github.com/pylint-dev/pylint/issues/5461 """ -var = [type for type in [] if type["id"]] +VAR = [type for type in [] if type["id"]] diff --git a/tests/functional/r/regression_02/regression_8067.py b/tests/functional/r/regression_02/regression_8067.py index f640aed9d1..a2ed2bf0df 100644 --- a/tests/functional/r/regression_02/regression_8067.py +++ b/tests/functional/r/regression_02/regression_8067.py @@ -2,8 +2,8 @@ # pylint: disable=missing-docstring,too-few-public-methods,disallowed-name -x = slice(42) -x() # [not-callable] +X = slice(42) +X() # [not-callable] class Foo: diff --git a/tests/functional/r/regression_02/regression_8067.txt b/tests/functional/r/regression_02/regression_8067.txt index 5dba68c456..d66e72fd16 100644 --- a/tests/functional/r/regression_02/regression_8067.txt +++ b/tests/functional/r/regression_02/regression_8067.txt @@ -1 +1 @@ -not-callable:6:0:6:3::x is not callable:UNDEFINED +not-callable:6:0:6:3::X is not callable:UNDEFINED diff --git a/tests/functional/r/renamed_import_logging_not_lazy.py b/tests/functional/r/renamed_import_logging_not_lazy.py index 5eb23bf95a..ed9f935c83 100644 --- a/tests/functional/r/renamed_import_logging_not_lazy.py +++ b/tests/functional/r/renamed_import_logging_not_lazy.py @@ -9,12 +9,12 @@ class Logger: """Fake logger""" -logger = renamed_logging.getLogger(__name__) -fake_logger = Logger() +LOGGER = renamed_logging.getLogger(__name__) +FAKE_LOGGER = Logger() # Statements that should be flagged renamed_logging.warning('%s, %s' % (4, 5)) # [logging-not-lazy] -logger.warning('%s' % 5) # [logging-not-lazy] +LOGGER.warning('%s' % 5) # [logging-not-lazy] # Statements that should not be flagged: -fake_logger.warn('%s' % 5) +FAKE_LOGGER.warn('%s' % 5) diff --git a/tests/functional/s/shallow_copy_environ.py b/tests/functional/s/shallow_copy_environ.py index 90710fae70..02a76e93a1 100644 --- a/tests/functional/s/shallow_copy_environ.py +++ b/tests/functional/s/shallow_copy_environ.py @@ -7,8 +7,8 @@ copy.copy(os.environ) # [shallow-copy-environ] # Copying a dictionary is okay -test_dict = {} -copy.copy(test_dict) +TEST_DICT = {} +copy.copy(TEST_DICT) # Test with renaming the functions from copy import copy as test_cp @@ -30,7 +30,7 @@ # Edge cases copy.copy() # [no-value-for-parameter] -copy.copy(x=test_dict) +copy.copy(x=TEST_DICT) copy.copy(x=os.environ) # [shallow-copy-environ] copy.copy(**{"x": os.environ}) # [shallow-copy-environ] copy.copy(**{"y": os.environ}) # [unexpected-keyword-arg] diff --git a/tests/functional/s/simplifiable/simplifiable_condition.py b/tests/functional/s/simplifiable/simplifiable_condition.py index d246afd2cc..0f3d146c3a 100644 --- a/tests/functional/s/simplifiable/simplifiable_condition.py +++ b/tests/functional/s/simplifiable/simplifiable_condition.py @@ -19,7 +19,7 @@ def func(_): while CONSTANT and True: # [simplifiable-condition] break 1 if CONSTANT or False else 2 # [simplifiable-condition] -z = [x for x in range(10) if x or False] # [simplifiable-condition] +Z = [x for x in range(10) if x or False] # [simplifiable-condition] # Simplifies recursively assert CONSTANT or (True and False) # [simplifiable-condition] @@ -36,6 +36,6 @@ def func(_): bool(func(CONSTANT or True)) # https://www.reddit.com/r/learnpython/comments/y5vtrw/confused_on_pylint_message_simplifiablecondition/ -board = {} -if "wking" and "bking" in board.values(): # [simplifiable-condition] +BOARD = {} +if "wking" and "bking" in BOARD.values(): # [simplifiable-condition] pass diff --git a/tests/functional/s/simplifiable/simplifiable_condition.txt b/tests/functional/s/simplifiable/simplifiable_condition.txt index 01f17a7530..3d43f06390 100644 --- a/tests/functional/s/simplifiable/simplifiable_condition.txt +++ b/tests/functional/s/simplifiable/simplifiable_condition.txt @@ -10,4 +10,4 @@ simplifiable-condition:26:7:26:34::"Boolean condition ""True and CONSTANT and OT simplifiable-condition:27:7:27:46::"Boolean condition ""(CONSTANT or False) and (OTHER or True)"" may be simplified to ""CONSTANT""":UNDEFINED simplifiable-condition:30:7:30:21::"Boolean condition ""[] or CONSTANT"" may be simplified to ""CONSTANT""":UNDEFINED simplifiable-condition:31:7:31:21::"Boolean condition ""{} or CONSTANT"" may be simplified to ""CONSTANT""":UNDEFINED -simplifiable-condition:40:3:40:40::"Boolean condition ""'wking' and 'bking' in board.values()"" may be simplified to ""'bking' in board.values()""":UNDEFINED +simplifiable-condition:40:3:40:40::"Boolean condition ""'wking' and 'bking' in BOARD.values()"" may be simplified to ""'bking' in BOARD.values()""":UNDEFINED diff --git a/tests/functional/s/slots_checks.py b/tests/functional/s/slots_checks.py index e0c76dbe45..a83989fca6 100644 --- a/tests/functional/s/slots_checks.py +++ b/tests/functional/s/slots_checks.py @@ -198,6 +198,6 @@ class TestChild(SlotsManipulationTest): __slots__ += ["d", "e", "f"] # pylint: disable=undefined-variable -t = TestChild() +T = TestChild() -print(t.__slots__) +print(T.__slots__) diff --git a/tests/functional/t/too/too_many_star_expressions.py b/tests/functional/t/too/too_many_star_expressions.py index c1bbfb9d32..94de4a1d40 100644 --- a/tests/functional/t/too/too_many_star_expressions.py +++ b/tests/functional/t/too/too_many_star_expressions.py @@ -1,5 +1,5 @@ """Test for too-many-star-expressions.""" -# pylint: disable=unbalanced-tuple-unpacking +# pylint: disable=unbalanced-tuple-unpacking, invalid-name *FIRST, *SECOND = [1, 2, 3] # [too-many-star-expressions] (FIRST, *SECOND), *THIRD = ((1, 2, 3), 4, 5) *FIRST_1, SECOND = (1, 2, 3) diff --git a/tests/functional/t/trailing_comma_tuple.py b/tests/functional/t/trailing_comma_tuple.py index 8effe475ec..c7b4722044 100644 --- a/tests/functional/t/trailing_comma_tuple.py +++ b/tests/functional/t/trailing_comma_tuple.py @@ -1,12 +1,12 @@ """Check trailing comma one element tuples.""" # pylint: disable=missing-docstring -AAA = 1, # [trailing-comma-tuple] -BBB = "aaaa", # [trailing-comma-tuple] -CCC="aaa", # [trailing-comma-tuple] -FFF=['f'], # [trailing-comma-tuple] +aaa = 1, # [trailing-comma-tuple] +bbb = "aaaa", # [trailing-comma-tuple] +ccc="aaa", # [trailing-comma-tuple] +fff=['f'], # [trailing-comma-tuple] -BBB = 1, 2 -CCC = (1, 2, 3) +bbb = 1, 2 +ccc = (1, 2, 3) DDD = ( 1, 2, 3, ) @@ -43,18 +43,18 @@ def some_other_func(): HHH = ["aaa" ] -III = some_func(0, +iii = some_func(0, 0), # [trailing-comma-tuple] JJJ = some_func(0, 0) # pylint: disable-next=trailing-comma-tuple -AAA = 1, -BBB = "aaaa", # [trailing-comma-tuple] +aaa = 1, +bbb = "aaaa", # [trailing-comma-tuple] # pylint: disable=trailing-comma-tuple -CCC="aaa", -III = some_func(0, +ccc="aaa", +iii = some_func(0, 0), # pylint: enable=trailing-comma-tuple -FFF=['f'], # [trailing-comma-tuple] +fff=['f'], # [trailing-comma-tuple] diff --git a/tests/functional/t/trailing_comma_tuple_9608.py b/tests/functional/t/trailing_comma_tuple_9608.py index 6ca408c2b9..e41526e112 100644 --- a/tests/functional/t/trailing_comma_tuple_9608.py +++ b/tests/functional/t/trailing_comma_tuple_9608.py @@ -1,10 +1,10 @@ """Check trailing comma tuple optimization.""" # pylint: disable=missing-docstring -AAA = 1, -BBB = "aaaa", -CCC="aaa", -FFF=['f'], +aaa = 1, +bbb = "aaaa", +ccc="aaa", +fff=['f'], def some_func(first, second): if first: @@ -14,11 +14,11 @@ def some_func(first, second): return first, second, #pylint:enable = trailing-comma-tuple -AAA = 1, # [trailing-comma-tuple] -BBB = "aaaa", # [trailing-comma-tuple] +aaa = 1, # [trailing-comma-tuple] +bbb = "aaaa", # [trailing-comma-tuple] # pylint: disable=trailing-comma-tuple -CCC="aaa", +ccc="aaa", III = some_func(0, 0), # pylint: enable=trailing-comma-tuple -FFF=['f'], # [trailing-comma-tuple] +fff=['f'], # [trailing-comma-tuple] diff --git a/tests/functional/u/unbalanced/unbalanced_tuple_unpacking.py b/tests/functional/u/unbalanced/unbalanced_tuple_unpacking.py index caca148cdf..d6c315e9e9 100644 --- a/tests/functional/u/unbalanced/unbalanced_tuple_unpacking.py +++ b/tests/functional/u/unbalanced/unbalanced_tuple_unpacking.py @@ -156,9 +156,9 @@ def my_function(mystring): return mylist -a, b = my_function("12") # [unbalanced-tuple-unpacking] -c = my_function("12") -d, *_ = my_function("12") +A, B = my_function("12") # [unbalanced-tuple-unpacking] +C = my_function("12") +D, *_ = my_function("12") # https://github.com/pylint-dev/pylint/issues/5998 x, y, z = (1, 2) # [unbalanced-tuple-unpacking] @@ -166,4 +166,4 @@ def my_function(mystring): # https://github.com/pylint-dev/pylint/issues/7710 # Using a lot of args, so we have a high probability to still trigger the problem if # we add arguments to our unittest command later -(p, q, r, s, t, u, v, w, x, y, z) = sys.argv +(p, q, r, s, t, u, v, w, x, y, z) = sys.argv # pylint: disable=invalid-name diff --git a/tests/functional/u/undefined/undefined_loop_variable.py b/tests/functional/u/undefined/undefined_loop_variable.py index 10d6dc60b5..813934c68d 100644 --- a/tests/functional/u/undefined/undefined_loop_variable.py +++ b/tests/functional/u/undefined/undefined_loop_variable.py @@ -31,13 +31,13 @@ def do_else(some_random_list): note.something() for line in __revision__: for note in line: - A = note.anotherthing() + a = note.anotherthing() for x in []: pass for x in range(3): - VAR5 = (lambda: x)() + var5 = (lambda: x)() def do_stuff_with_a_list(): @@ -140,17 +140,17 @@ def fail() -> NoReturn: print(thing) -lst = [] -lst2 = [1, 2, 3] +LIST = [] +LIST2 = [1, 2, 3] -for item in lst: +for item in LIST: pass -bigger = [ +BIGGER = [ [ - x for x in lst2 if x > item + x for x in LIST2 if x > item ] - for item in lst + for item in LIST ] @@ -166,7 +166,7 @@ def lambda_in_first_of_two_loops(): def variable_name_assigned_in_body_of_second_loop(): - for alias in tuple(bigger): + for alias in tuple(BIGGER): continue for _ in range(3): alias = True diff --git a/tests/functional/u/undefined/undefined_variable.py b/tests/functional/u/undefined/undefined_variable.py index 19c134e77b..e1349c2610 100644 --- a/tests/functional/u/undefined/undefined_variable.py +++ b/tests/functional/u/undefined/undefined_variable.py @@ -1,5 +1,5 @@ # pylint: disable=missing-docstring, multiple-statements, import-outside-toplevel -# pylint: disable=too-few-public-methods, bare-except, broad-except +# pylint: disable=too-few-public-methods, bare-except, broad-except, invalid-name # pylint: disable=using-constant-test, import-error, global-variable-not-assigned, unnecessary-comprehension # pylint: disable=unnecessary-lambda-assignment, use-yield-from diff --git a/tests/functional/u/undefined/undefined_variable_classes.py b/tests/functional/u/undefined/undefined_variable_classes.py index 64d0007a5f..c1f3bce704 100644 --- a/tests/functional/u/undefined/undefined_variable_classes.py +++ b/tests/functional/u/undefined/undefined_variable_classes.py @@ -6,10 +6,10 @@ import collections -l = ["a", "b", "c"] +L = ["a", "b", "c"] -class Foo(collections.namedtuple("Foo", [x + "_foo" for x in l])): +class Foo(collections.namedtuple("Foo", [x + "_foo" for x in L])): pass diff --git a/tests/functional/u/undefined/undefined_variable_py38.py b/tests/functional/u/undefined/undefined_variable_py38.py index 1f69a18a8e..87dc187ced 100644 --- a/tests/functional/u/undefined/undefined_variable_py38.py +++ b/tests/functional/u/undefined/undefined_variable_py38.py @@ -108,9 +108,9 @@ def no_parameters_in_function_default() -> None: # Tests for assignment expressions in lambda statements -things = [] -sorted_things = sorted( - things, +THINGS = [] +SORTED_THINGS = sorted( + THINGS, key=lambda thing: x_0 if (x_0 := thing.this_value) < (x_1 := thing.that_value) else x_1, @@ -161,7 +161,7 @@ def __init__(self, value): self.value = value -dummy = Dummy(value=val if (val := 'something') else 'anything') +DUMMY = Dummy(value=val if (val := 'something') else 'anything') def expression_in_ternary_operator_inside_container(): """Named expression in ternary operator: inside container""" diff --git a/tests/functional/u/unexpected_keyword_arg.py b/tests/functional/u/unexpected_keyword_arg.py index cd736005ff..d5f59788fb 100644 --- a/tests/functional/u/unexpected_keyword_arg.py +++ b/tests/functional/u/unexpected_keyword_arg.py @@ -1,5 +1,5 @@ """Tests for unexpected-keyword-arg""" -# pylint: disable=undefined-variable, too-few-public-methods, missing-function-docstring, missing-class-docstring +# pylint: disable=undefined-variable, too-few-public-methods, missing-function-docstring, missing-class-docstring, invalid-name def non_param_decorator(func): diff --git a/tests/functional/u/unhashable_member_py312.py b/tests/functional/u/unhashable_member_py312.py index 6badc35927..64a4b60786 100644 --- a/tests/functional/u/unhashable_member_py312.py +++ b/tests/functional/u/unhashable_member_py312.py @@ -1,2 +1,2 @@ """slices can be used as dict keys from python 3.12""" -var = {}[1:2] +VAR = {}[1:2] diff --git a/tests/functional/u/unicode/unicode_bidi_early_return.py b/tests/functional/u/unicode/unicode_bidi_early_return.py index 1de7a50406..2b11edcb7c 100644 --- a/tests/functional/u/unicode/unicode_bidi_early_return.py +++ b/tests/functional/u/unicode/unicode_bidi_early_return.py @@ -4,7 +4,7 @@ """ # pylint: disable=unreachable -bank = {"alice": 100} +BANK = {"alice": 100} # +4: [bidirectional-unicode] @@ -12,7 +12,7 @@ def subtract_funds(account: str, amount: int): """Subtract funds from bank account then ⁧""" return - bank[account] -= amount + BANK[account] -= amount return diff --git a/tests/functional/u/unnecessary/unnecessary_comprehension.py b/tests/functional/u/unnecessary/unnecessary_comprehension.py index ac26243071..59f79b03c9 100644 --- a/tests/functional/u/unnecessary/unnecessary_comprehension.py +++ b/tests/functional/u/unnecessary/unnecessary_comprehension.py @@ -15,8 +15,8 @@ [2 * x for x in iterable] # exclude useful comprehensions [(x, y, 1) for x, y in iterable] # exclude useful comprehensions # Test case for issue #4499 -a_dict = {} -item = [(k, v) for k, v in a_dict.items()] # [unnecessary-comprehension] +A_DICT = {} +item = [(k, v) for k, v in A_DICT.items()] # [unnecessary-comprehension] # Set comprehensions {x for x in iterable} # [unnecessary-comprehension] @@ -41,11 +41,11 @@ {2 * x: 3 + x for x in iterable} # exclude useful comprehensions # Some additional tests on helptext -- when object is already a list/set/dict -my_list = [] -my_dict = {} -my_set = set() +MY_LIST = [] +MY_DICT = {} +MY_SET = set() -[elem for elem in my_list] # [unnecessary-comprehension] -items = {k: v for k, v in my_dict.items()} # [unnecessary-comprehension] -{k: my_dict[k] for k in my_dict} # [consider-using-dict-items] -{elem for elem in my_set} # [unnecessary-comprehension] +[elem for elem in MY_LIST] # [unnecessary-comprehension] +ITEMS = {k: v for k, v in MY_DICT.items()} # [unnecessary-comprehension] +{k: MY_DICT[k] for k in MY_DICT} # [consider-using-dict-items] +{elem for elem in MY_SET} # [unnecessary-comprehension] diff --git a/tests/functional/u/unnecessary/unnecessary_comprehension.txt b/tests/functional/u/unnecessary/unnecessary_comprehension.txt index f9b28543de..854759e4b4 100644 --- a/tests/functional/u/unnecessary/unnecessary_comprehension.txt +++ b/tests/functional/u/unnecessary/unnecessary_comprehension.txt @@ -3,13 +3,13 @@ unnecessary-comprehension:7:0:7:21::Unnecessary use of a comprehension, use list unnecessary-comprehension:9:0:9:29::Unnecessary use of a comprehension, use list(iterable) instead.:UNDEFINED unnecessary-comprehension:10:0:10:31::Unnecessary use of a comprehension, use list(iterable) instead.:UNDEFINED unnecessary-comprehension:11:0:11:33::Unnecessary use of a comprehension, use list(iterable) instead.:UNDEFINED -unnecessary-comprehension:19:7:19:42::Unnecessary use of a comprehension, use list(a_dict.items()) instead.:UNDEFINED +unnecessary-comprehension:19:7:19:42::Unnecessary use of a comprehension, use list(A_DICT.items()) instead.:UNDEFINED unnecessary-comprehension:22:0:22:21::Unnecessary use of a comprehension, use set(iterable) instead.:UNDEFINED unnecessary-comprehension:25:0:25:31::Unnecessary use of a comprehension, use set(iterable) instead.:UNDEFINED unnecessary-comprehension:26:7:26:42::Unnecessary use of a comprehension, use set(iterable) instead.:UNDEFINED unnecessary-comprehension:34:0:34:27::Unnecessary use of a comprehension, use dict(iterable) instead.:UNDEFINED unnecessary-comprehension:36:0:36:29::Unnecessary use of a comprehension, use dict(iterable) instead.:UNDEFINED -unnecessary-comprehension:48:0:48:26::Unnecessary use of a comprehension, use list(my_list) instead.:UNDEFINED -unnecessary-comprehension:49:8:49:42::Unnecessary use of a comprehension, use dict(my_dict) instead.:UNDEFINED +unnecessary-comprehension:48:0:48:26::Unnecessary use of a comprehension, use list(MY_LIST) instead.:UNDEFINED +unnecessary-comprehension:49:8:49:42::Unnecessary use of a comprehension, use dict(MY_DICT) instead.:UNDEFINED consider-using-dict-items:50:0:None:None::Consider iterating with .items():UNDEFINED -unnecessary-comprehension:51:0:51:25::Unnecessary use of a comprehension, use set(my_set) instead.:UNDEFINED +unnecessary-comprehension:51:0:51:25::Unnecessary use of a comprehension, use set(MY_SET) instead.:UNDEFINED diff --git a/tests/functional/u/unnecessary/unnecessary_dict_index_lookup.py b/tests/functional/u/unnecessary/unnecessary_dict_index_lookup.py index e02df87e38..098066f814 100644 --- a/tests/functional/u/unnecessary/unnecessary_dict_index_lookup.py +++ b/tests/functional/u/unnecessary/unnecessary_dict_index_lookup.py @@ -1,33 +1,33 @@ # pylint: disable=missing-docstring, too-few-public-methods, expression-not-assigned, line-too-long -a_dict = {} -b_dict = {} +A_DICT = {} +B_DICT = {} -for k, v in a_dict.items(): - print(a_dict[k]) # [unnecessary-dict-index-lookup] - print(b_dict[k]) # Should not emit warning, accessing other dictionary - a_dict[k] = 123 # Should not emit warning, key access necessary - a_dict[k] += 123 # Should not emit warning, key access necessary - print(a_dict[k]) # Should not emit warning, v != a_dict[k] +for k, v in A_DICT.items(): + print(A_DICT[k]) # [unnecessary-dict-index-lookup] + print(B_DICT[k]) # Should not emit warning, accessing other dictionary + A_DICT[k] = 123 # Should not emit warning, key access necessary + A_DICT[k] += 123 # Should not emit warning, key access necessary + print(A_DICT[k]) # Should not emit warning, v != a_dict[k] -for k, v in b_dict.items(): +for k, v in B_DICT.items(): print(k) k = "another key" - print(b_dict[k]) # This is fine, key reassigned + print(B_DICT[k]) # This is fine, key reassigned # Tests on comprehensions -A = {v: 1 for k, v in a_dict.items() if a_dict[k]} # [unnecessary-dict-index-lookup] -B = {v: 1 for k, v in a_dict.items() if k} # This is fine, no indexing -C = {a_dict[k]: 1 for k, v in a_dict.items() if k} # [unnecessary-dict-index-lookup] +A = {v: 1 for k, v in A_DICT.items() if A_DICT[k]} # [unnecessary-dict-index-lookup] +B = {v: 1 for k, v in A_DICT.items() if k} # This is fine, no indexing +C = {A_DICT[k]: 1 for k, v in A_DICT.items() if k} # [unnecessary-dict-index-lookup] # +1: [unnecessary-dict-index-lookup, unnecessary-dict-index-lookup] -D = {a_dict[k]: 1 for k, v in a_dict.items() if a_dict[k]} +D = {A_DICT[k]: 1 for k, v in A_DICT.items() if A_DICT[k]} -E = [v for k, v in a_dict.items() if a_dict[k]] # [unnecessary-dict-index-lookup] -F = [v for k, v in a_dict.items() if k] # This is fine, no indexing -G = [a_dict[k] for k, v in a_dict.items() if k] # [unnecessary-dict-index-lookup] +E = [v for k, v in A_DICT.items() if A_DICT[k]] # [unnecessary-dict-index-lookup] +f = [v for k, v in A_DICT.items() if k] # This is fine, no indexing +G = [A_DICT[k] for k, v in A_DICT.items() if k] # [unnecessary-dict-index-lookup] # +1: [unnecessary-dict-index-lookup, unnecessary-dict-index-lookup] -H = [a_dict[k] for k, v in a_dict.items() if a_dict[k]] +H = [A_DICT[k] for k, v in A_DICT.items() if A_DICT[k]] # Tests on dict attribute of a class @@ -36,7 +36,7 @@ class Foo: for k, v in Foo.c_dict.items(): - print(b_dict[k]) # Should not emit warning, accessing other dictionary + print(B_DICT[k]) # Should not emit warning, accessing other dictionary print(Foo.c_dict[k]) # [unnecessary-dict-index-lookup] unnecessary = 0 # pylint: disable=invalid-name unnecessary += Foo.c_dict[k] # [unnecessary-dict-index-lookup] @@ -100,10 +100,10 @@ class Foo: del d[item[0]] break -outer_dict = {"inner_dict": {}} -for key, val in outer_dict.items(): +OUTER_DICT = {"inner_dict": {}} +for key, val in OUTER_DICT.items(): for key_two, val_two in val.items(): - del outer_dict[key][key_two] # [unnecessary-dict-index-lookup] + del OUTER_DICT[key][key_two] # [unnecessary-dict-index-lookup] break # Test partial unpacking of items diff --git a/tests/functional/u/unnecessary/unnecessary_dunder_call.py b/tests/functional/u/unnecessary/unnecessary_dunder_call.py index f86e14651d..81b10c03a7 100644 --- a/tests/functional/u/unnecessary/unnecessary_dunder_call.py +++ b/tests/functional/u/unnecessary/unnecessary_dunder_call.py @@ -1,5 +1,5 @@ """Checks for unnecessary-dunder-call.""" -# pylint: disable=too-few-public-methods, undefined-variable +# pylint: disable=too-few-public-methods, undefined-variable, invalid-name # pylint: disable=missing-class-docstring, missing-function-docstring # pylint: disable=protected-access, unnecessary-lambda-assignment, unnecessary-lambda from collections import OrderedDict diff --git a/tests/functional/u/unnecessary/unnecessary_lambda.py b/tests/functional/u/unnecessary/unnecessary_lambda.py index 6b379165fa..e67a66e415 100644 --- a/tests/functional/u/unnecessary/unnecessary_lambda.py +++ b/tests/functional/u/unnecessary/unnecessary_lambda.py @@ -12,17 +12,17 @@ _ = lambda x, y: min(x, y) # replaceable with "min" # A function that can take any arguments given to it. -_ANYARGS = lambda *args, **kwargs: 'completely arbitrary return value' +_anyargs = lambda *args, **kwargs: 'completely arbitrary return value' # Some more complex forms of unnecessary lambda expressions. # +1: [unnecessary-lambda] -_ = lambda *args: _ANYARGS(*args) +_ = lambda *args: _anyargs(*args) # +1: [unnecessary-lambda] -_ = lambda **kwargs: _ANYARGS(**kwargs) +_ = lambda **kwargs: _anyargs(**kwargs) # +1: [unnecessary-lambda] -_ = lambda *args, **kwargs: _ANYARGS(*args, **kwargs) +_ = lambda *args, **kwargs: _anyargs(*args, **kwargs) # +1: [unnecessary-lambda] -_ = lambda x, y, z, *args, **kwargs: _ANYARGS(x, y, z, *args, **kwargs) +_ = lambda x, y, z, *args, **kwargs: _anyargs(x, y, z, *args, **kwargs) # These don't use their parameters in their body # +1: [unnecessary-lambda] @@ -39,18 +39,18 @@ _ = lambda x, y: list(range(x, 5)) _ = lambda x, y, z: x.y(z) _ = lambda: 5 -_ = lambda **kwargs: _ANYARGS() -_ = lambda **kwargs: _ANYARGS(**dict([('three', 3)])) -_ = lambda **kwargs: _ANYARGS(**{'three': 3}) -_ = lambda dict_arg, **kwargs: _ANYARGS(kwargs, **dict_arg) -_ = lambda *args: _ANYARGS() -_ = lambda *args: _ANYARGS(*list([3, 4])) -_ = lambda *args: _ANYARGS(*[3, 4]) -_ = lambda list_arg, *args: _ANYARGS(args, *list_arg) -_ = lambda: _ANYARGS(*[3]) -_ = lambda: _ANYARGS(**{'three': 3}) -_ = lambda: _ANYARGS(*[3], **{'three': 3}) -_ = lambda: _ANYARGS(func=42) +_ = lambda **kwargs: _anyargs() +_ = lambda **kwargs: _anyargs(**dict([('three', 3)])) +_ = lambda **kwargs: _anyargs(**{'three': 3}) +_ = lambda dict_arg, **kwargs: _anyargs(kwargs, **dict_arg) +_ = lambda *args: _anyargs() +_ = lambda *args: _anyargs(*list([3, 4])) +_ = lambda *args: _anyargs(*[3, 4]) +_ = lambda list_arg, *args: _anyargs(args, *list_arg) +_ = lambda: _anyargs(*[3]) +_ = lambda: _anyargs(**{'three': 3}) +_ = lambda: _anyargs(*[3], **{'three': 3}) +_ = lambda: _anyargs(func=42) # pylint: disable=missing-function-docstring def f(d): diff --git a/tests/functional/u/unnecessary/unnecessary_lambda_assignment.py b/tests/functional/u/unnecessary/unnecessary_lambda_assignment.py index cad5cc4ac4..65b735f7e5 100644 --- a/tests/functional/u/unnecessary/unnecessary_lambda_assignment.py +++ b/tests/functional/u/unnecessary/unnecessary_lambda_assignment.py @@ -23,11 +23,11 @@ lambda y: y, # [unnecessary-lambda-assignment] lambda z: z, # This isn't assigned so don't flag. ) -a, b, c = lambda x: x, lambda y: y # [unnecessary-lambda-assignment,unnecessary-lambda-assignment] +a, b, C = lambda x: x, lambda y: y # [unnecessary-lambda-assignment,unnecessary-lambda-assignment] # Only flag lambdas directly assigned to variables. d["key"] = lambda x: x -squares = list(map(lambda x: x**2, range(10))) +SQUARES = list(map(lambda x: x**2, range(10))) DICT = {1: lambda x: x, 2: lambda x: x + 1} for key, value in DICT.items(): diff --git a/tests/functional/u/unnecessary/unnecessary_list_index_lookup.py b/tests/functional/u/unnecessary/unnecessary_list_index_lookup.py index b9f8b73251..037f4181ab 100644 --- a/tests/functional/u/unnecessary/unnecessary_list_index_lookup.py +++ b/tests/functional/u/unnecessary/unnecessary_list_index_lookup.py @@ -2,25 +2,25 @@ # pylint: disable=missing-docstring, too-few-public-methods, expression-not-assigned, line-too-long, unused-variable -my_list = ['a', 'b'] +MY_LIST = ['a', 'b'] -for idx, val in enumerate(my_list): - print(my_list[idx]) # [unnecessary-list-index-lookup] +for idx, val in enumerate(MY_LIST): + print(MY_LIST[idx]) # [unnecessary-list-index-lookup] -for idx, _ in enumerate(my_list): - print(my_list[0]) +for idx, _ in enumerate(MY_LIST): + print(MY_LIST[0]) if idx > 0: - print(my_list[idx - 1]) + print(MY_LIST[idx - 1]) -for idx, val in enumerate(my_list): - del my_list[idx] +for idx, val in enumerate(MY_LIST): + del MY_LIST[idx] -for idx, val in enumerate(my_list): - my_list[idx] = 42 +for idx, val in enumerate(MY_LIST): + MY_LIST[idx] = 42 -for vals in enumerate(my_list): +for vals in enumerate(MY_LIST): # This could be refactored, but too complex to infer - print(my_list[vals[0]]) + print(MY_LIST[vals[0]]) def process_list(data): for index, value in enumerate(data): @@ -32,23 +32,23 @@ def process_list_again(data): value = 1 print(data[index]) # Can't use value here, it's been redefined -other_list = [1, 2] -for idx, val in enumerate(my_list): - print(other_list[idx]) +OTHER_LIST = [1, 2] +for idx, val in enumerate(MY_LIST): + print(OTHER_LIST[idx]) OTHER_INDEX = 0 -for idx, val in enumerate(my_list): - print(my_list[OTHER_INDEX]) +for idx, val in enumerate(MY_LIST): + print(MY_LIST[OTHER_INDEX]) -result = [val for idx, val in enumerate(my_list) if my_list[idx] == 'a'] # [unnecessary-list-index-lookup] -result = [val for idx, val in enumerate(my_list) if idx > 0 and my_list[idx - 1] == 'a'] -result = [val for idx, val in enumerate(my_list) if other_list[idx] == 'a'] -result = [my_list[idx] for idx, val in enumerate(my_list)] # [unnecessary-list-index-lookup] +result = [val for idx, val in enumerate(MY_LIST) if MY_LIST[idx] == 'a'] # [unnecessary-list-index-lookup] +result = [val for idx, val in enumerate(MY_LIST) if idx > 0 and MY_LIST[idx - 1] == 'a'] +result = [val for idx, val in enumerate(MY_LIST) if OTHER_LIST[idx] == 'a'] +result = [MY_LIST[idx] for idx, val in enumerate(MY_LIST)] # [unnecessary-list-index-lookup] # Regression test for https://github.com/pylint-dev/pylint/issues/6049 -pairs = [(0, 0)] -for i, (a, b) in enumerate(pairs): - print(pairs[i][0]) +PAIRS = [(0, 0)] +for i, (a, b) in enumerate(PAIRS): + print(PAIRS[i][0]) # Regression test for https://github.com/pylint-dev/pylint/issues/6603 for i, num in enumerate(): # raises TypeError, but shouldn't crash pylint @@ -76,71 +76,71 @@ def process_list_again(data): print(updated_list[idx]) # Regression test for https://github.com/pylint-dev/pylint/issues/6896 -parts = ["a", "b", "c", "d"] -for i, part in enumerate(parts): +PARTS = ["a", "b", "c", "d"] +for i, part in enumerate(PARTS): if i == 3: # more complex condition actually - parts.insert(i, "X") - print(part, parts[i]) + PARTS.insert(i, "X") + print(part, PARTS[i]) # regression tests for https://github.com/pylint-dev/pylint/issues/7682 -series = [1, 2, 3, 4, 5] +SERIES = [1, 2, 3, 4, 5] output_list = [ - (item, series[index]) - for index, item in enumerate(series, start=1) - if index < len(series) + (item, SERIES[index]) + for index, item in enumerate(SERIES, start=1) + if index < len(SERIES) ] output_list = [ - (item, series[index]) - for index, item in enumerate(series, 1) - if index < len(series) + (item, SERIES[index]) + for index, item in enumerate(SERIES, 1) + if index < len(SERIES) ] -for idx, val in enumerate(series, start=2): - print(series[idx]) +for idx, val in enumerate(SERIES, start=2): + print(SERIES[idx]) -for idx, val in enumerate(series, 2): - print(series[idx]) +for idx, val in enumerate(SERIES, 2): + print(SERIES[idx]) -for idx, val in enumerate(series, start=-2): - print(series[idx]) +for idx, val in enumerate(SERIES, start=-2): + print(SERIES[idx]) -for idx, val in enumerate(series, -2): - print(series[idx]) +for idx, val in enumerate(SERIES, -2): + print(SERIES[idx]) -for idx, val in enumerate(series, start=0): - print(series[idx]) # [unnecessary-list-index-lookup] +for idx, val in enumerate(SERIES, start=0): + print(SERIES[idx]) # [unnecessary-list-index-lookup] -for idx, val in enumerate(series, 0): - print(series[idx]) # [unnecessary-list-index-lookup] +for idx, val in enumerate(SERIES, 0): + print(SERIES[idx]) # [unnecessary-list-index-lookup] -START = 0 -for idx, val in enumerate(series, start=START): - print(series[idx]) # [unnecessary-list-index-lookup] +start = 0 +for idx, val in enumerate(SERIES, start=start): + print(SERIES[idx]) # [unnecessary-list-index-lookup] -for idx, val in enumerate(series, START): - print(series[idx]) # [unnecessary-list-index-lookup] +for idx, val in enumerate(SERIES, start): + print(SERIES[idx]) # [unnecessary-list-index-lookup] -START = [1, 2, 3] -for i, k in enumerate(series, len(START)): - print(series[idx]) +start = [1, 2, 3] +for i, k in enumerate(SERIES, len(start)): + print(SERIES[idx]) -def return_start(start): - return start +def return_start(start_val): + return start_val -for i, k in enumerate(series, return_start(20)): - print(series[idx]) +for i, k in enumerate(SERIES, return_start(20)): + print(SERIES[idx]) -for idx, val in enumerate(iterable=series, start=0): - print(series[idx]) # [unnecessary-list-index-lookup] +for idx, val in enumerate(iterable=SERIES, start=0): + print(SERIES[idx]) # [unnecessary-list-index-lookup] -result = [my_list[idx] for idx, val in enumerate(iterable=my_list)] # [unnecessary-list-index-lookup] +result = [MY_LIST[idx] for idx, val in enumerate(iterable=MY_LIST)] # [unnecessary-list-index-lookup] -iterable_kwarg = {"iterable": my_list} -result = [my_list[idx] for idx, val in enumerate(**iterable_kwarg)] # [unnecessary-list-index-lookup] +ITERABLE_KWARG = {"iterable": MY_LIST} +result = [MY_LIST[idx] for idx, val in enumerate(**ITERABLE_KWARG)] # [unnecessary-list-index-lookup] for idx, val in enumerate(): - print(my_list[idx]) + print(MY_LIST[idx]) class Command: def _get_extra_attrs(self, extra_columns): @@ -149,12 +149,12 @@ def _get_extra_attrs(self, extra_columns): pass Y_START = 2 -nums = list(range(20)) -for y, x in enumerate(nums, start=Y_START + 1): +NUMS = list(range(20)) +for y, x in enumerate(NUMS, start=Y_START + 1): pass -for idx, val in enumerate(my_list): - if (val := 42) and my_list[idx] == 'b': +for idx, val in enumerate(MY_LIST): + if (val := 42) and MY_LIST[idx] == 'b': print(1) def regression_9078(apples, cant_infer_this): diff --git a/tests/functional/u/unnecessary/unnecessary_pass.py b/tests/functional/u/unnecessary/unnecessary_pass.py index c2733096ad..cae0536580 100644 --- a/tests/functional/u/unnecessary/unnecessary_pass.py +++ b/tests/functional/u/unnecessary/unnecessary_pass.py @@ -1,9 +1,9 @@ # pylint: disable=missing-docstring, too-few-public-methods try: - A = 2 + a = 2 except ValueError: - A = 24 + a = 24 pass # [unnecessary-pass] def docstring_only(): diff --git a/tests/functional/u/unpacking/unpacking_non_sequence_py310.py b/tests/functional/u/unpacking/unpacking_non_sequence_py310.py index 73492706a0..c0fa4ec697 100644 --- a/tests/functional/u/unpacking/unpacking_non_sequence_py310.py +++ b/tests/functional/u/unpacking/unpacking_non_sequence_py310.py @@ -8,4 +8,4 @@ def unpack(num) -> tuple[int, int]: case _: return 0, 0 -x, y = unpack(1) +X, Y = unpack(1) diff --git a/tests/functional/u/unreachable.py b/tests/functional/u/unreachable.py index 2c9d5ce97e..0a60f9435d 100644 --- a/tests/functional/u/unreachable.py +++ b/tests/functional/u/unreachable.py @@ -75,7 +75,7 @@ def func11(): var = 2 + 2 # [unreachable] print(var) -incognito_function = sys.exit +incognito_function = sys.exit # pylint: disable=invalid-name def func12(): incognito_function() var = 2 + 2 # [unreachable] diff --git a/tests/functional/u/unspecified_encoding_py38.py b/tests/functional/u/unspecified_encoding_py38.py index 9bcfdb5549..9ff2fd7dc8 100644 --- a/tests/functional/u/unspecified_encoding_py38.py +++ b/tests/functional/u/unspecified_encoding_py38.py @@ -1,5 +1,5 @@ """Warnings for using open() without specifying an encoding""" -# pylint: disable=consider-using-with, too-few-public-methods +# pylint: disable=consider-using-with, too-few-public-methods, invalid-name import dataclasses import io import locale diff --git a/tests/functional/u/unsubscriptable_object.py b/tests/functional/u/unsubscriptable_object.py index 464895c68a..ac07e81aaf 100644 --- a/tests/functional/u/unsubscriptable_object.py +++ b/tests/functional/u/unsubscriptable_object.py @@ -30,5 +30,5 @@ class Animal(Generic[T]): class Dog(Animal[Identity]): """It's a Dog.""" -dog = Dog(identity=Identity(name="Dog")) -print(dog.identity["name"]) +DOG = Dog(identity=Identity(name="Dog")) +print(DOG.identity["name"]) diff --git a/tests/functional/u/unused/unused_global_variable4.py b/tests/functional/u/unused/unused_global_variable4.py index aef49d68c6..52dcd4373e 100644 --- a/tests/functional/u/unused/unused_global_variable4.py +++ b/tests/functional/u/unused/unused_global_variable4.py @@ -1,3 +1,3 @@ # pylint: disable=missing-docstring -VAR = 'pylint' # [unused-variable] -VAR = 'pylint2' # [unused-variable] +var = 'pylint' # [unused-variable] +var = 'pylint2' # [unused-variable] diff --git a/tests/functional/u/unused/unused_global_variable4.txt b/tests/functional/u/unused/unused_global_variable4.txt index a90f8f6ff9..52ae49d3e0 100644 --- a/tests/functional/u/unused/unused_global_variable4.txt +++ b/tests/functional/u/unused/unused_global_variable4.txt @@ -1,2 +1,2 @@ -unused-variable:2:0:2:3::Unused variable 'VAR':UNDEFINED -unused-variable:3:0:3:3::Unused variable 'VAR':UNDEFINED +unused-variable:2:0:2:3::Unused variable 'var':UNDEFINED +unused-variable:3:0:3:3::Unused variable 'var':UNDEFINED diff --git a/tests/functional/u/unused/unused_import.py b/tests/functional/u/unused/unused_import.py index a2e3ceca3f..ffc6699d46 100644 --- a/tests/functional/u/unused/unused_import.py +++ b/tests/functional/u/unused/unused_import.py @@ -85,7 +85,7 @@ def blop(self): import trace as t import astroid as typing # pylint: disable=shadowed-import -TYPE_CHECKING = "red herring" +TYPE_CHECKING = "red herring" # pylint: disable=invalid-name if TYPE_CHECKING: import unittest # [unused-import] @@ -96,7 +96,7 @@ def blop(self): if typing.TYPE_CHECKING_WITH_MAGIC: # pylint: disable=no-member import compileall # [unused-import] -TYPE_CHECKING = False +TYPE_CHECKING = False # pylint: disable=invalid-name if TYPE_CHECKING: import zoneinfo diff --git a/tests/functional/u/use/use_sequence_for_iteration.py b/tests/functional/u/use/use_sequence_for_iteration.py index 264e6e7b9d..c1f695e997 100644 --- a/tests/functional/u/use/use_sequence_for_iteration.py +++ b/tests/functional/u/use/use_sequence_for_iteration.py @@ -1,19 +1,19 @@ # pylint: disable=missing-docstring,pointless-statement,unnecessary-comprehension -var = {1, 2, 3} +VAR = {1, 2, 3} -for x in var: +for x in VAR: pass for x in {1, 2, 3}: # [use-sequence-for-iteration] pass -(x for x in var) +(x for x in VAR) (x for x in {1, 2, 3}) # [use-sequence-for-iteration] -[x for x in var] +[x for x in VAR] [x for x in {1, 2, 3}] # [use-sequence-for-iteration] -[x for x in {*var, 4}] +[x for x in {*VAR, 4}] def deduplicate(list_in): for thing in {*list_in}: diff --git a/tests/functional/u/used/used_before_assignment.py b/tests/functional/u/used/used_before_assignment.py index 360be6a4f3..e4e3c3ff45 100644 --- a/tests/functional/u/used/used_before_assignment.py +++ b/tests/functional/u/used/used_before_assignment.py @@ -1,5 +1,5 @@ """Miscellaneous used-before-assignment cases""" -# pylint: disable=consider-using-f-string, missing-function-docstring, bare-except +# pylint: disable=consider-using-f-string, missing-function-docstring, bare-except, invalid-name import datetime import sys from typing import NoReturn diff --git a/tests/functional/u/used/used_before_assignment_comprehension_homonyms.py b/tests/functional/u/used/used_before_assignment_comprehension_homonyms.py index 6c7fe411a8..b5459bda9e 100644 --- a/tests/functional/u/used/used_before_assignment_comprehension_homonyms.py +++ b/tests/functional/u/used/used_before_assignment_comprehension_homonyms.py @@ -88,9 +88,9 @@ def func8(): # Module level cases -module_ints = [j | j for j in range(3)] +MODULE_INTS = [j | j for j in range(3)] try: 1 / 0 except ZeroDivisionError: j = None - print(j, module_ints) + print(j, MODULE_INTS) diff --git a/tests/functional/u/used/used_before_assignment_conditional.py b/tests/functional/u/used/used_before_assignment_conditional.py index b024d28982..506885fcf3 100644 --- a/tests/functional/u/used/used_before_assignment_conditional.py +++ b/tests/functional/u/used/used_before_assignment_conditional.py @@ -1,7 +1,7 @@ """used-before-assignment cases involving IF conditions""" if 1 + 1 == 2: - x = x + 1 # [used-before-assignment] + X = X + 1 # [used-before-assignment] -if y: # [used-before-assignment] - y = y + 1 +if Y: # [used-before-assignment] + Y = Y + 1 diff --git a/tests/functional/u/used/used_before_assignment_conditional.txt b/tests/functional/u/used/used_before_assignment_conditional.txt index a65f9f7387..6e4c505a01 100644 --- a/tests/functional/u/used/used_before_assignment_conditional.txt +++ b/tests/functional/u/used/used_before_assignment_conditional.txt @@ -1,2 +1,2 @@ -used-before-assignment:4:8:4:9::Using variable 'x' before assignment:HIGH -used-before-assignment:6:3:6:4::Using variable 'y' before assignment:HIGH +used-before-assignment:4:8:4:9::Using variable 'X' before assignment:HIGH +used-before-assignment:6:3:6:4::Using variable 'Y' before assignment:HIGH diff --git a/tests/functional/u/used/used_before_assignment_issue853.py b/tests/functional/u/used/used_before_assignment_issue853.py index 7da9fdd50c..0bb4ad328f 100644 --- a/tests/functional/u/used/used_before_assignment_issue853.py +++ b/tests/functional/u/used/used_before_assignment_issue853.py @@ -9,15 +9,15 @@ def strangeproblem(): try: - MY_INT = 1 - print("MY_INT = %d" % MY_INT) + my_int = 1 + print("MY_INT = %d" % my_int) finally: - MY_INT = 2 + my_int = 2 try: pass except: - FALSE_POSITIVE = 1 - FALSE_POSITIVE # here pylint claims used-before-assignment + false_positive = 1 + false_positive # here pylint claims used-before-assignment finally: - FALSE_POSITIVE = 2 # this line is needed to reproduce the issue + false_positive = 2 # this line is needed to reproduce the issue diff --git a/tests/functional/u/useless/useless_with_lock.py b/tests/functional/u/useless/useless_with_lock.py index 19d664084d..0269bafa1c 100644 --- a/tests/functional/u/useless/useless_with_lock.py +++ b/tests/functional/u/useless/useless_with_lock.py @@ -10,7 +10,7 @@ with Lock(): # [useless-with-lock] ... -with threading.Lock() as this_shouldnt_matter: # [useless-with-lock] +with threading.Lock() as THIS_SHOULDNT_MATTER: # [useless-with-lock] ... with threading.RLock(): # [useless-with-lock] @@ -37,22 +37,22 @@ with BoundedSemaphore(): # [useless-with-lock] ... -lock = threading.Lock() -with lock: # this is ok +LOCK = threading.Lock() +with LOCK: # this is ok ... -rlock = threading.RLock() -with rlock: # this is ok +RLOCK = threading.RLock() +with RLOCK: # this is ok ... -cond = threading.Condition() -with cond: # this is ok +COND = threading.Condition() +with COND: # this is ok ... -sem = threading.Semaphore() -with sem: # this is ok +SEM = threading.Semaphore() +with SEM: # this is ok ... -b_sem = threading.BoundedSemaphore() -with b_sem: # this is ok +B_SEM = threading.BoundedSemaphore() +with B_SEM: # this is ok ... diff --git a/tests/functional/w/wrong_import_order.txt b/tests/functional/w/wrong_import_order.txt index 9f143c292d..bfb11740d0 100644 --- a/tests/functional/w/wrong_import_order.txt +++ b/tests/functional/w/wrong_import_order.txt @@ -1,9 +1,5 @@ -wrong-import-order:12:0:12:14::"standard import ""os.path"" should be placed before third party import ""six""":UNDEFINED -wrong-import-order:14:0:14:10::"standard import ""sys"" should be placed before third party imports ""six"", ""astroid.are_exclusive""":UNDEFINED -wrong-import-order:15:0:15:15::"standard import ""datetime"" should be placed before third party imports ""six"", ""astroid.are_exclusive""":UNDEFINED -wrong-import-order:18:0:18:22::"third party import ""totally_missing"" should be placed before local import ""package.Class""":UNDEFINED -wrong-import-order:20:0:20:14::"third party import ""astroid"" should be placed before local imports ""package.Class"", "".package""":UNDEFINED -wrong-import-order:22:0:22:22::"first party import ""pylint.checkers"" should be placed before local imports ""package.Class"", "".package"", "".package2""":UNDEFINED +wrong-import-order:22:0:22:22::"first party import ""pylint.checkers"" should be placed before local imports ""package.Class"", "".pack +age"", "".package2""":UNDEFINED wrong-import-order:23:0:23:25::"first party import ""pylint.config"" should be placed before local imports ""package.Class"", "".package"", "".package2""":UNDEFINED wrong-import-order:24:0:24:17::"first party import ""pylint.sys"" should be placed before local imports ""package.Class"", "".package"", "".package2""":UNDEFINED wrong-import-order:25:0:25:28::"first party import ""pylint.pyreverse"" should be placed before local imports ""package.Class"", "".package"", "".package2""":UNDEFINED diff --git a/tests/functional/w/wrong_import_position.py b/tests/functional/w/wrong_import_position.py index 7d1fddfa3b..5468706c85 100644 --- a/tests/functional/w/wrong_import_position.py +++ b/tests/functional/w/wrong_import_position.py @@ -25,9 +25,9 @@ def some_func(self): import datetime # [wrong-import-position] -VAR = 0 +var = 0 for i in range(10): - VAR += i + var += i import scipy # [wrong-import-position] import astroid # [wrong-import-position] diff --git a/tests/functional/w/wrong_import_position_exclude_dunder_main.py b/tests/functional/w/wrong_import_position_exclude_dunder_main.py index 05f680377a..57b0f1b5cf 100644 --- a/tests/functional/w/wrong_import_position_exclude_dunder_main.py +++ b/tests/functional/w/wrong_import_position_exclude_dunder_main.py @@ -3,9 +3,9 @@ if __name__ == '__main__': CONSTANT = True - VAR = 0 + var = 0 for i in range(10): - VAR += i + var += i import six import datetime diff --git a/tests/functional/y/yield_from_outside_func.py b/tests/functional/y/yield_from_outside_func.py index 1c58af4295..8557f58b4a 100644 --- a/tests/functional/y/yield_from_outside_func.py +++ b/tests/functional/y/yield_from_outside_func.py @@ -3,4 +3,4 @@ yield from [1, 2] # [yield-outside-function] -LAMBDA_WITH_YIELD = lambda: (yield from [1, 2]) +lambda_with_yield = lambda: (yield from [1, 2]) diff --git a/tests/functional/y/yield_outside_func.py b/tests/functional/y/yield_outside_func.py index 198a103366..b2697e4d64 100644 --- a/tests/functional/y/yield_outside_func.py +++ b/tests/functional/y/yield_outside_func.py @@ -3,4 +3,4 @@ yield 1 # [yield-outside-function] -LAMBDA_WITH_YIELD = lambda: (yield) +lambda_with_yield = lambda: (yield) diff --git a/tests/messages/func_w0801.txt b/tests/messages/func_w0801.txt index 54355ab8af..fcad8f243f 100644 --- a/tests/messages/func_w0801.txt +++ b/tests/messages/func_w0801.txt @@ -1,3 +1,7 @@ +C: 5: Variable name "A" doesn't conform to snake_case naming style +C: 5: Variable name "A" doesn't conform to snake_case naming style +C: 7: Variable name "C" doesn't conform to snake_case naming style +C: 7: Variable name "C" doesn't conform to snake_case naming style R: 1: Similar lines in 2 files ==input.func_w0801:[3:10] ==input.w0801_same:[3:10] From cd354ae2b5178f14320e4aa42df8c37d10268bcf Mon Sep 17 00:00:00 2001 From: Jacob Walls Date: Sat, 1 Feb 2025 14:18:06 -0500 Subject: [PATCH 02/13] Treat exclusive assignments as "constants" --- pylint/checkers/base/name_checker/checker.py | 14 ++++++++++---- .../invalid_name/invalid_name_module_level.py | 6 ++++++ tests/functional/u/unnecessary/unnecessary_pass.py | 4 ++-- tests/functional/w/wrong_import_order.txt | 8 ++++++-- 4 files changed, 24 insertions(+), 8 deletions(-) diff --git a/pylint/checkers/base/name_checker/checker.py b/pylint/checkers/base/name_checker/checker.py index 3027cf4c16..110854e00c 100644 --- a/pylint/checkers/base/name_checker/checker.py +++ b/pylint/checkers/base/name_checker/checker.py @@ -475,11 +475,17 @@ def visit_assignname( # pylint: disable=too-many-branches ) ): self._check_name("const", node.name, node) - elif inferred_assign_type is not None and not isinstance( - inferred_assign_type, astroid.util.UninferableBase - ): + elif inferred_assign_type not in (None, astroid.util.Uninferable): + node_type = "variable" + iattrs = tuple(node.frame().igetattr(node.name)) + if ( + astroid.util.Uninferable not in iattrs + and len(iattrs) == 2 + and astroid.are_exclusive(*iattrs) + ): + node_type = "const" self._check_name( - "variable", + node_type, node.name, node, disallowed_check_only=redefines_import, diff --git a/tests/functional/i/invalid/invalid_name/invalid_name_module_level.py b/tests/functional/i/invalid/invalid_name/invalid_name_module_level.py index e818899d46..8c2c2f2482 100644 --- a/tests/functional/i/invalid/invalid_name/invalid_name_module_level.py +++ b/tests/functional/i/invalid/invalid_name/invalid_name_module_level.py @@ -24,3 +24,9 @@ def A(): # [invalid-name] ASSIGNMENT_THAT_CRASHED_PYLINT = type(float.__new__.__code__) + + +if CONST: + OTHER_CONST = 1 +else: + OTHER_CONST = 2 diff --git a/tests/functional/u/unnecessary/unnecessary_pass.py b/tests/functional/u/unnecessary/unnecessary_pass.py index cae0536580..c2733096ad 100644 --- a/tests/functional/u/unnecessary/unnecessary_pass.py +++ b/tests/functional/u/unnecessary/unnecessary_pass.py @@ -1,9 +1,9 @@ # pylint: disable=missing-docstring, too-few-public-methods try: - a = 2 + A = 2 except ValueError: - a = 24 + A = 24 pass # [unnecessary-pass] def docstring_only(): diff --git a/tests/functional/w/wrong_import_order.txt b/tests/functional/w/wrong_import_order.txt index bfb11740d0..9f143c292d 100644 --- a/tests/functional/w/wrong_import_order.txt +++ b/tests/functional/w/wrong_import_order.txt @@ -1,5 +1,9 @@ -wrong-import-order:22:0:22:22::"first party import ""pylint.checkers"" should be placed before local imports ""package.Class"", "".pack -age"", "".package2""":UNDEFINED +wrong-import-order:12:0:12:14::"standard import ""os.path"" should be placed before third party import ""six""":UNDEFINED +wrong-import-order:14:0:14:10::"standard import ""sys"" should be placed before third party imports ""six"", ""astroid.are_exclusive""":UNDEFINED +wrong-import-order:15:0:15:15::"standard import ""datetime"" should be placed before third party imports ""six"", ""astroid.are_exclusive""":UNDEFINED +wrong-import-order:18:0:18:22::"third party import ""totally_missing"" should be placed before local import ""package.Class""":UNDEFINED +wrong-import-order:20:0:20:14::"third party import ""astroid"" should be placed before local imports ""package.Class"", "".package""":UNDEFINED +wrong-import-order:22:0:22:22::"first party import ""pylint.checkers"" should be placed before local imports ""package.Class"", "".package"", "".package2""":UNDEFINED wrong-import-order:23:0:23:25::"first party import ""pylint.config"" should be placed before local imports ""package.Class"", "".package"", "".package2""":UNDEFINED wrong-import-order:24:0:24:17::"first party import ""pylint.sys"" should be placed before local imports ""package.Class"", "".package"", "".package2""":UNDEFINED wrong-import-order:25:0:25:28::"first party import ""pylint.pyreverse"" should be placed before local imports ""package.Class"", "".package"", "".package2""":UNDEFINED From 854141e06c04a35a85598752a91dd261fdf66c1c Mon Sep 17 00:00:00 2001 From: Jacob Walls Date: Sat, 1 Feb 2025 14:34:39 -0500 Subject: [PATCH 03/13] Fix bizarre failure --- pylint/checkers/utils.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/pylint/checkers/utils.py b/pylint/checkers/utils.py index be4c879fe3..79be96e725 100644 --- a/pylint/checkers/utils.py +++ b/pylint/checkers/utils.py @@ -2147,7 +2147,13 @@ def is_augmented_assign(node: nodes.Assign) -> tuple[bool, str]: binop.op in COMMUTATIVE_OPERATORS and _is_target_name_in_binop_side(target, binop.right) ): - inferred_left = safe_infer(binop.left) + if isinstance(binop.left, nodes.Const): + # This bizarrely became necessary after an unrelated call to igetattr(). + # Seems like a code smell uncovered in #10212. + # tuple(node.frame().igetattr(node.name)) + inferred_left = binop.left + else: + inferred_left = safe_infer(binop.left) if isinstance(inferred_left, nodes.Const) and isinstance( inferred_left.value, int ): From 5d113f279907606bccae7e71f972be49d7b03a8e Mon Sep 17 00:00:00 2001 From: Jacob Walls Date: Sat, 1 Feb 2025 15:08:00 -0500 Subject: [PATCH 04/13] Add igetattr to wordlist --- custom_dict.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/custom_dict.txt b/custom_dict.txt index 265c7cb881..77df598cf8 100644 --- a/custom_dict.txt +++ b/custom_dict.txt @@ -146,6 +146,7 @@ hmac html idgeneratormixin ifexpr +igetattr importedname importfrom importnode From babae7b73599b766866b4421d51cd6f88fc26293 Mon Sep 17 00:00:00 2001 From: Jacob Walls Date: Sat, 1 Feb 2025 17:29:24 -0500 Subject: [PATCH 05/13] [skip ci] Change news fragment type to breaking --- doc/whatsnew/fragments/{3585.false_negative => 3585.breaking} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename doc/whatsnew/fragments/{3585.false_negative => 3585.breaking} (100%) diff --git a/doc/whatsnew/fragments/3585.false_negative b/doc/whatsnew/fragments/3585.breaking similarity index 100% rename from doc/whatsnew/fragments/3585.false_negative rename to doc/whatsnew/fragments/3585.breaking From 93b8b978e69635e2a56e5e7c1ca7d4cdee55a70f Mon Sep 17 00:00:00 2001 From: Jacob Walls Date: Sat, 1 Feb 2025 17:33:07 -0500 Subject: [PATCH 06/13] [skip ci] Add hint about good names --- doc/whatsnew/fragments/3585.breaking | 3 +++ 1 file changed, 3 insertions(+) diff --git a/doc/whatsnew/fragments/3585.breaking b/doc/whatsnew/fragments/3585.breaking index e40317c66f..319c968e62 100644 --- a/doc/whatsnew/fragments/3585.breaking +++ b/doc/whatsnew/fragments/3585.breaking @@ -1,6 +1,9 @@ `invalid-name` now distinguishes module-level names that are assigned only once from those that are reassigned and now applies `--variable-rgx` to the latter. +Remember that `--good-names` or `--good-names-rgxs` can be provided to explicitly +allow good names. + Also, `invalid-name` is triggered for module-level names for additional types (e.g. lists and sets). From 18609e031089bbf9e4fbad01cdc7221f63ce039b Mon Sep 17 00:00:00 2001 From: Jacob Walls Date: Sun, 2 Feb 2025 08:31:05 -0500 Subject: [PATCH 07/13] Add "logger" to `--good-names` --- doc/user_guide/configuration/all-options.rst | 2 +- doc/whatsnew/2/2.5/summary.rst | 2 +- doc/whatsnew/fragments/3585.breaking | 2 +- examples/pylintrc | 1 + examples/pyproject.toml | 2 +- pylint/checkers/base/name_checker/checker.py | 2 +- pylintrc | 2 +- tests/functional/r/renamed_import_logging_not_lazy.py | 4 ++-- 8 files changed, 9 insertions(+), 8 deletions(-) diff --git a/doc/user_guide/configuration/all-options.rst b/doc/user_guide/configuration/all-options.rst index 58f3a04b7c..da4853720f 100644 --- a/doc/user_guide/configuration/all-options.rst +++ b/doc/user_guide/configuration/all-options.rst @@ -588,7 +588,7 @@ Standard Checkers # function-rgx = - good-names = ["i", "j", "k", "ex", "Run", "_"] + good-names = ["i", "j", "k", "logger", "ex", "Run", "_"] good-names-rgxs = [] diff --git a/doc/whatsnew/2/2.5/summary.rst b/doc/whatsnew/2/2.5/summary.rst index edc27197ad..6021f8ce2c 100644 --- a/doc/whatsnew/2/2.5/summary.rst +++ b/doc/whatsnew/2/2.5/summary.rst @@ -61,7 +61,7 @@ Other Changes * Add new ``good-names-rgx`` and ``bad-names-rgx`` to enable permitting or disallowing of names via regular expressions To enable better handling of permitted/disallowed names, we added two new config options: good-names-rgxs: a comma- - separated list of regexes, that if a name matches will be exempt of naming-checking. bad-names-rgxs: a comma- + separated list of regexes, that if a name matches will be exempt from naming-checking. bad-names-rgxs: a comma- separated list of regexes, that if a name matches will be always marked as a disallowed name. * Mutable ``collections.*`` are now flagged as dangerous defaults. diff --git a/doc/whatsnew/fragments/3585.breaking b/doc/whatsnew/fragments/3585.breaking index 319c968e62..3801f3625e 100644 --- a/doc/whatsnew/fragments/3585.breaking +++ b/doc/whatsnew/fragments/3585.breaking @@ -2,7 +2,7 @@ from those that are reassigned and now applies `--variable-rgx` to the latter. Remember that `--good-names` or `--good-names-rgxs` can be provided to explicitly -allow good names. +allow good names. `logger` has been added to the default `--good-names`. Also, `invalid-name` is triggered for module-level names for additional types (e.g. lists and sets). diff --git a/examples/pylintrc b/examples/pylintrc index c9f2fd56e6..4b4950f651 100644 --- a/examples/pylintrc +++ b/examples/pylintrc @@ -193,6 +193,7 @@ function-naming-style=snake_case good-names=i, j, k, + logger, ex, Run, _ diff --git a/examples/pyproject.toml b/examples/pyproject.toml index d98a413f8e..060576cfe0 100644 --- a/examples/pyproject.toml +++ b/examples/pyproject.toml @@ -167,7 +167,7 @@ function-naming-style = "snake_case" # function-rgx = # Good variable names which should always be accepted, separated by a comma. -good-names = ["i", "j", "k", "ex", "Run", "_"] +good-names = ["i", "j", "k", "logger", "ex", "Run", "_"] # Good variable names regexes, separated by a comma. If names match any regex, # they will always be accepted diff --git a/pylint/checkers/base/name_checker/checker.py b/pylint/checkers/base/name_checker/checker.py index 110854e00c..081d1dc59d 100644 --- a/pylint/checkers/base/name_checker/checker.py +++ b/pylint/checkers/base/name_checker/checker.py @@ -199,7 +199,7 @@ class NameChecker(_BasicChecker): ( "good-names", { - "default": ("i", "j", "k", "ex", "Run", "_"), + "default": ("i", "j", "k", "logger", "ex", "Run", "_"), "type": "csv", "metavar": "", "help": "Good variable names which should always be accepted," diff --git a/pylintrc b/pylintrc index 9eaa8cf007..e2140fd1ae 100644 --- a/pylintrc +++ b/pylintrc @@ -231,7 +231,7 @@ expected-line-ending-format= [BASIC] # Good variable names which should always be accepted, separated by a comma -good-names=i,j,k,ex,Run,_ +good-names=i,j,k,logger,ex,Run,_ # Good variable names regexes, separated by a comma. If names match any regex, # they will always be accepted diff --git a/tests/functional/r/renamed_import_logging_not_lazy.py b/tests/functional/r/renamed_import_logging_not_lazy.py index ed9f935c83..87f32953f6 100644 --- a/tests/functional/r/renamed_import_logging_not_lazy.py +++ b/tests/functional/r/renamed_import_logging_not_lazy.py @@ -9,12 +9,12 @@ class Logger: """Fake logger""" -LOGGER = renamed_logging.getLogger(__name__) +logger = renamed_logging.getLogger(__name__) FAKE_LOGGER = Logger() # Statements that should be flagged renamed_logging.warning('%s, %s' % (4, 5)) # [logging-not-lazy] -LOGGER.warning('%s' % 5) # [logging-not-lazy] +logger.warning('%s' % 5) # [logging-not-lazy] # Statements that should not be flagged: FAKE_LOGGER.warn('%s' % 5) From 45d80edd64742f6931e0b28aebfada6494344dc8 Mon Sep 17 00:00:00 2001 From: Jacob Walls Date: Sun, 2 Feb 2025 08:44:50 -0500 Subject: [PATCH 08/13] fixup! Add "logger" --- doc/user_guide/configuration/all-options.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/user_guide/configuration/all-options.rst b/doc/user_guide/configuration/all-options.rst index da4853720f..adc27ada07 100644 --- a/doc/user_guide/configuration/all-options.rst +++ b/doc/user_guide/configuration/all-options.rst @@ -428,7 +428,7 @@ Standard Checkers """""""""""" *Good variable names which should always be accepted, separated by a comma.* -**Default:** ``('i', 'j', 'k', 'ex', 'Run', '_')`` +**Default:** ``('i', 'j', 'k', 'logger', 'ex', 'Run', '_')`` --good-names-rgxs From dc7f7e7c0cfb28a75392d5e0cba77376c7585085 Mon Sep 17 00:00:00 2001 From: Jacob Walls Date: Sun, 2 Feb 2025 09:32:28 -0500 Subject: [PATCH 09/13] Adjust handling of uninferable --- pylint/checkers/base/name_checker/checker.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/pylint/checkers/base/name_checker/checker.py b/pylint/checkers/base/name_checker/checker.py index 081d1dc59d..082c94cfab 100644 --- a/pylint/checkers/base/name_checker/checker.py +++ b/pylint/checkers/base/name_checker/checker.py @@ -461,6 +461,9 @@ def visit_assignname( # pylint: disable=too-many-branches elif isinstance(inferred_assign_type, nodes.ClassDef): self._check_name("class", node.name, node) + elif inferred_assign_type in (None, astroid.util.Uninferable): + return + # Don't emit if the name redefines an import in an ImportError except handler # nor any other reassignment. elif ( @@ -475,11 +478,11 @@ def visit_assignname( # pylint: disable=too-many-branches ) ): self._check_name("const", node.name, node) - elif inferred_assign_type not in (None, astroid.util.Uninferable): + else: node_type = "variable" - iattrs = tuple(node.frame().igetattr(node.name)) if ( - astroid.util.Uninferable not in iattrs + (iattrs := tuple(node.frame().igetattr(node.name))) + and astroid.util.Uninferable not in iattrs and len(iattrs) == 2 and astroid.are_exclusive(*iattrs) ): From aff9dc5d46d751676d592567a5ba539df6232381 Mon Sep 17 00:00:00 2001 From: Jacob Walls Date: Sat, 8 Feb 2025 12:57:02 -0500 Subject: [PATCH 10/13] [skip ci] Update details.rst --- doc/data/messages/i/invalid-name/details.rst | 60 ++++++++++---------- 1 file changed, 30 insertions(+), 30 deletions(-) diff --git a/doc/data/messages/i/invalid-name/details.rst b/doc/data/messages/i/invalid-name/details.rst index 7cbf756380..3b2567402d 100644 --- a/doc/data/messages/i/invalid-name/details.rst +++ b/doc/data/messages/i/invalid-name/details.rst @@ -2,35 +2,35 @@ Pylint recognizes a number of different name types internally. With a few exceptions, the type of the name is governed by the location the assignment to a name is found in, and not the type of object assigned. -+--------------------+---------------------------------------------------------------------------------------------------+ -| Name Type | Description | -+====================+===================================================================================================+ -| ``module`` | Module and package names, same as the file names. | -+--------------------+---------------------------------------------------------------------------------------------------+ -| ``const`` | Module-level constants, any variable defined at module level that is not bound to a class object. | -+--------------------+---------------------------------------------------------------------------------------------------+ -| ``class`` | Names in ``class`` statements, as well as names bound to class objects at module level. | -+--------------------+---------------------------------------------------------------------------------------------------+ -| ``function`` | Functions, toplevel or nested in functions or methods. | -+--------------------+---------------------------------------------------------------------------------------------------+ -| ``method`` | Methods, functions defined in class bodies. Includes static and class methods. | -+--------------------+---------------------------------------------------------------------------------------------------+ -| ``attr`` | Attributes created on class instances inside methods. | -+--------------------+---------------------------------------------------------------------------------------------------+ -| ``argument`` | Arguments to any function type, including lambdas. | -+--------------------+---------------------------------------------------------------------------------------------------+ -| ``variable`` | Local variables in function scopes. | -+--------------------+---------------------------------------------------------------------------------------------------+ -| ``class-attribute``| Attributes defined in class bodies. | -+--------------------+---------------------------------------------------------------------------------------------------+ -| ``class-const`` | Enum constants and class variables annotated with ``Final`` | -+--------------------+---------------------------------------------------------------------------------------------------+ -| ``inlinevar`` | Loop variables in list comprehensions and generator expressions. | -+--------------------+---------------------------------------------------------------------------------------------------+ -| ``typevar`` | Type variable declared with ``TypeVar``. | -+--------------------+---------------------------------------------------------------------------------------------------+ -| ``typealias`` | Type alias declared with ``TypeAlias`` or assignments of ``Union``. | -+--------------------+---------------------------------------------------------------------------------------------------+ ++--------------------+-------------------------------------------------------------------------------------------------------------+ +| Name Type | Description | ++====================+=============================================================================================================+ +| ``module`` | Module and package names, same as the file names. | ++--------------------+-------------------------------------------------------------------------------------------------------------+ +| ``const`` | Module-level constants: any name defined at module level that is not bound to a class object nor reassigned.| ++--------------------+-------------------------------------------------------------------------------------------------------------+ +| ``class`` | Names in ``class`` statements, as well as names bound to class objects at module level. | ++--------------------+-------------------------------------------------------------------------------------------------------------+ +| ``function`` | Functions, toplevel or nested in functions or methods. | ++--------------------+-------------------------------------------------------------------------------------------------------------+ +| ``method`` | Methods, functions defined in class bodies. Includes static and class methods. | ++--------------------+-------------------------------------------------------------------------------------------------------------+ +| ``attr`` | Attributes created on class instances inside methods. | ++--------------------+-------------------------------------------------------------------------------------------------------------+ +| ``argument`` | Arguments to any function type, including lambdas. | ++--------------------+-------------------------------------------------------------------------------------------------------------+ +| ``variable`` | Local variables in function scopes or module-level names that are assigned multiple times. | ++--------------------+-------------------------------------------------------------------------------------------------------------+ +| ``class-attribute``| Attributes defined in class bodies. | ++--------------------+-------------------------------------------------------------------------------------------------------------+ +| ``class-const`` | Enum constants and class variables annotated with ``Final`` | ++--------------------+-------------------------------------------------------------------------------------------------------------+ +| ``inlinevar`` | Loop variables in list comprehensions and generator expressions. | ++--------------------+-------------------------------------------------------------------------------------------------------------+ +| ``typevar`` | Type variable declared with ``TypeVar``. | ++--------------------+-------------------------------------------------------------------------------------------------------------+ +| ``typealias`` | Type alias declared with ``TypeAlias`` or assignments of ``Union``. | ++--------------------+-------------------------------------------------------------------------------------------------------------+ Default behavior ~~~~~~~~~~~~~~~~ @@ -50,7 +50,7 @@ Following predefined naming styles are available: * ``UPPER_CASE`` * ``any`` - fake style which does not enforce any limitations -Following options are exposed: +The following options are exposed: .. option:: --module-naming-style=