omlish 0.0.0.dev117__py3-none-any.whl → 0.0.0.dev119__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/logs/_abc.py CHANGED
@@ -16,27 +16,80 @@ ExceptionInfo: ta.TypeAlias = tuple[type[BaseException], BaseException, types.Tr
16
16
 
17
17
 
18
18
  class LogRecord:
19
+ """https://docs.python.org/3/library/logging.html#logrecord-attributes"""
20
+
21
+ # Name of the logger used to log the call.
19
22
  name: str
23
+
24
+ # Human-readable time when the LogRecord was created. By default this is of the form '2003-07-08 16:49:45,896' (the
25
+ # numbers after the comma are millisecond portion of the time).
26
+ asctime: str
27
+
28
+ # The logged message, computed as msg % args. This is set when Formatter.format() is invoked.
29
+ message: str
30
+
31
+ # The format string passed in the original logging call. Merged with args to produce message, or an arbitrary object
32
+ # (see Using arbitrary objects as messages).
20
33
  msg: str
34
+
35
+ # The tuple of arguments merged into msg to produce message, or a dict whose values are used for the merge (when
36
+ # there is only one argument, and it is a dictionary).
21
37
  args: tuple
38
+
39
+ # Text logging level for the message ('DEBUG', 'INFO', 'WARNING', 'ERROR', 'CRITICAL').
22
40
  levelname: str
41
+
42
+ # # Numeric logging level for the message (DEBUG, INFO, WARNING, ERROR, CRITICAL).
23
43
  levelno: Level
44
+
45
+ # Full pathname of the source file where the logging call was issued (if available).
24
46
  pathname: str
47
+
48
+ # Filename portion of pathname.
25
49
  filename: str
50
+
51
+ # Module (name portion of filename).
26
52
  module: str
53
+
54
+ # Exception tuple (à la sys.exc_info) or, if no exception has occurred, None.
27
55
  exc_info: ExceptionInfo | None
56
+
28
57
  exc_text: str | None
58
+
59
+ # Stack frame information (where available) from the bottom of the stack in the current thread, up to and including
60
+ # the stack frame of the logging call which resulted in the creation of this record.
29
61
  stack_info: str | None
62
+
63
+ # Source line number where the logging call was issued (if available).
30
64
  lineno: int
65
+
66
+ # Name of function containing the logging call.
31
67
  funcName: str
68
+
69
+ # Time when the LogRecord was created (as returned by time.time_ns() / 1e9).
32
70
  created: float
71
+
72
+ # Millisecond portion of the time when the LogRecord was created.
33
73
  msecs: float
74
+
75
+ # Time in milliseconds when the LogRecord was created, relative to the time the logging module was loaded.
34
76
  relativeCreated: float
77
+
78
+ # Thread ID (if available).
35
79
  thread: int
80
+
81
+ # Thread name (if available).
36
82
  threadName: str
83
+
84
+ # Process name (if available).
37
85
  processName: str
86
+
87
+ # Process ID (if available).
38
88
  process: int
39
89
 
90
+ # asyncio.Task name (if available).
91
+ taskName: str
92
+
40
93
 
41
94
  ##
42
95
 
omlish/logs/handlers.py CHANGED
@@ -6,5 +6,5 @@ class ListHandler(logging.Handler):
6
6
  super().__init__()
7
7
  self.records: list[logging.LogRecord] = []
8
8
 
9
- def emit(self, record):
9
+ def emit(self, record: logging.LogRecord) -> None:
10
10
  self.records.append(record)
@@ -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
- def assign(name, expr) -> Node:
19
- return {'type': 'assign', 'children': [expr], 'value': name}
28
+ @property
29
+ def children(self) -> ta.Sequence[Node]:
30
+ return [self.expression]
20
31
 
21
32
 
22
- def comparator(name, first, second) -> Node:
23
- return {'type': 'comparator', 'children': [first, second], 'value': name}
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
- def root_node() -> Node:
31
- return {'type': 'root', 'children': []}
49
+ @property
50
+ def children(self) -> ta.Sequence[Node]:
51
+ return [self.expr]
32
52
 
33
53
 
34
- def expref(expression) -> Node:
35
- return {'type': 'expref', 'children': [expression]}
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
- def flatten(node) -> Node:
51
- return {'type': 'flatten', 'children': [node]}
79
+ @property
80
+ def children(self) -> ta.Sequence[Node]:
81
+ return [self.expression]
52
82
 
53
83
 
54
- def identity() -> Node:
55
- return {'type': 'identity', 'children': []}
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
- def key_val_pair(key_name, node) -> Node:
67
- return {'type': 'key_val_pair', 'children': [node], 'value': key_name}
105
+ @property
106
+ def children(self) -> ta.Sequence[Node]:
107
+ return [self.left, self.right, self.comparator]
68
108
 
69
109
 
70
- def let_expression(bindings, expr) -> Node:
71
- return {'type': 'let_expression', 'children': [*bindings, expr]}
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
- def or_expression(left, right) -> Node:
87
- return {'type': 'or_expression', 'children': [left, right]}
133
+ @property
134
+ def children(self) -> ta.Sequence[Node]:
135
+ return tuple(self.nodes)
88
136
 
89
137
 
90
- def and_expression(left, right) -> Node:
91
- return {'type': 'and_expression', 'children': [left, right]}
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
- def pipe(left: Node, right: Node) -> Node:
99
- return {'type': 'pipe', 'children': [left, right]}
153
+ @property
154
+ def children(self) -> ta.Sequence[Node]:
155
+ return [*self.bindings, self.expr]
100
156
 
101
157
 
102
- def projection(left: Node, right: Node) -> Node:
103
- return {'type': 'projection', 'children': [left, right]}
158
+ @dc.dataclass(frozen=True)
159
+ class Literal(LeafNode, lang.Final):
160
+ literal_value: ta.Any
104
161
 
105
162
 
106
- def subexpression(children) -> Node:
107
- return {'type': 'subexpression', 'children': children}
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
- def value_projection(left: Node, right: Node) -> Node:
115
- return {'type': 'value_projection', 'children': [left, right]}
176
+ @property
177
+ def children(self) -> ta.Sequence[Node]:
178
+ return tuple(self.nodes)
116
179
 
117
180
 
118
- def variable_ref(name: str) -> Node:
119
- return {'type': 'variable_ref', 'children': [], 'value': name}
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
@@ -1,35 +1,49 @@
1
1
  #!/usr/bin/env python3
2
2
  import argparse
3
- import json
4
- import pprint
3
+ import dataclasses as dc
5
4
  import sys
5
+ import typing as ta
6
6
 
7
- from . import exceptions
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 _main():
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
- '-f',
17
- '--filename',
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
- sys.stdout.write(pprint.pformat(expression.parsed))
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
- sys.stdout.write(json.dumps(search(expression, data), indent=4, ensure_ascii=False))
44
- sys.stdout.write('\n')
57
+ print(json_dumps(search(expression, data), ensure_ascii=False))
58
+ return 0
45
59
 
46
- except exceptions.ArityError as e:
47
- sys.stderr.write(f'invalid-arity: {e}\n')
60
+ except ArityError as e:
61
+ print(f'invalid-arity: {e}', file=sys.stderr)
48
62
  return 1
49
63
 
50
- except exceptions.JmespathTypeError as e:
51
- sys.stderr.write(f'invalid-type: {e}\n')
64
+ except JmespathTypeError as e:
65
+ print(f'invalid-type: {e}', file=sys.stderr)
52
66
  return 1
53
67
 
54
- except exceptions.JmespathValueError as e:
55
- sys.stderr.write(f'invalid-value: {e}\n')
68
+ except JmespathValueError as e:
69
+ print(f'invalid-value: {e}', file=sys.stderr)
56
70
  return 1
57
71
 
58
- except exceptions.UnknownFunctionError as e:
59
- sys.stderr.write(f'unknown-function: {e}\n')
72
+ except UnknownFunctionError as e:
73
+ print(f'unknown-function: {e}', file=sys.stderr)
60
74
  return 1
61
75
 
62
- except exceptions.ParseError as e:
63
- sys.stderr.write(f'syntax-error: {e}\n')
76
+ except ParseError as e:
77
+ print(f'syntax-error: {e}', file=sys.stderr)
64
78
  return 1
65
79
 
66
80