Skip to content

Commit d8488ea

Browse files
committed
Add path_diffs method for recursive key navigation and update version to 0.1.1
1 parent 1e8eb95 commit d8488ea

File tree

3 files changed

+80
-1
lines changed

3 files changed

+80
-1
lines changed

README.md

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,21 @@ item_diff = diff['items'][0]['properties']
7272
print(diff.location) # Shows path like 'root.items[0].properties'
7373
```
7474

75+
#### Path Pattern Matching
76+
77+
```python
78+
# Find all diffs matching a wildcard pattern
79+
for df in diff.path_diffs('root.models.*.windows.-1.model.calculations'):
80+
print('#'*80)
81+
print(df.path)
82+
print(df.diff_sidebyside())
83+
```
84+
85+
This allows you to:
86+
- Use `*` wildcards to match any key name
87+
- Use `-1` to reference the last item in arrays
88+
- Iterate through all matching paths in the structure
89+
7590
### Command Line
7691

7792
```bash

diffgetr/diff_get.py

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,11 +52,69 @@ def __getitem__(self, key):
5252
self.diff_summary()
5353
raise KeyError(f"{self.location} | key missing: {key}")
5454

55+
@property
56+
def path(self):
57+
return '.'.join(self.loc)
58+
5559
def keys(self):
5660
s0k = set(self.s0)
5761
s1k = set(self.s1)
5862
sa = set.intersection(s0k, s1k)
5963
return sa
64+
65+
def dict_keys(self)->set:
66+
return set(( k for k in self.keys() \
67+
if isinstance(self.s0[k],dict) \
68+
and isinstance(self.s1[k],dict)
69+
))
70+
71+
def path_diffs(self,syskey:str):
72+
"""take sys key like root.p1.p2.pk[0].*.po[*].val and generate diffs through each matching key. If there is a key prefix'd with path, such as root.p1.p2 be sure to strip that so you can navigate the data.
73+
"""
74+
if '.' not in syskey and '[' not in syskey:
75+
#you're here
76+
#print(f'returning {self.loc}')
77+
if syskey in self.dict_keys():
78+
yield self[syskey]
79+
else:
80+
yield self
81+
else:
82+
#recursive
83+
pre_path = '.'.join(self.loc)
84+
85+
find = syskey
86+
if pre_path in syskey:
87+
#print(f'replacing: {pre_path} in {syskey}')
88+
find = syskey.replace(pre_path,"")
89+
90+
pths = find.split('.')
91+
for i,key_seg in enumerate(pths):
92+
nx = pths[i+1:]
93+
nxt = '.'.join(nx)
94+
if not key_seg or key_seg == '.':
95+
continue
96+
elif nx:
97+
#print(f'getting {key_seg} -> {nxt}')
98+
99+
if '*' == key_seg:
100+
for ky in self.dict_keys():
101+
for val in self[ky].path_diffs(nxt):
102+
yield val
103+
104+
elif '[*]' in key_seg:
105+
array1 = self.s0[key_seg]
106+
array2 = self.s1[key_seg]
107+
for j in range(min(len(array1),len(array2))):
108+
v1 = array1[j]
109+
v2 = array2[j]
110+
for val in diff_getr(v1,v2).path_diffs(nxt):
111+
yield val
112+
113+
elif key_seg in self.dict_keys():
114+
for val in self[key_seg].path_diffs(nxt):
115+
yield val
116+
117+
60118

61119
def __iter__(self):
62120
return self.keys()
@@ -109,6 +167,12 @@ def print_here(self):
109167
pprint(d0, indent=2)
110168
pprint(d1, indent=2)
111169

170+
def print_below(self):
171+
print(f'## BASE')
172+
pprint(self.s0, indent=2)
173+
print(f'\n## TEST')
174+
pprint(self.s1, indent=2)
175+
112176
@property
113177
def diff_obj(self) -> deepdiff.DeepDiff:
114178
df = deepdiff.DeepDiff(self.s0, self.s1, **self.deep_diff_kw)

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[project]
22
name = "diffgetr"
3-
version = "0.1.0"
3+
version = "0.1.1"
44
description = "A Python library for comparing nested data structures with detailed diff reporting and interactive navigation."
55
authors = [
66
{ name = "Your Name", email = "your.email@example.com" }

0 commit comments

Comments
 (0)