Skip to content

Commit

Permalink
Merge pull request #1874 from Textualize/inspect-methods-bugfix
Browse files Browse the repository at this point in the history
Handle classes in inspect when methods=True
  • Loading branch information
willmcgugan authored Jan 27, 2022
2 parents 232c8aa + 8ceeb83 commit fcd684d
Show file tree
Hide file tree
Showing 4 changed files with 36 additions and 10 deletions.
2 changes: 1 addition & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Add `Syntax.guess_lexer`, add support for more lexers (e.g. Django templates etc.) https://github.com/Textualize/rich/pull/1869
- Add `lexer` parameter to `Syntax.from_path` to allow for overrides https://github.com/Textualize/rich/pull/1873
- 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

Expand Down
12 changes: 11 additions & 1 deletion rich/_inspect.py
Original file line number Diff line number Diff line change
@@ -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

Expand Down Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion rich/default_styles.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@

from .style import Style


DEFAULT_STYLES: Dict[str, Style] = {
"none": Style.null(),
"reset": Style(
Expand Down Expand Up @@ -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"),
Expand Down
30 changes: 23 additions & 7 deletions tests/test_inspect.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import io
import sys
from types import ModuleType

import pytest

Expand Down Expand Up @@ -81,7 +82,6 @@ def test_render():


def test_inspect_text():

expected = (
"╭──────────────── <class 'str'> ─────────────────╮\n"
"│ str(object='') -> str │\n"
Expand All @@ -99,7 +99,6 @@ def test_inspect_text():
@skip_py36
@skip_py37
def test_inspect_empty_dict():

expected = (
"╭──────────────── <class 'dict'> ────────────────╮\n"
"│ dict() -> new empty dictionary │\n"
Expand All @@ -121,7 +120,6 @@ def test_inspect_empty_dict():


def test_inspect_builtin_function():

expected = (
"╭────────── <built-in function print> ───────────╮\n"
"│ def print(...) │\n"
Expand All @@ -138,7 +136,6 @@ def test_inspect_builtin_function():

@skip_py36
def test_inspect_integer():

expected = (
"╭────── <class 'int'> ───────╮\n"
"│ int([x]) -> integer │\n"
Expand All @@ -155,7 +152,6 @@ def test_inspect_integer():

@skip_py36
def test_inspect_integer_with_value():

expected = "╭────── <class 'int'> ───────╮\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))
Expand All @@ -166,7 +162,6 @@ def test_inspect_integer_with_value():
@skip_py37
@skip_py310
def test_inspect_integer_with_methods():

expected = (
"╭──────────────── <class 'int'> ─────────────────╮\n"
"│ int([x]) -> integer │\n"
Expand Down Expand Up @@ -204,7 +199,6 @@ def test_inspect_integer_with_methods():
@skip_py38
@skip_py39
def test_inspect_integer_with_methods():

expected = (
"╭──────────────── <class 'int'> ─────────────────╮\n"
"│ int([x]) -> integer │\n"
Expand Down Expand Up @@ -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 = (
"╭────────── <module 'my_module'> ──────────╮\n"
"│ function = def function(): │\n"
"│ SomeClass = class SomeClass(): Docstring │\n"
"╰──────────────────────────────────────────╯\n"
)
assert render(module, methods=True) == expected

0 comments on commit fcd684d

Please sign in to comment.