From f934b09ecbd22b06103b946b94ed471036b5894d Mon Sep 17 00:00:00 2001 From: Will McGugan Date: Sat, 18 Sep 2021 09:43:09 +0100 Subject: [PATCH 1/6] test fake attributes --- rich/pretty.py | 12 ++++++++++-- tests/test_pretty.py | 12 ++++++++++++ 2 files changed, 22 insertions(+), 2 deletions(-) diff --git a/rich/pretty.py b/rich/pretty.py index 6d0295415..20d01ab0d 100644 --- a/rich/pretty.py +++ b/rich/pretty.py @@ -1,5 +1,6 @@ import builtins import os +from rich.repr import RichReprResult import sys from array import array from collections import Counter, defaultdict, deque, UserDict, UserList @@ -503,9 +504,16 @@ def iter_rich_args(rich_args: Any) -> Iterable[Union[Any, Tuple[str, Any]]]: else: yield arg - if hasattr(obj, "__rich_repr__") and not isclass(obj): + rich_repr_result: Optional[RichReprResult] = None + try: + if hasattr(obj, "__rich_repr__") and not isclass(obj): + rich_repr_result: Optional[RichReprResult] = obj.__rich_repr__() + except Exception: + pass + + if rich_repr_result is not None: angular = getattr(obj.__rich_repr__, "angular", False) - args = list(iter_rich_args(obj.__rich_repr__())) + args = list(iter_rich_args(rich_repr_result)) class_name = obj.__class__.__name__ if args: diff --git a/tests/test_pretty.py b/tests/test_pretty.py index cf838db20..938f216bb 100644 --- a/tests/test_pretty.py +++ b/tests/test_pretty.py @@ -250,3 +250,15 @@ def __repr__(self): result = pretty_repr(d2, expand_all=True) print(repr(result)) assert result == "FOO" + + +def test_lying_attribute(): + """Test getattr doesn't break rich repr protocol""" + + class Foo: + def __getattr__(self, attr): + return "foo" + + foo = Foo() + result = pretty_repr(foo) + assert "Foo" in result From 2cec85d81f417a0a386fc746ed53089edbed0af5 Mon Sep 17 00:00:00 2001 From: Will McGugan Date: Sat, 18 Sep 2021 09:45:55 +0100 Subject: [PATCH 2/6] changelog --- CHANGELOG.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7b4f70f39..9d6efc6b3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,12 +5,16 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). -## [Unreleased] +## [10.10.0] - Unreleased ### Added - Added stdin support to `rich.json` +### Fixed + +- Fixed pretty printing of objects with fo magic with **getattr** https://github.com/willmcgugan/rich/issues/1492 + ## [10.9.0] - 2021-08-29 ### Added From d589325d654069a9a007db7f37e60ade05a8c3d5 Mon Sep 17 00:00:00 2001 From: Will McGugan Date: Sat, 18 Sep 2021 09:49:36 +0100 Subject: [PATCH 3/6] fix typing --- rich/pretty.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rich/pretty.py b/rich/pretty.py index 20d01ab0d..d2ac4cc10 100644 --- a/rich/pretty.py +++ b/rich/pretty.py @@ -507,7 +507,7 @@ def iter_rich_args(rich_args: Any) -> Iterable[Union[Any, Tuple[str, Any]]]: rich_repr_result: Optional[RichReprResult] = None try: if hasattr(obj, "__rich_repr__") and not isclass(obj): - rich_repr_result: Optional[RichReprResult] = obj.__rich_repr__() + rich_repr_result = obj.__rich_repr__() except Exception: pass From d38ffef745ea510327c68004d75100d66de3b5d0 Mon Sep 17 00:00:00 2001 From: Will McGugan Date: Sat, 18 Sep 2021 10:00:06 +0100 Subject: [PATCH 4/6] handle fake attributes --- rich/pretty.py | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/rich/pretty.py b/rich/pretty.py index d2ac4cc10..c740236b9 100644 --- a/rich/pretty.py +++ b/rich/pretty.py @@ -504,12 +504,20 @@ def iter_rich_args(rich_args: Any) -> Iterable[Union[Any, Tuple[str, Any]]]: else: yield arg - rich_repr_result: Optional[RichReprResult] = None try: - if hasattr(obj, "__rich_repr__") and not isclass(obj): - rich_repr_result = obj.__rich_repr__() + fake_attributes = hasattr( + obj, "awehoi234_wdfjwljet234_234wdfoijsdfmmnxpi492", False + ) except Exception: - pass + fake_attributes = False + + rich_repr_result: Optional[RichReprResult] = None + if not fake_attributes: + try: + if hasattr(obj, "__rich_repr__") and not isclass(obj): + rich_repr_result = obj.__rich_repr__() + except Exception: + pass if rich_repr_result is not None: angular = getattr(obj.__rich_repr__, "angular", False) @@ -552,7 +560,7 @@ def iter_rich_args(rich_args: Any) -> Iterable[Union[Any, Tuple[str, Any]]]: children=[], last=root, ) - elif _is_attr_object(obj): + elif _is_attr_object(obj) and not fake_attributes: children = [] append = children.append @@ -600,6 +608,7 @@ def iter_attrs() -> Iterable[ elif ( is_dataclass(obj) and not isinstance(obj, type) + and not fake_attributes and ( "__create_fn__" in obj.__repr__.__qualname__ or py_version == (3, 6) ) # Check if __repr__ wasn't overridden From 195972dc9105dbacbd7890891a0eeacb24a04a9a Mon Sep 17 00:00:00 2001 From: Will McGugan Date: Sat, 18 Sep 2021 10:02:34 +0100 Subject: [PATCH 5/6] fake attribute fix --- rich/pretty.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rich/pretty.py b/rich/pretty.py index c740236b9..4997d5b8e 100644 --- a/rich/pretty.py +++ b/rich/pretty.py @@ -506,7 +506,7 @@ def iter_rich_args(rich_args: Any) -> Iterable[Union[Any, Tuple[str, Any]]]: try: fake_attributes = hasattr( - obj, "awehoi234_wdfjwljet234_234wdfoijsdfmmnxpi492", False + obj, "awehoi234_wdfjwljet234_234wdfoijsdfmmnxpi492" ) except Exception: fake_attributes = False From f613b3e0555961d6649c558aadbc987c80f57704 Mon Sep 17 00:00:00 2001 From: Will McGugan Date: Sat, 18 Sep 2021 10:37:17 +0100 Subject: [PATCH 6/6] version bump --- CHANGELOG.md | 2 +- pyproject.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9d6efc6b3..ef9e50ae3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,7 +5,7 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). -## [10.10.0] - Unreleased +## [10.10.0] - 2021-09-18 ### Added diff --git a/pyproject.toml b/pyproject.toml index aa4b9ea6a..7f9329aaa 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -2,7 +2,7 @@ name = "rich" homepage = "https://github.com/willmcgugan/rich" documentation = "https://rich.readthedocs.io/en/latest/" -version = "10.9.0" +version = "10.10.0" description = "Render rich text, tables, progress bars, syntax highlighting, markdown and more to the terminal" authors = ["Will McGugan "] license = "MIT"