Skip to content

Commit e12a93c

Browse files
committed
add include function
1 parent cd6e5e0 commit e12a93c

File tree

2 files changed

+125
-1
lines changed

2 files changed

+125
-1
lines changed

jsonpath_rw/jsonpath.py

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -267,6 +267,11 @@ def exclude(self, data):
267267
self.right.exclude(datum.value)
268268
return data
269269

270+
def include(self, data):
271+
for datum in self.left.find(data):
272+
self.right.include(datum.value)
273+
return data
274+
270275
def __eq__(self, other):
271276
return isinstance(other, Child) and self.left == other.left and self.right == other.right
272277

@@ -524,6 +529,23 @@ def exclude(self, data):
524529
del data[field]
525530
return data
526531

532+
def include(self, data):
533+
datum = DatumInContext.wrap(data)
534+
535+
try:
536+
all_fields = tuple(datum.value.keys())
537+
except AttributeError:
538+
all_fields = ()
539+
540+
path_fields = self.reified_fields(datum)
541+
remove_fields = set(all_fields) - set(path_fields)
542+
543+
for field in remove_fields:
544+
if field in data:
545+
del data[field]
546+
547+
return data
548+
527549
def __str__(self):
528550
return ','.join(map(str, self.fields))
529551

@@ -564,6 +586,15 @@ def exclude(self, data):
564586
del data[self.index]
565587
return data
566588

589+
def include(self, data):
590+
if data is None:
591+
return None
592+
593+
if len(data) > self.index:
594+
return [data[self.index]]
595+
596+
return []
597+
567598
def __eq__(self, other):
568599
return isinstance(other, Index) and self.index == other.index
569600

@@ -625,6 +656,18 @@ def exclude(self, data):
625656

626657
return data
627658

659+
def include(self, data):
660+
661+
if not data:
662+
return data
663+
664+
ret = []
665+
for datum in self.find(data):
666+
ret.append(datum.value)
667+
668+
data = ret
669+
return data
670+
628671
def __str__(self):
629672
if self.start == None and self.end == None and self.step == None:
630673
return '[*]'

tests/test_jsonpath.py

Lines changed: 82 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -463,7 +463,88 @@ def test_exclude_slice(self):
463463

464464
def check_include_cases(self, test_cases):
465465
for original, string, expected in test_cases:
466-
logging.debug('parse("%s").exclude(%s) =?= %s' % (string, original, expected))
466+
logging.debug('parse("%s").include(%s) =?= %s' % (string, original, expected))
467467
actual = parse(string).include(original)
468+
print ('actual: ', actual, 'expected: ', expected)
468469
assert actual == expected
469470

471+
def test_include_fields(self):
472+
self.check_include_cases([
473+
({'foo': 'baz'}, 'foo', {'foo': 'baz'}),
474+
({'foo': 1, 'baz': 2}, 'foo', {'foo': 1}),
475+
({'foo': 1, 'baz': 2}, 'foo,baz', {'foo': 1, 'baz': 2}),
476+
({'@foo': 1}, '@foo', {'@foo': 1}),
477+
({'@foo': 1, 'baz': 2}, '@foo', {'@foo': 1}),
478+
({'foo': 1, 'baz': 2}, '*', {'foo': 1, 'baz': 2}),
479+
])
480+
481+
def test_include_index(self):
482+
self.check_include_cases([
483+
([42], '[0]', [42]),
484+
([42], '[5]', []),
485+
([34, 65, 29, 59], '[2]', [29]),
486+
(None, '[0]', None),
487+
([], '[0]', []),
488+
(['foo', 'bar', 'baz'], '[0]', ['foo']),
489+
])
490+
491+
def test_include_slice(self):
492+
self.check_include_cases([
493+
(['foo', 'bar', 'baz'], '[0:2]', ['foo', 'bar']),
494+
(['foo', 'bar', 'baz'], '[0:1]', ['foo']),
495+
(['foo', 'bar', 'baz'], '[0:]', ['foo', 'bar', 'baz']),
496+
(['foo', 'bar', 'baz'], '[:2]', ['foo', 'bar']),
497+
(['foo', 'bar', 'baz'], '[:3]', ['foo', 'bar', 'baz']),
498+
(['foo', 'bar', 'baz'], '[0:0]', []),
499+
])
500+
501+
def test_include_root(self):
502+
self.check_include_cases([
503+
('foo', '$', 'foo'),
504+
({}, '$', {}),
505+
({'foo': 1}, '$', {'foo': 1})
506+
])
507+
508+
def test_include_this(self):
509+
self.check_include_cases([
510+
('foo', '`this`', 'foo'),
511+
({}, '`this`', {}),
512+
({'foo': 1}, '`this`', {'foo': 1}),
513+
# TODO: fixme
514+
#({'foo': 1}, 'foo.`this`', {}),
515+
({'foo': {'bar': 1}}, 'foo.`this`.bar', {'foo': {'bar': 1}}),
516+
({'foo': {'bar': 1, 'baz': 2}}, 'foo.`this`.bar', {'foo': {'bar': 1}})
517+
])
518+
519+
def test_include_child(self):
520+
self.check_include_cases([
521+
({'foo': 'bar'}, '$.foo', {'foo': 'bar'}),
522+
({'foo': 'bar'}, 'foo', {'foo': 'bar'}),
523+
({'foo': {'bar': 1}}, 'foo.bar', {'foo': {'bar': 1}}),
524+
({'foo': {'bar': 1}}, 'foo.$.foo.bar', {'foo': {'bar': 1}}),
525+
({'foo': {'bar': 1, 'baz': 2}}, 'foo.$.foo.bar', {'foo': {'bar': 1}}),
526+
({'foo': {'bar': 1, 'baz': 2}}, '*', {'foo': {'bar': 1, 'baz': 2}}),
527+
({'foo': {'bar': 1, 'baz': 2}}, 'non', {}),
528+
])
529+
530+
"""
531+
def test_include_where(self):
532+
self.check_include_cases([
533+
#({'foo': {'bar': {'baz': 1}}, 'bar': {'baz': 2}},
534+
# '*.bar where none', {}),
535+
536+
({'foo': {'bar': {'baz': 1}}, 'bar': {'baz': 2}},
537+
'*.bar where baz', {'foo': {'bar': {'baz': 1}}})
538+
])
539+
"""
540+
541+
"""
542+
def test_include_descendants(self):
543+
self.check_include_cases([
544+
({'somefield': 1}, '$..somefield', {'somefield': 1}),
545+
({'outer': {'nestedfield': 1}}, '$..nestedfield', {'outer': {'nestedfield': 1}}),
546+
({'outs': {'bar': 1, 'ins': {'bar': 9}}, 'outs2': {'bar': 2}},
547+
'$..bar',
548+
{'outs': {'bar': 1, 'ins': {'bar': 9}}, 'outs2': {'bar': 2}})
549+
])
550+
"""

0 commit comments

Comments
 (0)