Skip to main content

A Python package for handling nested JSON structures.

Project description

๐Ÿงญ JSONavigator

The Swiss Army knife for nested JSON โ€” traverse, flatten, search, validate, format, and diff JSON structures with a single lightweight Python library.

PyPI Downloads PyPI version Python Versions License: MIT CI Repo Size


๐Ÿค” Why JSONavigator?

Working with deeply nested JSON in Python is painful. Standard dict access breaks on missing keys; jmespath has a custom query language to learn; pandas is overkill for simple lookups.

JSONavigator solves this with a zero-dependency, pure-Python code that covers the whole lifecycle of nested JSON manipulation โ€” from traversal to diffing โ€” in a handful of intuitive functions.

4,000+ downloads  โ€ข  Zero dependencies  โ€ข  Python 3.8+  โ€ข  MIT Licensed

โœจ Features

Feature Function Description
๐Ÿ” Traverse traverse_json Recursively yield every (path, value) pair
๐Ÿ“ฆ Flatten flatten_json Collapse nested JSON into a single-level dict
๐ŸŽฏ Get by path get_value_at_path Retrieve a value using a dot-notation path
โœ๏ธ Set by path set_value_at_path Update or set a value at a dot-notation path
๐Ÿ—‘๏ธ Delete by path delete_at_path Remove a key/index at a dot-notation path
๐Ÿงน Delete key delete_key Recursively remove every occurrence of a key
๐Ÿ”Ž Find value find_value_of_element Search for first occurrence of a key, anywhere
๐Ÿ—บ๏ธ Find all paths find_all_paths_for_element Get every path where a key exists
๐Ÿงน Clear values empty_all_the_values Reset all leaf values to "" in-place
โœ… Validate path validate_path Assert a path string is well-formed
๐Ÿ’… Format path format_path Pretty-print a path for human readability
๐Ÿ“Š Compare JSON compare_files Diff two JSON objects or files with a summary
๐Ÿšจ Custom exceptions InvalidPathError, ElementNotFoundError Semantic error handling

๐Ÿ“ฆ Installation

pip install jsonavigator

From source:

git clone https://github.com/Nikhil-Singh-2503/JSONavigator.git
cd JSONavigator
python -m venv venv && source venv/bin/activate
pip install -r requirements.txt

Requires: Python โ‰ฅ 3.8. No runtime dependencies.


โšก Quick Start

from jsoninja import (
    traverse_json,
    get_value_at_path,
    flatten_json,
    find_value_of_element,
    find_all_paths_for_element,
    empty_all_the_values,
    validate_path,
    format_path,
    compare_files,
)

data = {
    "user": {
        "name": "Alice",
        "scores": [95, 87, 100],
        "address": {"city": "Berlin", "zip": "10115"}
    }
}

# Traverse every leaf
for path, value in traverse_json(data):
    print(f"{path}: {value}")
# user.name: Alice
# user.scores[0]: 95  ...

# Retrieve by path
print(get_value_at_path(data, "user.address.city"))  # Berlin

# Flatten to single level
flat = flatten_json(data)
# {"user.name": "Alice", "user.scores[0]": 95, ...}

๐Ÿ“– Usage Guide

1๏ธโƒฃ Traverse Nested JSON

View Details

Yields (path, value) tuples for every leaf node. Supports mixed dicts and lists.

from jsoninja import traverse_json

data = {"a": {"b": [1, 2], "c": 3}}

for path, value in traverse_json(data):
    print(f"Path: {path}, Value: {value}")
Path: a.b[0], Value: 1
Path: a.b[1], Value: 2
Path: a.c, Value: 3

Use the separator parameter to change the default . delimiter.

traverse_json(data, separator="/")  # a/b[0], a/b[1], a/c

2๏ธโƒฃ Get Value at a Specific Path

View Details
from jsoninja import get_value_at_path

data = {"a": {"b": [10, 20, 30]}}

print(get_value_at_path(data, "a.b[2]"))   # 30
print(get_value_at_path(data, "a.b[0]"))   # 10

3๏ธโƒฃ Set Value at a Specific Path

View Details

Update or create a leaf value using dot notation, modifying the dict in place.

from jsoninja import set_value_at_path

data = {"user": {"scores": [10, 20]}}
set_value_at_path(data, "user.scores[1]", 99)
print(data)  # {"user": {"scores": [10, 99]}}

4๏ธโƒฃ Delete Value at a Specific Path

View Details

Delete a key or pop an index at the specified path.

from jsoninja import delete_at_path

data = {"a": {"b": 1, "c": 2}}
delete_at_path(data, "a.b")
print(data)  # {"a": {"c": 2}}

5๏ธโƒฃ Flatten JSON

View Details

Collapses any depth of nesting into a flat {path: value} dictionary.

from jsoninja import flatten_json

data = {"a": {"b": [1, 2], "c": 3}}
print(flatten_json(data))
{
    "a.b[0]": 1,
    "a.b[1]": 2,
    "a.c": 3
}

