mirror of https://github.com/Textualize/rich.git
Merge branch 'master' into revert-1832-epsq-widths
This commit is contained in:
commit
1eb4f5db0d
|
@ -15,6 +15,8 @@ Edit this with a clear and concise description of what the bug.
|
|||
Provide a minimal code example that demonstrates the issue if you can. If the issue is visual in nature, consider posting a screenshot.
|
||||
|
||||
**Platform**
|
||||
<details>
|
||||
<summary>Click to expand</summary>
|
||||
|
||||
What platform (Win/Linux/Mac) are you running on? What terminal software are you using?
|
||||
|
||||
|
@ -25,3 +27,5 @@ python -m rich.diagnose
|
|||
python -m rich._windows
|
||||
pip freeze | grep rich
|
||||
```
|
||||
|
||||
</details>
|
||||
|
|
|
@ -5,7 +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).
|
||||
|
||||
## [11.0.0] - 2022-01-09
|
||||
## [Unreleased]
|
||||
|
||||
### Added
|
||||
|
||||
- Workaround for edge case of object from Faiss with no `__class__` https://github.com/Textualize/rich/issues/1838
|
||||
|
||||
|
||||
### Added
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
alabaster==0.7.12
|
||||
Sphinx==4.3.2
|
||||
Sphinx==4.4.0
|
||||
sphinx-rtd-theme==1.0.0
|
||||
sphinx-copybutton==0.4.0
|
||||
|
|
|
@ -3,7 +3,7 @@ from __future__ import absolute_import
|
|||
from inspect import cleandoc, getdoc, getfile, isclass, ismodule, signature
|
||||
from typing import Any, Iterable, Optional, Tuple
|
||||
|
||||
from .console import RenderableType, Group
|
||||
from .console import Group, RenderableType
|
||||
from .highlighter import ReprHighlighter
|
||||
from .jupyter import JupyterMixin
|
||||
from .panel import Panel
|
||||
|
@ -204,7 +204,8 @@ class Inspect(JupyterMixin):
|
|||
add_row(key_text, Pretty(value, highlighter=highlighter))
|
||||
if items_table.row_count:
|
||||
yield items_table
|
||||
else:
|
||||
elif not_shown_count:
|
||||
yield Text.from_markup(
|
||||
f"[b cyan]{not_shown_count}[/][i] attribute(s) not shown.[/i] Run [b][magenta]inspect[/]([not b]inspect[/])[/b] for options."
|
||||
f"[b cyan]{not_shown_count}[/][i] attribute(s) not shown.[/i] "
|
||||
f"Run [b][magenta]inspect[/]([not b]inspect[/])[/b] for options."
|
||||
)
|
||||
|
|
|
@ -2,7 +2,6 @@ import builtins
|
|||
import dataclasses
|
||||
import inspect
|
||||
import os
|
||||
import re
|
||||
import sys
|
||||
from array import array
|
||||
from collections import Counter, UserDict, UserList, defaultdict, deque
|
||||
|
@ -93,7 +92,7 @@ def _ipy_display_hook(
|
|||
from .console import ConsoleRenderable # needed here to prevent circular import
|
||||
|
||||
# always skip rich generated jupyter renderables or None values
|
||||
if isinstance(value, JupyterRenderable) or value is None:
|
||||
if _safe_isinstance(value, JupyterRenderable) or value is None:
|
||||
return
|
||||
|
||||
console = console or get_console()
|
||||
|
@ -124,12 +123,12 @@ def _ipy_display_hook(
|
|||
return # Delegate rendering to IPython
|
||||
|
||||
# certain renderables should start on a new line
|
||||
if isinstance(value, ConsoleRenderable):
|
||||
if _safe_isinstance(value, ConsoleRenderable):
|
||||
console.line()
|
||||
|
||||
console.print(
|
||||
value
|
||||
if isinstance(value, RichRenderable)
|
||||
if _safe_isinstance(value, RichRenderable)
|
||||
else Pretty(
|
||||
value,
|
||||
overflow=overflow,
|
||||
|
@ -144,6 +143,16 @@ def _ipy_display_hook(
|
|||
)
|
||||
|
||||
|
||||
def _safe_isinstance(
|
||||
obj: object, class_or_tuple: Union[type, Tuple[type, ...]]
|
||||
) -> bool:
|
||||
"""isinstance can fail in rare cases, for example types with no __class__"""
|
||||
try:
|
||||
return isinstance(obj, class_or_tuple)
|
||||
except Exception:
|
||||
return False
|
||||
|
||||
|
||||
def install(
|
||||
console: Optional["Console"] = None,
|
||||
overflow: "OverflowMethod" = "ignore",
|
||||
|
@ -178,7 +187,7 @@ def install(
|
|||
builtins._ = None # type: ignore
|
||||
console.print(
|
||||
value
|
||||
if isinstance(value, RichRenderable)
|
||||
if _safe_isinstance(value, RichRenderable)
|
||||
else Pretty(
|
||||
value,
|
||||
overflow=overflow,
|
||||
|
@ -355,7 +364,7 @@ _MAPPING_CONTAINERS = (dict, os._Environ, MappingProxyType, UserDict)
|
|||
def is_expandable(obj: Any) -> bool:
|
||||
"""Check if an object may be expanded by pretty print."""
|
||||
return (
|
||||
isinstance(obj, _CONTAINERS)
|
||||
_safe_isinstance(obj, _CONTAINERS)
|
||||
or (is_dataclass(obj))
|
||||
or (hasattr(obj, "__rich_repr__"))
|
||||
or _is_attr_object(obj)
|
||||
|
@ -539,7 +548,7 @@ def traverse(
|
|||
"""Get repr string for an object, but catch errors."""
|
||||
if (
|
||||
max_string is not None
|
||||
and isinstance(obj, (bytes, str))
|
||||
and _safe_isinstance(obj, (bytes, str))
|
||||
and len(obj) > max_string
|
||||
):
|
||||
truncated = len(obj) - max_string
|
||||
|
@ -565,7 +574,7 @@ def traverse(
|
|||
|
||||
def iter_rich_args(rich_args: Any) -> Iterable[Union[Any, Tuple[str, Any]]]:
|
||||
for arg in rich_args:
|
||||
if isinstance(arg, tuple):
|
||||
if _safe_isinstance(arg, tuple):
|
||||
if len(arg) == 3:
|
||||
key, child, default = arg
|
||||
if default == child:
|
||||
|
@ -622,7 +631,7 @@ def traverse(
|
|||
last=root,
|
||||
)
|
||||
for last, arg in loop_last(args):
|
||||
if isinstance(arg, tuple):
|
||||
if _safe_isinstance(arg, tuple):
|
||||
key, child = arg
|
||||
child_node = _traverse(child, depth=depth + 1)
|
||||
child_node.last = last
|
||||
|
@ -689,7 +698,7 @@ def traverse(
|
|||
|
||||
elif (
|
||||
is_dataclass(obj)
|
||||
and not isinstance(obj, type)
|
||||
and not _safe_isinstance(obj, type)
|
||||
and not fake_attributes
|
||||
and (_is_dataclass_repr(obj) or py_version == (3, 6))
|
||||
):
|
||||
|
@ -722,9 +731,9 @@ def traverse(
|
|||
|
||||
pop_visited(obj_id)
|
||||
|
||||
elif isinstance(obj, _CONTAINERS):
|
||||
elif _safe_isinstance(obj, _CONTAINERS):
|
||||
for container_type in _CONTAINERS:
|
||||
if isinstance(obj, container_type):
|
||||
if _safe_isinstance(obj, container_type):
|
||||
obj_type = container_type
|
||||
break
|
||||
|
||||
|
@ -752,7 +761,7 @@ def traverse(
|
|||
num_items = len(obj)
|
||||
last_item_index = num_items - 1
|
||||
|
||||
if isinstance(obj, _MAPPING_CONTAINERS):
|
||||
if _safe_isinstance(obj, _MAPPING_CONTAINERS):
|
||||
iter_items = iter(obj.items())
|
||||
if max_length is not None:
|
||||
iter_items = islice(iter_items, max_length)
|
||||
|
@ -777,7 +786,7 @@ def traverse(
|
|||
pop_visited(obj_id)
|
||||
else:
|
||||
node = Node(value_repr=to_repr(obj), last=root)
|
||||
node.is_tuple = isinstance(obj, tuple)
|
||||
node.is_tuple = _safe_isinstance(obj, tuple)
|
||||
return node
|
||||
|
||||
node = _traverse(_object, root=True)
|
||||
|
@ -812,13 +821,13 @@ def pretty_repr(
|
|||
str: A possibly multi-line representation of the object.
|
||||
"""
|
||||
|
||||
if isinstance(_object, Node):
|
||||
if _safe_isinstance(_object, Node):
|
||||
node = _object
|
||||
else:
|
||||
node = traverse(
|
||||
_object, max_length=max_length, max_string=max_string, max_depth=max_depth
|
||||
)
|
||||
repr_str = node.render(
|
||||
repr_str: str = node.render(
|
||||
max_width=max_width, indent_size=indent_size, expand_all=expand_all
|
||||
)
|
||||
return repr_str
|
||||
|
|
|
@ -6,7 +6,6 @@ import pytest
|
|||
from rich import inspect
|
||||
from rich.console import Console
|
||||
|
||||
|
||||
skip_py36 = pytest.mark.skipif(
|
||||
sys.version_info.minor == 6 and sys.version_info.major == 3,
|
||||
reason="rendered differently on py3.6",
|
||||
|
@ -260,3 +259,18 @@ def test_broken_call_attr():
|
|||
result = render(foo, methods=True, width=100)
|
||||
print(repr(result))
|
||||
assert expected == result
|
||||
|
||||
|
||||
def test_inspect_swig_edge_case():
|
||||
"""Issue #1838 - Edge case with Faiss library - object with empty dir()"""
|
||||
|
||||
class Thing:
|
||||
@property
|
||||
def __class__(self):
|
||||
raise AttributeError
|
||||
|
||||
thing = Thing()
|
||||
try:
|
||||
inspect(thing)
|
||||
except Exception as e:
|
||||
assert False, f"Object with no __class__ shouldn't raise {e}"
|
||||
|
|
Loading…
Reference in New Issue