Description
__eq__
and __ne__
are implemented incorrectly throughout the entire google-cloud-*
code base. I encountered this issue when trying to compare a google.cloud.datastore.Key
instance to unittest.mock.ANY
.
When implementing custom equality in Python (2 or 3), it should be written like this:
class A:
def __eq__(self, other):
if not isinstance(other, A):
# Delegate comparison to the other instance's __eq__.
return NotImplemented
# Whatever logic applies to equality of instances of A can be added here.
...
def __ne__(self, other):
# By using the == operator, the returned NotImplemented is handled correctly.
return not self == other
Throughout the entire code base of this repository, equality is implemented like this:
class A:
def __eq__(self, other):
if not isinstance(other, A):
# Other instances are never equal.
return False
# Whatever logic applies to equality of instances of A can be added here.
...
def __ne__(self, other):
# By negating the return value, NotImplemented is treated as False.
return not self.__eq__(other)
As a result gcloud instances can never equal entities of other classes if they are the first object in the comparison. This is not an issue for most cases, but there are cases where this is an issue. Also this behaviour is simply incorrect.
The __ne__
implementation works, because __eq__
is implemented incorrectly. The boolean value of NotImplemented
is True
.
>>> not NotImplemented
False
This is typically an issue when unittesting.
>>> from unittest.mock import ANY
>>>
>>> from google.cloud.datastore import Client
>>>
>>>
>>> client = Client()
>>> key = client.key('foo')
>>> key == ANY # Expected True
False
>>> ANY == key
True
>>> key != ANY # Expected False
True
>>> ANY != key
False
>>>