Skip to content

Commit fb4512c

Browse files
cdce8pnickdrozd
andauthored
Fix invalid type false positive (#8206) (#8386)
(cherry picked from commit e64f043) Co-authored-by: Nick Drozd <nicholasdrozd@gmail.com>
1 parent 08bac36 commit fb4512c

9 files changed

+57
-8
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
Fix false positive for isinstance-second-argument-not-valid-type with union types.
2+
3+
Closes #8205

pylint/checkers/typecheck.py

+14-1
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@
4848
supports_membership_test,
4949
supports_setitem,
5050
)
51+
from pylint.constants import PY310_PLUS
5152
from pylint.interfaces import HIGH, INFERENCE
5253
from pylint.typing import MessageDefinitionTuple
5354

@@ -796,6 +797,10 @@ def _is_c_extension(module_node: InferenceResult) -> bool:
796797

797798
def _is_invalid_isinstance_type(arg: nodes.NodeNG) -> bool:
798799
# Return True if we are sure that arg is not a type
800+
if PY310_PLUS and isinstance(arg, nodes.BinOp) and arg.op == "|":
801+
return _is_invalid_isinstance_type(arg.left) or _is_invalid_isinstance_type(
802+
arg.right
803+
)
799804
inferred = utils.safe_infer(arg)
800805
if not inferred:
801806
# Cannot infer it so skip it.
@@ -806,6 +811,10 @@ def _is_invalid_isinstance_type(arg: nodes.NodeNG) -> bool:
806811
return False
807812
if isinstance(inferred, astroid.Instance) and inferred.qname() == BUILTIN_TUPLE:
808813
return False
814+
if PY310_PLUS and isinstance(inferred, bases.UnionType):
815+
return _is_invalid_isinstance_type(
816+
inferred.left
817+
) or _is_invalid_isinstance_type(inferred.right)
809818
return True
810819

811820

@@ -1398,7 +1407,11 @@ def _check_isinstance_args(self, node: nodes.Call) -> None:
13981407

13991408
second_arg = node.args[1]
14001409
if _is_invalid_isinstance_type(second_arg):
1401-
self.add_message("isinstance-second-argument-not-valid-type", node=node)
1410+
self.add_message(
1411+
"isinstance-second-argument-not-valid-type",
1412+
node=node,
1413+
confidence=INFERENCE,
1414+
)
14021415

14031416
# pylint: disable = too-many-branches, too-many-locals, too-many-statements
14041417
def visit_call(self, node: nodes.Call) -> None:

pylint/constants.py

+1
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818

1919
PY38_PLUS = sys.version_info[:2] >= (3, 8)
2020
PY39_PLUS = sys.version_info[:2] >= (3, 9)
21+
PY310_PLUS = sys.version_info[:2] >= (3, 10)
2122

2223
IS_PYPY = platform.python_implementation() == "PyPy"
2324

tests/functional/d/dataclass/dataclass_typecheck.txt

+1-1
Original file line numberDiff line numberDiff line change
@@ -9,4 +9,4 @@ unsupported-delete-operation:72:4:72:13::'obj.attr1' does not support item delet
99
not-context-manager:97:0:98:8::Context manager 'str' doesn't implement __enter__ and __exit__.:UNDEFINED
1010
invalid-metaclass:105:0:105:11:Test2:Invalid metaclass 'Instance of builtins.int' used:UNDEFINED
1111
unhashable-member:111:0:111:2::'obj.attr5' is unhashable and can't be used as a key in a dict:INFERENCE
12-
isinstance-second-argument-not-valid-type:121:6:121:30::Second argument of isinstance is not a type:UNDEFINED
12+
isinstance-second-argument-not-valid-type:121:6:121:30::Second argument of isinstance is not a type:INFERENCE

tests/functional/ext/typing/redundant_typehint_argument.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
""""Checks for redundant Union typehints in assignments"""
1+
"""Checks for redundant Union typehints in assignments"""
22
# pylint: disable=deprecated-typing-alias,consider-alternative-union-syntax,consider-using-alias
33

44
from __future__ import annotations
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
isinstance-second-argument-not-valid-type:27:0:27:23::Second argument of isinstance is not a type:UNDEFINED
2-
isinstance-second-argument-not-valid-type:28:0:28:19::Second argument of isinstance is not a type:UNDEFINED
3-
isinstance-second-argument-not-valid-type:29:0:29:34::Second argument of isinstance is not a type:UNDEFINED
4-
isinstance-second-argument-not-valid-type:30:0:30:54::Second argument of isinstance is not a type:UNDEFINED
5-
isinstance-second-argument-not-valid-type:31:0:31:18::Second argument of isinstance is not a type:UNDEFINED
1+
isinstance-second-argument-not-valid-type:27:0:27:23::Second argument of isinstance is not a type:INFERENCE
2+
isinstance-second-argument-not-valid-type:28:0:28:19::Second argument of isinstance is not a type:INFERENCE
3+
isinstance-second-argument-not-valid-type:29:0:29:34::Second argument of isinstance is not a type:INFERENCE
4+
isinstance-second-argument-not-valid-type:30:0:30:54::Second argument of isinstance is not a type:INFERENCE
5+
isinstance-second-argument-not-valid-type:31:0:31:18::Second argument of isinstance is not a type:INFERENCE
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
'''Tests for invalid isinstance with compound types'''
2+
3+
# True negatives
4+
isinstance(0, int | str)
5+
isinstance(0, int | int | int)
6+
isinstance(0, int | str | list | float)
7+
isinstance(0, (int | str) | (list | float))
8+
9+
IntOrStr = int | str
10+
isinstance(0, IntOrStr)
11+
ListOrDict = list | dict
12+
isinstance(0, (float | ListOrDict) | IntOrStr)
13+
14+
# True positives
15+
isinstance(0, int | 5) # [isinstance-second-argument-not-valid-type]
16+
isinstance(0, str | 5 | int) # [isinstance-second-argument-not-valid-type]
17+
INT = 5
18+
isinstance(0, INT | int) # [isinstance-second-argument-not-valid-type]
19+
20+
21+
# FALSE NEGATIVES
22+
23+
# Parameterized generics will raise type errors at runtime.
24+
# Warnings should be raised, but aren't (yet).
25+
isinstance(0, list[int])
26+
ListOfInts = list[int]
27+
isinstance(0, ListOfInts)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
[testoptions]
2+
min_pyver=3.10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
isinstance-second-argument-not-valid-type:15:0:15:22::Second argument of isinstance is not a type:INFERENCE
2+
isinstance-second-argument-not-valid-type:16:0:16:28::Second argument of isinstance is not a type:INFERENCE
3+
isinstance-second-argument-not-valid-type:18:0:18:24::Second argument of isinstance is not a type:INFERENCE

0 commit comments

Comments
 (0)