diff --git a/CHANGELOG.md b/CHANGELOG.md index eb80f1dad..613fca7a7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,7 +12,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Workaround for edge case of object from Faiss with no `__class__` https://github.com/Textualize/rich/issues/1838 - Add `Syntax.guess_lexer`, add support for more lexers (e.g. Django templates etc.) https://github.com/Textualize/rich/pull/1869 - Ensure `Syntax` always justifies left https://github.com/Textualize/rich/pull/1872 - +- Handle classes in inspect when methods=True https://github.com/Textualize/rich/pull/1874 ### Added diff --git a/rich/_inspect.py b/rich/_inspect.py index 07b1b623b..b3652bfbd 100644 --- a/rich/_inspect.py +++ b/rich/_inspect.py @@ -1,5 +1,6 @@ from __future__ import absolute_import +import inspect from inspect import cleandoc, getdoc, getfile, isclass, ismodule, signature from typing import Any, Iterable, Optional, Tuple @@ -106,8 +107,17 @@ def _get_signature(self, name: str, obj: Any) -> Optional[Text]: signature_text = self.highlighter(_signature) qualname = name or getattr(obj, "__qualname__", name) + + # If obj is a module, there may be classes (which are callable) to display + if inspect.isclass(obj): + prefix = "class" + else: + prefix = "def" + qual_signature = Text.assemble( - ("def ", "inspect.def"), (qualname, "inspect.callable"), signature_text + (f"{prefix} ", f"inspect.{prefix}"), + (qualname, "inspect.callable"), + signature_text, ) return qual_signature diff --git a/rich/default_styles.py b/rich/default_styles.py index 63290bcab..d803eec91 100644 --- a/rich/default_styles.py +++ b/rich/default_styles.py @@ -2,7 +2,6 @@ from .style import Style - DEFAULT_STYLES: Dict[str, Style] = { "none": Style.null(), "reset": Style( @@ -41,6 +40,7 @@ "inspect.attr.dunder": Style(color="yellow", italic=True, dim=True), "inspect.callable": Style(bold=True, color="red"), "inspect.def": Style(italic=True, color="bright_cyan"), + "inspect.class": Style(italic=True, color="bright_cyan"), "inspect.error": Style(bold=True, color="red"), "inspect.equals": Style(), "inspect.help": Style(color="cyan"), diff --git a/tests/test_inspect.py b/tests/test_inspect.py index 05a78b871..63c5f0624 100644 --- a/tests/test_inspect.py +++ b/tests/test_inspect.py @@ -1,5 +1,6 @@ import io import sys +from types import ModuleType import pytest @@ -81,7 +82,6 @@ def test_render(): def test_inspect_text(): - expected = ( "╭──────────────── ─────────────────╮\n" "│ str(object='') -> str │\n" @@ -99,7 +99,6 @@ def test_inspect_text(): @skip_py36 @skip_py37 def test_inspect_empty_dict(): - expected = ( "╭──────────────── ────────────────╮\n" "│ dict() -> new empty dictionary │\n" @@ -121,7 +120,6 @@ def test_inspect_empty_dict(): def test_inspect_builtin_function(): - expected = ( "╭────────── ───────────╮\n" "│ def print(...) │\n" @@ -138,7 +136,6 @@ def test_inspect_builtin_function(): @skip_py36 def test_inspect_integer(): - expected = ( "╭────── ───────╮\n" "│ int([x]) -> integer │\n" @@ -155,7 +152,6 @@ def test_inspect_integer(): @skip_py36 def test_inspect_integer_with_value(): - expected = "╭────── ───────╮\n│ int([x]) -> integer │\n│ int(x, base=10) -> integer │\n│ │\n│ ╭────────────────────────╮ │\n│ │ 1 │ │\n│ ╰────────────────────────╯ │\n│ │\n│ denominator = 1 │\n│ imag = 0 │\n│ numerator = 1 │\n│ real = 1 │\n╰────────────────────────────╯\n" value = render(1, value=True) print(repr(value)) @@ -166,7 +162,6 @@ def test_inspect_integer_with_value(): @skip_py37 @skip_py310 def test_inspect_integer_with_methods(): - expected = ( "╭──────────────── ─────────────────╮\n" "│ int([x]) -> integer │\n" @@ -204,7 +199,6 @@ def test_inspect_integer_with_methods(): @skip_py38 @skip_py39 def test_inspect_integer_with_methods(): - expected = ( "╭──────────────── ─────────────────╮\n" "│ int([x]) -> integer │\n" @@ -274,3 +268,25 @@ def __class__(self): inspect(thing) except Exception as e: assert False, f"Object with no __class__ shouldn't raise {e}" + + +def test_inspect_module_with_class(): + def function(): + pass + + class Thing: + """Docstring""" + + pass + + module = ModuleType("my_module") + module.SomeClass = Thing + module.function = function + + expected = ( + "╭────────── ──────────╮\n" + "│ function = def function(): │\n" + "│ SomeClass = class SomeClass(): Docstring │\n" + "╰──────────────────────────────────────────╯\n" + ) + assert render(module, methods=True) == expected