fix TypeError in inspect

This commit is contained in:
Will McGugan 2021-01-13 16:51:38 +00:00
parent a1e9cc7cc6
commit f7c078313d
4 changed files with 51 additions and 18 deletions

View File

@ -5,6 +5,12 @@ 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).
## [9.8.1] 0 2021-01-13
### Fixed
- Fixed rich.inspect failing with attributes that claim to be callable but aren't https://github.com/willmcgugan/rich/issues/916
## [9.8.0] - 2021-01-11
### Added

View File

@ -2,7 +2,7 @@
name = "rich"
homepage = "https://github.com/willmcgugan/rich"
documentation = "https://rich.readthedocs.io/en/latest/"
version = "9.8.0"
version = "9.8.1"
description = "Render rich text, tables, progress bars, syntax highlighting, markdown and more to the terminal"
authors = ["Will McGugan <willmcgugan@gmail.com>"]
license = "MIT"

View File

@ -85,12 +85,14 @@ class Inspect(JupyterMixin):
padding=(0, 1),
)
def _get_signature(self, name: str, obj: Any) -> Text:
def _get_signature(self, name: str, obj: Any) -> Optional[Text]:
"""Get a signature for a callable."""
try:
_signature = str(signature(obj)) + ":"
except ValueError:
_signature = "(...)"
except TypeError:
return None
source_filename: Optional[str] = None
try:
@ -142,8 +144,10 @@ class Inspect(JupyterMixin):
highlighter = self.highlighter
if callable(obj):
yield self._get_signature("", obj)
yield ""
signature = self._get_signature("", obj)
if signature is not None:
yield signature
yield ""
_doc = getdoc(obj)
if _doc is not None:
@ -178,20 +182,23 @@ class Inspect(JupyterMixin):
if callable(value):
if not self.methods:
continue
_signature_text = self._get_signature(key, value)
if _signature_text is None:
add_row(key_text, Pretty(value, highlighter=highlighter))
else:
if self.docs:
docs = getdoc(value)
if docs is not None:
_doc = _reformat_doc(str(docs))
if not self.help:
_doc = _first_paragraph(_doc)
_signature_text.append("\n" if "\n" in _doc else " ")
doc = highlighter(_doc)
doc.stylize("inspect.doc")
_signature_text.append(doc)
if self.docs:
docs = getdoc(value)
if docs is not None:
_doc = _reformat_doc(str(docs))
if not self.help:
_doc = _first_paragraph(_doc)
_signature_text.append("\n" if "\n" in _doc else " ")
doc = highlighter(_doc)
doc.stylize("inspect.doc")
_signature_text.append(doc)
add_row(key_text, _signature_text)
add_row(key_text, _signature_text)
else:
add_row(key_text, Pretty(value, highlighter=highlighter))
if items_table.row_count:

View File

@ -19,8 +19,8 @@ skip_py37 = pytest.mark.skipif(
)
def render(obj, methods=False, value=False) -> str:
console = Console(file=io.StringIO(), width=50, legacy_windows=False)
def render(obj, methods=False, value=False, width=50) -> str:
console = Console(file=io.StringIO(), width=width, legacy_windows=False)
inspect(obj, console=console, methods=methods, value=value)
return console.file.getvalue()
@ -183,3 +183,23 @@ def test_inspect_integer_with_methods():
"╰────────────────────────────────────────────────╯\n"
)
assert expected == render(1, methods=True)
@skip_py36
@skip_py37
def test_broken_call_attr():
class NotCallable:
__call__ = 5 # Passes callable() but isn't really callable
def __repr__(self):
return "NotCallable()"
class Foo:
foo = NotCallable()
foo = Foo()
assert callable(foo.foo)
expected = "╭─ <class 'tests.test_inspect.test_broken_call_attr.<locals>.Foo'> ─╮\n│ foo = NotCallable() │\n╰───────────────────────────────────────────────────────────────────╯\n"
result = render(foo, methods=True, width=100)
print(repr(result))
assert expected == result