summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMarc Mueller <30130371+cdce8p@users.noreply.github.com>2021-02-16 01:05:48 +0100
committerPierre Sassoulas <pierre.sassoulas@gmail.com>2021-02-16 07:55:09 +0100
commitb5f21f45f711e467d6964a19885176ce2cae08b7 (patch)
treebdffdfb3a8eef7e3696584d74f453372476c3e93
parent958cea36ccee352f8d135aef0599b21b516fad78 (diff)
downloadpylint-git-b5f21f45f711e467d6964a19885176ce2cae08b7.tar.gz
Fix issue with nested PEP 585 syntax
-rw-r--r--ChangeLog2
-rw-r--r--pylint/checkers/utils.py14
-rw-r--r--tests/functional/p/postponed_evaluation_pep585.py21
-rw-r--r--tests/functional/p/postponed_evaluation_pep585.txt7
-rw-r--r--tests/functional/p/postponed_evaluation_pep585_error.py20
-rw-r--r--tests/functional/p/postponed_evaluation_pep585_error.txt27
-rw-r--r--tests/functional/p/postponed_evaluation_pep585_py39.py20
7 files changed, 95 insertions, 16 deletions
diff --git a/ChangeLog b/ChangeLog
index 84f0add2f..3c8c0c49b 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -49,6 +49,8 @@ Pylint's ChangeLog
Closes #1927
+* Fix issue with nested PEP 585 syntax
+
What's New in Pylint 2.6.1?
===========================
Release date: TBA
diff --git a/pylint/checkers/utils.py b/pylint/checkers/utils.py
index 404a5f0d6..3264a1195 100644
--- a/pylint/checkers/utils.py
+++ b/pylint/checkers/utils.py
@@ -1340,10 +1340,16 @@ def is_class_subscriptable_pep585_with_postponed_evaluation_enabled(
if not is_postponed_evaluation_enabled(node):
return False
- if not isinstance(
- node.parent, (astroid.AnnAssign, astroid.Arguments, astroid.FunctionDef)
- ):
- return False
+ parent_node = node.parent
+ while True:
+ # Check if any parent node matches condition
+ if isinstance(
+ parent_node, (astroid.AnnAssign, astroid.Arguments, astroid.FunctionDef)
+ ):
+ break
+ parent_node = parent_node.parent
+ if isinstance(parent_node, astroid.Module):
+ return False
if value.name in SUBSCRIPTABLE_CLASSES_PEP585:
return True
for name in value.basenames:
diff --git a/tests/functional/p/postponed_evaluation_pep585.py b/tests/functional/p/postponed_evaluation_pep585.py
index a91d5995b..73072f308 100644
--- a/tests/functional/p/postponed_evaluation_pep585.py
+++ b/tests/functional/p/postponed_evaluation_pep585.py
@@ -3,13 +3,13 @@
This check requires Python 3.7 or 3.8!
Testing with 3.8 only, to support TypedDict.
"""
-# pylint: disable=missing-docstring,unused-argument,unused-import,too-few-public-methods,invalid-name,inherit-non-class
+# pylint: disable=missing-docstring,unused-argument,unused-import,too-few-public-methods,invalid-name,inherit-non-class,unsupported-binary-operation
from __future__ import annotations
import collections
import dataclasses
import typing
-from typing import NamedTuple, TypedDict
from dataclasses import dataclass
+from typing import Dict, NamedTuple, TypedDict, Union, Tuple
AliasInvalid = list[int] # [unsubscriptable-object]
@@ -75,12 +75,27 @@ class CustomDataClass4:
my_var: list[int]
-# Allowed use cases
var1: set[int]
var2: collections.OrderedDict[str, int]
+var3: dict[str, list[int]]
+var4: Dict[str, list[int]]
+var5: dict[tuple[int, int], str]
+var6: Dict[tuple[int, int], str]
+var7: list[list[int]]
+var8: tuple[list[int]]
+var9: int | list[str | int]
+var10: Union[list[str], None]
+var11: Union[Union[list[int], int]]
def func(arg: list[int]):
pass
def func2() -> list[int]:
pass
+
+Alias2 = Union[list[str], None] # [unsubscriptable-object]
+Alias3 = Union[Union[list[int], int]] # [unsubscriptable-object]
+Alias4 = Tuple[list[int]] # [unsubscriptable-object]
+Alias5 = Dict[str, list[int]] # [unsubscriptable-object]
+Alias6 = int | list[int] # [unsubscriptable-object]
+Alias7 = list[list[int]] # [unsubscriptable-object,unsubscriptable-object]
diff --git a/tests/functional/p/postponed_evaluation_pep585.txt b/tests/functional/p/postponed_evaluation_pep585.txt
index 45a93dfec..8fbec8077 100644
--- a/tests/functional/p/postponed_evaluation_pep585.txt
+++ b/tests/functional/p/postponed_evaluation_pep585.txt
@@ -6,3 +6,10 @@ unsubscriptable-object:28:14::Value 'list' is unsubscriptable
unsubscriptable-object:33:36::Value 'list' is unsubscriptable
unsubscriptable-object:43:54::Value 'list' is unsubscriptable
unsubscriptable-object:45:60::Value 'list' is unsubscriptable
+unsubscriptable-object:96:15::Value 'list' is unsubscriptable
+unsubscriptable-object:97:21::Value 'list' is unsubscriptable
+unsubscriptable-object:98:15::Value 'list' is unsubscriptable
+unsubscriptable-object:99:19::Value 'list' is unsubscriptable
+unsubscriptable-object:100:15::Value 'list' is unsubscriptable
+unsubscriptable-object:101:9::Value 'list' is unsubscriptable
+unsubscriptable-object:101:14::Value 'list' is unsubscriptable
diff --git a/tests/functional/p/postponed_evaluation_pep585_error.py b/tests/functional/p/postponed_evaluation_pep585_error.py
index cbffb135c..bcc41def8 100644
--- a/tests/functional/p/postponed_evaluation_pep585_error.py
+++ b/tests/functional/p/postponed_evaluation_pep585_error.py
@@ -3,12 +3,12 @@
This check requires Python 3.7 or Python 3.8!
Testing with 3.8 only, to support TypedDict.
"""
-# pylint: disable=missing-docstring,unused-argument,unused-import,too-few-public-methods,invalid-name,inherit-non-class
+# pylint: disable=missing-docstring,unused-argument,unused-import,too-few-public-methods,invalid-name,inherit-non-class,unsupported-binary-operation
import collections
import dataclasses
import typing
-from typing import NamedTuple, TypedDict
from dataclasses import dataclass
+from typing import Dict, NamedTuple, TypedDict, Union
AliasInvalid = list[int] # [unsubscriptable-object]
@@ -74,12 +74,26 @@ class CustomDataClass4:
my_var: list[int] # [unsubscriptable-object]
-
var1: set[int] # [unsubscriptable-object]
var2: collections.OrderedDict[str, int] # [unsubscriptable-object]
+var3: dict[str, list[int]] # [unsubscriptable-object,unsubscriptable-object]
+var4: Dict[str, list[int]] # [unsubscriptable-object]
+var5: dict[tuple[int, int], str] # [unsubscriptable-object,unsubscriptable-object]
+var6: Dict[tuple[int, int], str] # [unsubscriptable-object]
+var7: list[list[int]] # [unsubscriptable-object,unsubscriptable-object]
+var8: tuple[list[int]] # [unsubscriptable-object,unsubscriptable-object]
+var9: int | list[str | int] # [unsubscriptable-object]
+var10: Union[list[str], None] # [unsubscriptable-object]
+var11: Union[Union[list[int], int]] # [unsubscriptable-object]
def func(arg: list[int]): # [unsubscriptable-object]
pass
def func2() -> list[int]: # [unsubscriptable-object]
pass
+
+Alias2 = Union[list[str], None] # [unsubscriptable-object]
+Alias3 = Union[Union[list[int], int]] # [unsubscriptable-object]
+Alias5 = Dict[str, list[int]] # [unsubscriptable-object]
+Alias6 = int | list[int] # [unsubscriptable-object]
+Alias7 = list[list[int]] # [unsubscriptable-object,unsubscriptable-object]
diff --git a/tests/functional/p/postponed_evaluation_pep585_error.txt b/tests/functional/p/postponed_evaluation_pep585_error.txt
index b04634142..31dd1f465 100644
--- a/tests/functional/p/postponed_evaluation_pep585_error.txt
+++ b/tests/functional/p/postponed_evaluation_pep585_error.txt
@@ -14,7 +14,26 @@ unsubscriptable-object:61:12:CustomDataClass:Value 'list' is unsubscriptable
unsubscriptable-object:65:12:CustomDataClass2:Value 'list' is unsubscriptable
unsubscriptable-object:69:12:CustomDataClass3:Value 'list' is unsubscriptable
unsubscriptable-object:74:12:CustomDataClass4:Value 'list' is unsubscriptable
-unsubscriptable-object:78:6::Value 'set' is unsubscriptable
-unsubscriptable-object:79:6::Value 'collections.OrderedDict' is unsubscriptable
-unsubscriptable-object:81:14:func:Value 'list' is unsubscriptable
-unsubscriptable-object:84:15:func2:Value 'list' is unsubscriptable
+unsubscriptable-object:77:6::Value 'set' is unsubscriptable
+unsubscriptable-object:78:6::Value 'collections.OrderedDict' is unsubscriptable
+unsubscriptable-object:79:6::Value 'dict' is unsubscriptable
+unsubscriptable-object:79:16::Value 'list' is unsubscriptable
+unsubscriptable-object:80:16::Value 'list' is unsubscriptable
+unsubscriptable-object:81:6::Value 'dict' is unsubscriptable
+unsubscriptable-object:81:11::Value 'tuple' is unsubscriptable
+unsubscriptable-object:82:11::Value 'tuple' is unsubscriptable
+unsubscriptable-object:83:6::Value 'list' is unsubscriptable
+unsubscriptable-object:83:11::Value 'list' is unsubscriptable
+unsubscriptable-object:84:12::Value 'list' is unsubscriptable
+unsubscriptable-object:84:6::Value 'tuple' is unsubscriptable
+unsubscriptable-object:85:12::Value 'list' is unsubscriptable
+unsubscriptable-object:86:13::Value 'list' is unsubscriptable
+unsubscriptable-object:87:19::Value 'list' is unsubscriptable
+unsubscriptable-object:89:14:func:Value 'list' is unsubscriptable
+unsubscriptable-object:92:15:func2:Value 'list' is unsubscriptable
+unsubscriptable-object:95:15::Value 'list' is unsubscriptable
+unsubscriptable-object:96:21::Value 'list' is unsubscriptable
+unsubscriptable-object:97:19::Value 'list' is unsubscriptable
+unsubscriptable-object:98:15::Value 'list' is unsubscriptable
+unsubscriptable-object:99:9::Value 'list' is unsubscriptable
+unsubscriptable-object:99:14::Value 'list' is unsubscriptable
diff --git a/tests/functional/p/postponed_evaluation_pep585_py39.py b/tests/functional/p/postponed_evaluation_pep585_py39.py
index bcc991292..5c7261605 100644
--- a/tests/functional/p/postponed_evaluation_pep585_py39.py
+++ b/tests/functional/p/postponed_evaluation_pep585_py39.py
@@ -1,10 +1,10 @@
"""Test PEP 585 works as expected, starting with Python 3.9"""
-# pylint: disable=missing-docstring,unused-argument,unused-import,too-few-public-methods,invalid-name,inherit-non-class
+# pylint: disable=missing-docstring,unused-argument,unused-import,too-few-public-methods,invalid-name,inherit-non-class,unsupported-binary-operation
import collections
import dataclasses
import typing
-from typing import NamedTuple, TypedDict
from dataclasses import dataclass
+from typing import Dict, NamedTuple, TypedDict, Union, Tuple
AliasValid = list[int]
@@ -72,9 +72,25 @@ class CustomDataClass4:
var1: set[int]
var2: collections.OrderedDict[str, int]
+var3: dict[str, list[int]]
+var4: Dict[str, list[int]]
+var5: dict[tuple[int, int], str]
+var6: Dict[tuple[int, int], str]
+var7: list[list[int]]
+var8: tuple[list[int]]
+var9: int | list[str | int]
+var10: Union[list[str], None]
+var11: Union[Union[list[int], int]]
def func(arg: list[int]):
pass
def func2() -> list[int]:
pass
+
+Alias2 = Union[list[str], None]
+Alias3 = Union[Union[list[int], int]]
+Alias4 = Tuple[list[int]]
+Alias5 = Dict[str, list[int]]
+Alias6 = int | list[int]
+Alias7 = list[list[int]]