Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add typecheck tests for dataclass attributes #4870

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion requirements_test_min.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
-e .
astroid==2.7.0 # Pinned to a specific version for tests
astroid==2.7.1 # Pinned to a specific version for tests
pytest~=6.2
pytest-benchmark~=3.4
2 changes: 1 addition & 1 deletion setup.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ project_urls =
packages = find:
install_requires =
appdirs>=1.4.0
astroid>=2.7.0,<2.8 # (You should also upgrade requirements_test_min.txt)
astroid>=2.7.1,<2.8 # (You should also upgrade requirements_test_min.txt)
isort>=4.2.5,<6
mccabe>=0.6,<0.7
toml>=0.7.1
Expand Down
115 changes: 115 additions & 0 deletions tests/functional/d/deprecated/dataclass_typecheck.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
"""Tests for dataclass attributes with basic type annotations.

Tests for regressions from https://github.com/PyCQA/astroid/pull/1126
"""
# pylint: disable=missing-docstring,too-few-public-methods,pointless-statement,redefined-builtin, fixme
from dataclasses import dataclass
from typing import Callable, Dict, List, Optional


class Dummy:
pass


@dataclass
class MyClass:
# Attribute inference does not support Optional, so Uninferable is yielded
# This should not trigger any type errors from pylint
attr0: Optional[Dummy]

attr1: int
attr2: str
attr3: Callable[[int], int]
attr4: List[int]
attr5: Dict[str, str]


obj = MyClass(None, 1, 'hi', lambda x: x, [], {})

lst = [0, 1, 2]
print(lst[obj.attr0])
print(lst[obj.attr1])
print(lst[obj.attr2]) # [invalid-sequence-index]

print(lst[obj.attr0::])
print(lst[obj.attr1::])
print(lst[obj.attr2::]) # [invalid-slice-index]

obj.attr0(100)
obj.attr1(100) # [not-callable]
obj.attr3(100)

print(-obj.attr0)
print(-obj.attr1)
print(-obj.attr2) # [invalid-unary-operand-type]

print(1 + obj.attr0)
print(1 + obj.attr1)
print(1 + obj.attr2) # Should be an error here once unsupported-binary-operation is enabled

print(1 in obj.attr0)
print(1 in obj.attr1) # [unsupported-membership-test]
print(1 in obj.attr4)
print('hi' in obj.attr5)

print(obj.attr0[1])
print(obj.attr1[1]) # [unsubscriptable-object]
print(obj.attr4[1])
print(obj.attr5['hi'])

obj.attr0[1] = 1
obj.attr1[1] = 1 # [unsupported-assignment-operation]
obj.attr4[1] = 1
obj.attr5['hi'] = 'bye'

del obj.attr0[1]
del obj.attr1[1] # [unsupported-delete-operation]
del obj.attr4[1]
del obj.attr5['hi']


class Manager:
def __enter__(self):
pass

def __exit__(self, type_, value, traceback):
pass


@dataclass
class MyClass2:
attr0: Optional[Dummy]
attr1: Manager
attr2: str


obj2 = MyClass2(None, Manager(), 'hi')
with obj2.attr0:
pass
with obj2.attr1:
pass
with obj2.attr2: # [not-context-manager]
pass


class Test1(metaclass=obj.attr0):
pass


class Test2(metaclass=obj.attr1): # [invalid-metaclass]
pass


{}[obj.attr0] = 1
{}[obj.attr1] = 1
{}[obj.attr5] = 1 # [unhashable-dict-key]

for k, v in obj.attr5: # TODO: Should be an dict-iter-missing-items error
print(k, v)

__name__ = obj.attr0
__name__ = obj.attr1 # TODO: Should be a non-str-assignment-to-dunder-name error
__name__ = obj.attr2

print(isinstance(1, obj.attr0))
print(isinstance(1, obj.attr1)) # [isinstance-second-argument-not-valid-type]
2 changes: 2 additions & 0 deletions tests/functional/d/deprecated/dataclass_typecheck.rc
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
[testoptions]
min_pyver=3.7
12 changes: 12 additions & 0 deletions tests/functional/d/deprecated/dataclass_typecheck.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
invalid-sequence-index:32:6::Sequence index is not an int, slice, or instance with __index__:HIGH
invalid-slice-index:36:0::Slice index is not an int, None, or instance with __index__:HIGH
not-callable:39:0::obj.attr1 is not callable:HIGH
invalid-unary-operand-type:44:6::"bad operand type for unary -: str":HIGH
unsupported-membership-test:51:11::Value 'obj.attr1' doesn't support membership test:HIGH
unsubscriptable-object:56:6::Value 'obj.attr1' is unsubscriptable:HIGH
unsupported-assignment-operation:61:0::'obj.attr1' does not support item assignment:HIGH
unsupported-delete-operation:66:4::'obj.attr1' does not support item deletion:HIGH
not-context-manager:91:0::Context manager 'str' doesn't implement __enter__ and __exit__.:HIGH
invalid-metaclass:99:0:Test2:Invalid metaclass 'Instance of builtins.int' used:HIGH
unhashable-dict-key:105:0::Dict key is unhashable:HIGH
isinstance-second-argument-not-valid-type:115:6::Second argument of isinstance is not a type:HIGH