failed NO_PATCH NO_PATCH UNSUBMITTED empty_patch(None) · None tool calls · 0 s · Textualize/rich
Handle unusual __qualname__ in inspect
<!--
Please note that Rich isn't accepting any new features at this point.
If a feature can be implemented without modifying the core library, then
they should be released as a third-party module. I can accept updates to the
core library that make it easier to extend (think hooks).
Bugfixes are always welcome of course.
Sometimes it is not clear what is a feature and what is a bug fix.
If there is any doubt, please open a discussion first.
-->
<!--
*Are you contributing typo fixes?*
If your PR solely consists of typos, at least one must be in the docs to warrant an addition to CONTRIBUTORS.md
-->
## Type of changes
- [x] Bug fix
- [ ] New feature
- [ ] Documentation / docstrings
- [x] Tests
- [ ] Other
## Checklist
- [x] I've run the latest [black](https://github.com/psf/black) with default args on new code.
- [x] I've updated CHANGELOG.md and CONTRIBUTORS.md where appropriate (see note about typos above).
- [x] I've added tests for new code.
- [x] I accept that @willmcgugan may be pedantic in the code review.
## Description
I discovered, that an object with an unusual `__qualname__` attribute (not a `str`, e.g. a descriptor) causes `inspect` to fail.
This can happen if an object is created this way intentionally, but I discovered it, when decorating a class with `@functools.lru_cache` which forwards the underlying attributes using a descriptor when it can't add the to it's `__dict__` because the class uses `__slots__`:
```python
from functools import lru_cache
from rich import inspect
@lru_cache
class Klaas:
__slots__ = ("__qualname__",)
if __name__ == "__main__":
from rich.traceback import install
install()
inspect(Klaas.__qualname__)
inspect(Klaas, all=True)
```
I fixed it by checking the type of `__qualname__` falling back to `__name__` and if that isn't a `str` using the already provided fallback.
| # | Tool | Arguments | Result |
|---|---|---|---|
| No trace captured. | |||
...s....sss...F
=================================== FAILURES ===================================
____________________________ test_qualname_in_slots ____________________________
def test_qualname_in_slots():
from functools import lru_cache
@lru_cache
class Klass:
__slots__ = ("__qualname__",)
try:
> inspect(Klass)
tests/test_inspect.py:415:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
rich/__init__.py:173: in inspect
_console.print(_inspect)
rich/console.py:1698: in print
renderables = self._collect_renderables(
rich/console.py:1555: in _collect_renderables
renderable = rich_cast(renderable)
rich/protocol.py:36: in rich_cast
renderable = cast_method()
rich/_inspect.py:76: in __rich__
Group(*self._render()),
rich/_inspect.py:153: in _render
signature = self._get_signature("", obj)
rich/_inspect.py:113: in _get_signature
qual_signature = Text.assemble(
rich/text.py:397: in assemble
append(*part)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
self = <text 'def ' [Span(0, 4, 'inspect.def')] ''>
text = <member '__qualname__' of 'Klass' objects>, style = 'inspect.callable'
def append(
self, text: Union["Text", str], style: Optional[Union[str, "Style"]] = None
) -> "Text":
"""Add text with an optional style.
Args:
text (Union[Text, str]): A str or Text to append.
style (str, optional): A style name. Defaults to None.
Returns:
Text: Returns self for chaining.
"""
if not isinstance(text, (str, Text)):
> raise TypeError("Only str or Text can be appended to Text")
E TypeError: Only str or Text can be appended to Text
rich/text.py:979: TypeError
During handling of the above exception, another exception occurred:
def test_qualname_in_slots():
from functools import lru_cache
@lru_cache
class Klass:
__slots__ = ("__qualname__",)
try:
inspect(Klass)
except Exception as e:
> assert False, f"Class with __qualname__ in __slots__ shouldn't raise {e}"
E AssertionError: Class with __qualname__ in __slots__ shouldn't raise Only str or Text can be appended to Text
E assert False
tests/test_inspect.py:417: AssertionError
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 10 passed, 4 skipped in 0.18s