From 71c8d4dfc514a2ca993dc2cf60722afbabf375d1 Mon Sep 17 00:00:00 2001 From: Marc Mueller <30130371+cdce8p@users.noreply.github.com> Date: Mon, 22 Sep 2025 01:37:38 +0200 Subject: [PATCH 1/2] Improve conditionals --- pylint/checkers/base/docstring_checker.py | 8 +++----- pylint/checkers/classes/class_checker.py | 2 +- pylint/checkers/logging.py | 4 +--- pylint/checkers/modified_iterating_checker.py | 12 ++++++------ .../checkers/refactoring/refactoring_checker.py | 17 ++++++++--------- pylint/checkers/typecheck.py | 15 ++++++--------- pylint/checkers/utils.py | 11 +++++------ pylint/checkers/variables.py | 9 +++++---- pylint/extensions/_check_docs_utils.py | 5 ++--- .../extensions/consider_ternary_expression.py | 9 ++++----- 10 files changed, 41 insertions(+), 51 deletions(-) diff --git a/pylint/checkers/base/docstring_checker.py b/pylint/checkers/base/docstring_checker.py index ac99755bd3..710c98b06f 100644 --- a/pylint/checkers/base/docstring_checker.py +++ b/pylint/checkers/base/docstring_checker.py @@ -35,11 +35,9 @@ def _infer_dunder_doc_attribute( return None docstring = utils.safe_infer(docstring) - if not docstring: - return None - if not isinstance(docstring, nodes.Const): - return None - return str(docstring.value) + if isinstance(docstring, nodes.Const): + return str(docstring.value) + return None class DocStringChecker(_BasicChecker): diff --git a/pylint/checkers/classes/class_checker.py b/pylint/checkers/classes/class_checker.py index 1cb0ee4990..9dbec4983c 100644 --- a/pylint/checkers/classes/class_checker.py +++ b/pylint/checkers/classes/class_checker.py @@ -2215,7 +2215,7 @@ def _check_init(self, node: nodes.FunctionDef, klass_node: nodes.ClassDef) -> No parents_with_called_inits: set[bases.UnboundMethod] = set() for stmt in node.nodes_of_class(nodes.Call): expr = stmt.func - if not isinstance(expr, nodes.Attribute) or expr.attrname != "__init__": + if not (isinstance(expr, nodes.Attribute) and expr.attrname == "__init__"): continue # skip the test if using super match expr.expr: diff --git a/pylint/checkers/logging.py b/pylint/checkers/logging.py index 804ae5b85f..3426abdd67 100644 --- a/pylint/checkers/logging.py +++ b/pylint/checkers/logging.py @@ -374,9 +374,7 @@ def _check_format_string(self, node: nodes.Call, format_arg: Literal[0, 1]) -> N def is_complex_format_str(node: nodes.NodeNG) -> bool: """Return whether the node represents a string with complex formatting specs.""" inferred = utils.safe_infer(node) - if inferred is None or not ( - isinstance(inferred, nodes.Const) and isinstance(inferred.value, str) - ): + if not (isinstance(inferred, nodes.Const) and isinstance(inferred.value, str)): return True try: parsed = list(string.Formatter().parse(inferred.value)) diff --git a/pylint/checkers/modified_iterating_checker.py b/pylint/checkers/modified_iterating_checker.py index af4cf421d0..630739a139 100644 --- a/pylint/checkers/modified_iterating_checker.py +++ b/pylint/checkers/modified_iterating_checker.py @@ -180,12 +180,12 @@ def _modified_iterating_set_cond( def _deleted_iteration_target_cond( self, node: nodes.DelName, iter_obj: nodes.NodeNG ) -> bool: - if not isinstance(node, nodes.DelName): - return False - if not isinstance(iter_obj.parent, nodes.For): - return False - if not isinstance( - iter_obj.parent.target, (nodes.AssignName, nodes.BaseContainer) + if not ( + isinstance(node, nodes.DelName) + and isinstance(iter_obj.parent, nodes.For) + and isinstance( + iter_obj.parent.target, (nodes.AssignName, nodes.BaseContainer) + ) ): return False return any( diff --git a/pylint/checkers/refactoring/refactoring_checker.py b/pylint/checkers/refactoring/refactoring_checker.py index 37ce125c69..daef258ded 100644 --- a/pylint/checkers/refactoring/refactoring_checker.py +++ b/pylint/checkers/refactoring/refactoring_checker.py @@ -1060,7 +1060,7 @@ def _check_stop_iteration_inside_generator(self, node: nodes.Raise) -> None: if not node.exc: return exc = utils.safe_infer(node.exc) - if not exc or not isinstance(exc, (bases.Instance, nodes.ClassDef)): + if not isinstance(exc, (bases.Instance, nodes.ClassDef)): return if self._check_exception_inherit_from_stopiteration(exc): self.add_message("stop-iteration-return", node=node, confidence=INFERENCE) @@ -1712,7 +1712,7 @@ def _check_use_list_literal(self, node: nodes.Call) -> None: def _check_use_dict_literal(self, node: nodes.Call) -> None: """Check if dict is created by using the literal {}.""" - if not isinstance(node.func, astroid.Name) or node.func.name != "dict": + if not (isinstance(node.func, astroid.Name) and node.func.name == "dict"): return inferred = utils.safe_infer(node.func) if ( @@ -1753,7 +1753,7 @@ def _name_to_concatenate(self, node: nodes.NodeNG) -> str | None: values = [ value for value in node.values if isinstance(value, nodes.FormattedValue) ] - if len(values) != 1 or not isinstance(values[0].value, nodes.Name): + if not (len(values) == 1 and isinstance(values[0].value, nodes.Name)): return None # If there are more values in joined string than formatted values, # they are probably separators. @@ -1772,7 +1772,7 @@ def _check_consider_using_join(self, aug_assign: nodes.AugAssign) -> None: result += number # aug_assign """ for_loop = aug_assign.parent - if not isinstance(for_loop, nodes.For) or len(for_loop.body) > 1: + if not (isinstance(for_loop, nodes.For) and len(for_loop.body) == 1): return assign = for_loop.previous_sibling() if not isinstance(assign, nodes.Assign): @@ -1810,11 +1810,10 @@ def visit_comprehension(self, node: nodes.Comprehension) -> None: self._check_unnecessary_list_index_lookup(node) def _check_unnecessary_comprehension(self, node: nodes.Comprehension) -> None: - if ( - isinstance(node.parent, nodes.GeneratorExp) - or len(node.ifs) != 0 - or len(node.parent.generators) != 1 - or node.is_async + if isinstance(node.parent, nodes.GeneratorExp) or not ( + len(node.ifs) == 0 + and len(node.parent.generators) == 1 + and node.is_async is False ): return diff --git a/pylint/checkers/typecheck.py b/pylint/checkers/typecheck.py index 428a702488..4a9595497a 100644 --- a/pylint/checkers/typecheck.py +++ b/pylint/checkers/typecheck.py @@ -2199,10 +2199,7 @@ def visit_subscript(self, node: nodes.Subscript) -> None: @only_required_for_messages("dict-items-missing-iter") def visit_for(self, node: nodes.For) -> None: - if not isinstance(node.target, nodes.Tuple): - # target is not a tuple - return - if not len(node.target.elts) == 2: + if not (isinstance(node.target, nodes.Tuple) and len(node.target.elts) == 2): # target is not a tuple of two elements return @@ -2281,11 +2278,11 @@ def _is_asyncio_coroutine(node: nodes.NodeNG) -> bool: return False for decorator in inferred_func.decorators.nodes: inferred_decorator = safe_infer(decorator) - if not isinstance(inferred_decorator, nodes.FunctionDef): - continue - if inferred_decorator.qname() != ASYNCIO_COROUTINE: - continue - return True + if ( + isinstance(inferred_decorator, nodes.FunctionDef) + and inferred_decorator.qname() == ASYNCIO_COROUTINE + ): + return True return False def _check_iterable(self, node: nodes.NodeNG, check_async: bool = False) -> None: diff --git a/pylint/checkers/utils.py b/pylint/checkers/utils.py index 88c5bce0f6..aff254617d 100644 --- a/pylint/checkers/utils.py +++ b/pylint/checkers/utils.py @@ -1526,7 +1526,7 @@ def is_registered_in_singledispatch_function(node: nodes.FunctionDef) -> bool: case _: continue - if not isinstance(func, nodes.Attribute) or func.attrname != "register": + if not (isinstance(func, nodes.Attribute) and func.attrname == "register"): continue try: @@ -1549,7 +1549,7 @@ def find_inferred_fn_from_register(node: nodes.NodeNG) -> nodes.FunctionDef | No case _: return None - if not isinstance(func, nodes.Attribute) or func.attrname != "register": + if not (isinstance(func, nodes.Attribute) and func.attrname == "register"): return None func_def = safe_infer(func.expr) @@ -2169,10 +2169,9 @@ def is_terminating_func(node: nodes.Call) -> bool: """Detect call to exit(), quit(), os._exit(), sys.exit(), or functions annotated with `typing.NoReturn` or `typing.Never`. """ - if ( - not isinstance(node.func, nodes.Attribute) - and not (isinstance(node.func, nodes.Name)) - ) or isinstance(node.parent, nodes.Lambda): + if not isinstance(node.func, (nodes.Attribute, nodes.Name)) or isinstance( + node.parent, nodes.Lambda + ): return False try: diff --git a/pylint/checkers/variables.py b/pylint/checkers/variables.py index 5fc6e07ea5..defc508b1e 100644 --- a/pylint/checkers/variables.py +++ b/pylint/checkers/variables.py @@ -1687,7 +1687,7 @@ def visit_name(self, node: nodes.Name | nodes.AssignName | nodes.DelName) -> Non @utils.only_required_for_messages("redefined-outer-name") def visit_excepthandler(self, node: nodes.ExceptHandler) -> None: - if not node.name or not isinstance(node.name, nodes.AssignName): + if not isinstance(node.name, nodes.AssignName): return for outer_except, outer_except_assign_name in self._except_handler_names_queue: @@ -2481,7 +2481,7 @@ def _is_only_type_assignment( defstmt: _base_nodes.Statement, ) -> bool: """Check if variable only gets assigned a type and never a value.""" - if not isinstance(defstmt, nodes.AnnAssign) or defstmt.value: + if not (isinstance(defstmt, nodes.AnnAssign) and defstmt.value is None): return False defstmt_frame = defstmt.frame() @@ -3472,8 +3472,9 @@ def _check_potential_index_error( ) -> None: """Check for the potential-index-error message.""" # Currently we only check simple slices of a single integer - if not isinstance(inferred_slice, nodes.Const) or not isinstance( - inferred_slice.value, int + if not ( + isinstance(inferred_slice, nodes.Const) + and isinstance(inferred_slice.value, int) ): return diff --git a/pylint/extensions/_check_docs_utils.py b/pylint/extensions/_check_docs_utils.py index 5664e70474..6308b1bda8 100644 --- a/pylint/extensions/_check_docs_utils.py +++ b/pylint/extensions/_check_docs_utils.py @@ -84,10 +84,9 @@ def returns_something(return_node: nodes.Return) -> bool: """ returns = return_node.value - if returns is None: + if returns is None or (isinstance(returns, nodes.Const) and returns.value is None): return False - - return not (isinstance(returns, nodes.Const) and returns.value is None) + return True def _get_raise_target(node: nodes.NodeNG) -> nodes.NodeNG | UninferableBase | None: diff --git a/pylint/extensions/consider_ternary_expression.py b/pylint/extensions/consider_ternary_expression.py index 4601a779f7..9bf3e04113 100644 --- a/pylint/extensions/consider_ternary_expression.py +++ b/pylint/extensions/consider_ternary_expression.py @@ -38,14 +38,13 @@ def visit_if(self, node: nodes.If) -> None: return for bname, oname in zip(bst.targets, ost.targets): - if not isinstance(bname, nodes.AssignName) or not isinstance( - oname, nodes.AssignName + if not ( + isinstance(bname, nodes.AssignName) + and isinstance(oname, nodes.AssignName) + and bname.name == oname.name ): return - if bname.name != oname.name: - return - self.add_message("consider-ternary-expression", node=node) From f3701d7a64009cd22321d5e4773aee968439fe17 Mon Sep 17 00:00:00 2001 From: Marc Mueller <30130371+cdce8p@users.noreply.github.com> Date: Tue, 23 Sep 2025 01:22:10 +0200 Subject: [PATCH 2/2] Code review Co-authored-by: Pierre Sassoulas --- pylint/extensions/_check_docs_utils.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/pylint/extensions/_check_docs_utils.py b/pylint/extensions/_check_docs_utils.py index 6308b1bda8..17ea3f1a83 100644 --- a/pylint/extensions/_check_docs_utils.py +++ b/pylint/extensions/_check_docs_utils.py @@ -83,10 +83,9 @@ def returns_something(return_node: nodes.Return) -> bool: False otherwise. """ returns = return_node.value - - if returns is None or (isinstance(returns, nodes.Const) and returns.value is None): - return False - return True + return not ( + returns is None or (isinstance(returns, nodes.Const) and returns.value is None) + ) def _get_raise_target(node: nodes.NodeNG) -> nodes.NodeNG | UninferableBase | None: