added types to pretty printer

This commit is contained in:
Will McGugan 2021-05-12 15:31:19 +01:00
parent 201fe91a34
commit 410a06e18f
5 changed files with 48 additions and 8 deletions

View file

@ -10,9 +10,19 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Added
- Added syntax for call, i.e. "Foo(bar)"
- Fixed initial blank lines removed from Syntax https://github.com/willmcgugan/rich/issues/1214
- Added Console.measure as a convenient alias for Measurement.get
- Added support for pretty printing attrs objects
- Added mappingproxy to pretty print
- Added UserDict and UserList support to pretty printer
### Changed
- Changed colorama init to set strip=False
- Changed highlighter for False, True, None to not match in the middle of a word. i.e. NoneType is no longer highlighted as None
### Fixed
- Fixed initial blank lines removed from Syntax https://github.com/willmcgugan/rich/issues/1214
## [10.1.0] - 2020-04-03

View file

@ -527,7 +527,7 @@ def detect_legacy_windows() -> bool:
if detect_legacy_windows(): # pragma: no cover
from colorama import init
init()
init(strip=False)
class Console:

View file

@ -90,7 +90,7 @@ class ReprHighlighter(RegexHighlighter):
r"(?P<eui64>(?:[0-9A-Fa-f]{1,2}-){7}[0-9A-Fa-f]{1,2}|(?:[0-9A-Fa-f]{1,2}:){7}[0-9A-Fa-f]{1,2}|(?:[0-9A-Fa-f]{4}\.){3}[0-9A-Fa-f]{4})",
r"(?P<eui48>(?:[0-9A-Fa-f]{1,2}-){5}[0-9A-Fa-f]{1,2}|(?:[0-9A-Fa-f]{1,2}:){5}[0-9A-Fa-f]{1,2}|(?:[0-9A-Fa-f]{4}\.){2}[0-9A-Fa-f]{4})",
r"(?P<call>[\w\.]*?)\(",
r"(?P<bool_true>True)|(?P<bool_false>False)|(?P<none>None)",
r"\b(?P<bool_true>True)\b|\b(?P<bool_false>False)\b|\b(?P<none>None)\b",
r"(?P<ellipsis>\.\.\.)",
r"(?P<number>(?<!\w)\-?[0-9]+\.?[0-9]*(e[\-\+]?\d+?)?\b|0x[0-9a-fA-F]*)",
r"(?P<path>\B(\/[\w\.\-\_\+]+)*\/)(?P<filename>[\w\.\-\_\+]*)?",

View file

@ -2,10 +2,11 @@ import builtins
import os
import sys
from array import array
from collections import Counter, defaultdict, deque
from collections import Counter, defaultdict, deque, UserDict, UserList
from dataclasses import dataclass, fields, is_dataclass
from itertools import islice
from typing import (
Mapping,
TYPE_CHECKING,
Any,
Callable,
@ -17,6 +18,7 @@ from typing import (
Union,
Tuple,
)
from types import MappingProxyType
try:
import attr as _attr_module
@ -264,13 +266,16 @@ _BRACES: Dict[type, Callable[[Any], Tuple[str, str, str]]] = {
Counter: lambda _object: ("Counter({", "})", "Counter()"),
deque: lambda _object: ("deque([", "])", "deque()"),
dict: lambda _object: ("{", "}", "{}"),
UserDict: lambda _object: ("{", "}", "{}"),
frozenset: lambda _object: ("frozenset({", "})", "frozenset()"),
list: lambda _object: ("[", "]", "[]"),
UserList: lambda _object: ("[", "]", "[]"),
set: lambda _object: ("{", "}", "set()"),
tuple: lambda _object: ("(", ")", "()"),
MappingProxyType: lambda _object: ("mappingproxy({", "})", "mappingproxy({})"),
}
_CONTAINERS = tuple(_BRACES.keys())
_MAPPING_CONTAINERS = (dict, os._Environ)
_MAPPING_CONTAINERS = (dict, os._Environ, MappingProxyType, UserDict)
def is_expandable(obj: Any) -> bool:
@ -592,7 +597,12 @@ def traverse(
pop_visited(obj_id)
elif obj_type in _CONTAINERS:
elif isinstance(obj, _CONTAINERS):
for container_type in _CONTAINERS:
if isinstance(obj, container_type):
obj_type = container_type
break
obj_id = id(obj)
if obj_id in visited_ids:
# Recursion detected
@ -601,7 +611,9 @@ def traverse(
open_brace, close_brace, empty = _BRACES[obj_type](obj)
if obj:
if obj_type.__repr__ != type(obj).__repr__:
node = Node(value_repr=to_repr(obj), last=root)
elif obj:
children = []
node = Node(
open_brace=open_brace,

View file

@ -1,5 +1,5 @@
from array import array
from collections import defaultdict
from collections import defaultdict, UserDict, UserList
from dataclasses import dataclass, field
import io
import sys
@ -229,3 +229,21 @@ def test_attrs_broken():
print(repr(result))
expected = "Foo(bar=AttributeError('bar'))"
assert result == expected
def test_user_dict():
class D1(UserDict):
pass
class D2(UserDict):
def __repr__(self):
return "FOO"
d1 = D1({"foo": "bar"})
d2 = D2({"foo": "bar"})
result = pretty_repr(d1, expand_all=True)
print(repr(result))
assert result == "{\n 'foo': 'bar'\n}"
result = pretty_repr(d2, expand_all=True)
print(repr(result))
assert result == "FOO"