Skip to content

Commit

Permalink
Merge pull request #1644 from willmcgugan/json-params
Browse files Browse the repository at this point in the history
Added json.dumps parameters
  • Loading branch information
willmcgugan committed Nov 5, 2021
2 parents 9ad5191 + 5d601fa commit 5f6cec2
Show file tree
Hide file tree
Showing 6 changed files with 129 additions and 10 deletions.
7 changes: 6 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,16 @@ 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).

## [10.12.1] - unreleased
## [10.13.0] - unreleased

### Added

- Added json.dumps parameters to print_json https://github.com/willmcgugan/rich/issues/1638

### Fixed

- Fixed an edge case bug when console module try to detect if they are in a tty at the end of a pytest run
- Fixed issue with TERM env vars that have more than one hyphen https://github.com/willmcgugan/rich/issues/1640

## [10.12.0] - 2021-10-06

Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
name = "rich"
homepage = "https://github.com/willmcgugan/rich"
documentation = "https://rich.readthedocs.io/en/latest/"
version = "10.12.0"
version = "10.13.0"
description = "Render rich text, tables, progress bars, syntax highlighting, markdown and more to the terminal"
authors = ["Will McGugan <willmcgugan@gmail.com>"]
license = "MIT"
Expand Down
28 changes: 26 additions & 2 deletions rich/__init__.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
"""Rich text and beautiful formatting in the terminal."""

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

from ._extension import load_ipython_extension

Expand Down Expand Up @@ -75,6 +75,12 @@ def print_json(
data: Any = None,
indent: int = 2,
highlight: bool = True,
skip_keys: bool = False,
ensure_ascii: bool = True,
check_circular: bool = True,
allow_nan: bool = True,
default: Optional[Callable[[Any], Any]] = None,
sort_keys: bool = False,
) -> None:
"""Pretty prints JSON. Output will be valid JSON.
Expand All @@ -83,9 +89,27 @@ def print_json(
data (Any): If json is not supplied, then encode this data.
indent (int, optional): Number of spaces to indent. Defaults to 2.
highlight (bool, optional): Enable highlighting of output: Defaults to True.
skip_keys (bool, optional): Skip keys not of a basic type. Defaults to False.
ensure_ascii (bool, optional): Escape all non-ascii characters. Defaults to False.
check_circular (bool, optional): Check for circular references. Defaults to True.
allow_nan (bool, optional): Allow NaN and Infinity values. Defaults to True.
default (Callable, optional): A callable that converts values that can not be encoded
in to something that can be JSON encoded. Defaults to None.
sort_keys (bool, optional): Sort dictionary keys. Defaults to False.
"""

get_console().print_json(json, data=data, indent=indent, highlight=highlight)
get_console().print_json(
json,
data=data,
indent=indent,
highlight=highlight,
skip_keys=skip_keys,
ensure_ascii=ensure_ascii,
check_circular=check_circular,
allow_nan=allow_nan,
default=default,
sort_keys=sort_keys,
)


def inspect(
Expand Down
37 changes: 35 additions & 2 deletions rich/console.py
Original file line number Diff line number Diff line change
Expand Up @@ -1627,6 +1627,12 @@ def print_json(
data: Any = None,
indent: int = 2,
highlight: bool = True,
skip_keys: bool = False,
ensure_ascii: bool = True,
check_circular: bool = True,
allow_nan: bool = True,
default: Optional[Callable[[Any], Any]] = None,
sort_keys: bool = False,
) -> None:
"""Pretty prints JSON. Output will be valid JSON.
Expand All @@ -1635,17 +1641,44 @@ def print_json(
data (Any): If json is not supplied, then encode this data.
indent (int, optional): Number of spaces to indent. Defaults to 2.
highlight (bool, optional): Enable highlighting of output: Defaults to True.
skip_keys (bool, optional): Skip keys not of a basic type. Defaults to False.
ensure_ascii (bool, optional): Escape all non-ascii characters. Defaults to False.
check_circular (bool, optional): Check for circular references. Defaults to True.
allow_nan (bool, optional): Allow NaN and Infinity values. Defaults to True.
default (Callable, optional): A callable that converts values that can not be encoded
in to something that can be JSON encoded. Defaults to None.
sort_keys (bool, optional): Sort dictionary keys. Defaults to False.
"""
from rich.json import JSON

if json is None:
json_renderable = JSON.from_data(data, indent=indent, highlight=highlight)
json_renderable = JSON.from_data(
data,
indent=indent,
highlight=highlight,
skip_keys=skip_keys,
ensure_ascii=ensure_ascii,
check_circular=check_circular,
allow_nan=allow_nan,
default=default,
sort_keys=sort_keys,
)
else:
if not isinstance(json, str):
raise TypeError(
f"json must be str. Did you mean print_json(data={json!r}) ?"
)
json_renderable = JSON(json, indent=indent, highlight=highlight)
json_renderable = JSON(
json,
indent=indent,
highlight=highlight,
skip_keys=skip_keys,
ensure_ascii=ensure_ascii,
check_circular=check_circular,
allow_nan=allow_nan,
default=default,
sort_keys=sort_keys,
)
self.print(json_renderable)

def update_screen(
Expand Down
54 changes: 51 additions & 3 deletions rich/json.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,38 @@ class JSON:
json (str): JSON encoded data.
indent (int, optional): Number of characters to indent by. Defaults to 2.
highlight (bool, optional): Enable highlighting. Defaults to True.
skip_keys (bool, optional): Skip keys not of a basic type. Defaults to False.
ensure_ascii (bool, optional): Escape all non-ascii characters. Defaults to False.
check_circular (bool, optional): Check for circular references. Defaults to True.
allow_nan (bool, optional): Allow NaN and Infinity values. Defaults to True.
default (Callable, optional): A callable that converts values that can not be encoded
in to something that can be JSON encoded. Defaults to None.
sort_keys (bool, optional): Sort dictionary keys. Defaults to False.
"""

def __init__(self, json: str, indent: int = 2, highlight: bool = True) -> None:
def __init__(
self,
json: str,
indent: int = 2,
highlight: bool = True,
skip_keys: bool = False,
ensure_ascii: bool = True,
check_circular: bool = True,
allow_nan: bool = True,
default: Optional[Callable[[Any], Any]] = None,
sort_keys: bool = False,
) -> None:
data = loads(json)
json = dumps(data, indent=indent)
json = dumps(
data,
indent=indent,
skipkeys=skip_keys,
ensure_ascii=ensure_ascii,
check_circular=check_circular,
allow_nan=allow_nan,
default=default,
sort_keys=sort_keys,
)
highlighter = JSONHighlighter() if highlight else NullHighlighter()
self.text = highlighter(json)
self.text.no_wrap = True
Expand All @@ -28,7 +55,12 @@ def from_data(
data: Any,
indent: int = 2,
highlight: bool = True,
skip_keys: bool = False,
ensure_ascii: bool = True,
check_circular: bool = True,
allow_nan: bool = True,
default: Optional[Callable[[Any], Any]] = None,
sort_keys: bool = False,
) -> "JSON":
"""Encodes a JSON object from arbitrary data.
Expand All @@ -37,12 +69,28 @@ def from_data(
indent (int, optional): Number of characters to indent by. Defaults to 2.
highlight (bool, optional): Enable highlighting. Defaults to True.
default (Callable, optional): Optional callable which will be called for objects that cannot be serialized. Defaults to None.
skip_keys (bool, optional): Skip keys not of a basic type. Defaults to False.
ensure_ascii (bool, optional): Escape all non-ascii characters. Defaults to False.
check_circular (bool, optional): Check for circular references. Defaults to True.
allow_nan (bool, optional): Allow NaN and Infinity values. Defaults to True.
default (Callable, optional): A callable that converts values that can not be encoded
in to something that can be JSON encoded. Defaults to None.
sort_keys (bool, optional): Sort dictionary keys. Defaults to False.
Returns:
JSON: New JSON object from the given data.
"""
json_instance: "JSON" = cls.__new__(cls)
json = dumps(data, indent=indent, default=default)
json = dumps(
data,
indent=indent,
skipkeys=skip_keys,
ensure_ascii=ensure_ascii,
check_circular=check_circular,
allow_nan=allow_nan,
default=default,
sort_keys=sort_keys,
)
highlighter = JSONHighlighter() if highlight else NullHighlighter()
json_instance.text = highlighter(json)
json_instance.text.no_wrap = True
Expand Down
11 changes: 10 additions & 1 deletion tests/test_console.py
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,15 @@ def test_print_json_data():
assert result == expected


def test_print_json_ensure_ascii():
console = Console(file=io.StringIO(), color_system="truecolor")
console.print_json(data={"foo": "💩"}, ensure_ascii=False)
result = console.file.getvalue()
print(repr(result))
expected = '\x1b[1m{\x1b[0m\n \x1b[1;34m"foo"\x1b[0m: \x1b[32m"💩"\x1b[0m\n\x1b[1m}\x1b[0m\n'
assert result == expected


def test_log():
console = Console(
file=io.StringIO(),
Expand Down Expand Up @@ -714,4 +723,4 @@ def _mock_isatty():
@pytest.mark.skipif(sys.platform == "win32", reason="not relevant on Windows")
def test_detect_color_system():
console = Console(_environ={"TERM": "rxvt-unicode-256color"}, force_terminal=True)
assert console._detect_color_system() == ColorSystem.EIGHT_BIT
assert console._detect_color_system() == ColorSystem.EIGHT_BIT

0 comments on commit 5f6cec2

Please sign in to comment.