Skip to content

Remove __eq__ and __ne__ overrides for dataclasses and attrs #8642

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

Merged
merged 1 commit into from
Apr 8, 2020
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
23 changes: 5 additions & 18 deletions mypy/plugins/attrs.py
Original file line number Diff line number Diff line change
Expand Up @@ -176,10 +176,10 @@ def deserialize(cls, info: TypeInfo, data: JsonDict) -> 'Attribute':
)


def _determine_eq_order(ctx: 'mypy.plugin.ClassDefContext') -> Tuple[bool, bool]:
def _determine_eq_order(ctx: 'mypy.plugin.ClassDefContext') -> bool:
"""
Validate the combination of *cmp*, *eq*, and *order*. Derive the effective
values of eq and order.
value of order.
"""
cmp = _get_decorator_optional_bool_argument(ctx, 'cmp')
eq = _get_decorator_optional_bool_argument(ctx, 'eq')
Expand All @@ -190,7 +190,7 @@ def _determine_eq_order(ctx: 'mypy.plugin.ClassDefContext') -> Tuple[bool, bool]

# cmp takes precedence due to bw-compatibility.
if cmp is not None:
return cmp, cmp
return cmp

# If left None, equality is on and ordering mirrors equality.
if eq is None:
Expand All @@ -202,7 +202,7 @@ def _determine_eq_order(ctx: 'mypy.plugin.ClassDefContext') -> Tuple[bool, bool]
if eq is False and order is True:
ctx.api.fail("eq must be True if order is True", ctx.reason)

return eq, order
return order


