diff options
author | Mark Byrne <31762852+mbyrnepr2@users.noreply.github.com> | 2021-08-18 17:52:22 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-08-18 17:52:22 +0200 |
commit | be039201f0d3ce2c0664f312646733b2a5af69c5 (patch) | |
tree | e42a3a209811b993626ea9b7270b58f988f80cc2 | |
parent | 53da6541dbe621b55f2c7f1bfcf821541dc823e8 (diff) | |
download | pylint-git-be039201f0d3ce2c0664f312646733b2a5af69c5.tar.gz |
pyreverse - Handle a regression with typehints of type astroid.Subscript (#4859)
* pyreverse - Handle a regression with typehints of type astroid.Subscript
Closes #4845
* [pre-commit.ci] auto fixes from pre-commit.com hooks
for more information, see https://pre-commit.ci
* pyreverse - Handle a regression with typehints of type astroid.Subscript
- Add test-case to pyreverse data files
Closes #4845
Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
-rw-r--r-- | pylint/pyreverse/utils.py | 2 | ||||
-rw-r--r-- | tests/data/suppliermodule_test.py | 8 | ||||
-rw-r--r-- | tests/pyreverse/data/classes_No_Name.dot | 2 | ||||
-rw-r--r-- | tests/pyreverse/data/classes_No_Name.puml | 1 | ||||
-rw-r--r-- | tests/pyreverse/data/classes_No_Name.vcg | 2 | ||||
-rw-r--r-- | tests/pyreverse/data/classes_colorized.dot | 2 | ||||
-rw-r--r-- | tests/pyreverse/data/classes_colorized.puml | 1 | ||||
-rw-r--r-- | tests/pyreverse/test_utils.py | 20 |
8 files changed, 34 insertions, 4 deletions
diff --git a/pylint/pyreverse/utils.py b/pylint/pyreverse/utils.py index 7ca4501f1..bc0e40fc6 100644 --- a/pylint/pyreverse/utils.py +++ b/pylint/pyreverse/utils.py @@ -272,6 +272,8 @@ def infer_node(node: Union[astroid.AssignAttr, astroid.AssignName]) -> set: ann = get_annotation(node) try: if ann: + if isinstance(ann, astroid.Subscript): + return {ann} return set(ann.infer()) return set(node.infer()) except astroid.InferenceError: diff --git a/tests/data/suppliermodule_test.py b/tests/data/suppliermodule_test.py index add637d4a..9c8b05d52 100644 --- a/tests/data/suppliermodule_test.py +++ b/tests/data/suppliermodule_test.py @@ -1,4 +1,5 @@ """ file suppliermodule.py """ +from typing import Optional class Interface: def get_value(self): @@ -14,9 +15,14 @@ class DoNothing: pass class DoNothing2: pass class DoSomething: - def __init__(self, a_string: str, optional_int: int = None): + def __init__( + self, + a_string: str, + optional_int: int = None, + optional_int_2: Optional[int] = None): self.my_string = a_string self.my_int = optional_int + self.my_int_2 = optional_int_2 def do_it(self, new_int: int) -> int: return self.my_int + new_int diff --git a/tests/pyreverse/data/classes_No_Name.dot b/tests/pyreverse/data/classes_No_Name.dot index f3e7b9625..cbe3d155d 100644 --- a/tests/pyreverse/data/classes_No_Name.dot +++ b/tests/pyreverse/data/classes_No_Name.dot @@ -5,7 +5,7 @@ charset="utf-8" "data.suppliermodule_test.CustomException" [color="black", fontcolor="red", label="{CustomException|\l|}", shape="record", style="solid"]; "data.suppliermodule_test.DoNothing" [color="black", fontcolor="black", label="{DoNothing|\l|}", shape="record", style="solid"]; "data.suppliermodule_test.DoNothing2" [color="black", fontcolor="black", label="{DoNothing2|\l|}", shape="record", style="solid"]; -"data.suppliermodule_test.DoSomething" [color="black", fontcolor="black", label="{DoSomething|my_int : Optional[int]\lmy_string : str\l|do_it(new_int: int): int\l}", shape="record", style="solid"]; +"data.suppliermodule_test.DoSomething" [color="black", fontcolor="black", label="{DoSomething|my_int : Optional[int]\lmy_int_2 : Optional[int]\lmy_string : str\l|do_it(new_int: int): int\l}", shape="record", style="solid"]; "data.suppliermodule_test.Interface" [color="black", fontcolor="black", label="{Interface|\l|get_value()\lset_value(value)\l}", shape="record", style="solid"]; "data.clientmodule_test.Specialization" [color="black", fontcolor="black", label="{Specialization|TYPE : str\lrelation\lrelation2\ltop : str\l|}", shape="record", style="solid"]; "data.clientmodule_test.Specialization" -> "data.clientmodule_test.Ancestor" [arrowhead="empty", arrowtail="none"]; diff --git a/tests/pyreverse/data/classes_No_Name.puml b/tests/pyreverse/data/classes_No_Name.puml index 5acbe93d0..35bda65c1 100644 --- a/tests/pyreverse/data/classes_No_Name.puml +++ b/tests/pyreverse/data/classes_No_Name.puml @@ -14,6 +14,7 @@ class "DoNothing2" as data.suppliermodule_test.DoNothing2 { } class "DoSomething" as data.suppliermodule_test.DoSomething { my_int : Optional[int] + my_int_2 : Optional[int] my_string : str do_it(new_int: int) -> int } diff --git a/tests/pyreverse/data/classes_No_Name.vcg b/tests/pyreverse/data/classes_No_Name.vcg index 89697ce84..748c432f2 100644 --- a/tests/pyreverse/data/classes_No_Name.vcg +++ b/tests/pyreverse/data/classes_No_Name.vcg @@ -16,7 +16,7 @@ graph:{ node: {title:"data.suppliermodule_test.DoNothing2" label:"\fbDoNothing2\fn\n\f____________" shape:box } - node: {title:"data.suppliermodule_test.DoSomething" label:"\fbDoSomething\fn\n\f________________________\n\f08my_int : Optional[int]\n\f08my_string : str\n\f________________________\n\f10do_it()" + node: {title:"data.suppliermodule_test.DoSomething" label:"\fbDoSomething\fn\n\f__________________________\n\f08my_int : Optional[int]\n\f08my_int_2 : Optional[int]\n\f08my_string : str\n\f__________________________\n\f10do_it()" shape:box } node: {title:"data.suppliermodule_test.Interface" label:"\fbInterface\fn\n\f___________\n\f10get_value()\n\f10set_value()" diff --git a/tests/pyreverse/data/classes_colorized.dot b/tests/pyreverse/data/classes_colorized.dot index 41c81d94f..ff96df77c 100644 --- a/tests/pyreverse/data/classes_colorized.dot +++ b/tests/pyreverse/data/classes_colorized.dot @@ -5,7 +5,7 @@ charset="utf-8" "data.suppliermodule_test.CustomException" [color="aliceblue", fontcolor="red", label="{CustomException|\l|}", shape="record", style="filled"]; "data.suppliermodule_test.DoNothing" [color="aliceblue", fontcolor="black", label="{DoNothing|\l|}", shape="record", style="filled"]; "data.suppliermodule_test.DoNothing2" [color="aliceblue", fontcolor="black", label="{DoNothing2|\l|}", shape="record", style="filled"]; -"data.suppliermodule_test.DoSomething" [color="aliceblue", fontcolor="black", label="{DoSomething|my_int : Optional[int]\lmy_string : str\l|do_it(new_int: int): int\l}", shape="record", style="filled"]; +"data.suppliermodule_test.DoSomething" [color="aliceblue", fontcolor="black", label="{DoSomething|my_int : Optional[int]\lmy_int_2 : Optional[int]\lmy_string : str\l|do_it(new_int: int): int\l}", shape="record", style="filled"]; "data.suppliermodule_test.Interface" [color="aliceblue", fontcolor="black", label="{Interface|\l|get_value()\lset_value(value)\l}", shape="record", style="filled"]; "data.clientmodule_test.Specialization" [color="aliceblue", fontcolor="black", label="{Specialization|TYPE : str\lrelation\lrelation2\ltop : str\l|}", shape="record", style="filled"]; "data.clientmodule_test.Specialization" -> "data.clientmodule_test.Ancestor" [arrowhead="empty", arrowtail="none"]; diff --git a/tests/pyreverse/data/classes_colorized.puml b/tests/pyreverse/data/classes_colorized.puml index cbbc3b02e..25c0f34e9 100644 --- a/tests/pyreverse/data/classes_colorized.puml +++ b/tests/pyreverse/data/classes_colorized.puml @@ -14,6 +14,7 @@ class "DoNothing2" as data.suppliermodule_test.DoNothing2 #aliceblue { } class "DoSomething" as data.suppliermodule_test.DoSomething #aliceblue { my_int : Optional[int] + my_int_2 : Optional[int] my_string : str do_it(new_int: int) -> int } diff --git a/tests/pyreverse/test_utils.py b/tests/pyreverse/test_utils.py index c82a63e52..bc3a5baf6 100644 --- a/tests/pyreverse/test_utils.py +++ b/tests/pyreverse/test_utils.py @@ -117,3 +117,23 @@ def test_infer_node_3(): instance_attr = node.instance_attrs.get("component")[0] assert isinstance(infer_node(instance_attr), set) assert isinstance(infer_node(instance_attr).pop(), astroid.ClassDef) + + +def test_infer_node_4(): + """Verify the label for an argument with a typehint of the type + astroid.Subscript + """ + node = astroid.extract_node( + """ + class MyClass: + def __init__(self, my_int: Optional[int] = None): + self.my_test_int = my_int + """ + ) + + instance_attr = node.instance_attrs.get("my_test_int")[0] + assert isinstance(instance_attr, astroid.AssignAttr) + + inferred = infer_node(instance_attr).pop() + assert isinstance(inferred, astroid.Subscript) + assert inferred.name == "Optional[int]" |