from pathlib import Path
from json import loads , dumps
from typing import Any , Callable , Optional , Union
from . text import Text
from . highlighter import JSONHighlighter , NullHighlighter
class JSON :
""" A renderable which pretty prints JSON.
Args :
json ( str ) : JSON encoded data .
indent ( Union [ None , int , str ] , 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 : Union [ None , int , str ] = 2 ,
highlight : bool = True ,
skip_keys : bool = False ,
ensure_ascii : bool = False ,
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 ,
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
self . text . overflow = None
@classmethod
def from_data (
cls ,
data : Any ,
indent : Union [ None , int , str ] = 2 ,
highlight : bool = True ,
skip_keys : bool = False ,
ensure_ascii : bool = False ,
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.
Args :
data ( Any ) : An object that may be encoded in to JSON
indent ( Union [ None , int , str ] , 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 ,
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
json_instance . text . overflow = None
return json_instance
def __rich__ ( self ) - > Text :
return self . text
if __name__ == " __main__ " :
import argparse
import sys
parser = argparse . ArgumentParser ( description = " Pretty print json " )
parser . add_argument (
" path " ,
metavar = " PATH " ,
help = " path to file, or - for stdin " ,
)
parser . add_argument (
" -i " ,
" --indent " ,
metavar = " SPACES " ,
type = int ,
help = " Number of spaces in an indent " ,
default = 2 ,
)
args = parser . parse_args ( )
from rich . console import Console
console = Console ( )
error_console = Console ( stderr = True )
try :
if args . path == " - " :
json_data = sys . stdin . read ( )
else :
json_data = Path ( args . path ) . read_text ( )
except Exception as error :
error_console . print ( f " Unable to read { args . path !r} ; { error } " )
sys . exit ( - 1 )
console . print ( JSON ( json_data , indent = args . indent ) , soft_wrap = True )