From aa7aae5387c55dac751a388278973685970e6955 Mon Sep 17 00:00:00 2001 From: Jim Crist-Harif Date: Tue, 27 Feb 2024 08:55:52 -0600 Subject: [PATCH] feat(api): make deferred objects hashable by their identity --- ibis/common/deferred.py | 3 +++ ibis/common/tests/test_deferred.py | 24 +++++++++++++++--------- 2 files changed, 18 insertions(+), 9 deletions(-) diff --git a/ibis/common/deferred.py b/ibis/common/deferred.py index f13ee2fbf160..b8946f78fe15 100644 --- a/ibis/common/deferred.py +++ b/ibis/common/deferred.py @@ -104,6 +104,9 @@ def __bool__(self): f"The truth value of {self.__class__.__name__} objects is not defined" ) + def __hash__(self): + return id(self) + def __getitem__(self, name): return Deferred(Item(self, name)) diff --git a/ibis/common/tests/test_deferred.py b/ibis/common/tests/test_deferred.py index 616eebb47097..4d12e359c515 100644 --- a/ibis/common/tests/test_deferred.py +++ b/ibis/common/tests/test_deferred.py @@ -202,10 +202,21 @@ def test_deferred_supports_string_arguments(): assert b.resolve({}) == "3.14" -def test_deferred_object_are_not_hashable(): - # since __eq__ is overloaded, Deferred objects are not hashable - with pytest.raises(TypeError, match="unhashable type"): - hash(_.a) +def test_deferred_objects_are_hashable(): + a = _.a + assert hash(a) == hash(a) + + # Works in dicts + d = {a: 1, _.b: 2} + assert d[a] == 1 + assert _.c not in d + assert _.a not in d # hash by identity only + + # Works in sets + s = {a, a, _.b} + assert len(s) == 2 + assert a in s + assert _.a not in s # hash by identity only def test_deferred_const(): @@ -541,11 +552,6 @@ def myfunc(x): assert repr(myfunc(_.a)) == "" -def test_deferred_set_raises(): - with pytest.raises(TypeError, match="unhashable type"): - {_.a, _.b} # noqa: B018 - - @pytest.mark.parametrize( "case", [