Coverage for jsonfind/_cli.py: 53%

99 statements  

« 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 

5 

6import click 

7 

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) 

23 

24log = getLogger(__name__) 

25 

26 

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()) 

33 

34 

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) 

41 

42 

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] 

49 

50 

51def common_option(decs): 

52 def deco(f): 

53 for dec in reversed(decs): 

54 f = dec(f) 

55 return f 

56 

57 return deco 

58 

59 

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) 

70 

71 return common_option(_common_option)(wrap) 

72 

73 

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)) 

86 

87 

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)) 

95 

96 

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)) 

104 

105 

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)) 

115 

116 

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)) 

124 

125 

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)) 

136 

137 

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} 

149 

150filter_fn = { 

151 "sub": JsonFind.filter_compare_subset, 

152 "super": JsonFind.filter_compare_superset, 

153 "set": JsonFind.filter_compare, 

154} 

155 

156 

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)) 

177 

178 

179if __name__ == "__main__": 179 ↛ 180line 179 didn't jump to line 180 because the condition on line 179 was never true

180 cli()