From a79acf279a80bbbac0a05d8fadf62649753c668a Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Tue, 1 Oct 2019 20:40:13 +0200 Subject: [PATCH] Fix warnings with attrs 19.2 and fix object assertions attrs 19.2 deprecated cmp in favor of the dataclass-ish eq/order duo. This causes deprecation warnings that in turn break some of the cool new deep object comparisons. Since we at attrs expected this to be a problem, it shipped with helpers to write backward and forward compatible code. This PR uses that and avoids changed to minimal versions. --- src/_pytest/assertion/util.py | 15 ++++++++++++++- src/_pytest/compat.py | 7 +++++++ src/_pytest/mark/structures.py | 3 ++- testing/test_assertion.py | 3 ++- 4 files changed, 25 insertions(+), 3 deletions(-) diff --git a/src/_pytest/assertion/util.py b/src/_pytest/assertion/util.py index 11c7bdf6f..21ec72803 100644 --- a/src/_pytest/assertion/util.py +++ b/src/_pytest/assertion/util.py @@ -8,6 +8,7 @@ from typing import Optional import _pytest._code from _pytest import outcomes from _pytest._io.saferepr import saferepr +from _pytest.compat import attrs_has_eq # The _reprcompare attribute on the util module is used by the new assertion # interpretation code and assertion rewriter to detect this plugin was @@ -112,6 +113,18 @@ def isattrs(obj): return getattr(obj, "__attrs_attrs__", None) is not None +if attrs_has_eq: + + def attrsfieldhaseq(a): + return a.eq + + +else: + + def attrsfieldhaseq(a): + return a.cmp + + def isiterable(obj): try: iter(obj) @@ -375,7 +388,7 @@ def _compare_eq_cls(left, right, verbose, type_fns): fields_to_check = [field for field, info in all_fields.items() if info.compare] elif isattrs(left): all_fields = left.__attrs_attrs__ - fields_to_check = [field.name for field in all_fields if field.cmp] + fields_to_check = [field.name for field in all_fields if attrsfieldhaseq(field)] same = [] diff = [] diff --git a/src/_pytest/compat.py b/src/_pytest/compat.py index 3d1531e77..575e85b9a 100644 --- a/src/_pytest/compat.py +++ b/src/_pytest/compat.py @@ -354,3 +354,10 @@ if sys.version_info < (3, 5, 2): # pragma: no cover def overload(f): # noqa: F811 return f + + +attrs_has_eq = getattr(attr, "__version_info__", (0, 0)) >= (19, 2) +if attrs_has_eq: + attrs_no_eq = {"eq": False} +else: + attrs_no_eq = {"cmp": False} diff --git a/src/_pytest/mark/structures.py b/src/_pytest/mark/structures.py index f8cf55b4c..19333453f 100644 --- a/src/_pytest/mark/structures.py +++ b/src/_pytest/mark/structures.py @@ -8,6 +8,7 @@ from typing import Set import attr from ..compat import ascii_escaped +from ..compat import attrs_no_eq from ..compat import getfslineno from ..compat import NOTSET from _pytest.outcomes import fail @@ -367,7 +368,7 @@ class NodeKeywords(MutableMapping): return "".format(self.node) -@attr.s(cmp=False, hash=False) +@attr.s(hash=False, **attrs_no_eq) # type: ignore class NodeMarkers: """ internal structure for storing marks belonging to a node diff --git a/testing/test_assertion.py b/testing/test_assertion.py index bf23e3202..83370fb43 100644 --- a/testing/test_assertion.py +++ b/testing/test_assertion.py @@ -9,6 +9,7 @@ import pytest from _pytest import outcomes from _pytest.assertion import truncate from _pytest.assertion import util +from _pytest.compat import attrs_no_eq def mock_config(): @@ -687,7 +688,7 @@ class TestAssert_reprcompare_attrsclass: @attr.s class SimpleDataObject: field_a = attr.ib() - field_b = attr.ib(cmp=False) + field_b = attr.ib(**attrs_no_eq) left = SimpleDataObject(1, "b") right = SimpleDataObject(1, "b")