pyapi-diff 0.0.1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
pyapi/__init__.py ADDED
@@ -0,0 +1,4 @@
1
+ from .comparator import json_compare
2
+ from .models import Change
3
+
4
+ __all__ = ["json_compare", "Change"]
pyapi/comparator.py ADDED
@@ -0,0 +1,101 @@
1
+ from pyapi.models import Change
2
+ from pathlib import Path
3
+ import json
4
+
5
+ def _json_type(value: any) -> any:
6
+
7
+ if value is None:
8
+ return "null"
9
+ if isinstance(value, bool):
10
+ return "boolean"
11
+ if isinstance(value, int):
12
+ return "number"
13
+ if isinstance(value, str):
14
+ return "string"
15
+ if isinstance(value, dict):
16
+ return "object"
17
+ if isinstance(value, list):
18
+ return "array"
19
+ return "Unknown"
20
+
21
+ def _compare(old: dict, new: dict, path: str, changes: list)-> list:
22
+
23
+ old_type: any = _json_type(old)
24
+ new_type: any = _json_type(new)
25
+
26
+ if old_type != new_type:
27
+ changes.append(
28
+ Change(
29
+ kind= "type_changed",
30
+ path= path or "$",
31
+ old_value= old_type,
32
+ new_value= new_type
33
+ )
34
+ )
35
+ return
36
+
37
+ if isinstance(old, dict):
38
+ old_keys: list = set(old)
39
+ new_keys: list = set(new)
40
+
41
+ for key in sorted(old_keys - new_keys):
42
+ changes.append(
43
+ Change(
44
+ kind="key_removed",
45
+ path= f"{path}.{key}",
46
+ old_value=old[key]
47
+ )
48
+ )
49
+
50
+ for key in sorted(new_keys - old_keys):
51
+ changes.append(
52
+ Change(
53
+ kind= "key_added",
54
+ path= f"{path}.{key}",
55
+ new_value= new[key]
56
+ )
57
+ )
58
+
59
+ for key in sorted(old_keys & new_keys):
60
+ _compare(
61
+ old[key],
62
+ new[key],
63
+ f"{path}.{key}",
64
+ changes
65
+ )
66
+
67
+ elif isinstance(old, list):
68
+ for index, (old_item, new_item) in enumerate(zip(old, new)):
69
+ _compare(
70
+ old_item,
71
+ new_item,
72
+ f"{path}[{index}]",
73
+ changes
74
+ )
75
+
76
+ def json_compare(old: dict, new: dict) -> list:
77
+ old_path: str = Path(old)
78
+ new_path: str = Path(new)
79
+
80
+ with old_path.open(encoding="utf-8") as f:
81
+ old_data: dict = json.load(f)
82
+
83
+ with new_path.open(encoding="utf-8") as f:
84
+ new_data: dict = json.load(f)
85
+
86
+ changes: list= []
87
+ _compare(
88
+ old_data,
89
+ new_data,
90
+ "$",
91
+ changes
92
+ )
93
+ return changes
94
+
95
+
96
+
97
+
98
+
99
+
100
+
101
+
pyapi/models.py ADDED
@@ -0,0 +1,20 @@
1
+ from dataclasses import dataclass
2
+
3
+ @dataclass(frozen=True)
4
+ class Change:
5
+ kind:str
6
+ path: str
7
+ old_value: object = None
8
+ new_value: object = None
9
+
10
+ def __str__(self)-> str:
11
+ """
12
+ This magical method will allow to represent the data in format.
13
+ :return: data in format
14
+ :rtype: str
15
+ """
16
+ return (
17
+ f"{self.kind}: {self.path} "
18
+ f"(old = {self.old_value!r}, "
19
+ f"new = {self.new_value!r})"
20
+ )
@@ -0,0 +1,168 @@
1
+ Metadata-Version: 2.5
2
+ Name: pyapi-diff
3
+ Version: 0.0.1
4
+ Summary: python tool to indentify breaking changes in apis.
5
+ Author-email: Prashant Sharma <prashant.ps9833@gmail.com>
6
+ License-Expression: MIT
7
+ License-File: LICENSE
8
+ Keywords: comparison,developer-tools,json,json-diff
9
+ Classifier: Operating System :: OS Independent
10
+ Classifier: Programming Language :: Python :: 3
11
+ Classifier: Programming Language :: Python :: 3 :: Only
12
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
13
+ Requires-Python: >=3.10
14
+ Description-Content-Type: text/markdown
15
+
16
+ # pyapi
17
+
18
+ **A lightweight Python library to detect structural changes in JSON data.**
19
+
20
+ `pyapi` compares two JSON-compatible data structures and identifies changes in their structure and data types, without reporting ordinary value changes.
21
+
22
+ It is useful for detecting changes in API response structures, checking compatibility between API versions, and identifying unexpected changes in JSON data.
23
+
24
+ ## Features
25
+
26
+ - **Key Addition Detection** — Identifies keys present in the new structure but missing from the old structure.
27
+ - **Key Removal Detection** — Identifies keys present in the old structure but missing from the new structure.
28
+ - **Type Change Detection** — Detects when a value's data type changes between two structures.
29
+ - **Nested Structure Comparison** — Detects structural changes within nested JSON objects.
30
+ - **Value-Agnostic Comparison** — Ignores changes to values when their data types remain the same.
31
+ - **Readable Change Paths** — Reports the location of each detected change using JSON-style paths.
32
+
33
+ ## Installation
34
+
35
+ ```bash
36
+ pip install pyapi
37
+ ```
38
+
39
+ ## Quick Start
40
+
41
+ ```python
42
+ from pyapi import json_compare
43
+
44
+ old = {
45
+ "id": 101,
46
+ "name": "abc",
47
+ "age": 55,
48
+ "address": {
49
+ "city": "san francisco",
50
+ "pincode": 12345
51
+ },
52
+ "skills": ["Python", "SQL"]
53
+ }
54
+
55
+ new = {
56
+ "id": "101",
57
+ "name": "xyz",
58
+ "contact": 1234567890,
59
+ "address": {
60
+ "city": "Seattle",
61
+ "pincode": 1234
62
+ },
63
+ "skills": ["Python", "SQL"]
64
+ }
65
+
66
+ json_compare(old, new)
67
+ ```
68
+
69
+ ### Output
70
+
71
+ ```text
72
+ key_removed: $.age (old = 55, new = None)
73
+ key_added: $.contact (old = None, new = 1234567890)
74
+ type_changed: $.id (old = 'number', new = 'string')
75
+ ```
76
+
77
+ ## Detected Change Types
78
+
79
+ | Change Type | Description |
80
+ |---|---|
81
+ | `key_added` | A key exists in the new structure but not in the old structure. |
82
+ | `key_removed` | A key exists in the old structure but not in the new structure. |
83
+ | `type_changed` | A value's data type differs between the old and new structures. |
84
+
85
+ ## How It Works
86
+
87
+ `pyapi` compares an old JSON-compatible structure against a new one and reports structural differences.
88
+
89
+ For example, consider these two objects:
90
+
91
+ **Old structure**
92
+
93
+ ```json
94
+ {
95
+ "user": {
96
+ "id": 101,
97
+ "name": "Alice"
98
+ }
99
+ }
100
+ ```
101
+
102
+ **New structure**
103
+
104
+ ```json
105
+ {
106
+ "user": {
107
+ "id": "101",
108
+ "name": "Bob",
109
+ "email": "alice@example.com"
110
+ }
111
+ }
112
+ ```
113
+
114
+ The detected changes include:
115
+
116
+ - `type_changed` at `$.user.id`, because `id` changes from a number to a string.
117
+ - `key_added` at `$.user.email`, because `email` is newly introduced.
118
+
119
+ The change from `"Alice"` to `"Bob"` is ignored because the value remains a string.
120
+
121
+ ## Use Cases
122
+
123
+ - **API Response Comparison:** Identify structural changes between responses from different API versions.
124
+ - **Breaking Change Detection:** Find removed keys or changed data types that could break API consumers.
125
+ - **Regression Testing:** Detect unexpected changes in JSON response structures during development.
126
+ - **Data Validation:** Check whether incoming JSON data maintains the expected structure.
127
+ - **Configuration Comparison:** Identify added or removed settings and changes in their data types.
128
+
129
+ ## Requirements
130
+
131
+ - Python 3.10 or later
132
+
133
+ ## Development
134
+
135
+ Clone the repository:
136
+
137
+ ```bash
138
+ git clone YOUR_REPOSITORY_URL
139
+ cd pyapi
140
+ ```
141
+
142
+ Install dependencies using [uv](https://docs.astral.sh/uv/):
143
+
144
+ ```bash
145
+ uv sync
146
+ ```
147
+
148
+ Run the example or test script:
149
+
150
+ ```bash
151
+ uv run python tests/test1.py
152
+ ```
153
+
154
+ ## Project Status
155
+
156
+ `pyapi` is currently in its initial release, `0.0.1`.
157
+
158
+ The current focus is on detecting JSON structural and data type changes. Additional functionality may be introduced in future releases.
159
+
160
+ ## Contributing
161
+
162
+ Contributions, bug reports, and feature suggestions are welcome.
163
+
164
+ Feel free to open an issue or submit a pull request in the project's GitHub repository.
165
+
166
+ ## License
167
+
168
+ This project is licensed under the MIT License. See the `LICENSE` file for details.
@@ -0,0 +1,7 @@
1
+ pyapi/__init__.py,sha256=TbYWYNFAFsIaxtiHBLqpI_cxsTleRY1-W3Dha4IzPF8,101
2
+ pyapi/comparator.py,sha256=HwkykHy9xJFwKnpKqlJdoytoTyHjEmi3KyS5CqbRwzM,2360
3
+ pyapi/models.py,sha256=RvdW6MI-IK8UVYuyEAcICK-Mn5rwg0-M-3jUvhXbbAQ,487
4
+ pyapi_diff-0.0.1.dist-info/METADATA,sha256=of2bYWDdSEopfLNY9lGZ-mkw_MBvtl-srInnCu0-8EM,4452
5
+ pyapi_diff-0.0.1.dist-info/WHEEL,sha256=W3fkpkm7-wf9vBI5Z-7s0eWkeM-spu78I8Neb98DeEg,87
6
+ pyapi_diff-0.0.1.dist-info/licenses/LICENSE,sha256=LQrD-qdW6uCj3h5BBAk0C5MVrvuiYDBBjxJAM8BE1_k,1072
7
+ pyapi_diff-0.0.1.dist-info/RECORD,,
@@ -0,0 +1,4 @@
1
+ Wheel-Version: 1.0
2
+ Generator: hatchling 1.32.4
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Prashant Sharma
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.