Metadata-Version: 2.1
Name: jsonavigator
Version: 1.3.0
Summary: A Python package for handling nested JSON structures.
Home-page: https://github.com/Nikhil-Singh-2503/JSONavigator
Author: Nikhil Singh
Author-email: nikhilraj7654@gmail.com
License: UNKNOWN
Description: <div align="center">
        
        <h1>🧭 JSONavigator</h1>
        
        <p><strong>The Swiss Army knife for nested JSON</strong> — traverse, flatten, search, validate, format, and diff JSON structures with a single lightweight Python library.</p>
        
        [![PyPI Downloads](https://static.pepy.tech/badge/jsonavigator)](https://pepy.tech/projects/jsonavigator)
        [![PyPI version](https://img.shields.io/pypi/v/jsonavigator?color=blue&logo=pypi&logoColor=white)](https://pypi.org/project/jsonavigator/)
        [![Python Versions](https://img.shields.io/pypi/pyversions/jsonavigator?logo=python&logoColor=white)](https://pypi.org/project/jsonavigator/)
        [![License: MIT](https://img.shields.io/pypi/l/jsonavigator?color=green)](https://github.com/Nikhil-Singh-2503/JSONavigator/blob/main/LICENSE)
        [![CI](https://img.shields.io/github/actions/workflow/status/Nikhil-Singh-2503/JSONavigator/publish-to-pypi.yml?label=CI%2FCD&logo=github)](https://github.com/Nikhil-Singh-2503/JSONavigator/actions)
        [![Repo Size](https://img.shields.io/github/repo-size/Nikhil-Singh-2503/Jsonavigator)](https://github.com/Nikhil-Singh-2503/JSONavigator)
        
        </div>
        
        ---
        
        ## 🤔 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 |
        | ⏭️ **Ignore keys** | `compare_files(ignore_keys=...)` | Skip specified keys during comparison |
        | 🔀 **Ignore order** | `compare_files(ignore_order=...)` | Treat lists as unordered sets during comparison |
        | 🧬 **Deep merge** | `merge_json` | Recursively merge two JSON objects with conflict strategies |
        | 🚨 **Custom exceptions** | `InvalidPathError`, `ElementNotFoundError`, `MergeConflictError` | Semantic error handling |
        
        ---
        
        ## 📦 Installation
        
        ```bash
        pip install jsonavigator
        ```
        
        **From source:**
        
        ```bash
        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
        
        ```python
        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,
            merge_json,
            MergeConflictError,
        )
        
        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
        <details>
        <summary>View Details</summary>
        
        Yields `(path, value)` tuples for every leaf node. Supports mixed dicts and lists.
        
        ```python
        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.
        >
        > ```python
        > traverse_json(data, separator="/")  # a/b[0], a/b[1], a/c
        > ```
        
        </details>
        
        ---
        
        ### 2️⃣ Get Value at a Specific Path
        <details>
        <summary>View Details</summary>
        
        ```python
        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
        ```
        
        </details>
        
        ---
        
        ### 3️⃣ Set Value at a Specific Path
        <details>
        <summary>View Details</summary>
        
        Update or create a leaf value using dot notation, modifying the dict in place.
        
        ```python
        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]}}
        ```
        
        </details>
        
        ---
        
        ### 4️⃣ Delete Value at a Specific Path
        <details>
        <summary>View Details</summary>
        
        Delete a key or pop an index at the specified path.
        
        ```python
        from jsoninja import delete_at_path
        
        data = {"a": {"b": 1, "c": 2}}
        delete_at_path(data, "a.b")
        print(data)  # {"a": {"c": 2}}
        ```
        
        </details>
        
        ---
        
        ### 5️⃣ Flatten JSON
        <details>
        <summary>View Details</summary>
        
        Collapses any depth of nesting into a flat `{path: value}` dictionary.
        
        ```python
        from jsoninja import flatten_json
        
        data = {"a": {"b": [1, 2], "c": 3}}
        print(flatten_json(data))
        ```
        
        ```python
        {
            "a.b[0]": 1,
            "a.b[1]": 2,
            "a.c": 3
        }
        ```
        
        </details>
        
        ---
        
        ### 6️⃣ Find a Value by Key
        <details>
        <summary>View Details</summary>
        
        Returns the first occurrence of a key anywhere in the structure.
        
        ```python
        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)
        ```
        
        </details>
        
        ---
        
        ### 7️⃣ Find All Paths for a Key
        <details>
        <summary>View Details</summary>
        
        Returns **every** path where the target key appears — great for duplicate-key analysis.
        
        ```python
        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"]
        ```
        
        </details>
        
        ---
        
        ### 8️⃣ Empty All Values
        <details>
        <summary>View Details</summary>
        
        Resets every leaf value to `""` — useful for creating JSON templates or anonymising data.
        
        ```python
        from jsoninja import empty_all_the_values
        
        data = {
            "a": 1,
            "b": {"c": 42, "d": [1, 2, {"e": "hello"}]},
        }
        print(empty_all_the_values(data))
        ```
        
        ```python
        {
            "a": "",
            "b": {"c": "", "d": ["", "", {"e": ""}]}
        }
        ```
        
        </details>
        
        ---
        
        ### 9️⃣ Recursively Delete a Key
        <details>
        <summary>View Details</summary>
        
        Recursively remove every occurrence of a key name anywhere in the nested object.
        
        ```python
        from jsoninja import delete_key
        
        data = {"id": 1, "user": {"id": 2, "name": "Alice"}}
        delete_key(data, "id")
        print(data)  # {"user": {"name": "Alice"}}
        ```
        
        </details>
        
        ---
        
        ### 🔟 Validate & Format Paths
        <details>
        <summary>View Details</summary>
        
        ```python
        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]
        ```
        
        </details>
        
        ---
        
        ### 1️⃣1️⃣ Compare Two JSON Structures
        <details>
        <summary>View Details</summary>
        
        Diff two JSON objects or files and receive a structured list of changes plus a summary.
        
        ```python
        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:**
        
        ```python
        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 |
        
        </details>
        
        ---
        
        ## 🗂️ 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
        
        ```bash
        # 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`.
        
        ```bash
        # 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:
           ```bash
           git clone https://github.com/<your-username>/JSONavigator.git
           ```
        3. **Create** a feature branch:
           ```bash
           git checkout -b feature/my-feature
           ```
        4. **Make changes** and add tests for any new functionality.
        5. **Run tests** to make sure everything passes:
           ```bash
           pytest
           ```
        6. **Commit** and **push** your changes:
           ```bash
           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
        
        - [x] `set_value_at_path` — update a value at a given path in place
        - [x] `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](https://github.com/Nikhil-Singh-2503/JSONavigator/blob/main/LICENSE) file for details.
        
        ---
        
        ## 👤 Author
        
        **Nikhil Singh**
        
        - 📧 Email: [nikhilraj7654@gmail.com](mailto:nikhilraj7654@gmail.com)
        - 🐙 GitHub: [@Nikhil-Singh-2503](https://github.com/Nikhil-Singh-2503)
        - 📦 PyPI: [jsonavigator](https://pypi.org/project/jsonavigator/)
        
        ---
        
        ## ⭐ Star the Repo
        
        If JSONavigator saves you time, please consider giving it a ⭐ on GitHub — it helps others discover the project!
        
        ---
        
        <div align="center">
          Built with ❤️ using Python &nbsp;|&nbsp; <a href="https://pypi.org/project/jsonavigator/">PyPI</a> &nbsp;|&nbsp; <a href="https://github.com/Nikhil-Singh-2503/JSONavigator">GitHub</a>
        </div>
        
Platform: UNKNOWN
Classifier: Programming Language :: Python
Classifier: Programming Language :: Python :: 3
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: OS Independent
Classifier: Intended Audience :: Developers
Classifier: Topic :: Utilities
Classifier: Topic :: File Formats
Classifier: Topic :: File Formats :: JSON
Classifier: Topic :: Software Development :: Libraries
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Requires-Python: >=3.8
Description-Content-Type: text/markdown
