Skip to content

Commit 011dd1a

Browse files
committed
Fall back to inspect.getattr_static for raising descriptors
Fixes #3794
1 parent 46cebbb commit 011dd1a

4 files changed

Lines changed: 35 additions & 1 deletion

File tree

CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,12 @@ All notable changes to this project will be documented in this file.
55
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
66
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
77

8+
## [Unreleased]
9+
10+
### Fixed
11+
12+
- Fixed `inspect` showing `AttributeError` for descriptors that raise; now falls back to `inspect.getattr_static` https://github.com/Textualize/rich/pull/4124
13+
814
## [15.0.0] - 2026-04-12
915

1016
### Changed

CONTRIBUTORS.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,3 +101,4 @@ The following people have contributed to the development of Rich:
101101
- [Alex Zheng](https://github.com/alexzheng111)
102102
- [Sebastian Speitel](https://github.com/SebastianSpeitel)
103103
- [Kevin Turcios](https://github.com/KRRT7)
104+
- [Truffle](https://github.com/truffle-dev)

rich/_inspect.py

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -130,9 +130,19 @@ def sort_items(item: Tuple[str, Any]) -> Tuple[bool, str]:
130130
return (callable(value), key.strip("_").lower())
131131

132132
def safe_getattr(attr_name: str) -> Tuple[Any, Any]:
133-
"""Get attribute or any exception."""
133+
"""Get attribute or any exception.
134+
135+
Falls back to ``inspect.getattr_static`` if ``getattr`` raises
136+
``AttributeError``, so that descriptors which signal "no such
137+
attribute" (e.g. SWIG bindings, lazy properties) are still surfaced.
138+
"""
134139
try:
135140
return (None, getattr(obj, attr_name))
141+
except AttributeError:
142+
try:
143+
return (None, inspect.getattr_static(obj, attr_name))
144+
except AttributeError as error:
145+
return (error, None)
136146
except Exception as error:
137147
return (error, None)
138148

tests/test_inspect.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -382,6 +382,23 @@ def __class__(self):
382382
assert False, f"Object with no __class__ shouldn't raise {e}"
383383

384384

385+
def test_inspect_getattr_static_fallback():
386+
"""Issue #3794 - Properties that raise AttributeError fall back to
387+
inspect.getattr_static so the descriptor is shown instead of the error."""
388+
389+
class Thing:
390+
@property
391+
def maybe(self):
392+
raise AttributeError("not available on this instance")
393+
394+
def __dir__(self):
395+
return ["maybe"]
396+
397+
rendered = render(Thing())
398+
assert "AttributeError" not in rendered
399+
assert "property" in rendered
400+
401+
385402
def test_inspect_module_with_class():
386403
def function():
387404
pass

0 commit comments

Comments
 (0)