From 84d495968cebf368c69932f538ba8d7d2f0bdbd9 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 6 Apr 2023 19:38:05 +0200 Subject: Fix check unused arguments false positive bug (#8542) (#8545) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Problem: the special method `__new__` must match the arguments of the `__init__` method even if `__new__` method does not use them. This generate `unused-argument` for the `__new__` method. Fix: the unused arguments check should not be done on the `__new__` method if the `__init__` method is defined in the same class. Update `unused-argument` test to include a check for the case of `__init__` and `__new__` being defined in a class but `__new__` does not use all of the argument. This is fine because `__new__` must have the same argument of `__init__`. Update with a second check in case of `__init__` being not defined in a class. Then the unused arguments check must be done on `__new__`. Fixes https://github.com/pylint-dev/pylint/issues/3670 (cherry picked from commit 156da64d0fb4c06e15c5b619b91ce550d594a770) Co-authored-by: Théo Battrel --- doc/whatsnew/fragments/3670.false_positive | 3 +++ pylint/checkers/variables.py | 10 ++++++++++ tests/functional/u/unused/unused_argument.py | 21 +++++++++++++++++++++ tests/functional/u/unused/unused_argument.txt | 2 ++ 4 files changed, 36 insertions(+) create mode 100644 doc/whatsnew/fragments/3670.false_positive diff --git a/doc/whatsnew/fragments/3670.false_positive b/doc/whatsnew/fragments/3670.false_positive new file mode 100644 index 000000000..562a41de2 --- /dev/null +++ b/doc/whatsnew/fragments/3670.false_positive @@ -0,0 +1,3 @@ +Fix `unused-argument` false positive when `__new__` does not use all the arguments of `__init__`. + +Closes #3670 diff --git a/pylint/checkers/variables.py b/pylint/checkers/variables.py index f55b71264..79d9ded08 100644 --- a/pylint/checkers/variables.py +++ b/pylint/checkers/variables.py @@ -2602,6 +2602,16 @@ class VariablesChecker(BaseChecker): argnames = node.argnames() # Care about functions with unknown argument (builtins) if name in argnames: + if node.name == "__new__": + is_init_def = False + # Look for the `__init__` method in all the methods of the same class. + for n in node.parent.get_children(): + is_init_def = hasattr(n, "name") and (n.name == "__init__") + if is_init_def: + break + # Ignore unused arguments check for `__new__` if `__init__` is defined. + if is_init_def: + return self._check_unused_arguments(name, node, stmt, argnames, nonlocal_names) else: if stmt.parent and isinstance( diff --git a/tests/functional/u/unused/unused_argument.py b/tests/functional/u/unused/unused_argument.py index b46c1e4d7..69c37feef 100644 --- a/tests/functional/u/unused/unused_argument.py +++ b/tests/functional/u/unused/unused_argument.py @@ -107,3 +107,24 @@ class Descendant(Ancestor): def set_thing(self, thing, *, other=None): """Subclass does not raise unused-argument""" self.thing = thing + + +# Test that Class with both `__init__` and `__new__` don't check +# on `__new__` for unused arguments + +# pylint: disable=invalid-name + +class TestClassWithInitAndNew: + def __init__(self, argA, argB): + self.argA = argA + self.argB = argB + + def __new__(cls, argA, argB): + return object.__new__(cls) + +# Test that `__new__` method is checked for unused arguments +# when `__init__` is not in the Class + +class TestClassWithOnlyNew: + def __new__(cls, argA, argB): # [unused-argument, unused-argument] + return object.__new__(cls) diff --git a/tests/functional/u/unused/unused_argument.txt b/tests/functional/u/unused/unused_argument.txt index 19c439304..bca2700ac 100644 --- a/tests/functional/u/unused/unused_argument.txt +++ b/tests/functional/u/unused/unused_argument.txt @@ -7,3 +7,5 @@ unused-argument:73:0:None:None:AAAA.selected:Unused argument 'args':INFERENCE unused-argument:73:0:None:None:AAAA.selected:Unused argument 'kwargs':INFERENCE unused-argument:92:23:92:26:BBBB.__init__:Unused argument 'arg':INFERENCE unused-argument:103:34:103:39:Ancestor.set_thing:Unused argument 'other':INFERENCE +unused-argument:129:21:129:25:TestClassWithOnlyNew.__new__:Unused argument 'argA':INFERENCE +unused-argument:129:27:129:31:TestClassWithOnlyNew.__new__:Unused argument 'argB':INFERENCE -- cgit v1.2.1 From 011c6ac1a4efa41ce82fb230ca06f97ae50d662e Mon Sep 17 00:00:00 2001 From: "Yilei \"Dolee\" Yang" Date: Fri, 7 Apr 2023 00:06:54 -0700 Subject: Do not emit `logging-not-lazy` for explicitly concatenated strings. (#8546) (cherry picked from commit eeddd667a6e73ef58fb47cdda154c1751f0ffe71) --- doc/whatsnew/fragments/8410.false_positive | 3 +++ pylint/checkers/logging.py | 15 ++++++++++++++- tests/functional/l/logging/logging_not_lazy.py | 7 ++++++- tests/functional/l/logging/logging_not_lazy.txt | 12 ++++++------ 4 files changed, 29 insertions(+), 8 deletions(-) create mode 100644 doc/whatsnew/fragments/8410.false_positive diff --git a/doc/whatsnew/fragments/8410.false_positive b/doc/whatsnew/fragments/8410.false_positive new file mode 100644 index 000000000..264542a7d --- /dev/null +++ b/doc/whatsnew/fragments/8410.false_positive @@ -0,0 +1,3 @@ +`logging-not-lazy` is not longer emitted for explicitly concatenated string arguments. + +Closes #8410 diff --git a/pylint/checkers/logging.py b/pylint/checkers/logging.py index f7568a3a4..3064dc926 100644 --- a/pylint/checkers/logging.py +++ b/pylint/checkers/logging.py @@ -246,7 +246,7 @@ class LoggingChecker(checkers.BaseChecker): if isinstance(format_arg, nodes.BinOp): binop = format_arg emit = binop.op == "%" - if binop.op == "+": + if binop.op == "+" and not self._is_node_explicit_str_concatenation(binop): total_number_of_strings = sum( 1 for operand in (binop.left, binop.right) @@ -294,6 +294,19 @@ class LoggingChecker(checkers.BaseChecker): """Return True if the operand in argument is a literal string.""" return isinstance(operand, nodes.Const) and operand.name == "str" + @staticmethod + def _is_node_explicit_str_concatenation(node: nodes.NodeNG) -> bool: + """Return True if the node represents an explicitly concatenated string.""" + if not isinstance(node, nodes.BinOp): + return False + return ( + LoggingChecker._is_operand_literal_str(node.left) + or LoggingChecker._is_node_explicit_str_concatenation(node.left) + ) and ( + LoggingChecker._is_operand_literal_str(node.right) + or LoggingChecker._is_node_explicit_str_concatenation(node.right) + ) + def _check_call_func(self, node: nodes.Call) -> None: """Checks that function call is not format_string.format().""" func = utils.safe_infer(node.func) diff --git a/tests/functional/l/logging/logging_not_lazy.py b/tests/functional/l/logging/logging_not_lazy.py index ab1ce008c..aa2401dbc 100644 --- a/tests/functional/l/logging/logging_not_lazy.py +++ b/tests/functional/l/logging/logging_not_lazy.py @@ -9,10 +9,10 @@ var = "123" var_name = "Var:" # Statements that should be flagged: renamed_logging.warn("%s, %s" % (4, 5)) # [logging-not-lazy] +renamed_logging.warn("Var: " + var) # [logging-not-lazy] renamed_logging.exception("%s" % "Exceptional!") # [logging-not-lazy] renamed_logging.log(renamed_logging.INFO, "msg: %s" % "Run!") # [logging-not-lazy] renamed_logging.log(renamed_logging.INFO, "Var: " + var) # [logging-not-lazy] -renamed_logging.warn("%s" + " the rest of a single string") # [logging-not-lazy] renamed_logging.log(renamed_logging.INFO, var_name + var) # [logging-not-lazy] # Statements that should not be flagged: @@ -21,6 +21,11 @@ renamed_logging.log(renamed_logging.INFO, "msg: %s", "Run!") logging.warn("%s, %s" % (4, 5)) logging.log(logging.INFO, "msg: %s" % "Run!") logging.log("Var: " + var) +# Explicit string concatenations are fine: +renamed_logging.warn("%s" + " the rest of a single string") +renamed_logging.warn("Msg: " + "%s", "first piece " + "second piece") +renamed_logging.warn("first" + "second" + "third %s", "parameter") +renamed_logging.warn(("first" + "second" + "third %s")) # Regression crash test for incorrect format call renamed_logging.error( diff --git a/tests/functional/l/logging/logging_not_lazy.txt b/tests/functional/l/logging/logging_not_lazy.txt index 564fa65c3..774082eb7 100644 --- a/tests/functional/l/logging/logging_not_lazy.txt +++ b/tests/functional/l/logging/logging_not_lazy.txt @@ -1,8 +1,8 @@ logging-not-lazy:11:0:11:39::Use lazy % formatting in logging functions:UNDEFINED -logging-not-lazy:12:0:12:48::Use lazy % formatting in logging functions:UNDEFINED -logging-not-lazy:13:0:13:61::Use lazy % formatting in logging functions:UNDEFINED -logging-not-lazy:14:0:14:56::Use lazy % formatting in logging functions:UNDEFINED -logging-not-lazy:15:0:15:59::Use lazy % formatting in logging functions:UNDEFINED +logging-not-lazy:12:0:12:35::Use lazy % formatting in logging functions:UNDEFINED +logging-not-lazy:13:0:13:48::Use lazy % formatting in logging functions:UNDEFINED +logging-not-lazy:14:0:14:61::Use lazy % formatting in logging functions:UNDEFINED +logging-not-lazy:15:0:15:56::Use lazy % formatting in logging functions:UNDEFINED logging-not-lazy:16:0:16:57::Use lazy % formatting in logging functions:UNDEFINED -bad-format-string:27:4:27:27::Invalid format string:UNDEFINED -logging-format-interpolation:27:4:27:27::Use lazy % formatting in logging functions:UNDEFINED +bad-format-string:32:4:32:27::Invalid format string:UNDEFINED +logging-format-interpolation:32:4:32:27::Use lazy % formatting in logging functions:UNDEFINED -- cgit v1.2.1 From ed67cc806606668bec945c9b62f006d7aad02664 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Fri, 7 Apr 2023 11:53:06 +0000 Subject: Fix typelias `invalid-name` false positives for Union variables without assignment. (#8541) (#8548) (cherry picked from commit cb255eaaed8bba6bec1f7bf5d4cde15821c1dd46) Co-authored-by: Yilei "Dolee" Yang --- doc/whatsnew/fragments/8540.false_positive | 4 ++++ pylint/checkers/base/name_checker/checker.py | 5 +---- tests/functional/t/typealias_naming_style_default.py | 5 ++++- tests/functional/t/typealias_naming_style_rgx.py | 4 ++-- 4 files changed, 11 insertions(+), 7 deletions(-) create mode 100644 doc/whatsnew/fragments/8540.false_positive diff --git a/doc/whatsnew/fragments/8540.false_positive b/doc/whatsnew/fragments/8540.false_positive new file mode 100644 index 000000000..543913637 --- /dev/null +++ b/doc/whatsnew/fragments/8540.false_positive @@ -0,0 +1,4 @@ +`Union` typed variables without assignment are no longer treated as +`TypeAlias`. + +Closes #8540 diff --git a/pylint/checkers/base/name_checker/checker.py b/pylint/checkers/base/name_checker/checker.py index c2b615a48..58f7198ef 100644 --- a/pylint/checkers/base/name_checker/checker.py +++ b/pylint/checkers/base/name_checker/checker.py @@ -602,10 +602,7 @@ class NameChecker(_BasicChecker): # 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 - return not ( - isinstance(node.parent, nodes.AnnAssign) - and node.parent.value is not None - ) + return not isinstance(node.parent, nodes.AnnAssign) elif isinstance(inferred, nodes.FunctionDef): if inferred.qname() == "typing.TypeAlias": return True diff --git a/tests/functional/t/typealias_naming_style_default.py b/tests/functional/t/typealias_naming_style_default.py index 6b27c14a0..8baabb49c 100644 --- a/tests/functional/t/typealias_naming_style_default.py +++ b/tests/functional/t/typealias_naming_style_default.py @@ -26,5 +26,8 @@ _1BadName = Union[int, str] # [invalid-name] ANOTHERBADNAME = Union[int, str] # [invalid-name] # Regression tests -# This is not a TypeAlias, and thus shouldn't flag the message +# They are not TypeAlias, and thus shouldn't flag the message x: Union[str, int] = 42 +y: Union[str, int] +# But the following, using a good TypeAlias name, is: +GoodTypeAliasToUnion: TypeAlias = Union[str, int] diff --git a/tests/functional/t/typealias_naming_style_rgx.py b/tests/functional/t/typealias_naming_style_rgx.py index 0910644da..bc43b930d 100644 --- a/tests/functional/t/typealias_naming_style_rgx.py +++ b/tests/functional/t/typealias_naming_style_rgx.py @@ -3,8 +3,8 @@ from typing import TypeAlias, Union # Valid TypeAliasShouldBeLikeThis: TypeAlias = int -_TypeAliasShouldBeLikeThis: Union[str, int] +_TypeAliasShouldBeLikeThis = Union[str, int] # Invalid TypeAliasShouldntBeLikeThis: TypeAlias = int # [invalid-name] -_TypeAliasShouldntBeLikeThis: Union[str, int] # [invalid-name] +_TypeAliasShouldntBeLikeThis = Union[str, int] # [invalid-name] -- cgit v1.2.1 From bcceff6be5903d8f3c203c59906b7fd46d72b499 Mon Sep 17 00:00:00 2001 From: Rogdham Date: Fri, 7 Apr 2023 18:54:23 +0200 Subject: Fix isinstance-second-argument-not-valid-type for union types with None (cherry picked from commit b5f2b01635edd23fecc1546f3fdb2a41e6a51995) --- doc/whatsnew/fragments/8424.false_positive | 3 +++ pylint/checkers/typecheck.py | 13 ++++++++----- tests/functional/i/isinstance_second_argument_py310.py | 6 +++++- tests/functional/i/isinstance_second_argument_py310.txt | 6 +++--- 4 files changed, 19 insertions(+), 9 deletions(-) create mode 100644 doc/whatsnew/fragments/8424.false_positive diff --git a/doc/whatsnew/fragments/8424.false_positive b/doc/whatsnew/fragments/8424.false_positive new file mode 100644 index 000000000..22dc8b844 --- /dev/null +++ b/doc/whatsnew/fragments/8424.false_positive @@ -0,0 +1,3 @@ +Fix false positive for isinstance-second-argument-not-valid-type when union types contains None. + +Closes #8424 diff --git a/pylint/checkers/typecheck.py b/pylint/checkers/typecheck.py index 8e00384d7..0c8c44a15 100644 --- a/pylint/checkers/typecheck.py +++ b/pylint/checkers/typecheck.py @@ -37,6 +37,7 @@ from pylint.checkers.utils import ( is_mapping, is_module_ignored, is_node_in_type_annotation_context, + is_none, is_overload_stub, is_postponed_evaluation_enabled, is_super, @@ -798,8 +799,9 @@ def _is_c_extension(module_node: InferenceResult) -> bool: def _is_invalid_isinstance_type(arg: nodes.NodeNG) -> bool: # Return True if we are sure that arg is not a type if PY310_PLUS and isinstance(arg, nodes.BinOp) and arg.op == "|": - return _is_invalid_isinstance_type(arg.left) or _is_invalid_isinstance_type( - arg.right + return any( + _is_invalid_isinstance_type(elt) and not is_none(elt) + for elt in (arg.left, arg.right) ) inferred = utils.safe_infer(arg) if not inferred: @@ -812,9 +814,10 @@ def _is_invalid_isinstance_type(arg: nodes.NodeNG) -> bool: if isinstance(inferred, astroid.Instance) and inferred.qname() == BUILTIN_TUPLE: return False if PY310_PLUS and isinstance(inferred, bases.UnionType): - return _is_invalid_isinstance_type( - inferred.left - ) or _is_invalid_isinstance_type(inferred.right) + return any( + _is_invalid_isinstance_type(elt) and not is_none(elt) + for elt in (inferred.left, inferred.right) + ) return True diff --git a/tests/functional/i/isinstance_second_argument_py310.py b/tests/functional/i/isinstance_second_argument_py310.py index 8a0c17af5..ad2033b31 100644 --- a/tests/functional/i/isinstance_second_argument_py310.py +++ b/tests/functional/i/isinstance_second_argument_py310.py @@ -1,13 +1,17 @@ -'''Tests for invalid isinstance with compound types''' +"""Tests for invalid isinstance with compound types""" # True negatives isinstance(0, int | str) isinstance(0, int | int | int) isinstance(0, int | str | list | float) isinstance(0, (int | str) | (list | float)) +isinstance(0, int | None) +isinstance(0, None | int) IntOrStr = int | str isinstance(0, IntOrStr) +IntOrNone = int | None +isinstance(0, IntOrNone) ListOrDict = list | dict isinstance(0, (float | ListOrDict) | IntOrStr) diff --git a/tests/functional/i/isinstance_second_argument_py310.txt b/tests/functional/i/isinstance_second_argument_py310.txt index 776bf3c2e..aa50da29d 100644 --- a/tests/functional/i/isinstance_second_argument_py310.txt +++ b/tests/functional/i/isinstance_second_argument_py310.txt @@ -1,3 +1,3 @@ -isinstance-second-argument-not-valid-type:15:0:15:22::Second argument of isinstance is not a type:INFERENCE -isinstance-second-argument-not-valid-type:16:0:16:28::Second argument of isinstance is not a type:INFERENCE -isinstance-second-argument-not-valid-type:18:0:18:24::Second argument of isinstance is not a type:INFERENCE +isinstance-second-argument-not-valid-type:19:0:19:22::Second argument of isinstance is not a type:INFERENCE +isinstance-second-argument-not-valid-type:20:0:20:28::Second argument of isinstance is not a type:INFERENCE +isinstance-second-argument-not-valid-type:22:0:22:24::Second argument of isinstance is not a type:INFERENCE -- cgit v1.2.1 From 61dae1e5f4fa4b8f2f93d8846e66f4eee6cc877f Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Mon, 10 Apr 2023 05:55:35 +0000 Subject: Fix false positive for ``positional-only-arguments-expected`` when a function contains both a positional-only parameter that has a default value, and ``**kwargs``. (#8556) (#8560) (cherry picked from commit db17860fd61154c59f3acc13ff34b120cc5ba091) Co-authored-by: Mark Byrne <31762852+mbyrnepr2@users.noreply.github.com> --- doc/whatsnew/fragments/8555.false_positive | 3 +++ pylint/checkers/method_args.py | 2 ++ .../functional/p/positional_only_arguments_expected.py | 18 ++++++++++++++++++ 3 files changed, 23 insertions(+) create mode 100644 doc/whatsnew/fragments/8555.false_positive diff --git a/doc/whatsnew/fragments/8555.false_positive b/doc/whatsnew/fragments/8555.false_positive new file mode 100644 index 000000000..157486b39 --- /dev/null +++ b/doc/whatsnew/fragments/8555.false_positive @@ -0,0 +1,3 @@ +Fix false positive for ``positional-only-arguments-expected`` when a function contains both a positional-only parameter that has a default value, and ``**kwargs``. + +Closes #8555 diff --git a/pylint/checkers/method_args.py b/pylint/checkers/method_args.py index e88248219..8862328e3 100644 --- a/pylint/checkers/method_args.py +++ b/pylint/checkers/method_args.py @@ -111,6 +111,8 @@ class MethodArgsChecker(BaseChecker): and inferred_func.args.posonlyargs ): return + if inferred_func.args.kwarg: + return pos_args = [a.name for a in inferred_func.args.posonlyargs] kws = [k.arg for k in node.keywords if k.arg in pos_args] if not kws: diff --git a/tests/functional/p/positional_only_arguments_expected.py b/tests/functional/p/positional_only_arguments_expected.py index 7bde59ab8..98a2d65f5 100644 --- a/tests/functional/p/positional_only_arguments_expected.py +++ b/tests/functional/p/positional_only_arguments_expected.py @@ -16,3 +16,21 @@ 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): + """ + Calling this function with the `banana` keyword should not emit + `positional-only-arguments-expected` since it is added to `**kwargs`. + + >>> function_with_kwargs("Red apple", banana="Green banana") + >>> "Red apple" + >>> "Yellow banana" + >>> {"banana": "Green banana"} + """ + print(apple) + print(banana) + print(kwargs) + + +function_with_kwargs("Red apple", banana="Green banana") -- cgit v1.2.1 From 16fe498b68c170b317eaea94bf85efd568a1dd0a Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Wed, 12 Apr 2023 17:34:34 +0200 Subject: Fix `unused-import` to check`dummy-variables-rgx` (#8566) (#8568) Resolve #8500 Co-authored-by: Pierre Sassoulas (cherry picked from commit 0cd41b1fb15e31eb311b61f93bc27f7cacc2f7ac) Co-authored-by: RSTdefg <34202999+RSTdefg@users.noreply.github.com> --- doc/whatsnew/fragments/8500.false_positive | 3 +++ pylint/checkers/variables.py | 15 +++++++++++---- tests/checkers/unittest_typecheck.py | 2 +- tests/functional/i/import_dummy.py | 5 +++++ 4 files changed, 20 insertions(+), 5 deletions(-) create mode 100644 doc/whatsnew/fragments/8500.false_positive create mode 100644 tests/functional/i/import_dummy.py diff --git a/doc/whatsnew/fragments/8500.false_positive b/doc/whatsnew/fragments/8500.false_positive new file mode 100644 index 000000000..ced61766a --- /dev/null +++ b/doc/whatsnew/fragments/8500.false_positive @@ -0,0 +1,3 @@ +Fixed `unused-import` so that it observes the `dummy-variables-rgx` option. + +Closes #8500 diff --git a/pylint/checkers/variables.py b/pylint/checkers/variables.py index 79d9ded08..8cd1ed83c 100644 --- a/pylint/checkers/variables.py +++ b/pylint/checkers/variables.py @@ -3062,6 +3062,13 @@ class VariablesChecker(BaseChecker): imported_name in self._type_annotation_names or as_name in self._type_annotation_names ) + + is_dummy_import = ( + as_name + and self.linter.config.dummy_variables_rgx + and self.linter.config.dummy_variables_rgx.match(as_name) + ) + if isinstance(stmt, nodes.Import) or ( isinstance(stmt, nodes.ImportFrom) and not stmt.modname ): @@ -3072,12 +3079,11 @@ class VariablesChecker(BaseChecker): # because they can be imported for exporting. continue - if is_type_annotation_import: + if is_type_annotation_import or is_dummy_import: # Most likely a typing import if it wasn't used so far. + # Also filter dummy variables. continue - if as_name == "_": - continue if as_name is None: msg = f"import {imported_name}" else: @@ -3095,8 +3101,9 @@ class VariablesChecker(BaseChecker): # __future__ import in another module. continue - if is_type_annotation_import: + if is_type_annotation_import or is_dummy_import: # Most likely a typing import if it wasn't used so far. + # Also filter dummy variables. continue if imported_name == "*": diff --git a/tests/checkers/unittest_typecheck.py b/tests/checkers/unittest_typecheck.py index afcc2dc2e..dba69eaf3 100644 --- a/tests/checkers/unittest_typecheck.py +++ b/tests/checkers/unittest_typecheck.py @@ -10,7 +10,7 @@ from pylint.interfaces import INFERENCE, UNDEFINED from pylint.testutils import CheckerTestCase, MessageTest, set_config try: - from coverage import tracer as _ # pylint: disable=unused-import + from coverage import tracer as _ C_EXTENTIONS_AVAILABLE = True except ImportError: diff --git a/tests/functional/i/import_dummy.py b/tests/functional/i/import_dummy.py new file mode 100644 index 000000000..eecfa0d8a --- /dev/null +++ b/tests/functional/i/import_dummy.py @@ -0,0 +1,5 @@ +"""Testing importing module as dummy variable.""" +import gettext as _ +import sys as __ +import typing as ___dummy +from base64 import b64encode as ____dummy -- cgit v1.2.1 From ec96bdc206350e378137da27c2f4cd103a94dc63 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Sat, 15 Apr 2023 10:38:55 +0200 Subject: Fix false positive for ``keyword-arg-before-vararg`` (#8571) (#8578) * Fix false positive for ``keyword-arg-before-vararg`` when a positional-only parameter with a default value precedes ``*args``. Closes #8570 (cherry picked from commit 56fa5dce747a46f1dcba6eca003bb22fcc347247) Co-authored-by: Mark Byrne <31762852+mbyrnepr2@users.noreply.github.com> --- doc/whatsnew/fragments/8570.false_positive | 3 +++ pylint/checkers/typecheck.py | 8 +++++++- .../k/keyword_arg_before_vararg_positional_only.py | 13 +++++++++++++ .../k/keyword_arg_before_vararg_positional_only.rc | 2 ++ .../k/keyword_arg_before_vararg_positional_only.txt | 3 +++ 5 files changed, 28 insertions(+), 1 deletion(-) create mode 100644 doc/whatsnew/fragments/8570.false_positive create mode 100644 tests/functional/k/keyword_arg_before_vararg_positional_only.py create mode 100644 tests/functional/k/keyword_arg_before_vararg_positional_only.rc create mode 100644 tests/functional/k/keyword_arg_before_vararg_positional_only.txt diff --git a/doc/whatsnew/fragments/8570.false_positive b/doc/whatsnew/fragments/8570.false_positive new file mode 100644 index 000000000..fec3a855e --- /dev/null +++ b/doc/whatsnew/fragments/8570.false_positive @@ -0,0 +1,3 @@ +Fix false positive for ``keyword-arg-before-vararg`` when a positional-only parameter with a default value precedes ``*args``. + +Closes #8570 diff --git a/pylint/checkers/typecheck.py b/pylint/checkers/typecheck.py index 0c8c44a15..1a628f231 100644 --- a/pylint/checkers/typecheck.py +++ b/pylint/checkers/typecheck.py @@ -1001,8 +1001,14 @@ accessed. Python regular expressions are accepted.", @only_required_for_messages("keyword-arg-before-vararg") def visit_functiondef(self, node: nodes.FunctionDef) -> None: - # check for keyword arg before varargs + # check for keyword arg before varargs. + if node.args.vararg and node.args.defaults: + # When `positional-only` parameters are present then only + # `positional-or-keyword` parameters are checked. I.e: + # >>> def name(pos_only_params, /, pos_or_keyword_params, *args): ... + if node.args.posonlyargs and not node.args.args: + return self.add_message("keyword-arg-before-vararg", node=node, args=(node.name)) visit_asyncfunctiondef = visit_functiondef diff --git a/tests/functional/k/keyword_arg_before_vararg_positional_only.py b/tests/functional/k/keyword_arg_before_vararg_positional_only.py new file mode 100644 index 000000000..70b5f9929 --- /dev/null +++ b/tests/functional/k/keyword_arg_before_vararg_positional_only.py @@ -0,0 +1,13 @@ +"""Test `keyword-arg-before-vararg` in the context of positional-only parameters""" + +# pylint: disable=missing-function-docstring, unused-argument + + +def name1(param1, /, param2=True, *args): ... # [keyword-arg-before-vararg] +def name2(param1=True, /, param2=True, *args): ... # [keyword-arg-before-vararg] +def name3(param1, param2=True, /, param3=True, *args): ... # [keyword-arg-before-vararg] +def name4(param1, /, *args): ... +def name5(param1=True, /, *args): ... +def name6(param1, /, *args, param2=True): ... +def name7(param1=True, /, *args, param2=True): ... +def name8(param1, param2=True, /, *args, param3=True): ... diff --git a/tests/functional/k/keyword_arg_before_vararg_positional_only.rc b/tests/functional/k/keyword_arg_before_vararg_positional_only.rc new file mode 100644 index 000000000..85fc502b3 --- /dev/null +++ b/tests/functional/k/keyword_arg_before_vararg_positional_only.rc @@ -0,0 +1,2 @@ +[testoptions] +min_pyver=3.8 diff --git a/tests/functional/k/keyword_arg_before_vararg_positional_only.txt b/tests/functional/k/keyword_arg_before_vararg_positional_only.txt new file mode 100644 index 000000000..18700e2e4 --- /dev/null +++ b/tests/functional/k/keyword_arg_before_vararg_positional_only.txt @@ -0,0 +1,3 @@ +keyword-arg-before-vararg:6:0:6:9:name1:Keyword argument before variable positional arguments list in the definition of name1 function:UNDEFINED +keyword-arg-before-vararg:7:0:7:9:name2:Keyword argument before variable positional arguments list in the definition of name2 function:UNDEFINED +keyword-arg-before-vararg:8:0:8:9:name3:Keyword argument before variable positional arguments list in the definition of name3 function:UNDEFINED -- cgit v1.2.1 From 1dba30b43ce7d2c43e6cc94120d8daca5d9ddabd Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Mon, 17 Apr 2023 07:25:14 +0000 Subject: Improve output of `consider-using-generator` message for `min()` calls with `default` keyword (#8582) (#8583) (cherry picked from commit 4a485e28f0a5118b37550123c79f1f6d0dec42a4) Co-authored-by: Jacob Walls --- doc/whatsnew/fragments/8563.bugfix | 3 +++ pylint/checkers/refactoring/refactoring_checker.py | 6 +++++- tests/functional/c/consider/consider_using_generator.py | 5 +++++ tests/functional/c/consider/consider_using_generator.txt | 1 + 4 files changed, 14 insertions(+), 1 deletion(-) create mode 100644 doc/whatsnew/fragments/8563.bugfix diff --git a/doc/whatsnew/fragments/8563.bugfix b/doc/whatsnew/fragments/8563.bugfix new file mode 100644 index 000000000..3c9d38b1c --- /dev/null +++ b/doc/whatsnew/fragments/8563.bugfix @@ -0,0 +1,3 @@ +Improve output of ``consider-using-generator`` message for ``min()` calls with ``default`` keyword. + +Closes #8563 diff --git a/pylint/checkers/refactoring/refactoring_checker.py b/pylint/checkers/refactoring/refactoring_checker.py index b0a87b4c9..ec4d3d71e 100644 --- a/pylint/checkers/refactoring/refactoring_checker.py +++ b/pylint/checkers/refactoring/refactoring_checker.py @@ -1070,11 +1070,15 @@ class RefactoringChecker(checkers.BaseTokenChecker): and isinstance(node.func, nodes.Name) and node.func.name in checked_call ): - # functions in checked_calls take exactly one argument + # functions in checked_calls take exactly one positional argument # check whether the argument is list comprehension if len(node.args) == 1 and isinstance(node.args[0], nodes.ListComp): # remove square brackets '[]' inside_comp = node.args[0].as_string()[1:-1] + if node.keywords: + inside_comp = f"({inside_comp})" + inside_comp += ", " + inside_comp += ", ".join(kw.as_string() for kw in node.keywords) call_name = node.func.name if call_name in {"any", "all"}: self.add_message( diff --git a/tests/functional/c/consider/consider_using_generator.py b/tests/functional/c/consider/consider_using_generator.py index e5ac31f32..ee561a7e9 100644 --- a/tests/functional/c/consider/consider_using_generator.py +++ b/tests/functional/c/consider/consider_using_generator.py @@ -18,3 +18,8 @@ tuple(0 for y in list(range(10))) sum(x*x for x in range(10)) min(x*x for x in range(10)) max(x*x for x in range(10)) + +# Keyword arguments +# https://github.com/pylint-dev/pylint/issues/8563 +min([x*x for x in range(10)], default=42) # [consider-using-generator] +min((x*x for x in range(10)), default=42) diff --git a/tests/functional/c/consider/consider_using_generator.txt b/tests/functional/c/consider/consider_using_generator.txt index 2c89a8d7e..8a2a4ec6d 100644 --- a/tests/functional/c/consider/consider_using_generator.txt +++ b/tests/functional/c/consider/consider_using_generator.txt @@ -3,3 +3,4 @@ consider-using-generator:11:0:11:35::Consider using a generator instead 'tuple(0 consider-using-generator:12:0:12:29::Consider using a generator instead 'sum(x * x for x in range(10))':UNDEFINED consider-using-generator:13:0:13:29::Consider using a generator instead 'min(x * x for x in range(10))':UNDEFINED consider-using-generator:14:0:14:29::Consider using a generator instead 'max(x * x for x in range(10))':UNDEFINED +consider-using-generator:24:0:24:41::Consider using a generator instead 'min((x * x for x in range(10)), default=42)':UNDEFINED -- cgit v1.2.1 From 5f7e2a51bf008b0bb4acf2ecbcadcf1c903a72f4 Mon Sep 17 00:00:00 2001 From: Pierre Sassoulas Date: Sun, 23 Apr 2023 13:35:32 +0200 Subject: Upgrade astroid to 2.15.3 (#8584) Co-authored-by: Marc Mueller <30130371+cdce8p@users.noreply.github.com> (cherry picked from commit 3d036b78fca6e80222f9ca2ffd0f25950d261aed) --- pyproject.toml | 2 +- requirements_test_min.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 559341011..09142f42b 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -39,7 +39,7 @@ dependencies = [ # Also upgrade requirements_test_min.txt. # Pinned to dev of second minor update to allow editable installs and fix primer issues, # see https://github.com/pylint-dev/astroid/issues/1341 - "astroid>=2.15.2,<=2.17.0-dev0", + "astroid>=2.15.3,<=2.17.0-dev0", "isort>=4.2.5,<6", "mccabe>=0.6,<0.8", "tomli>=1.1.0;python_version<'3.11'", diff --git a/requirements_test_min.txt b/requirements_test_min.txt index 08321b54f..801bd5831 100644 --- a/requirements_test_min.txt +++ b/requirements_test_min.txt @@ -1,6 +1,6 @@ -e .[testutils,spelling] # astroid dependency is also defined in pyproject.toml -astroid==2.15.2 # Pinned to a specific version for tests +astroid==2.15.3 # Pinned to a specific version for tests typing-extensions~=4.5 py~=1.11.0 pytest~=7.2 -- cgit v1.2.1 From c2936a541f570a4a854672cbb4899651d39d6088 Mon Sep 17 00:00:00 2001 From: Marc Mueller <30130371+cdce8p@users.noreply.github.com> Date: Sun, 23 Apr 2023 12:24:09 +0200 Subject: Disable import-error as attrs is no longer a test dependency --- tests/functional/r/regression/regression_4439.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/functional/r/regression/regression_4439.py b/tests/functional/r/regression/regression_4439.py index 257a20a86..dd9c39253 100644 --- a/tests/functional/r/regression/regression_4439.py +++ b/tests/functional/r/regression/regression_4439.py @@ -7,7 +7,7 @@ from typing import Optional -from attr import attrib, attrs +from attr import attrib, attrs # pylint: disable=import-error @attrs() -- cgit v1.2.1 From 3fc153ac67f8264275f846bc25daccc57a8f8a5a Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Mon, 24 Apr 2023 15:14:01 +0000 Subject: Upgrade astroid to 2.15.4 (#8615) (#8618) Co-authored-by: Pierre Sassoulas (cherry picked from commit a83137da3d72990d41ae993128fdde297cbc36cf) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- pyproject.toml | 2 +- requirements_test_min.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 09142f42b..bd542646b 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -39,7 +39,7 @@ dependencies = [ # Also upgrade requirements_test_min.txt. # Pinned to dev of second minor update to allow editable installs and fix primer issues, # see https://github.com/pylint-dev/astroid/issues/1341 - "astroid>=2.15.3,<=2.17.0-dev0", + "astroid>=2.15.4,<=2.17.0-dev0", "isort>=4.2.5,<6", "mccabe>=0.6,<0.8", "tomli>=1.1.0;python_version<'3.11'", diff --git a/requirements_test_min.txt b/requirements_test_min.txt index 801bd5831..499d287f6 100644 --- a/requirements_test_min.txt +++ b/requirements_test_min.txt @@ -1,6 +1,6 @@ -e .[testutils,spelling] # astroid dependency is also defined in pyproject.toml -astroid==2.15.3 # Pinned to a specific version for tests +astroid==2.15.4 # Pinned to a specific version for tests typing-extensions~=4.5 py~=1.11.0 pytest~=7.2 -- cgit v1.2.1 From 389e14c36819cb87190fd412d3f366a3283f0078 Mon Sep 17 00:00:00 2001 From: Pierre Sassoulas Date: Mon, 24 Apr 2023 20:17:48 +0200 Subject: Bump pylint to 2.17.3, update changelog (#8620) --- CONTRIBUTORS.txt | 4 +-- doc/whatsnew/2/2.17/index.rst | 58 ++++++++++++++++++++++++++++++ doc/whatsnew/fragments/3670.false_positive | 3 -- doc/whatsnew/fragments/7506.false_positive | 3 -- doc/whatsnew/fragments/8410.false_positive | 3 -- doc/whatsnew/fragments/8424.false_positive | 3 -- doc/whatsnew/fragments/8500.false_positive | 3 -- doc/whatsnew/fragments/8540.false_positive | 4 --- doc/whatsnew/fragments/8555.false_positive | 3 -- doc/whatsnew/fragments/8563.bugfix | 3 -- doc/whatsnew/fragments/8570.false_positive | 3 -- pylint/__pkginfo__.py | 2 +- tbump.toml | 2 +- towncrier.toml | 2 +- 14 files changed, 63 insertions(+), 33 deletions(-) delete mode 100644 doc/whatsnew/fragments/3670.false_positive delete mode 100644 doc/whatsnew/fragments/7506.false_positive delete mode 100644 doc/whatsnew/fragments/8410.false_positive delete mode 100644 doc/whatsnew/fragments/8424.false_positive delete mode 100644 doc/whatsnew/fragments/8500.false_positive delete mode 100644 doc/whatsnew/fragments/8540.false_positive delete mode 100644 doc/whatsnew/fragments/8555.false_positive delete mode 100644 doc/whatsnew/fragments/8563.bugfix delete mode 100644 doc/whatsnew/fragments/8570.false_positive diff --git a/CONTRIBUTORS.txt b/CONTRIBUTORS.txt index 59af3e059..2de0c8d4a 100644 --- a/CONTRIBUTORS.txt +++ b/CONTRIBUTORS.txt @@ -130,10 +130,10 @@ contributors: - Eli Fine (eli88fine): Fixed false positive duplicate code warning for lines with symbols only - Andrew Haigh (nelfin) - Émile Crater +- Yilei "Dolee" Yang - Pavel Roskin - David Gilman - へーさん -- Yilei "Dolee" Yang - Thomas Hisch - Marianna Polatoglou : minor contribution for wildcard import check - Manuel Vázquez Acosta @@ -206,6 +206,7 @@ contributors: - chohner - Tiago Honorato <61059243+tiagohonorato@users.noreply.github.com> - Steven M. Vascellaro +- Rogdham - Robin Tweedie <70587124+robin-wayve@users.noreply.github.com> - Roberto Leinardi : PyCharm plugin maintainer - Ricardo Gemignani @@ -254,7 +255,6 @@ contributors: - Scott Worley - Saugat Pachhai - Rémi Cardona -- Rogdham - Raphael Gaschignard - Ram Rachum (cool-RR) - Radostin Stoyanov diff --git a/doc/whatsnew/2/2.17/index.rst b/doc/whatsnew/2/2.17/index.rst index cd06bbc2e..974ebb501 100644 --- a/doc/whatsnew/2/2.17/index.rst +++ b/doc/whatsnew/2/2.17/index.rst @@ -29,6 +29,64 @@ so we find problems before the actual release. .. towncrier release notes start +What's new in Pylint 2.17.3? +---------------------------- +Release date: 2023-04-24 + + +False Positives Fixed +--------------------- + +- Fix `unused-argument` false positive when `__new__` does not use all the + arguments of `__init__`. + + Closes #3670 (`#3670 `_) + +- Fix ``unused-import`` false positive for usage of ``six.with_metaclass``. + + Closes #7506 (`#7506 `_) + +- `logging-not-lazy` is not longer emitted for explicitly concatenated string + arguments. + + Closes #8410 (`#8410 `_) + +- Fix false positive for isinstance-second-argument-not-valid-type when union + types contains None. + + Closes #8424 (`#8424 `_) + +- Fixed `unused-import` so that it observes the `dummy-variables-rgx` option. + + Closes #8500 (`#8500 `_) + +- `Union` typed variables without assignment are no longer treated as + `TypeAlias`. + + Closes #8540 (`#8540 `_) + +- Fix false positive for ``positional-only-arguments-expected`` when a function + contains both a positional-only parameter that has a default value, and + ``**kwargs``. + + Closes #8555 (`#8555 `_) + +- Fix false positive for ``keyword-arg-before-vararg`` when a positional-only + parameter with a default value precedes ``*args``. + + Closes #8570 (`#8570 `_) + + + +Other Bug Fixes +--------------- + +- Improve output of ``consider-using-generator`` message for ``min()` calls + with ``default`` keyword. + + Closes #8563 (`#8563 `_) + + What's new in Pylint 2.17.2? ---------------------------- Release date: 2023-04-03 diff --git a/doc/whatsnew/fragments/3670.false_positive b/doc/whatsnew/fragments/3670.false_positive deleted file mode 100644 index 562a41de2..000000000 --- a/doc/whatsnew/fragments/3670.false_positive +++ /dev/null @@ -1,3 +0,0 @@ -Fix `unused-argument` false positive when `__new__` does not use all the arguments of `__init__`. - -Closes #3670 diff --git a/doc/whatsnew/fragments/7506.false_positive b/doc/whatsnew/fragments/7506.false_positive deleted file mode 100644 index c6424e1f2..000000000 --- a/doc/whatsnew/fragments/7506.false_positive +++ /dev/null @@ -1,3 +0,0 @@ -Fix ``unused-import`` false positive for usage of ``six.with_metaclass``. - -Closes #7506 diff --git a/doc/whatsnew/fragments/8410.false_positive b/doc/whatsnew/fragments/8410.false_positive deleted file mode 100644 index 264542a7d..000000000 --- a/doc/whatsnew/fragments/8410.false_positive +++ /dev/null @@ -1,3 +0,0 @@ -`logging-not-lazy` is not longer emitted for explicitly concatenated string arguments. - -Closes #8410 diff --git a/doc/whatsnew/fragments/8424.false_positive b/doc/whatsnew/fragments/8424.false_positive deleted file mode 100644 index 22dc8b844..000000000 --- a/doc/whatsnew/fragments/8424.false_positive +++ /dev/null @@ -1,3 +0,0 @@ -Fix false positive for isinstance-second-argument-not-valid-type when union types contains None. - -Closes #8424 diff --git a/doc/whatsnew/fragments/8500.false_positive b/doc/whatsnew/fragments/8500.false_positive deleted file mode 100644 index ced61766a..000000000 --- a/doc/whatsnew/fragments/8500.false_positive +++ /dev/null @@ -1,3 +0,0 @@ -Fixed `unused-import` so that it observes the `dummy-variables-rgx` option. - -Closes #8500 diff --git a/doc/whatsnew/fragments/8540.false_positive b/doc/whatsnew/fragments/8540.false_positive deleted file mode 100644 index 543913637..000000000 --- a/doc/whatsnew/fragments/8540.false_positive +++ /dev/null @@ -1,4 +0,0 @@ -`Union` typed variables without assignment are no longer treated as -`TypeAlias`. - -Closes #8540 diff --git a/doc/whatsnew/fragments/8555.false_positive b/doc/whatsnew/fragments/8555.false_positive deleted file mode 100644 index 157486b39..000000000 --- a/doc/whatsnew/fragments/8555.false_positive +++ /dev/null @@ -1,3 +0,0 @@ -Fix false positive for ``positional-only-arguments-expected`` when a function contains both a positional-only parameter that has a default value, and ``**kwargs``. - -Closes #8555 diff --git a/doc/whatsnew/fragments/8563.bugfix b/doc/whatsnew/fragments/8563.bugfix deleted file mode 100644 index 3c9d38b1c..000000000 --- a/doc/whatsnew/fragments/8563.bugfix +++ /dev/null @@ -1,3 +0,0 @@ -Improve output of ``consider-using-generator`` message for ``min()` calls with ``default`` keyword. - -Closes #8563 diff --git a/doc/whatsnew/fragments/8570.false_positive b/doc/whatsnew/fragments/8570.false_positive deleted file mode 100644 index fec3a855e..000000000 --- a/doc/whatsnew/fragments/8570.false_positive +++ /dev/null @@ -1,3 +0,0 @@ -Fix false positive for ``keyword-arg-before-vararg`` when a positional-only parameter with a default value precedes ``*args``. - -Closes #8570 diff --git a/pylint/__pkginfo__.py b/pylint/__pkginfo__.py index beebd2492..a140a9791 100644 --- a/pylint/__pkginfo__.py +++ b/pylint/__pkginfo__.py @@ -9,7 +9,7 @@ It's updated via tbump, do not modify. from __future__ import annotations -__version__ = "2.17.2" +__version__ = "2.17.3" def get_numversion_from_version(v: str) -> tuple[int, int, int]: diff --git a/tbump.toml b/tbump.toml index 1f6594b2e..62cfd5498 100644 --- a/tbump.toml +++ b/tbump.toml @@ -1,7 +1,7 @@ github_url = "https://github.com/PyCQA/pylint" [version] -current = "2.17.2" +current = "2.17.3" regex = ''' ^(?P0|[1-9]\d*) \. diff --git a/towncrier.toml b/towncrier.toml index 35ce27243..fce326ad6 100644 --- a/towncrier.toml +++ b/towncrier.toml @@ -1,5 +1,5 @@ [tool.towncrier] -version = "2.17.2" +version = "2.17.3" directory = "doc/whatsnew/fragments" filename = "doc/whatsnew/2/2.17/index.rst" template = "doc/whatsnew/fragments/_template.rst" -- cgit v1.2.1