diff options
author | yushao2 <36848472+yushao2@users.noreply.github.com> | 2023-01-28 23:52:47 +0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2023-01-28 16:52:47 +0100 |
commit | 2cfc8f5d38a2e0ea46be7b3908729cca8c8fb8c4 (patch) | |
tree | 80e0d17cb484c51703356b86ed73d975b0417a6e /pylint | |
parent | 660405e6218258cee90570e8037c3b5e1440dcb6 (diff) | |
download | pylint-git-2cfc8f5d38a2e0ea46be7b3908729cca8c8fb8c4.tar.gz |
feat(6489): implement `positional-only-arguments-expected` checker (#8121)
* feat(6489): implement positional-only-arguments-expected checker
* Update doc/user_guide/configuration/all-options.rst
* update good/bad examples
Diffstat (limited to 'pylint')
-rw-r--r-- | pylint/checkers/method_args.py | 41 |
1 files changed, 40 insertions, 1 deletions
diff --git a/pylint/checkers/method_args.py b/pylint/checkers/method_args.py index 58fcae5c0..e88248219 100644 --- a/pylint/checkers/method_args.py +++ b/pylint/checkers/method_args.py @@ -8,6 +8,7 @@ from __future__ import annotations from typing import TYPE_CHECKING +import astroid from astroid import arguments, bases, nodes from pylint.checkers import BaseChecker, utils @@ -22,6 +23,7 @@ class MethodArgsChecker(BaseChecker): Checks for * missing-timeout + * positional-only-arguments-expected """ name = "method_args" @@ -34,6 +36,13 @@ class MethodArgsChecker(BaseChecker): "is used. For example for 'requests' the program will never time out " "(i.e. hang indefinitely).", ), + "E3102": ( + "`%s()` got some positional-only arguments passed as keyword arguments: %s", + "positional-only-arguments-expected", + "Emitted when positional-only arguments have been passed as keyword arguments. " + "Remove the keywords for the affected arguments in the function call.", + {"minversion": (3, 8)}, + ), } options = ( ( @@ -57,8 +66,14 @@ class MethodArgsChecker(BaseChecker): ), ) - @utils.only_required_for_messages("missing-timeout") + @utils.only_required_for_messages( + "missing-timeout", "positional-only-arguments-expected" + ) def visit_call(self, node: nodes.Call) -> None: + self._check_missing_timeout(node) + self._check_positional_only_arguments_expected(node) + + def _check_missing_timeout(self, node: nodes.Call) -> None: """Check if the call needs a timeout parameter based on package.func_name configured in config.timeout_methods. @@ -84,6 +99,30 @@ class MethodArgsChecker(BaseChecker): confidence=INFERENCE, ) + def _check_positional_only_arguments_expected(self, node: nodes.Call) -> None: + """Check if positional only arguments have been passed as keyword arguments by + inspecting its method definition. + """ + inferred_func = utils.safe_infer(node.func) + while isinstance(inferred_func, (astroid.BoundMethod, astroid.UnboundMethod)): + inferred_func = inferred_func._proxied + if not ( + isinstance(inferred_func, (nodes.FunctionDef)) + and inferred_func.args.posonlyargs + ): + 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: + return + + self.add_message( + "positional-only-arguments-expected", + node=node, + args=(node.func.as_string(), ", ".join(f"'{k}'" for k in kws)), + confidence=INFERENCE, + ) + def register(linter: PyLinter) -> None: linter.register_checker(MethodArgsChecker(linter)) |