Created
January 22, 2025 12:03
-
-
Save afspies/e679e3a02aa05e87cafff9e00ea90779 to your computer and use it in GitHub Desktop.
Python function to visually inspect json structure
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
from typing import Any | |
from rich.console import Console | |
from rich.theme import Theme | |
from rich.text import Text | |
custom_theme = Theme({ | |
"key": "yellow", | |
"type": "cyan", | |
"value": "green", | |
"tree": "bright_black", | |
}) | |
console = Console(theme=custom_theme, soft_wrap=True) | |
def _get_tree_prefix(indent: int, is_last: bool = False) -> str: | |
"""Generate tree-style prefix with proper indentation.""" | |
if indent == 0: | |
return "" | |
return "│ " * (indent - 1) + ("└── " if is_last else "├── ") | |
def _format_content(content: Any, show_content: bool, max_length: int) -> str: | |
"""Format content with truncation.""" | |
if not show_content: | |
return "" | |
content_str = str(content) | |
if len(content_str) > max_length: | |
content_str = content_str[:max_length] + "..." | |
return f" = {content_str}" if content_str else "" | |
def _build_visualization( | |
obj: Any, | |
*, | |
show_content: bool, | |
max_length: int, | |
indent: int = 0, | |
is_last: bool = True, | |
key: str = "", | |
output: Text = None | |
) -> Text: | |
"""Build visualization as a single Rich Text object.""" | |
if output is None: | |
output = Text() | |
def add_node(label: str, type_name: str, content: str = ""): | |
"""Add a node to the text output.""" | |
if output.plain: # If not first line, add newline | |
output.append("\n") | |
output.append(_get_tree_prefix(indent, is_last), style="tree") | |
output.append(label, style="key") | |
output.append(": ", style="tree") | |
output.append(type_name, style="type") | |
if content: | |
output.append(content, style="value") | |
if isinstance(obj, dict): | |
if key: # Print dict header if this is a nested dict | |
add_node(key, "dict") | |
items = list(obj.items()) | |
for i, (k, v) in enumerate(items): | |
_build_visualization( | |
v, show_content=show_content, max_length=max_length, | |
indent=indent + 1, is_last=i == len(items) - 1, | |
key=k, output=output | |
) | |
elif isinstance(obj, list): | |
label = key if key else "" | |
if not obj: | |
add_node(label, "list", " (empty)") | |
return output | |
if all(not isinstance(x, (dict, list)) for x in obj): | |
types = {type(x).__name__ for x in obj} | |
type_str = f"list of {' or '.join(types)} [{len(obj)} items]" | |
add_node(label, type_str) | |
if show_content: | |
for i, item in enumerate(obj): | |
_build_visualization( | |
item, show_content=show_content, max_length=max_length, | |
indent=indent + 1, is_last=i == len(obj) - 1, | |
key=f"[{i}]", output=output | |
) | |
return output | |
add_node(label, "list") | |
for i, item in enumerate(obj): | |
_build_visualization( | |
item, show_content=show_content, max_length=max_length, | |
indent=indent + 1, is_last=i == len(obj) - 1, | |
key=f"[{i}]", output=output | |
) | |
else: | |
content = _format_content(obj, show_content, max_length) | |
add_node(key, type(obj).__name__, content) | |
return output | |
def visualize_json( | |
obj: Any, | |
*, | |
show_content: bool = False, | |
max_length: int = 100, | |
) -> None: | |
""" | |
Visualize JSON structure with tree-style indicators and colored output. | |
Args: | |
obj: The JSON object to visualize | |
show_content: Whether to display the actual values (default: False) | |
max_length: Maximum length for displayed values before truncation (default: 100) | |
Example: | |
>>> data = { | |
... "name": "John Doe", | |
... "contacts": { | |
... "email": "[email protected]", | |
... "phones": ["+1234567890"] | |
... } | |
... } | |
>>> visualize_json(data) # Shows structure only | |
>>> visualize_json(data, show_content=True) # Shows values | |
""" | |
output = _build_visualization(obj, show_content=show_content, max_length=max_length) | |
console.print(output) | |
# Example usage: | |
if __name__ == "__main__": | |
sample_json = { | |
"name": "John Doe", | |
"contacts": { | |
"email": "[email protected]", | |
"phones": ["+1234567890", "+0987654321"], | |
"emergency": [] | |
}, | |
"addresses": [ | |
{ | |
"type": "home", | |
"street": "123 Main St", | |
"city": "Anytown" | |
}, | |
{ | |
"type": "work", | |
"street": "456 Office Blvd", | |
"city": "Workville" | |
} | |
], | |
"scores": [95, 87, 91], | |
"notes": [], | |
"active": True | |
} | |
print("\nStructure only:") | |
visualize_json(sample_json) | |
print("\nWith content:") | |
visualize_json(sample_json, show_content=True, max_length=50) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment