Skip to content

Commit d9048d4

Browse files
authored
Merge pull request #6 from zhangxianbing/ft_user_defined_func
fix: fix sorter by number string
2 parents 5d1f9d5 + 8712e4c commit d9048d4

File tree

1 file changed

+40
-8
lines changed

1 file changed

+40
-8
lines changed

jsonpath/__init__.py

Lines changed: 40 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
Author : zhangxianbing
33
Date : 2020-12-27 09:22:14
44
LastEditors : zhangxianbing
5-
LastEditTime : 2021-03-02 15:56:00
5+
LastEditTime : 2021-03-02 19:53:38
66
Description : JSONPath
77
"""
88
__version__ = "1.0.4"
@@ -12,6 +12,7 @@
1212
import logging
1313
import os
1414
import re
15+
import sys
1516
from collections import defaultdict
1617
from typing import Union
1718

@@ -57,6 +58,8 @@ class JSONPath:
5758
# save special patterns
5859
REP_GET_QUOTE = re.compile(r"['](.*?)[']")
5960
REP_PUT_QUOTE = re.compile(r"#Q(\d+)")
61+
REP_GET_BACKQUOTE = re.compile(r"[`](.*?)[`]")
62+
REP_PUT_BACKQUOTE = re.compile(r"#BQ(\d+)")
6063
REP_GET_BRACKET = re.compile(r"[\[](.*?)[\]]")
6164
REP_PUT_BRACKET = re.compile(r"#B(\d+)")
6265
REP_GET_PAREN = re.compile(r"[\(](.*?)[\)]")
@@ -70,6 +73,7 @@ class JSONPath:
7073
)
7174

7275
# annotations
76+
f: list
7377
segments: list
7478
lpath: int
7579
subx = defaultdict(list)
@@ -82,6 +86,8 @@ def __init__(self, expr: str):
8286
self.lpath = len(self.segments)
8387
logger.debug(f"segments : {self.segments}")
8488

89+
self.caller_globals = sys._getframe(1).f_globals
90+
8591
def parse(self, obj, result_type="VALUE"):
8692
if not isinstance(obj, (list, dict)):
8793
raise TypeError("obj must be a list or a dict.")
@@ -99,21 +105,26 @@ def parse(self, obj, result_type="VALUE"):
99105

100106
def _parse_expr(self, expr):
101107
logger.debug(f"before expr : {expr}")
102-
108+
# pick up special patterns
103109
expr = JSONPath.REP_GET_QUOTE.sub(self._get_quote, expr)
110+
expr = JSONPath.REP_GET_BACKQUOTE.sub(self._get_backquote, expr)
104111
expr = JSONPath.REP_GET_BRACKET.sub(self._get_bracket, expr)
105112
expr = JSONPath.REP_GET_PAREN.sub(self._get_paren, expr)
113+
# split
106114
expr = JSONPath.REP_DOUBLEDOT.sub(f"{JSONPath.SEP}..{JSONPath.SEP}", expr)
107115
expr = JSONPath.REP_DOT.sub(JSONPath.SEP, expr)
116+
# put back
108117
expr = JSONPath.REP_PUT_PAREN.sub(self._put_paren, expr)
109118
expr = JSONPath.REP_PUT_BRACKET.sub(self._put_bracket, expr)
119+
expr = JSONPath.REP_PUT_BACKQUOTE.sub(self._put_backquote, expr)
110120
expr = JSONPath.REP_PUT_QUOTE.sub(self._put_quote, expr)
111121
if expr.startswith("$;"):
112122
expr = expr[2:]
113123

114124
logger.debug(f"after expr : {expr}")
115125
return expr
116126

127+
# TODO abstract get and put procedures
117128
def _get_quote(self, m):
118129
n = len(self.subx["#Q"])
119130
self.subx["#Q"].append(m.group(1))
@@ -122,6 +133,14 @@ def _get_quote(self, m):
122133
def _put_quote(self, m):
123134
return self.subx["#Q"][int(m.group(1))]
124135

136+
def _get_backquote(self, m):
137+
n = len(self.subx["#BQ"])
138+
self.subx["#BQ"].append(m.group(1))
139+
return f"`#BQ{n}`"
140+
141+
def _put_backquote(self, m):
142+
return self.subx["#BQ"][int(m.group(1))]
143+
125144
def _get_bracket(self, m):
126145
n = len(self.subx["#B"])
127146
self.subx["#B"].append(m.group(1))
@@ -139,7 +158,7 @@ def _put_paren(self, m):
139158
return self.subx["#P"][int(m.group(1))]
140159

141160
@staticmethod
142-
def _f_brackets(m):
161+
def _gen_obj(m):
143162
ret = "__obj"
144163
for e in m.group(1).split("."):
145164
ret += '["%s"]' % e
@@ -155,26 +174,39 @@ def _traverse(f, obj, i: int, path: str, *args):
155174
f(v, i, f"{path}{JSONPath.SEP}{k}", *args)
156175

157176
@staticmethod
158-
def _getattr(obj: dict, path: str):
177+
def _getattr(obj: dict, path: str, *, convert_number_str=False):
159178
r = obj
160179
for k in path.split("."):
161180
try:
162181
r = r.get(k)
163182
except (AttributeError, KeyError) as err:
164183
logger.error(err)
165184
return None
166-
185+
if convert_number_str and isinstance(r, str):
186+
try:
187+
if r.isdigit():
188+
return int(r)
189+
return float(r)
190+
except ValueError:
191+
pass
167192
return r
168193

169194
@staticmethod
170195
def _sorter(obj, sortbys):
171196
for sortby in sortbys.split(",")[::-1]:
172197
if sortby.startswith("~"):
173198
obj.sort(
174-
key=lambda t, k=sortby: JSONPath._getattr(t[1], k[1:]), reverse=True
199+
key=lambda t, k=sortby: JSONPath._getattr(
200+
t[1], k[1:], convert_number_str=True
201+
),
202+
reverse=True,
175203
)
176204
else:
177-
obj.sort(key=lambda t, k=sortby: JSONPath._getattr(t[1], k))
205+
obj.sort(
206+
key=lambda t, k=sortby: JSONPath._getattr(
207+
t[1], k, convert_number_str=True
208+
)
209+
)
178210

179211
def _filter(self, obj, i: int, path: str, step: str):
180212
r = False
@@ -245,7 +277,7 @@ def _trace(self, obj, i: int, path):
245277
# filter
246278
if step.startswith("?(") and step.endswith(")"):
247279
step = step[2:-1]
248-
step = JSONPath.REP_FILTER_CONTENT.sub(self._f_brackets, step)
280+
step = JSONPath.REP_FILTER_CONTENT.sub(self._gen_obj, step)
249281
self._traverse(self._filter, obj, i + 1, path, step)
250282
return
251283

0 commit comments

Comments
 (0)