Coverage for jsonfind/_cli.py: 53%
99 statements
« prev ^ index » next coverage.py v7.16.0, created at 2026-09-05 14:23 +0000
« prev ^ index » next coverage.py v7.16.0, created at 2026-09-05 14:23 +0000
1import functools
2import json
3import sys
4from logging import DEBUG, INFO, basicConfig, getLogger
6import click
8from ._version import VERSION
9from .jsonfind import (
10 EQ,
11 IN1,
12 IN2,
13 IS,
14 JsonFind,
15 compare_eval,
16 compare_fnmatch,
17 compare_range,
18 compare_regexp,
19 compare_regexp_substr,
20 find_format_list,
21 format_list,
22)
24log = getLogger(__name__)
27@click.group(invoke_without_command=True)
28@click.version_option(VERSION)
29@click.pass_context
30def cli(ctx):
31 if ctx.invoked_subcommand is None:
32 print(ctx.get_help())
35def set_verbose(flag):
36 fmt = "%(asctime)s %(levelname)s %(message)s"
37 if flag:
38 basicConfig(level=DEBUG, format=fmt)
39 else:
40 basicConfig(level=INFO, format=fmt)
43_common_option = [
44 click.option("--verbose/--no-verbose", default=False),
45 click.option("--target", type=str, required=True, help="query(JSON string)"),
46 click.option("--format", type=click.Choice(format_list), default="jsonpointer"),
47 click.argument("obj", type=click.File("r"), default=sys.stdin),
48]
51def common_option(decs):
52 def deco(f):
53 for dec in reversed(decs):
54 f = dec(f)
55 return f
57 return deco
60def obj_option(func):
61 @functools.wraps(func)
62 def wrap(verbose, obj, target, format, *args, **kwargs):
63 set_verbose(verbose)
64 objdata = json.load(obj)
65 try:
66 targetdata = json.loads(target)
67 except json.decoder.JSONDecodeError:
68 targetdata = target
69 return func(verbose, objdata, targetdata, format, *args, **kwargs)
71 return common_option(_common_option)(wrap)
74@cli.command()
75@click.option("--verbose/--no-verbose", default=False)
76@click.option(
77 "--query", type=str, required=True, help="query string(jsonpointer or jsonpath)"
78)
79@click.option("--format", type=click.Choice(find_format_list), default="jsonpointer")
80@click.argument("obj", type=click.File("r"), default=sys.stdin)
81def find_by(verbose, obj, query, format):
82 set_verbose(verbose)
83 log.debug("finding(by) %s from %s (%s)", query, obj, format)
84 res = JsonFind.find_by(mode=format, obj=json.load(obj), path=query)
85 click.echo(json.dumps(res))
88@cli.command()
89@obj_option
90def find_eq(verbose, obj, target, format):
91 log.debug("finding(eq) %s from %s", target, obj)
92 result = [JsonFind.format_to(format, x) for x in JsonFind.filter_eq(obj, target)]
93 log.debug("result: %s", result)
94 click.echo(json.dumps(result))
97@cli.command()
98@obj_option
99def find_is(verbose, obj, target, format):
100 log.debug("finding(is) %s from %s", target, obj)
101 result = [JsonFind.format_to(format, x) for x in JsonFind.filter_is(obj, target)]
102 log.debug("result: %s", result)
103 click.echo(json.dumps(result))
106@cli.command()
107@obj_option
108def find_subset(verbose, obj, target, format):
109 log.debug("finding(subset) %s from %s", target, obj)
110 result = [
111 JsonFind.format_to(format, x) for x in JsonFind.filter_subset(obj, target)
112 ]
113 log.debug("result: %s", result)
114 click.echo(json.dumps(result))
117@cli.command()
118@obj_option
119def find_key(verbose, obj, target, format):
120 log.debug("finding(subset) %s from %s", target, obj)
121 result = [JsonFind.format_to(format, x) for x in JsonFind.filter_key(obj, target)]
122 log.debug("result: %s", result)
123 click.echo(json.dumps(result))
126@cli.command()
127@obj_option
128def find_regex(verbose, obj, target, format):
129 log.debug("finding(regex val) %s from %s", target, obj)
130 result = [
131 JsonFind.format_to(format, x)
132 for x in JsonFind.filter_compare(obj, target, EQ, compare_regexp)
133 ]
134 log.debug("result: %s", result)
135 click.echo(json.dumps(result))
138compare_fn = {
139 "eq": EQ,
140 "is": IS,
141 "in1": IN1,
142 "in2": IN2,
143 "match": compare_regexp,
144 "sub": compare_regexp_substr,
145 "eval": compare_eval,
146 "fnmatch": compare_fnmatch,
147 "range": compare_range,
148}
150filter_fn = {
151 "sub": JsonFind.filter_compare_subset,
152 "super": JsonFind.filter_compare_superset,
153 "set": JsonFind.filter_compare,
154}
157@cli.command()
158@obj_option
159@click.option("--key", type=click.Choice(compare_fn.keys()), default="eq")
160@click.option("--value", type=click.Choice(compare_fn.keys()), default="eq")
161@click.option("--mode", type=click.Choice(filter_fn.keys()), default="set")
162def find_any(verbose, obj, target, format, key, value, mode):
163 log.debug(
164 "finding(regex val) %s from %s (key=%s, value=%s, mode=%s)",
165 target,
166 obj,
167 key,
168 value,
169 mode,
170 )
171 key_fn = compare_fn.get(key)
172 val_fn = compare_fn.get(value)
173 cmpfn = filter_fn.get(mode)
174 result = [JsonFind.format_to(format, x) for x in cmpfn(obj, target, key_fn, val_fn)]
175 log.debug("result: %s", result)
176 click.echo(json.dumps(result))
179if __name__ == "__main__": 179 ↛ 180line 179 didn't jump to line 180 because the condition on line 179 was never true
180 cli()