6๏ธโƒฃ Find a Value by Key

View Details

Returns the first occurrence of a key anywhere in the structure.

from jsoninja import find_value_of_element

data = {"a": {"b": {"c": 42}}}
print(find_value_of_element("c", data))  # 42
print(find_value_of_element("z", data))  # "" (not found)

7๏ธโƒฃ Find All Paths for a Key

View Details

Returns every path where the target key appears โ€” great for duplicate-key analysis.

from jsoninja import find_all_paths_for_element

data = {"a": 1, "b": {"a": 2}, "c": [{"a": 3}]}
print(find_all_paths_for_element(data, "a"))
# ["a", "b.a", "c[0].a"]

8๏ธโƒฃ Empty All Values

View Details

Resets every leaf value to "" โ€” useful for creating JSON templates or anonymising data.

from jsoninja import empty_all_the_values

data = {
    "a": 1,
    "b": {"c": 42, "d": [1, 2, {"e": "hello"}]},
}
print(empty_all_the_values(data))
{
    "a": "",
    "b": {"c": "", "d": ["", "", {"e": ""}]}
}

9๏ธโƒฃ Recursively Delete a Key

View Details

Recursively remove every occurrence of a key name anywhere in the nested object.

from jsoninja import delete_key

data = {"id": 1, "user": {"id": 2, "name": "Alice"}}
delete_key(data, "id")
print(data)  # {"user": {"name": "Alice"}}

๐Ÿ”Ÿ Validate & Format Paths

View Details
from jsoninja import validate_path, format_path
from jsoninja.exceptions import InvalidPathError

# Validation
try:
    validate_path("a.b[1]")         # returns True
    validate_path("a.b[1")          # raises InvalidPathError (mismatched brackets)
except InvalidPathError as e:
    print(f"Error: {e}")

# Human-readable formatting
print(format_path("user.address.city"))   # user -> address -> city
print(format_path("a.b[1]"))             # a -> b[1]

1๏ธโƒฃ1๏ธโƒฃ Compare Two JSON Structures

View Details

Diff two JSON objects or files and receive a structured list of changes plus a summary.

from jsoninja import compare_files

json1 = {"a": {"b": 1, "c": 2}, "d": [1, 2]}
json2 = {"a": {"b": 1, "c": 99}, "d": [1, 2, 3], "e": "new"}

changes, summary = compare_files(json1, json2)

print(summary)
# {"added": 2, "removed": 0, "changed": 1, "type_changed": 0, "unknown": 0}

for change in changes:
    print(change)
# {"type": "changed",  "path": "a-->c", "old_value": 2,    "new_value": 99}
# {"type": "added",    "path": "d[2]",  "new_value": 3}
# {"type": "added",    "path": "e",     "new_value": "new"}

Compare from file paths:

changes, summary = compare_files(
    r"path/to/old.json",
    r"path/to/new.json",
    isPath=True
)

Note: When passing file paths as strings, use raw strings (r"...") or double backslashes (\\) to avoid escape-sequence issues.

Change types returned:

Type Meaning
added Key/value exists in JSON 2 but not JSON 1
removed Key/value exists in JSON 1 but not JSON 2
changed Same path, different value
type_changed Same path, different Python type

๐Ÿ—‚๏ธ Project Structure

JSONavigator/
โ”œโ”€โ”€ jsoninja/
โ”‚   โ”œโ”€โ”€ __init__.py        # Public API surface
โ”‚   โ”œโ”€โ”€ core.py            # traverse, get, find, empty functions
โ”‚   โ”œโ”€โ”€ utils.py           # flatten, validate, format helpers
โ”‚   โ”œโ”€โ”€ compare.py         # JSON diff engine
โ”‚   โ””โ”€โ”€ exceptions.py      # Custom exception hierarchy
โ”œโ”€โ”€ tests/
โ”‚   โ”œโ”€โ”€ test_core.py       # 30+ core function tests
โ”‚   โ”œโ”€โ”€ test_compare.py    # Compare module tests
โ”‚   โ”œโ”€โ”€ test_utils.py      # Utility function tests
โ”‚   โ””โ”€โ”€ conftest.py        # pytest fixtures
โ”œโ”€โ”€ .github/workflows/
โ”‚   โ””โ”€โ”€ publish-to-pypi.yml  # Automated PyPI release CI
โ”œโ”€โ”€ requirements.txt       # Dev/test dependencies
โ”œโ”€โ”€ setup.py
โ””โ”€โ”€ README.md

๐Ÿ› ๏ธ Package Reference

jsoninja.core

Function Signature Returns
traverse_json (data, parent_key='', separator='.') Generator of (path, value)
get_value_at_path (data, path, separator='.') Value at the path
set_value_at_path (data, path, new_value, separator='.') Mutated data
delete_at_path (data, path, separator='.') Mutated data
delete_key (data, target_key) Mutated data
find_value_of_element (target_key, data) First matched value or ""
find_all_paths_for_element (file_data, target_key, path='', separator='.') list[str] of all paths
empty_all_the_values (data) Mutated data with "" leaves, or None

