omlish 0.0.0.dev116__py3-none-any.whl → 0.0.0.dev118__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- omlish/__about__.py +2 -2
- omlish/check.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.dev116.dist-info → omlish-0.0.0.dev118.dist-info}/METADATA +1 -1
- {omlish-0.0.0.dev116.dist-info → omlish-0.0.0.dev118.dist-info}/RECORD +25 -23
- {omlish-0.0.0.dev116.dist-info → omlish-0.0.0.dev118.dist-info}/LICENSE +0 -0
- {omlish-0.0.0.dev116.dist-info → omlish-0.0.0.dev118.dist-info}/WHEEL +0 -0
- {omlish-0.0.0.dev116.dist-info → omlish-0.0.0.dev118.dist-info}/entry_points.txt +0 -0
- {omlish-0.0.0.dev116.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
|
|