Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
51 changes: 51 additions & 0 deletions jsonpath_rw/bin/jsonpath.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
#!/usr/bin/python
# encoding: utf-8
# Copyright © 2012 Felix Richter <wtfpl@syntax-fehler.de>
# This work is free. You can redistribute it and/or modify it under the
# terms of the Do What The Fuck You Want To Public License, Version 2,
# as published by Sam Hocevar. See the COPYING file for more details.

from jsonpath_rw import parse
import json
import sys
import glob
if len(sys.argv) < 2:
print("""usage: jsonpath.py expression [files]

The expression is JSONPath and can be:

atomics:
$ - root object
`this` - current object

operators:
path1.path2 - same as xpath /
path1|path2 - union
path1..path2 - somewhere in between

fiels:
fieldname - field with name
* - any field
[_start_?:_end_?] - array slice
[*] - any array index
""")
sys.exit(1)

expr = parse(sys.argv[1])
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See comment below. Would love the main logic to be wrapped up into a function (maybe using argparse since I'm sure it will end up having options) so that it can be tested and generally invoked from Python as well. I can merge and do the adaptation but if you would be willing to, that would be great too.

An example of the CLI style I like is https://github.com/dimagi/commcare-export/blob/master/commcare_export/cli.py (I wrote it).


def find_matches_for_file(f):
return [unicode(match.value) for match in expr.find(json.load(f))]
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Probably will have to use some Python 2 & 3 adaptation here - str in Python 3 and unicode in Python 2. I've done this a few times, but I think it is not quite provided by six.


def print_matches(matches):
print(u"\n".join(matches).encode("utf-8"))

if len(sys.argv) < 3:
# stdin mode
print_matches(find_matches_for_file(sys.stdin))
else:
# file paths mode
for pattern in sys.argv[2:]:
for filename in glob.glob(pattern):
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I just noticed this. This makes it break when the files have special characters in their name. Globbing is the shell's job. Do you actually require this? Is this a Windows thing?

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ugh. Just discovered that, at least at the time of some SO answers, DOS/Windows shell does not glob.This behavior is a bug in the DOS/Windows shell. I'll leave this in until someone on a unixy OS reports a bug, at which point I'll be forced to fix this to not glob. It is just a rare corner case so who knows if it will ever come up.

with open(filename) as f:
print_matches(find_matches_for_file(f))

1 change: 1 addition & 0 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
license='Apache 2.0',
long_description=io.open('README.rst', encoding='utf-8').read(),
packages = ['jsonpath_rw'],
scripts = ['jsonpath_rw/bin/jsonpath.py'],
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In the past I've used something like

    entry_points = {
        'console_scripts': ['jsonpath = jsonpath_rw.cli:entry_point']
    }

Two things I really like about that are:

  1. You can test the function easily
  2. The name of the script is independent

Is there any pitfall to this method? I know the packaging situation is confusing in Python so I could have got something wrong.

test_suite = 'tests',
install_requires = [ 'ply', 'decorator', 'six' ],
classifiers = [
Expand Down