def _get_decorator_optional_bool_argument(
Expand Down Expand Up @@ -248,7 +248,7 @@ def attr_class_maker_callback(ctx: 'mypy.plugin.ClassDefContext',

init = _get_decorator_bool_argument(ctx, 'init', True)
frozen = _get_frozen(ctx)
eq, order = _determine_eq_order(ctx)
order = _determine_eq_order(ctx)

auto_attribs = _get_decorator_bool_argument(ctx, 'auto_attribs', auto_attribs_default)
kw_only = _get_decorator_bool_argument(ctx, 'kw_only', False)
Expand Down Expand Up @@ -287,8 +287,6 @@ def attr_class_maker_callback(ctx: 'mypy.plugin.ClassDefContext',
adder = MethodAdder(ctx)
if init:
_add_init(ctx, attributes, adder)
if eq:
_add_eq(ctx, adder)
if order:
_add_order(ctx, adder)
if frozen:
Expand Down Expand Up @@ -587,17 +585,6 @@ def _parse_assignments(
return lvalues, rvalues


def _add_eq(ctx: 'mypy.plugin.ClassDefContext', adder: 'MethodAdder') -> None:
"""Generate __eq__ and __ne__ for this class."""
# For __ne__ and __eq__ the type is:
# def __ne__(self, other: object) -> bool
bool_type = ctx.api.named_type('__builtins__.bool')
object_type = ctx.api.named_type('__builtins__.object')
args = [Argument(Var('other', object_type), object_type, None, ARG_POS)]
for method in ['__ne__', '__eq__']:
adder.add_method(method, args, bool_type)


def _add_order(ctx: 'mypy.plugin.ClassDefContext', adder: 'MethodAdder') -> None:
"""Generate all the ordering methods for this class."""
bool_type = ctx.api.named_type('__builtins__.bool')
Expand Down
21 changes: 0 additions & 21 deletions mypy/plugins/dataclasses.py
Original file line number Diff line number Diff line change
Expand Up @@ -123,27 +123,6 @@ def transform(self) -> None:
[], obj_type)
info.names[SELF_TVAR_NAME] = SymbolTableNode(MDEF, self_tvar_expr)

# Add an eq method, but only if the class doesn't already have one.
if decorator_arguments['eq'] and info.get('__eq__') is None:
for method_name in ['__eq__', '__ne__']:
# The TVar is used to enforce that "other" must have
# the same type as self (covariant). Note the
# "self_type" parameter to add_method.
obj_type = ctx.api.named_type('__builtins__.object')
cmp_tvar_def = TypeVarDef(SELF_TVAR_NAME, info.fullname + '.' + SELF_TVAR_NAME,
-1, [], obj_type)
cmp_other_type = TypeVarType(cmp_tvar_def)
cmp_return_type = ctx.api.named_type('__builtins__.bool')

add_method(
ctx,
method_name,
args=[Argument(Var('other', cmp_other_type), cmp_other_type, None, ARG_POS)],
return_type=cmp_return_type,
self_type=cmp_other_type,
tvar_def=cmp_tvar_def,
)

# Add <, >, <=, >=, but only if the class has an eq method.
if decorator_arguments['order']:
if not decorator_arguments['eq']:
Expand Down
13 changes: 0 additions & 13 deletions test-data/unit/check-attr.test
Original file line number Diff line number Diff line change
Expand Up @@ -185,8 +185,6 @@ from attr import attrib, attrs
class A:
a: int
reveal_type(A) # N: Revealed type is 'def (a: builtins.int) -> __main__.A'
reveal_type(A.__eq__) # N: Revealed type is 'def (self: __main__.A, other: builtins.object) -> builtins.bool'
reveal_type(A.__ne__) # N: Revealed type is 'def (self: __main__.A, other: builtins.object) -> builtins.bool'
reveal_type(A.__lt__) # N: Revealed type is 'def [_AT] (self: _AT`-1, other: _AT`-1) -> builtins.bool'
reveal_type(A.__le__) # N: Revealed type is 'def [_AT] (self: _AT`-1, other: _AT`-1) -> builtins.bool'
reveal_type(A.__gt__) # N: Revealed type is 'def [_AT] (self: _AT`-1, other: _AT`-1) -> builtins.bool'
Expand Down Expand Up @@ -251,8 +249,6 @@ from attr import attrib, attrs
class A:
a: int
reveal_type(A) # N: Revealed type is 'def (a: builtins.int) -> __main__.A'
reveal_type(A.__eq__) # N: Revealed type is 'def (self: __main__.A, other: builtins.object) -> builtins.bool'
reveal_type(A.__ne__) # N: Revealed type is 'def (self: __main__.A, other: builtins.object) -> builtins.bool'

A(1) < A(2) # E: Unsupported left operand type for < ("A")
A(1) <= A(2) # E: Unsupported left operand type for <= ("A")
Expand Down Expand Up @@ -771,15 +767,6 @@ B() <= 1 # E: Unsupported operand types for <= ("B" and "int")
C() <= 1 # E: Unsupported operand types for <= ("C" and "int")
D() <= 1 # E: Unsupported operand types for <= ("D" and "int")

A() == A()
B() == A()
C() == A()
D() == A()

A() == int
B() == int
C() == int
D() == int
[builtins fixtures/list.pyi]

[case testAttrsComplexSuperclass]
Expand Down
42 changes: 0 additions & 42 deletions test-data/unit/check-dataclasses.test
Original file line number Diff line number Diff line change
Expand Up @@ -377,48 +377,6 @@ Application.COUNTER = 1

[builtins fixtures/list.pyi]

[case testDataclassEquality]
# flags: --python-version 3.6
from dataclasses import dataclass

@dataclass
class Application:
name: str
rating: int

app1 = Application("example-1", 5)
app2 = Application("example-2", 5)
app1 == app2
app1 != app2
app1 == None # E: Unsupported operand types for == ("Application" and "None")

[builtins fixtures/list.pyi]

[case testDataclassCustomEquality]
# flags: --python-version 3.6
from dataclasses import dataclass

@dataclass
class Application:
name: str
rating: int

def __eq__(self, other: 'Application') -> bool:
...

app1 = Application("example-1", 5)
app2 = Application("example-2", 5)
app1 == app2
app1 != app2 # E: Unsupported left operand type for != ("Application")
app1 == None # E: Unsupported operand types for == ("Application" and "None")

class SpecializedApplication(Application):
...

app1 == SpecializedApplication("example-3", 5)

[builtins fixtures/list.pyi]

[case testDataclassOrdering]
# flags: --python-version 3.6
from dataclasses import dataclass
Expand Down
24 changes: 10 additions & 14 deletions test-data/unit/check-incremental.test
Original file line number Diff line number Diff line change
Expand Up @@ -2993,8 +2993,6 @@ main:15: error: Unsupported left operand type for >= ("NoCmp")
[case testAttrsIncrementalDunder]
from a import A
reveal_type(A) # N: Revealed type is 'def (a: builtins.int) -> a.A'
reveal_type(A.__eq__) # N: Revealed type is 'def (self: a.A, other: builtins.object) -> builtins.bool'
reveal_type(A.__ne__) # N: Revealed type is 'def (self: a.A, other: builtins.object) -> builtins.bool'
reveal_type(A.__lt__) # N: Revealed type is 'def [_AT] (self: _AT`-1, other: _AT`-1) -> builtins.bool'
reveal_type(A.__le__) # N: Revealed type is 'def [_AT] (self: _AT`-1, other: _AT`-1) -> builtins.bool'
reveal_type(A.__gt__) # N: Revealed type is 'def [_AT] (self: _AT`-1, other: _AT`-1) -> builtins.bool'
Expand Down Expand Up @@ -3032,20 +3030,18 @@ class A:
[stale]
[out2]
main:2: note: Revealed type is 'def (a: builtins.int) -> a.A'
main:3: note: Revealed type is 'def (self: a.A, other: builtins.object) -> builtins.bool'
main:4: note: Revealed type is 'def (self: a.A, other: builtins.object) -> builtins.bool'
main:3: note: Revealed type is 'def [_AT] (self: _AT`-1, other: _AT`-1) -> builtins.bool'
main:4: note: Revealed type is 'def [_AT] (self: _AT`-1, other: _AT`-1) -> builtins.bool'
main:5: note: Revealed type is 'def [_AT] (self: _AT`-1, other: _AT`-1) -> builtins.bool'
main:6: note: Revealed type is 'def [_AT] (self: _AT`-1, other: _AT`-1) -> builtins.bool'
main:7: note: Revealed type is 'def [_AT] (self: _AT`-1, other: _AT`-1) -> builtins.bool'
main:8: note: Revealed type is 'def [_AT] (self: _AT`-1, other: _AT`-1) -> builtins.bool'
main:17: error: Unsupported operand types for < ("A" and "int")
main:18: error: Unsupported operand types for <= ("A" and "int")
main:19: error: Unsupported operand types for > ("A" and "int")
main:20: error: Unsupported operand types for >= ("A" and "int")
main:24: error: Unsupported operand types for > ("A" and "int")
main:25: error: Unsupported operand types for >= ("A" and "int")
main:26: error: Unsupported operand types for < ("A" and "int")
main:27: error: Unsupported operand types for <= ("A" and "int")
main:15: error: Unsupported operand types for < ("A" and "int")
main:16: error: Unsupported operand types for <= ("A" and "int")
main:17: error: Unsupported operand types for > ("A" and "int")
main:18: error: Unsupported operand types for >= ("A" and "int")
main:22: error: Unsupported operand types for > ("A" and "int")
main:23: error: Unsupported operand types for >= ("A" and "int")
main:24: error: Unsupported operand types for < ("A" and "int")
main:25: error: Unsupported operand types for <= ("A" and "int")

[case testAttrsIncrementalSubclassModified]
from b import B
Expand Down
2 changes: 0 additions & 2 deletions test-data/unit/deps.test
Original file line number Diff line number Diff line change
Expand Up @@ -1435,9 +1435,7 @@ class B(A):
[out]
<m.A.(abstract)> -> <m.B.__init__>, m
<m.A._DT> -> <m.B._DT>
<m.A.__eq__> -> <m.B.__eq__>
<m.A.__init__> -> <m.B.__init__>, m.B.__init__
<m.A.__ne__> -> <m.B.__ne__>
<m.A.__new__> -> <m.B.__new__>
<m.A.x> -> <m.B.x>
<m.A.y> -> <m.B.y>
Expand Down
2 changes: 0 additions & 2 deletions test-data/unit/stubgen.test
Original file line number Diff line number Diff line change
Expand Up @@ -2162,8 +2162,6 @@ from typing import Any
class C:
x: Any = ...
def __init__(self, x: Any) -> None: ...
def __ne__(self, other: Any) -> Any: ...
def __eq__(self, other: Any) -> Any: ...
def __lt__(self, other: Any) -> Any: ...
def __le__(self, other: Any) -> Any: ...
def __gt__(self, other: Any) -> Any: ...
Expand Down