Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add the ability to disable the display of object attributes, or to only display selected attributes in the inspect function. #3294

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
6 changes: 6 additions & 0 deletions CHANGELOG.md
Expand Up @@ -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).

## Unreleased

### Added

- Add the ability to display selected attributes using rich.inspect

## [13.7.1] - 2023-02-28

### Fixed
Expand Down
1 change: 1 addition & 0 deletions CONTRIBUTORS.md
Expand Up @@ -75,4 +75,5 @@ The following people have contributed to the development of Rich:
- [James Addison](https://github.com/jayaddison)
- [Pierro](https://github.com/xpierroz)
- [Bernhard Wagner](https://github.com/bwagner)
- [Mateusz Wozny](https://github.com/mateusz-wozny)
- [Aaron Beaudoin](https://github.com/AaronBeaudoin)
10 changes: 9 additions & 1 deletion rich/__init__.py
@@ -1,7 +1,7 @@
"""Rich text and beautiful formatting in the terminal."""

import os
from typing import IO, TYPE_CHECKING, Any, Callable, Optional, Union
from typing import IO, TYPE_CHECKING, Any, Callable, Optional, Union, Collection

from ._extension import load_ipython_extension # noqa: F401

Expand Down Expand Up @@ -130,11 +130,15 @@ def inspect(
sort: bool = True,
all: bool = False,
value: bool = True,
attributes: bool = True,
attributes_to_display: Collection[str] = (),
) -> None:
"""Inspect any Python object.

* inspect(<OBJECT>) to see summarized info.
* inspect(<OBJECT>, methods=True) to see methods.
* inspect(<OBJECT>, attributes=True) to see attributes.
* inspect(<OBJECT>, attributes=True, attributes_to_display=["attr1", "attr2"]) to see only specified attributes.
* inspect(<OBJECT>, help=True) to see full (non-abbreviated) help.
* inspect(<OBJECT>, private=True) to see private attributes (single underscore).
* inspect(<OBJECT>, dunder=True) to see attributes beginning with double underscore.
Expand All @@ -151,6 +155,8 @@ def inspect(
sort (bool, optional): Sort attributes alphabetically. Defaults to True.
all (bool, optional): Show all attributes. Defaults to False.
value (bool, optional): Pretty print value. Defaults to True.
attributes (bool, optional): Show object attributes. Defaults to True.
attributes_to_display (Collection[str], optional): List of attributes to display. Defaults to (). If empty, all attributes are displayed.
"""
_console = console or get_console()
from rich._inspect import Inspect
Expand All @@ -169,6 +175,8 @@ def inspect(
sort=sort,
all=all,
value=value,
attributes=attributes,
attributes_to_display=attributes_to_display,
)
_console.print(_inspect)

Expand Down
12 changes: 11 additions & 1 deletion rich/_inspect.py
Expand Up @@ -34,6 +34,8 @@ class Inspect(JupyterMixin):
sort (bool, optional): Sort attributes alphabetically. Defaults to True.
all (bool, optional): Show all attributes. Defaults to False.
value (bool, optional): Pretty print value of object. Defaults to True.
attributes (bool, optional): Show object attributes. Defaults to True.
attributes_to_display (Collection[str], optional): List of attributes to display. Defaults to (). If empty, all attributes are displayed.
"""

def __init__(
Expand All @@ -49,14 +51,18 @@ def __init__(
sort: bool = True,
all: bool = True,
value: bool = True,
attributes: bool = True,
attributes_to_display: Collection[str] = (),
) -> None:
self.highlighter = ReprHighlighter()
self.obj = obj
self.title = title or self._make_title(obj)
if all:
methods = private = dunder = True
methods = private = dunder = attributes = True
self.help = help
self.methods = methods
self.attributes = attributes
self.attributes_to_display = attributes_to_display
self.docs = docs or help
self.private = private or dunder
self.dunder = dunder
Expand Down Expand Up @@ -204,6 +210,10 @@ def safe_getattr(attr_name: str) -> Tuple[Any, Any]:

add_row(key_text, _signature_text)
else:
if not self.attributes:
continue
if self.attributes_to_display and key not in self.attributes_to_display:
continue
add_row(key_text, Pretty(value, highlighter=highlighter))
if items_table.row_count:
yield items_table
Expand Down
32 changes: 30 additions & 2 deletions tests/test_inspect.py
Expand Up @@ -49,9 +49,18 @@
)


def render(obj, methods=False, value=False, width=50) -> str:
def render(
obj, methods=False, value=False, width=50, attributes=True, attributes_to_display=()
) -> str:
console = Console(file=io.StringIO(), width=width, legacy_windows=False)
inspect(obj, console=console, methods=methods, value=value)
inspect(
obj,
console=console,
methods=methods,
value=value,
attributes=attributes,
attributes_to_display=attributes_to_display,
)
return console.file.getvalue()


Expand Down Expand Up @@ -208,6 +217,25 @@ def test_inspect_integer():
assert expected == render(1)


def test_inspect_integer_without_attributes():
expected = ("╭──────────────── <class 'int'> ─────────────────╮\n"
"│ int([x]) -> integer │\n"
"│ int(x, base=10) -> integer │\n"
"│ │\n"
"│ 62 attribute(s) not shown. Run │\n"
"│ inspect(inspect) for options. │\n"
"╰────────────────────────────────────────────────╯\n")
assert expected == render(1, attributes=False)

def test_inspect_integer_with_denominator():
expected = ("╭────── <class 'int'> ───────╮\n"
"│ int([x]) -> integer │\n"
"│ int(x, base=10) -> integer │\n"
"│ │\n"
"│ denominator = 1 │\n"
"╰────────────────────────────╯\n")
assert expected == render(1, attributes=True, attributes_to_display=["denominator"])

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)
Expand Down