jsoninja.utils

Function Signature Returns
flatten_json (data, parent_key='', separator='.') Flat dict
validate_path (path, separator='.') True or raises InvalidPathError
format_path (path, separator='.') Human-readable path string

jsoninja.compare

Function Signature Returns
compare_files (file1, file2, separator='-->', isPath=False) (changes_list, summary_dict)

jsoninja.exceptions

Exception When raised
InvalidPathError Malformed path string passed to validate_path / format_path
ElementNotFoundError Target element absent from JSON structure
JSONStructureError Unexpected JSON structure type

๐Ÿ’ก Use Cases

  • ๐Ÿ”ฌ API response inspection โ€” quickly explore the shape of deeply nested API payloads.
  • ๐Ÿงช Test assertion helpers โ€” flatten and validate JSON responses in pytest fixtures.
  • ๐Ÿ“‹ Config file diffing โ€” compare application config files between environments.
  • ๐Ÿ—๏ธ JSON schema generation โ€” traverse and collect all paths to infer structure.
  • ๐Ÿ•ต๏ธ Data anonymisation โ€” empty_all_the_values strips sensitive data for safe sharing.
  • ๐Ÿ“ฅ ETL pipelines โ€” flatten nested JSON before inserting into relational databases.

๐Ÿ”ง Development Setup

# 1. Clone the repository
git clone https://github.com/Nikhil-Singh-2503/JSONavigator.git
cd JSONavigator

# 2. Create and activate a virtual environment
python -m venv venv
source venv/bin/activate       # Windows: venv\Scripts\activate

# 3. Install development dependencies
pip install -r requirements.txt

# 4. Run the tests
pytest

# 5. Run with coverage report
pytest --cov=jsoninja --cov-report=term-missing

๐Ÿงช Testing

The test suite covers all public functions with 30+ unit tests using pytest.

# All tests
pytest

# Specific module
pytest tests/test_core.py
pytest tests/test_compare.py
pytest tests/test_utils.py

# With HTML coverage report
pytest --cov=jsoninja --cov-report=html

๐Ÿค Contributing

Contributions are warmly welcome! Here's how to get started:

  1. Fork the repository on GitHub.
  2. Clone your fork:
    git clone https://github.com/<your-username>/JSONavigator.git
    
  3. Create a feature branch:
    git checkout -b feature/my-feature
    
  4. Make changes and add tests for any new functionality.
  5. Run tests to make sure everything passes:
    pytest
    
  6. Commit and push your changes:
    git commit -m "feat: add my-feature"
    git push origin feature/my-feature
    
  7. Open a Pull Request against the main branch.

Please follow the existing code style and write docstrings for any new functions.


๐Ÿš€ Roadmap

  • set_value_at_path โ€” update a value at a given path in place
  • delete_key โ€” remove a key anywhere in the structure
  • JSONPath ($) query syntax support
  • Async-friendly streaming traversal for large JSON files
  • Type-annotated stubs (py.typed marker)
  • compare_files โ€” side-by-side HTML diff report

๐Ÿ“„ License

This project is licensed under the MIT License โ€” see the LICENSE file for details.


๐Ÿ‘ค Author

Nikhil Singh


โญ Star the Repo

If JSONavigator saves you time, please consider giving it a โญ on GitHub โ€” it helps others discover the project!


Built with โค๏ธ using Python ย |ย  PyPI ย |ย  GitHub

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

jsonavigator-1.2.0.tar.gz (18.2 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

jsonavigator-1.2.0-py3-none-any.whl (17.7 kB view details)

Uploaded Python 3

File details

Details for the file jsonavigator-1.2.0.tar.gz.

File metadata

  • Download URL: jsonavigator-1.2.0.tar.gz
  • Upload date:
  • Size: 18.2 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for jsonavigator-1.2.0.tar.gz
Algorithm Hash digest
SHA256 4756d09b8dde44639772a74f17fa44d977cb57d0f3097a2034faa817b5c0099b
MD5 bd015314229df8161c50357f370b6b50
BLAKE2b-256 1dc147608cf57172fdceff99ad4a765263d5de8fa258d042f97710cd16f65161

See more details on using hashes here.

File details

Details for the file jsonavigator-1.2.0-py3-none-any.whl.

File metadata

  • Download URL: jsonavigator-1.2.0-py3-none-any.whl
  • Upload date:
  • Size: 17.7 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for jsonavigator-1.2.0-py3-none-any.whl
Algorithm Hash digest
SHA256 1736ba3138ae8c9dbdff12fd64a721f5fafcef7df5c7085d3f2b42ab3754c576
MD5 2ded76557ec671dd75c7aba0f5c3a5a3
BLAKE2b-256 db741d36142a7d36fe7b205f287ced845d15bf26bdcc3ce6490f1da0fb86d75c

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page