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

Added json.dumps parameters #1644

Merged
merged 4 commits into from
Nov 5, 2021
Merged
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
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