From bcceff6be5903d8f3c203c59906b7fd46d72b499 Mon Sep 17 00:00:00 2001 From: Rogdham Date: Fri, 7 Apr 2023 18:54:23 +0200 Subject: [PATCH] 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 ++++++++----- .../i/isinstance_second_argument_py310.py | 6 +++++- .../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 0000000000..22dc8b8441 --- /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 8e00384d7c..0c8c44a15a 100644 --- a/pylint/checkers/typecheck.py +++ b/pylint/checkers/typecheck.py @@ -37,6 +37,7 @@ 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 8a0c17af58..ad2033b310 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 776bf3c2e1..aa50da29d4 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