omlish 0.0.0.dev117__py3-none-any.whl → 0.0.0.dev118__py3-none-any.whl
Sign up to get free protection for your applications and to get access to all the features.
- omlish/__about__.py +2 -2
- omlish/collections/hasheq.py +0 -10
- omlish/fnpairs.py +1 -10
- omlish/formats/json/__init__.py +5 -0
- omlish/formats/json/literals.py +179 -0
- omlish/formats/json/render.py +2 -3
- omlish/formats/json/stream/render.py +1 -1
- omlish/formats/json/types.py +6 -0
- omlish/lang/classes/abstract.py +37 -14
- omlish/lang/imports.py +1 -1
- omlish/lang/maybes.py +10 -12
- omlish/specs/jmespath/ast.py +199 -60
- omlish/specs/jmespath/cli.py +43 -29
- omlish/specs/jmespath/functions.py +397 -274
- omlish/specs/jmespath/lexer.py +2 -2
- omlish/specs/jmespath/parser.py +169 -133
- omlish/specs/jmespath/scope.py +15 -11
- omlish/specs/jmespath/visitor.py +211 -137
- {omlish-0.0.0.dev117.dist-info → omlish-0.0.0.dev118.dist-info}/METADATA +1 -1
- {omlish-0.0.0.dev117.dist-info → omlish-0.0.0.dev118.dist-info}/RECORD +24 -22
- {omlish-0.0.0.dev117.dist-info → omlish-0.0.0.dev118.dist-info}/LICENSE +0 -0
- {omlish-0.0.0.dev117.dist-info → omlish-0.0.0.dev118.dist-info}/WHEEL +0 -0
- {omlish-0.0.0.dev117.dist-info → omlish-0.0.0.dev118.dist-info}/entry_points.txt +0 -0
- {omlish-0.0.0.dev117.dist-info → omlish-0.0.0.dev118.dist-info}/top_level.txt +0 -0
omlish/specs/jmespath/ast.py
CHANGED
@@ -1,119 +1,258 @@
|
|
1
|
+
import abc
|
2
|
+
import dataclasses as dc
|
1
3
|
import typing as ta
|
2
4
|
|
5
|
+
from ... import lang
|
3
6
|
|
4
|
-
class Node(ta.TypedDict):
|
5
|
-
type: str
|
6
|
-
children: list['Node']
|
7
|
-
value: ta.NotRequired[ta.Any]
|
8
7
|
|
8
|
+
@dc.dataclass(frozen=True)
|
9
|
+
class Node(lang.Abstract):
|
10
|
+
@property
|
11
|
+
@abc.abstractmethod
|
12
|
+
def children(self) -> ta.Sequence['Node']:
|
13
|
+
raise NotImplementedError
|
9
14
|
|
10
|
-
def arithmetic_unary(operator, expression) -> Node:
|
11
|
-
return {'type': 'arithmetic_unary', 'children': [expression], 'value': operator}
|
12
15
|
|
16
|
+
@dc.dataclass(frozen=True)
|
17
|
+
class LeafNode(Node, lang.Abstract):
|
18
|
+
@property
|
19
|
+
def children(self) -> ta.Sequence[Node]:
|
20
|
+
return []
|
13
21
|
|
14
|
-
def arithmetic(operator, left, right) -> Node:
|
15
|
-
return {'type': 'arithmetic', 'children': [left, right], 'value': operator}
|
16
22
|
|
23
|
+
@dc.dataclass(frozen=True)
|
24
|
+
class ArithmeticUnary(Node, lang.Final):
|
25
|
+
operator: str
|
26
|
+
expression: Node
|
17
27
|
|
18
|
-
|
19
|
-
|
28
|
+
@property
|
29
|
+
def children(self) -> ta.Sequence[Node]:
|
30
|
+
return [self.expression]
|
20
31
|
|
21
32
|
|
22
|
-
|
23
|
-
|
33
|
+
@dc.dataclass(frozen=True)
|
34
|
+
class Arithmetic(Node, lang.Final):
|
35
|
+
operator: str
|
36
|
+
left: Node
|
37
|
+
right: Node
|
24
38
|
|
39
|
+
@property
|
40
|
+
def children(self) -> ta.Sequence[Node]:
|
41
|
+
return [self.left, self.right]
|
25
42
|
|
26
|
-
def current_node() -> Node:
|
27
|
-
return {'type': 'current', 'children': []}
|
28
43
|
|
44
|
+
@dc.dataclass(frozen=True)
|
45
|
+
class Assign(Node, lang.Final):
|
46
|
+
name: str
|
47
|
+
expr: Node
|
29
48
|
|
30
|
-
|
31
|
-
|
49
|
+
@property
|
50
|
+
def children(self) -> ta.Sequence[Node]:
|
51
|
+
return [self.expr]
|
32
52
|
|
33
53
|
|
34
|
-
|
35
|
-
|
54
|
+
@dc.dataclass(frozen=True)
|
55
|
+
class Comparator(Node, lang.Final):
|
56
|
+
name: str
|
57
|
+
first: Node
|
58
|
+
second: Node
|
36
59
|
|
60
|
+
@property
|
61
|
+
def children(self) -> ta.Sequence[Node]:
|
62
|
+
return [self.first, self.second]
|
37
63
|
|
38
|
-
def function_expression(name, args) -> Node:
|
39
|
-
return {'type': 'function_expression', 'children': args, 'value': name}
|
40
64
|
|
65
|
+
@dc.dataclass(frozen=True)
|
66
|
+
class CurrentNode(LeafNode, lang.Final):
|
67
|
+
pass
|
41
68
|
|
42
|
-
def field(name) -> Node:
|
43
|
-
return {'type': 'field', 'children': [], 'value': name}
|
44
69
|
|
70
|
+
@dc.dataclass(frozen=True)
|
71
|
+
class RootNode(LeafNode, lang.Final):
|
72
|
+
pass
|
45
73
|
|
46
|
-
def filter_projection(left, right, comparator) -> Node:
|
47
|
-
return {'type': 'filter_projection', 'children': [left, right, comparator]}
|
48
74
|
|
75
|
+
@dc.dataclass(frozen=True)
|
76
|
+
class Expref(Node, lang.Final):
|
77
|
+
expression: Node
|
49
78
|
|
50
|
-
|
51
|
-
|
79
|
+
@property
|
80
|
+
def children(self) -> ta.Sequence[Node]:
|
81
|
+
return [self.expression]
|
52
82
|
|
53
83
|
|
54
|
-
|
55
|
-
|
84
|
+
@dc.dataclass(frozen=True)
|
85
|
+
class FunctionExpression(Node, lang.Final):
|
86
|
+
name: str
|
87
|
+
args: ta.Sequence[Node]
|
56
88
|
|
89
|
+
@property
|
90
|
+
def children(self) -> ta.Sequence[Node]:
|
91
|
+
return tuple(self.args)
|
57
92
|
|
58
|
-
def index(index) -> Node:
|
59
|
-
return {'type': 'index', 'value': index, 'children': []}
|
60
93
|
|
94
|
+
@dc.dataclass(frozen=True)
|
95
|
+
class Field(LeafNode, lang.Final):
|
96
|
+
name: str
|
61
97
|
|
62
|
-
def index_expression(children) -> Node:
|
63
|
-
return {'type': 'index_expression', 'children': children}
|
64
98
|
|
99
|
+
@dc.dataclass(frozen=True)
|
100
|
+
class FilterProjection(Node, lang.Final):
|
101
|
+
left: Node
|
102
|
+
right: Node
|
103
|
+
comparator: Node
|
65
104
|
|
66
|
-
|
67
|
-
|
105
|
+
@property
|
106
|
+
def children(self) -> ta.Sequence[Node]:
|
107
|
+
return [self.left, self.right, self.comparator]
|
68
108
|
|
69
109
|
|
70
|
-
|
71
|
-
|
110
|
+
@dc.dataclass(frozen=True)
|
111
|
+
class Flatten(Node, lang.Final):
|
112
|
+
node: Node
|
72
113
|
|
114
|
+
@property
|
115
|
+
def children(self) -> ta.Sequence[Node]:
|
116
|
+
return [self.node]
|
73
117
|
|
74
|
-
def literal(literal_value) -> Node:
|
75
|
-
return {'type': 'literal', 'value': literal_value, 'children': []}
|
76
118
|
|
119
|
+
@dc.dataclass(frozen=True)
|
120
|
+
class Identity(LeafNode, lang.Final):
|
121
|
+
pass
|
77
122
|
|
78
|
-
def multi_select_dict(nodes) -> Node:
|
79
|
-
return {'type': 'multi_select_dict', 'children': nodes}
|
80
123
|
|
124
|
+
@dc.dataclass(frozen=True)
|
125
|
+
class Index(LeafNode, lang.Final):
|
126
|
+
index: int
|
81
127
|
|
82
|
-
def multi_select_list(nodes) -> Node:
|
83
|
-
return {'type': 'multi_select_list', 'children': nodes}
|
84
128
|
|
129
|
+
@dc.dataclass(frozen=True)
|
130
|
+
class IndexExpression(Node, lang.Final):
|
131
|
+
nodes: ta.Sequence[Node]
|
85
132
|
|
86
|
-
|
87
|
-
|
133
|
+
@property
|
134
|
+
def children(self) -> ta.Sequence[Node]:
|
135
|
+
return tuple(self.nodes)
|
88
136
|
|
89
137
|
|
90
|
-
|
91
|
-
|
138
|
+
@dc.dataclass(frozen=True)
|
139
|
+
class KeyValPair(Node, lang.Final):
|
140
|
+
key_name: str
|
141
|
+
node: Node
|
92
142
|
|
143
|
+
@property
|
144
|
+
def children(self) -> ta.Sequence[Node]:
|
145
|
+
return [self.node]
|
93
146
|
|
94
|
-
def not_expression(expr) -> Node:
|
95
|
-
return {'type': 'not_expression', 'children': [expr]}
|
96
147
|
|
148
|
+
@dc.dataclass(frozen=True)
|
149
|
+
class LetExpression(Node, lang.Final):
|
150
|
+
bindings: ta.Sequence[Node]
|
151
|
+
expr: Node
|
97
152
|
|
98
|
-
|
99
|
-
|
153
|
+
@property
|
154
|
+
def children(self) -> ta.Sequence[Node]:
|
155
|
+
return [*self.bindings, self.expr]
|
100
156
|
|
101
157
|
|
102
|
-
|
103
|
-
|
158
|
+
@dc.dataclass(frozen=True)
|
159
|
+
class Literal(LeafNode, lang.Final):
|
160
|
+
literal_value: ta.Any
|
104
161
|
|
105
162
|
|
106
|
-
|
107
|
-
|
163
|
+
@dc.dataclass(frozen=True)
|
164
|
+
class MultiSelectDict(Node, lang.Final):
|
165
|
+
nodes: ta.Sequence[KeyValPair]
|
108
166
|
|
167
|
+
@property
|
168
|
+
def children(self) -> ta.Sequence[Node]:
|
169
|
+
return tuple(self.nodes)
|
109
170
|
|
110
|
-
def slice(start, end, step) -> Node: # noqa
|
111
|
-
return {'type': 'slice', 'children': [start, end, step]}
|
112
171
|
|
172
|
+
@dc.dataclass(frozen=True)
|
173
|
+
class MultiSelectList(Node, lang.Final):
|
174
|
+
nodes: ta.Sequence[Node]
|
113
175
|
|
114
|
-
|
115
|
-
|
176
|
+
@property
|
177
|
+
def children(self) -> ta.Sequence[Node]:
|
178
|
+
return tuple(self.nodes)
|
116
179
|
|
117
180
|
|
118
|
-
|
119
|
-
|
181
|
+
@dc.dataclass(frozen=True)
|
182
|
+
class OrExpression(Node, lang.Final):
|
183
|
+
left: Node
|
184
|
+
right: Node
|
185
|
+
|
186
|
+
@property
|
187
|
+
def children(self) -> ta.Sequence[Node]:
|
188
|
+
return [self.left, self.right]
|
189
|
+
|
190
|
+
|
191
|
+
@dc.dataclass(frozen=True)
|
192
|
+
class AndExpression(Node, lang.Final):
|
193
|
+
left: Node
|
194
|
+
right: Node
|
195
|
+
|
196
|
+
@property
|
197
|
+
def children(self) -> ta.Sequence[Node]:
|
198
|
+
return [self.left, self.right]
|
199
|
+
|
200
|
+
|
201
|
+
@dc.dataclass(frozen=True)
|
202
|
+
class NotExpression(Node, lang.Final):
|
203
|
+
expr: Node
|
204
|
+
|
205
|
+
@property
|
206
|
+
def children(self) -> ta.Sequence[Node]:
|
207
|
+
return [self.expr]
|
208
|
+
|
209
|
+
|
210
|
+
@dc.dataclass(frozen=True)
|
211
|
+
class Pipe(Node, lang.Final):
|
212
|
+
left: Node
|
213
|
+
right: Node
|
214
|
+
|
215
|
+
@property
|
216
|
+
def children(self) -> ta.Sequence[Node]:
|
217
|
+
return [self.left, self.right]
|
218
|
+
|
219
|
+
|
220
|
+
@dc.dataclass(frozen=True)
|
221
|
+
class Projection(Node, lang.Final):
|
222
|
+
left: Node
|
223
|
+
right: Node
|
224
|
+
|
225
|
+
@property
|
226
|
+
def children(self) -> ta.Sequence[Node]:
|
227
|
+
return [self.left, self.right]
|
228
|
+
|
229
|
+
|
230
|
+
@dc.dataclass(frozen=True)
|
231
|
+
class Subexpression(Node, lang.Final):
|
232
|
+
children_nodes: ta.Sequence[Node]
|
233
|
+
|
234
|
+
@property
|
235
|
+
def children(self) -> ta.Sequence[Node]:
|
236
|
+
return tuple(self.children_nodes)
|
237
|
+
|
238
|
+
|
239
|
+
@dc.dataclass(frozen=True)
|
240
|
+
class Slice(LeafNode, lang.Final):
|
241
|
+
start: int | None
|
242
|
+
end: int | None
|
243
|
+
step: int | None
|
244
|
+
|
245
|
+
|
246
|
+
@dc.dataclass(frozen=True)
|
247
|
+
class ValueProjection(Node, lang.Final):
|
248
|
+
left: Node
|
249
|
+
right: Node
|
250
|
+
|
251
|
+
@property
|
252
|
+
def children(self) -> ta.Sequence[Node]:
|
253
|
+
return [self.left, self.right]
|
254
|
+
|
255
|
+
|
256
|
+
@dc.dataclass(frozen=True)
|
257
|
+
class VariableRef(LeafNode, lang.Final):
|
258
|
+
name: str
|
omlish/specs/jmespath/cli.py
CHANGED
@@ -1,35 +1,49 @@
|
|
1
1
|
#!/usr/bin/env python3
|
2
2
|
import argparse
|
3
|
-
import
|
4
|
-
import pprint
|
3
|
+
import dataclasses as dc
|
5
4
|
import sys
|
5
|
+
import typing as ta
|
6
6
|
|
7
|
-
from
|
7
|
+
from ...formats import json
|
8
|
+
from .ast import Node
|
9
|
+
from .exceptions import ArityError
|
10
|
+
from .exceptions import JmespathTypeError
|
11
|
+
from .exceptions import JmespathValueError
|
12
|
+
from .exceptions import ParseError
|
13
|
+
from .exceptions import UnknownFunctionError
|
8
14
|
from .parser import compile
|
9
15
|
from .parser import search
|
16
|
+
from .visitor import node_type
|
10
17
|
|
11
18
|
|
12
|
-
def
|
19
|
+
def _ast_to_json(o: ta.Any) -> ta.Any:
|
20
|
+
if isinstance(o, json.SCALAR_TYPES):
|
21
|
+
return o
|
22
|
+
elif isinstance(o, Node):
|
23
|
+
return {node_type(o): {f.name: _ast_to_json(getattr(o, f.name)) for f in dc.fields(o)}}
|
24
|
+
elif isinstance(o, (list, tuple)):
|
25
|
+
return [_ast_to_json(e) for e in o]
|
26
|
+
else:
|
27
|
+
raise TypeError(o)
|
28
|
+
|
29
|
+
|
30
|
+
def _main() -> int:
|
13
31
|
parser = argparse.ArgumentParser()
|
14
32
|
parser.add_argument('expression')
|
15
|
-
parser.add_argument(
|
16
|
-
|
17
|
-
|
18
|
-
help='The filename containing the input data. If a filename is not given then data is read from stdin.',
|
19
|
-
)
|
20
|
-
parser.add_argument(
|
21
|
-
'--ast',
|
22
|
-
action='store_true',
|
23
|
-
help='Pretty print the AST, do not search the data.',
|
24
|
-
)
|
33
|
+
parser.add_argument('-f', '--filename')
|
34
|
+
parser.add_argument('-c', '--compact', action='store_true')
|
35
|
+
parser.add_argument('--ast', action='store_true')
|
25
36
|
args = parser.parse_args()
|
26
37
|
|
38
|
+
if args.compact:
|
39
|
+
json_dumps = json.dumps_compact
|
40
|
+
else:
|
41
|
+
json_dumps = json.dumps_pretty
|
42
|
+
|
27
43
|
expression = args.expression
|
28
44
|
if args.ast:
|
29
|
-
# Only print the AST
|
30
45
|
expression = compile(args.expression)
|
31
|
-
|
32
|
-
sys.stdout.write('\n')
|
46
|
+
print(json_dumps(_ast_to_json(expression.parsed)))
|
33
47
|
return 0
|
34
48
|
|
35
49
|
if args.filename:
|
@@ -40,27 +54,27 @@ def _main():
|
|
40
54
|
data = json.loads(data)
|
41
55
|
|
42
56
|
try:
|
43
|
-
|
44
|
-
|
57
|
+
print(json_dumps(search(expression, data), ensure_ascii=False))
|
58
|
+
return 0
|
45
59
|
|
46
|
-
except
|
47
|
-
|
60
|
+
except ArityError as e:
|
61
|
+
print(f'invalid-arity: {e}', file=sys.stderr)
|
48
62
|
return 1
|
49
63
|
|
50
|
-
except
|
51
|
-
|
64
|
+
except JmespathTypeError as e:
|
65
|
+
print(f'invalid-type: {e}', file=sys.stderr)
|
52
66
|
return 1
|
53
67
|
|
54
|
-
except
|
55
|
-
|
68
|
+
except JmespathValueError as e:
|
69
|
+
print(f'invalid-value: {e}', file=sys.stderr)
|
56
70
|
return 1
|
57
71
|
|
58
|
-
except
|
59
|
-
|
72
|
+
except UnknownFunctionError as e:
|
73
|
+
print(f'unknown-function: {e}', file=sys.stderr)
|
60
74
|
return 1
|
61
75
|
|
62
|
-
except
|
63
|
-
|
76
|
+
except ParseError as e:
|
77
|
+
print(f'syntax-error: {e}', file=sys.stderr)
|
64
78
|
return 1
|
65
79
|
|
66
80
|
|