added print_json

This commit is contained in:
Will McGugan 2021-08-28 15:04:06 +01:00
parent 69ea180f75
commit 6e76b2216f
11 changed files with 159 additions and 2 deletions

View file

@ -5,12 +5,17 @@ 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]
## [10.8.0] - 2020-08-28
### Added
- Added Panel.subtitle
- Added Panel.subtitle_align
### Fixed
- Fixed a bug where calling `rich.reconfigure` within a `pytest_configure` hook would lead to a crash
- Fixed highlight not being passed through options https://github.com/willmcgugan/rich/issues/1404
## [10.7.0] - 2021-08-05

View file

@ -69,6 +69,24 @@ The :meth:`~rich.console.Console.log` methods offers the same capabilities as pr
To help with debugging, the log() method has a ``log_locals`` parameter. If you set this to ``True``, Rich will display a table of local variables where the method was called.
Printing JSON
-------------
The :meth:`~rich.console.Console.print_json` method will pretty print (format and style) a string containing JSON. Here's a short example::
console.print_json('[false, true, null, "foo"]')
You can also *log* json by printing a :class:`~rich.json.JSON` object::
from rich.json import JSON
console.print_json(JSON('["foo", "bar"]'))
Because printing JSON is a common requirement, you may import ``print_json`` from the main namespace::
from rich import print_json
Low level output
----------------
@ -78,6 +96,7 @@ Here's an example::
>>> console.out("Locals", locals())
Rules
-----

View file

@ -0,0 +1,7 @@
rich.json
=========
.. automodule:: rich.json
:members:

View file

@ -2,7 +2,7 @@
name = "rich"
homepage = "https://github.com/willmcgugan/rich"
documentation = "https://rich.readthedocs.io/en/latest/"
version = "10.7.0"
version = "10.8.0"
description = "Render rich text, tables, progress bars, syntax highlighting, markdown and more to the terminal"
authors = ["Will McGugan <willmcgugan@gmail.com>"]
license = "MIT"

View file

@ -69,6 +69,17 @@ def print(
return write_console.print(*objects, sep=sep, end=end)
def print_json(json: str, indent: int = 4, highlight: bool = True) -> None:
"""Pretty prints JSON. Output will be valid JSON.
Args:
json (str): A string containing JSON.
indent (int, optional): Number of spaces to indent. Defaults to 4.
"""
get_console().print_json(json, indent=indent, highlight=highlight)
def inspect(
obj: Any,
*,

View file

@ -1583,6 +1583,7 @@ class Console:
height=height,
no_wrap=no_wrap,
markup=markup,
highlight=highlight,
)
new_segments: List[Segment] = []
@ -1613,6 +1614,17 @@ class Console:
else:
self._buffer.extend(new_segments)
def print_json(self, json:str, indent:int=4, highlight:bool=True) -> None:
"""Pretty prints JSON. Output will be valid JSON.
Args:
json (str): A string containing JSON.
indent (int, optional): Number of spaces to indent. Defaults to 4.
"""
from rich.json import JSON
json_renderable = JSON(json, indent=indent, highlight=highlight)
self.print(json_renderable)
def update_screen(
self,
renderable: RenderableType,

View file

@ -88,6 +88,12 @@ DEFAULT_STYLES: Dict[str, Style] = {
"repr.filename": Style(color="bright_magenta"),
"rule.line": Style(color="bright_green"),
"rule.text": Style.null(),
"json.brace": Style(bold=True),
"json.bool_true": Style(color="bright_green", italic=True),
"json.bool_false": Style(color="bright_red", italic=True),
"json.null": Style(color="magenta", italic=True),
"json.number": Style(color="cyan", bold=True, italic=False),
"json.str": Style(color="green", italic=False, bold=False),
"prompt": Style.null(),
"prompt.choices": Style(color="magenta", bold=True),
"prompt.default": Style(color="cyan", bold=True),

View file

@ -101,6 +101,20 @@ class ReprHighlighter(RegexHighlighter):
]
class JSONHighlighter(RegexHighlighter):
"""Highlights JSON"""
base_style = "json."
highlights = [
_combine_regex(
r"(?P<brace>[\{\[\(\)\]\}])",
r"\b(?P<bool_true>true)\b|\b(?P<bool_false>false)\b|\b(?P<null>null)\b",
r"(?P<number>(?<!\w)\-?[0-9]+\.?[0-9]*(e[\-\+]?\d+?)?\b|0x[0-9a-fA-F]*)",
r"(?<![\\\w])(?P<str>b?\".*?(?<!\\)\")",
),
]
if __name__ == "__main__": # pragma: no cover
from .console import Console

64
rich/json.py Normal file
View file

@ -0,0 +1,64 @@
from json import loads, dumps
from .text import Text
from .highlighter import JSONHighlighter, NullHighlighter
class JSON:
"""A rebderable which pretty prints JSON.
Args:
json (str): JSON encoded data.
indent (int, optional): Number of characters to indent by. Defaults to True.
highlight (bool, optional): Enable highlighting. Defaults to True.
"""
def __init__(self, json: str, indent: int = 4, highlight: bool = True) -> None:
data = loads(json)
json = dumps(data, indent=indent)
highlighter = JSONHighlighter() if highlight else NullHighlighter()
self.text = highlighter(json)
self.text.no_wrap = True
self.text.overflow = None
def __rich__(self) -> Text:
return self.text
if __name__ == "__main__":
j = """
{ "atomic": [false, true, null],
"widget": {
"debug": true,
"window": {
"title": "Sample Konfabulator Widget",
"name": "main_window",
"width": 500,
"height": 500
},
"image": {
"src": "Images/Sun.png",
"name": "sun1",
"hOffset": 250,
"vOffset": 250,
"alignment": "center"
},
"text": {
"data": "Click Here",
"size": 36,
"style": "bold",
"name": "text1",
"hOffset": 250,
"vOffset": 100,
"alignment": "center",
"onMouseUp": "sun1.opacity = (sun1.opacity / 100) * 90;"
}
}}
"""
from rich.console import Console
console = Console()
print(dumps(loads(j)))
console.print(JSON(j), soft_wrap=True)

View file

@ -117,6 +117,15 @@ def test_print():
assert console.file.getvalue() == "foo\n"
def test_print_json():
console = Console(file=io.StringIO(), color_system="truecolor")
console.print_json('[false, true, null, "foo"]')
result = console.file.getvalue()
print(repr(result))
expected = '\x1b[1m[\x1b[0m\n \x1b[3;91mfalse\x1b[0m,\n \x1b[3;92mtrue\x1b[0m,\n \x1b[3;35mnull\x1b[0m,\n \x1b[32m"foo"\x1b[0m\n\x1b[1m]\x1b[0m\n'
assert result == expected
def test_log():
console = Console(
file=io.StringIO(),

View file

@ -28,6 +28,16 @@ def test_rich_print():
console.file = backup_file
def test_rich_print_json():
console = rich.get_console()
with console.capture() as capture:
rich.print_json('[false, true, null, "foo"]')
result = capture.get()
print(repr(result))
expected = '[\n false,\n true,\n null,\n "foo"\n]\n'
assert result == expected
def test_rich_print_X():
console = rich.get_console()
output = io.StringIO()