diff options
author | David Liu <david@cs.toronto.edu> | 2021-08-15 13:08:45 -0400 |
---|---|---|
committer | Pierre Sassoulas <pierre.sassoulas@gmail.com> | 2021-08-16 19:01:54 +0200 |
commit | d277a4fca12e5e72ac439c410e8dfbaddccdfcc1 (patch) | |
tree | 9f0f39ca2a223a1460a9f82750122e6bc0415580 | |
parent | a874d9a82c39fac368d1283b5d9c9181810f3d3a (diff) | |
download | pylint-git-d277a4fca12e5e72ac439c410e8dfbaddccdfcc1.tar.gz |
Additional tests for PyCQA/astroid#1126
10 files changed, 160 insertions, 3 deletions
diff --git a/tests/functional/d/dataclass_with_default_factory.py b/tests/functional/d/dataclass_with_default_factory.py index b01f38977..8f24d5e6e 100644 --- a/tests/functional/d/dataclass_with_default_factory.py +++ b/tests/functional/d/dataclass_with_default_factory.py @@ -1,6 +1,9 @@ -"""A test script the confuses pylint.""" -# https://github.com/PyCQA/pylint/issues/2605 +"""Various regression tests for dataclasses.""" +# See issues: +# - https://github.com/PyCQA/pylint/issues/2605 +# - https://github.com/PyCQA/pylint/issues/2698 from dataclasses import dataclass, field +import dataclasses as dc @dataclass @@ -13,3 +16,28 @@ class Test: TEST = Test() TEST.test.append(1) print(TEST.test[0]) + + +@dc.dataclass # Note the use of dc instead of dataclasses +class Test2: + """Test dataclass that uses a renamed import of dataclasses""" + int_prop: int = dc.field(default=10) + list_prop: list = dc.field(default_factory=list) + dict_prop: dict = dc.field(default_factory=dict) + + +TEST2 = Test2() +for _ in TEST2.list_prop: # This is okay + pass + + +TEST2.dict_prop["key"] = "value" # This is okay + + +# Test2.int_prop is inferred as 10, not a Field +print(Test2.int_prop + 1) +for _ in Test2.int_prop: # [not-an-iterable] + pass + + +Test2.int_prop["key"] = "value" # [unsupported-assignment-operation] diff --git a/tests/functional/d/dataclass_with_default_factory.txt b/tests/functional/d/dataclass_with_default_factory.txt new file mode 100644 index 000000000..c33a7d3a4 --- /dev/null +++ b/tests/functional/d/dataclass_with_default_factory.txt @@ -0,0 +1,2 @@ +not-an-iterable:39:9::Non-iterable value Test2.int_prop is used in an iterating context:HIGH +unsupported-assignment-operation:43:0::'Test2.int_prop' does not support item assignment:HIGH diff --git a/tests/functional/i/invalid/invalid_name_issue_3405.py b/tests/functional/i/invalid/invalid_name_issue_3405.py new file mode 100644 index 000000000..9b0dd37cd --- /dev/null +++ b/tests/functional/i/invalid/invalid_name_issue_3405.py @@ -0,0 +1,11 @@ +""" Regression test for https://github.com/PyCQA/pylint/issues/3405. """ + +import dataclasses +from typing import ClassVar + + +@dataclasses.dataclass +class Foo: + """ClassVar attribute should be matched against class-attribute-rgx, not attr-rgx""" + # class-attribute-rgx='^y$' + x: ClassVar[int] = 0 # [invalid-name] diff --git a/tests/functional/i/invalid/invalid_name_issue_3405.rc b/tests/functional/i/invalid/invalid_name_issue_3405.rc new file mode 100644 index 000000000..c8bdd0efd --- /dev/null +++ b/tests/functional/i/invalid/invalid_name_issue_3405.rc @@ -0,0 +1,9 @@ +[MESSAGES CONTROL] +enable=invalid-name + +[BASIC] +attr-rgx=^x$ +class-attribute-rgx=^y$ + +[testoptions] +min_pyver=3.7 diff --git a/tests/functional/i/invalid/invalid_name_issue_3405.txt b/tests/functional/i/invalid/invalid_name_issue_3405.txt new file mode 100644 index 000000000..999137e42 --- /dev/null +++ b/tests/functional/i/invalid/invalid_name_issue_3405.txt @@ -0,0 +1 @@ +invalid-name:11:4:Foo:"Class attribute name ""x"" doesn't conform to '^y$' pattern":HIGH diff --git a/tests/functional/n/no/no_member_dataclasses.py b/tests/functional/n/no/no_member_dataclasses.py new file mode 100644 index 000000000..972da9ad9 --- /dev/null +++ b/tests/functional/n/no/no_member_dataclasses.py @@ -0,0 +1,83 @@ +"""Test various regressions for dataclasses and no-member. +""" +# pylint: disable=missing-docstring, too-few-public-methods +from abc import ABCMeta, abstractmethod +from dataclasses import asdict, dataclass, field +from typing import Any, Dict + + +# https://github.com/PyCQA/pylint/issues/3754 +@dataclass(frozen=True) +class DeploymentState(metaclass=ABCMeta): + type: str + + @abstractmethod + def to_dict(self) -> Dict: + """ + Serializes given DeploymentState instance to Dict. + :return: + """ + + +@dataclass(frozen=True) +class DeploymentStateEcs(DeploymentState): + blue: Any + green: Any + candidate: Any + + def to_dict(self) -> Dict: + return { + 'type': self.type, # No error here + 'blue': asdict(self.blue), + 'green': asdict(self.green), + 'candidate': self.candidate.value, + } + + +@dataclass(frozen=True) +class DeploymentStateLambda(DeploymentState): + current: Any + candidate: Any + + def to_dict(self) -> Dict: + return { + 'type': self.type, # No error here + 'current': asdict(self.current), + 'candidate': asdict(self.candidate) if self.candidate else None, + } + + +# https://github.com/PyCQA/pylint/issues/2600 +@dataclass +class TestClass: + attr1: str + attr2: str + dict_prop: Dict[str, str] = field(default_factory=dict) + + def some_func(self) -> None: + for key, value in self.dict_prop.items(): # No error here + print(key) + print(value) + + +class TestClass2: # not a dataclass, field inferred to a Field + attr1: str + attr2: str + dict_prop: Dict[str, str] = field(default_factory=dict) + + def some_func(self) -> None: + for key, value in self.dict_prop.items(): # [no-member] + print(key) + print(value) + + +@dataclass +class TestClass3: + attr1: str + attr2: str + dict_prop = field(default_factory=dict) # No type annotation, not treated as field + + def some_func(self) -> None: + for key, value in self.dict_prop.items(): # [no-member] + print(key) + print(value) diff --git a/tests/functional/n/no/no_member_dataclasses.rc b/tests/functional/n/no/no_member_dataclasses.rc new file mode 100644 index 000000000..a17bb22da --- /dev/null +++ b/tests/functional/n/no/no_member_dataclasses.rc @@ -0,0 +1,2 @@ +[testoptions] +min_pyver=3.7 diff --git a/tests/functional/n/no/no_member_dataclasses.txt b/tests/functional/n/no/no_member_dataclasses.txt new file mode 100644 index 000000000..ffa499e71 --- /dev/null +++ b/tests/functional/n/no/no_member_dataclasses.txt @@ -0,0 +1,2 @@ +no-member:69:26:TestClass2.some_func:Instance of 'Field' has no 'items' member:INFERENCE +no-member:81:26:TestClass3.some_func:Instance of 'Field' has no 'items' member:INFERENCE diff --git a/tests/functional/t/too/too_many_instance_attributes.py b/tests/functional/t/too/too_many_instance_attributes.py index f6703e0b7..11ddb915a 100644 --- a/tests/functional/t/too/too_many_instance_attributes.py +++ b/tests/functional/t/too/too_many_instance_attributes.py @@ -1,4 +1,6 @@ # pylint: disable=missing-docstring, too-few-public-methods, useless-object-inheritance +from dataclasses import dataclass, InitVar + class Aaaa(object): # [too-many-instance-attributes] @@ -24,3 +26,20 @@ class Aaaa(object): # [too-many-instance-attributes] self._iiii = 9 self._jjjj = 10 self.tomuch = None + + +# InitVars should not count as instance attributes (see issue #3754) +# Default max_instance_attributes is 7 +@dataclass +class Hello: + a_1: int + a_2: int + a_3: int + a_4: int + a_5: int + a_6: int + a_7: int + a_8: InitVar[int] + + def __post_init__(self, a_8): + self.a_1 += a_8 diff --git a/tests/functional/t/too/too_many_instance_attributes.txt b/tests/functional/t/too/too_many_instance_attributes.txt index 42c85493c..e9be267c0 100644 --- a/tests/functional/t/too/too_many_instance_attributes.txt +++ b/tests/functional/t/too/too_many_instance_attributes.txt @@ -1 +1 @@ -too-many-instance-attributes:3:0:Aaaa:Too many instance attributes (21/7) +too-many-instance-attributes:5:0:Aaaa:Too many instance attributes (21/7):HIGH |