Skip to content

Commit f19e9bf

Browse files
committed
Add more tests
1 parent 820e078 commit f19e9bf

File tree

2 files changed

+209
-1
lines changed

2 files changed

+209
-1
lines changed

tests/test_constraint.py

Lines changed: 141 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -867,6 +867,82 @@ class B(A):
867867
assert inferred[0] is Uninferable
868868

869869

870+
def test_isinstance_multiple_inheritance():
871+
"""Test constraint for an object that inherits from more than one parent class."""
872+
n1, n2, n3 = builder.extract_node(
873+
"""
874+
class A:
875+
pass
876+
877+
class B:
878+
pass
879+
880+
class C(A, B):
881+
pass
882+
883+
x = C()
884+
885+
if isinstance(x, C):
886+
x #@
887+
888+
if isinstance(x, A):
889+
x #@
890+
891+
if isinstance(x, B):
892+
x #@
893+
"""
894+
)
895+
896+
for node in (n1, n2, n3):
897+
inferred = node.inferred()
898+
assert len(inferred) == 1
899+
assert isinstance(inferred[0], Instance)
900+
assert isinstance(inferred[0]._proxied, nodes.ClassDef)
901+
assert inferred[0].name == "C"
902+
903+
904+
def test_isinstance_diamond_inheritance():
905+
"""Test constraint for an object that inherits from parent classes
906+
in diamond inheritance.
907+
"""
908+
n1, n2, n3, n4 = builder.extract_node(
909+
"""
910+
class A():
911+
pass
912+
913+
class B(A):
914+
pass
915+
916+
class C(A):
917+
pass
918+
919+
class D(B, C):
920+
pass
921+
922+
x = D()
923+
924+
if isinstance(x, D):
925+
x #@
926+
927+
if isinstance(x, B):
928+
x #@
929+
930+
if isinstance(x, C):
931+
x #@
932+
933+
if isinstance(x, A):
934+
x #@
935+
"""
936+
)
937+
938+
for node in (n1, n2, n3, n4):
939+
inferred = node.inferred()
940+
assert len(inferred) == 1
941+
assert isinstance(inferred[0], Instance)
942+
assert isinstance(inferred[0]._proxied, nodes.ClassDef)
943+
assert inferred[0].name == "D"
944+
945+
870946
def test_isinstance_keyword_arguments():
871947
"""Test that constraint does not apply when `isinstance` is called
872948
with keyword arguments.
@@ -907,3 +983,68 @@ def test_isinstance_extra_argument():
907983
assert len(inferred) == 1
908984
assert isinstance(inferred[0], nodes.Const)
909985
assert inferred[0].value == 3
986+
987+
988+
def test_isinstance_classinfo_inference_error():
989+
"""Test that constraint is satisfied when `isinstance` is called with
990+
classinfo that raises an inference error.
991+
"""
992+
node = builder.extract_node(
993+
"""
994+
x = 3
995+
996+
if isinstance(x, undefined_type):
997+
x #@
998+
"""
999+
)
1000+
1001+
inferred = node.inferred()
1002+
assert len(inferred) == 1
1003+
assert isinstance(inferred[0], nodes.Const)
1004+
assert inferred[0].value == 3
1005+
1006+
1007+
def test_isinstance_uninferable_classinfo():
1008+
"""Test that constraint is satisfied when `isinstance` is called with
1009+
uninferable classinfo.
1010+
"""
1011+
node = builder.extract_node(
1012+
"""
1013+
def f(classinfo):
1014+
x = 3
1015+
1016+
if isinstance(x, classinfo):
1017+
x #@
1018+
"""
1019+
)
1020+
1021+
inferred = node.inferred()
1022+
assert len(inferred) == 1
1023+
assert isinstance(inferred[0], nodes.Const)
1024+
assert inferred[0].value == 3
1025+
1026+
1027+
def test_isinstance_mro_error():
1028+
"""Test that constraint is satisfied when computing the object's
1029+
method resolution order raises an MRO error.
1030+
"""
1031+
node = builder.extract_node(
1032+
"""
1033+
class A():
1034+
pass
1035+
1036+
class B(A, A):
1037+
pass
1038+
1039+
x = B()
1040+
1041+
if isinstance(x, A):
1042+
x #@
1043+
"""
1044+
)
1045+
1046+
inferred = node.inferred()
1047+
assert len(inferred) == 1
1048+
assert isinstance(inferred[0], Instance)
1049+
assert isinstance(inferred[0]._proxied, nodes.ClassDef)
1050+
assert inferred[0].name == "B"

tests/test_helpers.py

Lines changed: 68 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
from astroid import builder, helpers, manager, nodes, raw_building, util
1111
from astroid.builder import AstroidBuilder
1212
from astroid.const import IS_PYPY
13-
from astroid.exceptions import _NonDeducibleTypeHierarchy
13+
from astroid.exceptions import InferenceError, _NonDeducibleTypeHierarchy
1414
from astroid.nodes.node_classes import UNATTACHED_UNKNOWN
1515

1616

@@ -275,3 +275,70 @@ def test_safe_infer_shim() -> None:
275275
"Import safe_infer from astroid.util; this shim in astroid.helpers will be removed."
276276
in records[0].message.args[0]
277277
)
278+
279+
280+
def test_class_to_container() -> None:
281+
node = builder.extract_node("""isinstance(3, int)""")
282+
283+
container = helpers.class_or_tuple_to_container(node.args[1])
284+
285+
assert len(container) == 1
286+
assert isinstance(container[0], nodes.ClassDef)
287+
assert container[0].name == "int"
288+
289+
290+
def test_tuple_to_container() -> None:
291+
node = builder.extract_node("""isinstance(3, (int, str))""")
292+
293+
container = helpers.class_or_tuple_to_container(node.args[1])
294+
295+
assert len(container) == 2
296+
297+
assert isinstance(container[0], nodes.ClassDef)
298+
assert container[0].name == "int"
299+
300+
assert isinstance(container[1], nodes.ClassDef)
301+
assert container[1].name == "str"
302+
303+
304+
def test_class_to_container_uninferable() -> None:
305+
node = builder.extract_node(
306+
"""
307+
def f(x):
308+
isinstance(3, x) #@
309+
"""
310+
)
311+
312+
container = helpers.class_or_tuple_to_container(node.args[1])
313+
314+
assert len(container) == 1
315+
assert container[0] is util.Uninferable
316+
317+
318+
def test_tuple_to_container_uninferable() -> None:
319+
node = builder.extract_node(
320+
"""
321+
def f(x, y):
322+
isinstance(3, (x, y)) #@
323+
"""
324+
)
325+
326+
container = helpers.class_or_tuple_to_container(node.args[1])
327+
328+
assert len(container) == 2
329+
assert container[0] is util.Uninferable
330+
assert container[1] is util.Uninferable
331+
332+
333+
def test_class_to_container_inference_error() -> None:
334+
node = builder.extract_node("""isinstance(3, undefined_type)""")
335+
336+
with pytest.raises(InferenceError):
337+
helpers.class_or_tuple_to_container(node.args[1])
338+
339+
340+
def test_tuple_to_container_inference_error() -> None:
341+
node = builder.extract_node("""isinstance(3, (int, undefined_type))""")
342+
343+
with pytest.raises(InferenceError):
344+
helpers.class_or_tuple_to_container(node.args[1])

0 commit comments

Comments
 (0)