diff --git a/CHANGELOG.md b/CHANGELOG.md index bbbfecf89..60267c5ee 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Fix for escaping strings with a trailing backslash https://github.com/Textualize/rich/issues/2987 - Fixed exception in Markdown with partial table https://github.com/Textualize/rich/issues/3053 - Fixed the HTML export template so that the `` tag comes before the `` tag https://github.com/Textualize/rich/issues/3021 +- Fixed issue with custom classes overwriting `__eq__` https://github.com/Textualize/rich/issues/2875 ### Added diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md index fe88b7893..43165b0ee 100644 --- a/CONTRIBUTORS.md +++ b/CONTRIBUTORS.md @@ -13,6 +13,7 @@ The following people have contributed to the development of Rich: - [Ed Davis](https://github.com/davised) - [Pete Davison](https://github.com/pd93) - [James Estevez](https://github.com/jstvz) +- [Aryaz Eghbali](https://github.com/AryazE) - [Oleksis Fraga](https://github.com/oleksis) - [Andy Gimblett](https://github.com/gimbo) - [Michał Górny](https://github.com/mgorny) diff --git a/rich/repr.py b/rich/repr.py index 9dd65cdec..95331006e 100644 --- a/rich/repr.py +++ b/rich/repr.py @@ -76,7 +76,7 @@ def auto_rich_repr(self: Type[T]) -> Result: param.POSITIONAL_OR_KEYWORD, param.KEYWORD_ONLY, ): - if param.default == param.empty: + if param.default is param.empty: yield getattr(self, param.name) else: yield param.name, getattr(self, param.name), param.default diff --git a/tests/test_repr.py b/tests/test_repr.py index faabb90f0..3d3e74c8b 100644 --- a/tests/test_repr.py +++ b/tests/test_repr.py @@ -6,6 +6,8 @@ import rich.repr from rich.console import Console +from inspect import Parameter + skip_py37 = pytest.mark.skipif( sys.version_info.minor == 7 and sys.version_info.major == 3, reason="rendered differently on py3.7", @@ -61,6 +63,38 @@ def __rich_repr__(self): __rich_repr__.angular = True +class StupidClass: + def __init__(self, a): + self.a = a + + def __eq__(self, other) -> bool: + if other is Parameter.empty: + return True + try: + return self.a == other.a + except Exception: + return False + + def __ne__(self, other: object) -> bool: + return not self.__eq__(other) + + +class NotStupid: + pass + + +@rich.repr.auto +class Bird: + def __init__( + self, name, eats, fly=True, another=StupidClass(2), extinct=NotStupid() + ): + self.name = name + self.eats = eats + self.fly = fly + self.another = another + self.extinct = extinct + + def test_rich_repr() -> None: assert (repr(Foo("hello"))) == "Foo('hello', 'hello', egg=1)" assert (repr(Foo("hello", bar=3))) == "Foo('hello', 'hello', bar=3, egg=1)" @@ -90,6 +124,12 @@ def test_rich_angular() -> None: def test_rich_repr_auto() -> None: assert repr(Egg("hello", egg=2)) == "Egg('hello', egg=2)" + stupid_class = StupidClass(9) + not_stupid = NotStupid() + assert ( + repr(Bird("penguin", ["fish"], another=stupid_class, extinct=not_stupid)) + == f"Bird('penguin', ['fish'], another={repr(stupid_class)}, extinct={repr(not_stupid)})" + ) def test_rich_repr_auto_angular() -> None: