Repository: samuelcolvin/dirty-equals

Issue:
dirty-equals causes a infinite-loop if it is used with `functools.singledispatch`
The following code causes a infinite-loop inside `functools.singledispatch`


``` python
from dirty_equals import IsStr

from functools import singledispatch


@singledispatch
def dispatch(a):
    print("generic", a)


s = IsStr()
dispatch(s)
```

It looks like this is caused by the fact that `IsStr == IsStr` is `False`.

I already created a pull-request, please let me know if this can be fixed this way.

Discussion:

Solution patch:
diff --git a/dirty_equals/_base.py b/dirty_equals/_base.py
index df7d1ec..d0fda1e 100644
--- a/dirty_equals/_base.py
+++ b/dirty_equals/_base.py
@@ -13,6 +13,9 @@ __all__ = 'DirtyEqualsMeta', 'DirtyEquals', 'AnyThing', 'IsOneOf'
 
 class DirtyEqualsMeta(ABCMeta):
     def __eq__(self, other: Any) -> bool:
+        if self is other:
+            return True
+
         # this is required as fancy things happen when creating generics which include equals checks, without it,
         # we get some recursive errors
         if self is DirtyEquals or other is Generic or other is Protocol:


Test patch:
diff --git a/tests/test_base.py b/tests/test_base.py
index 7545d2f..54558e3 100644
--- a/tests/test_base.py
+++ b/tests/test_base.py
@@ -1,10 +1,11 @@
 import platform
 import pprint
+from functools import singledispatch
 
 import packaging.version
 import pytest
 
-from dirty_equals import Contains, IsApprox, IsInt, IsList, IsNegative, IsOneOf, IsPositive, IsStr
+from dirty_equals import Contains, DirtyEquals, IsApprox, IsInt, IsList, IsNegative, IsOneOf, IsPositive, IsStr
 from dirty_equals.version import VERSION
 
 
@@ -192,3 +193,23 @@ def test_is_one_of(value, dirty):
 
 def test_version():
     packaging.version.parse(VERSION)
+
+
+def test_singledispatch():
+    @singledispatch
+    def dispatch(value):
+        return 'generic'
+
+    assert dispatch(IsStr()) == 'generic'
+
+    @dispatch.register
+    def _(value: DirtyEquals):
+        return 'DirtyEquals'
+
+    assert dispatch(IsStr()) == 'DirtyEquals'
+
+    @dispatch.register
+    def _(value: IsStr):
+        return 'IsStr'
+
+    assert dispatch(IsStr()) == 'IsStr'