8000 Get datum paths all checking out · j3hyde/python-jsonpath-rw@c38c928 · GitHub
[go: up one dir, main page]

Skip to content

Commit c38c928

Browse files
committed
Get datum paths all checking out
1 parent 2831d2b commit c38c928

File tree

2 files changed

+60
-14
lines changed

2 files changed

+60
-14
lines changed

jsonpath_rw/jsonpath.py

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -157,7 +157,7 @@ def match_recursively(data):
157157
for i in xrange(0, len(data))]
158158

159159
elif isinstance(data, dict):
160-
recursive_matches = [submatch.in_context(Fields([field]))
160+
recursive_matches = [submatch.in_context(Fields(field))
161161
for field in data.keys()
162162
for submatch in match_recursively(data[field])]
163163

@@ -242,11 +242,11 @@ def safe_get(self, val, field):
242242
def find(self, data):
243243
if '*' in self.fields:
244244
try:
245-
return [DatumAtPath(data[field], path=Fields([field])) for field in data.keys()]
245+
return [DatumAtPath(data[field], path=Fields(field)) for field in data.keys()]
246246
except AttributeError:
247247
return []
248248
else:
249-
result = [DatumAtPath(val, path=Fields([field]))
249+
result = [DatumAtPath(val, path=Fields(field))
250250
for field, val in [(field, self.safe_get(data, field)) for field in self.fields]
251251
if val is not None]
252252

@@ -280,6 +280,9 @@ def find(self, data):
280280
def __eq__(self, other):
281281
return isinstance(other, Index) and self.index == other.index
282282

283+
def __str__(self):
284+
return '[%i]' % self.index
285+
283286
class Slice(JSONPath):
284287
"""
285288
JSONPath matching a slice of an array.

tests/test_jsonpath.py

Lines changed: 54 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,9 @@ class TestJsonPath(unittest.TestCase):
88
def setup_class(cls):
99
logging.basicConfig()
8000
1010

11+
#
12+
# Check that the data value returned is good
13+
#
1114
def check_cases(self, test_cases):
1215
# Note that just manually building an AST would avoid this dep and isolate the tests, but that would suck a bit
1316
# Also, we coerce iterables, etc, into the desired target type
@@ -25,17 +28,6 @@ def test_fields(self):
2528
('foo,baz', {'foo': 1, 'baz': 2}, [1, 2]),
2629
('*', {'foo': 1, 'baz': 2}, [1, 2]) ])
2730

28-
def test_magic_id(self):
29-
self.check_cases([
30-
('id', {'id': 'baz'}, ['baz']),
31-
# ('id', {}, '@'),
32-
#('id', {}, '@'),
33-
# ('foo.id', {'foo': {}}, ['foo']),
34-
# ('foo[*].id', {'foo': {}}, 'foo[0]'),
35-
# ('foo.baz.id', {'foo': {'baz': {}}}, ['foo.baz']),
36-
# ('foo.id', [{'foo': {}}, {'foo': {}}], ['foo[0]', 'foo[1]'])
37-
])
38-
3931
def test_index(self):
4032
self.check_cases([('[0]', [42], [42]),
4133
('[2]', [34, 65, 29, 59], [29])])
@@ -53,3 +45,54 @@ def test_child(self):
5345

5446
def test_descendants(self):
5547
self.check_cases([('foo..baz', {'foo': {'baz': 1, 'bing': {'baz': 2}}}, [1, 2] )])
48+
49+
#
50+
# Check that the paths for the data are correct.
51+
# FIXME: merge these tests with the above, since the inputs are the same anyhow
52+
#
53+
def check_paths(self, test_cases):
54+
# Note that just manually building an AST would avoid this dep and isolate the tests, but that would suck a bit
55+
# Also, we coerce iterables, etc, into the desired target type
56+
57+
for string, data, target in test_cases:
58+
print 'parse("%s").find(%s).paths =?= %s' % (string, data, target)
59+
result = parse(string).find(data)
60+
if isinstance(target, list):
61+
assert [str(r.path) for r in result] == target
62+
else:
63+
assert str(result.path) == target
64+
65+
def test_fields_paths(self):
66+
self.check_paths([ ('foo', {'foo': 'baz'}, ['foo']),
67+
('foo,baz', {'foo': 1, 'baz': 2}, ['foo', 'baz']),
68+
('*', {'foo': 1, 'baz': 2}, ['foo', 'baz']) ])
69+
70+
def test_index_paths(self):
71+
self.check_paths([('[0]', [42], ['[0]']),
72+
('[2]', [34, 65, 29, 59], ['[2]'])])
73+
74+
def test_slice_paths(self):
75+
self.check_paths([ ('[*]', [1, 2, 3], ['[0]', '[1]', '[2]']),
76+
('[1:]', [1, 2, 3, 4], ['[1]', '[2]', '[3]']) ])
77+
78+
def test_child_paths(self):
79+
self.check_paths([('foo.baz', {'foo': {'baz': 3}}, ['foo.baz']),
80+
('foo.baz', {'foo': {'baz': [3]}}, ['foo.baz']),
81+
('foo.baz.bizzle', {'foo': {'baz': {'bizzle': 5}}}, ['foo.baz.bizzle'])])
82+
83+
def test_descendants_paths(self):
84+
self.check_paths([('foo..baz', {'foo': {'baz': 1, 'bing': {'baz': 2}}}, ['foo.baz', 'foo.bing.baz'] )] 6D40 )
85+
86+
#
87+
# And a final hack... the field "id" should always return the path of the queryset if it is not present in the object...
88+
#
89+
#def test_magic_id(self):
90+
# self.check_cases([
91+
# ('id', {'id': 'baz'}, ['baz']),
92+
# ('id', {}, '@'),
93+
#('id', {}, '@'),
94+
# ('foo.id', {'foo': {}}, ['foo']),
95+
# ('foo[*].id', {'foo': {}}, 'foo[0]'),
96+
# ('foo.baz.id', {'foo': {'baz': {}}}, ['foo.baz']),
97+
# ('foo.id', [{'foo': {}}, {'foo': {}}], ['foo[0]', 'foo[1]'])
98+
# ])

0 commit comments

Comments
 (0)
0