omlish 0.0.0.dev133__py3-none-any.whl → 0.0.0.dev177__py3-none-any.whl

Sign up to get free protection for your applications and to get access to all the features.
Files changed (210) hide show
  1. omlish/.manifests.json +265 -7
  2. omlish/__about__.py +5 -3
  3. omlish/antlr/_runtime/__init__.py +0 -22
  4. omlish/antlr/_runtime/_all.py +24 -0
  5. omlish/antlr/_runtime/atn/ParserATNSimulator.py +1 -1
  6. omlish/antlr/_runtime/dfa/DFASerializer.py +1 -1
  7. omlish/antlr/_runtime/error/DiagnosticErrorListener.py +2 -1
  8. omlish/antlr/_runtime/xpath/XPath.py +7 -1
  9. omlish/antlr/_runtime/xpath/XPathLexer.py +1 -1
  10. omlish/antlr/delimit.py +106 -0
  11. omlish/antlr/dot.py +31 -0
  12. omlish/antlr/errors.py +11 -0
  13. omlish/antlr/input.py +96 -0
  14. omlish/antlr/parsing.py +19 -0
  15. omlish/antlr/runtime.py +102 -0
  16. omlish/antlr/utils.py +38 -0
  17. omlish/argparse/all.py +45 -0
  18. omlish/{argparse.py → argparse/cli.py} +112 -107
  19. omlish/asyncs/__init__.py +0 -35
  20. omlish/asyncs/all.py +35 -0
  21. omlish/asyncs/asyncio/all.py +7 -0
  22. omlish/asyncs/asyncio/channels.py +40 -0
  23. omlish/asyncs/asyncio/streams.py +45 -0
  24. omlish/asyncs/asyncio/subprocesses.py +238 -0
  25. omlish/asyncs/asyncio/timeouts.py +16 -0
  26. omlish/asyncs/bluelet/LICENSE +6 -0
  27. omlish/asyncs/bluelet/all.py +67 -0
  28. omlish/asyncs/bluelet/api.py +23 -0
  29. omlish/asyncs/bluelet/core.py +178 -0
  30. omlish/asyncs/bluelet/events.py +78 -0
  31. omlish/asyncs/bluelet/files.py +80 -0
  32. omlish/asyncs/bluelet/runner.py +416 -0
  33. omlish/asyncs/bluelet/sockets.py +214 -0
  34. omlish/bootstrap/sys.py +3 -3
  35. omlish/cached.py +2 -2
  36. omlish/check.py +49 -460
  37. omlish/codecs/__init__.py +72 -0
  38. omlish/codecs/base.py +106 -0
  39. omlish/codecs/bytes.py +119 -0
  40. omlish/codecs/chain.py +23 -0
  41. omlish/codecs/funcs.py +39 -0
  42. omlish/codecs/registry.py +139 -0
  43. omlish/codecs/standard.py +4 -0
  44. omlish/codecs/text.py +217 -0
  45. omlish/collections/cache/impl.py +50 -57
  46. omlish/collections/coerce.py +1 -0
  47. omlish/collections/mappings.py +1 -1
  48. omlish/configs/flattening.py +1 -1
  49. omlish/defs.py +1 -1
  50. omlish/diag/_pycharm/runhack.py +8 -2
  51. omlish/diag/procfs.py +8 -8
  52. omlish/docker/__init__.py +0 -36
  53. omlish/docker/all.py +31 -0
  54. omlish/docker/consts.py +4 -0
  55. omlish/{lite/docker.py → docker/detect.py} +18 -0
  56. omlish/docker/{helpers.py → timebomb.py} +0 -21
  57. omlish/formats/cbor.py +31 -0
  58. omlish/formats/cloudpickle.py +31 -0
  59. omlish/formats/codecs.py +93 -0
  60. omlish/formats/json/codecs.py +29 -0
  61. omlish/formats/json/delimted.py +4 -0
  62. omlish/formats/json/stream/errors.py +2 -0
  63. omlish/formats/json/stream/lex.py +12 -6
  64. omlish/formats/json/stream/parse.py +38 -22
  65. omlish/formats/json5.py +31 -0
  66. omlish/formats/pickle.py +31 -0
  67. omlish/formats/repr.py +25 -0
  68. omlish/formats/toml.py +17 -0
  69. omlish/formats/yaml.py +25 -0
  70. omlish/funcs/__init__.py +0 -0
  71. omlish/{genmachine.py → funcs/genmachine.py} +5 -4
  72. omlish/{matchfns.py → funcs/match.py} +1 -1
  73. omlish/funcs/pairs.py +215 -0
  74. omlish/http/__init__.py +0 -48
  75. omlish/http/all.py +48 -0
  76. omlish/http/coro/__init__.py +0 -0
  77. omlish/{lite/fdio/corohttp.py → http/coro/fdio.py} +21 -19
  78. omlish/{lite/http/coroserver.py → http/coro/server.py} +20 -21
  79. omlish/{lite/http → http}/handlers.py +3 -2
  80. omlish/{lite/http → http}/parsing.py +1 -0
  81. omlish/http/sessions.py +1 -1
  82. omlish/{lite/http → http}/versions.py +1 -0
  83. omlish/inject/managed.py +2 -2
  84. omlish/io/__init__.py +0 -3
  85. omlish/{lite/io.py → io/buffers.py} +8 -9
  86. omlish/io/compress/__init__.py +9 -0
  87. omlish/io/compress/abc.py +104 -0
  88. omlish/io/compress/adapters.py +148 -0
  89. omlish/io/compress/base.py +24 -0
  90. omlish/io/compress/brotli.py +47 -0
  91. omlish/io/compress/bz2.py +61 -0
  92. omlish/io/compress/codecs.py +78 -0
  93. omlish/io/compress/gzip.py +350 -0
  94. omlish/io/compress/lz4.py +91 -0
  95. omlish/io/compress/lzma.py +81 -0
  96. omlish/io/compress/snappy.py +34 -0
  97. omlish/io/compress/zlib.py +74 -0
  98. omlish/io/compress/zstd.py +44 -0
  99. omlish/io/fdio/__init__.py +1 -0
  100. omlish/{lite → io}/fdio/handlers.py +5 -5
  101. omlish/{lite → io}/fdio/kqueue.py +8 -8
  102. omlish/{lite → io}/fdio/manager.py +7 -7
  103. omlish/{lite → io}/fdio/pollers.py +13 -13
  104. omlish/io/generators/__init__.py +56 -0
  105. omlish/io/generators/consts.py +1 -0
  106. omlish/io/generators/direct.py +13 -0
  107. omlish/io/generators/readers.py +189 -0
  108. omlish/io/generators/stepped.py +191 -0
  109. omlish/io/pyio.py +5 -2
  110. omlish/iterators/__init__.py +24 -0
  111. omlish/iterators/iterators.py +132 -0
  112. omlish/iterators/recipes.py +18 -0
  113. omlish/iterators/tools.py +96 -0
  114. omlish/iterators/unique.py +67 -0
  115. omlish/lang/__init__.py +13 -1
  116. omlish/lang/functions.py +11 -2
  117. omlish/lang/generators.py +243 -0
  118. omlish/lang/iterables.py +46 -49
  119. omlish/lang/maybes.py +4 -4
  120. omlish/lite/cached.py +39 -6
  121. omlish/lite/check.py +438 -75
  122. omlish/lite/contextmanagers.py +17 -4
  123. omlish/lite/dataclasses.py +42 -0
  124. omlish/lite/inject.py +28 -45
  125. omlish/lite/logs.py +0 -270
  126. omlish/lite/marshal.py +309 -144
  127. omlish/lite/pycharm.py +47 -0
  128. omlish/lite/reflect.py +33 -0
  129. omlish/lite/resources.py +8 -0
  130. omlish/lite/runtime.py +4 -4
  131. omlish/lite/shlex.py +12 -0
  132. omlish/lite/socketserver.py +2 -2
  133. omlish/lite/strings.py +31 -0
  134. omlish/logs/__init__.py +0 -32
  135. omlish/logs/{_abc.py → abc.py} +0 -1
  136. omlish/logs/all.py +37 -0
  137. omlish/logs/{formatters.py → color.py} +1 -2
  138. omlish/logs/configs.py +7 -38
  139. omlish/logs/filters.py +10 -0
  140. omlish/logs/handlers.py +4 -1
  141. omlish/logs/json.py +56 -0
  142. omlish/logs/proxy.py +99 -0
  143. omlish/logs/standard.py +128 -0
  144. omlish/logs/utils.py +2 -2
  145. omlish/manifests/__init__.py +2 -0
  146. omlish/manifests/load.py +209 -0
  147. omlish/manifests/types.py +17 -0
  148. omlish/marshal/base.py +1 -1
  149. omlish/marshal/factories.py +1 -1
  150. omlish/marshal/forbidden.py +1 -1
  151. omlish/marshal/iterables.py +1 -1
  152. omlish/marshal/literals.py +50 -0
  153. omlish/marshal/mappings.py +1 -1
  154. omlish/marshal/maybes.py +1 -1
  155. omlish/marshal/standard.py +5 -1
  156. omlish/marshal/unions.py +1 -1
  157. omlish/os/__init__.py +0 -0
  158. omlish/os/atomics.py +205 -0
  159. omlish/os/deathsig.py +23 -0
  160. omlish/{os.py → os/files.py} +0 -9
  161. omlish/{lite → os}/journald.py +2 -1
  162. omlish/os/linux.py +484 -0
  163. omlish/os/paths.py +36 -0
  164. omlish/{lite → os}/pidfile.py +1 -0
  165. omlish/os/sizes.py +9 -0
  166. omlish/reflect/__init__.py +3 -0
  167. omlish/reflect/subst.py +2 -1
  168. omlish/reflect/types.py +126 -44
  169. omlish/secrets/pwhash.py +1 -1
  170. omlish/secrets/subprocesses.py +3 -1
  171. omlish/specs/jsonrpc/marshal.py +1 -1
  172. omlish/specs/openapi/marshal.py +1 -1
  173. omlish/sql/alchemy/asyncs.py +1 -1
  174. omlish/sql/queries/__init__.py +9 -1
  175. omlish/sql/queries/building.py +3 -0
  176. omlish/sql/queries/exprs.py +10 -27
  177. omlish/sql/queries/idents.py +48 -10
  178. omlish/sql/queries/names.py +80 -13
  179. omlish/sql/queries/params.py +64 -0
  180. omlish/sql/queries/rendering.py +1 -1
  181. omlish/subprocesses.py +340 -0
  182. omlish/term.py +29 -14
  183. omlish/testing/pytest/marks.py +2 -2
  184. omlish/testing/pytest/plugins/asyncs.py +6 -1
  185. omlish/testing/pytest/plugins/logging.py +1 -1
  186. omlish/testing/pytest/plugins/switches.py +1 -1
  187. {omlish-0.0.0.dev133.dist-info → omlish-0.0.0.dev177.dist-info}/METADATA +7 -5
  188. {omlish-0.0.0.dev133.dist-info → omlish-0.0.0.dev177.dist-info}/RECORD +200 -117
  189. omlish/fnpairs.py +0 -496
  190. omlish/formats/json/cli/__main__.py +0 -11
  191. omlish/formats/json/cli/cli.py +0 -298
  192. omlish/formats/json/cli/formats.py +0 -71
  193. omlish/formats/json/cli/io.py +0 -74
  194. omlish/formats/json/cli/parsing.py +0 -82
  195. omlish/formats/json/cli/processing.py +0 -48
  196. omlish/formats/json/cli/rendering.py +0 -92
  197. omlish/iterators.py +0 -300
  198. omlish/lite/subprocesses.py +0 -130
  199. /omlish/{formats/json/cli → argparse}/__init__.py +0 -0
  200. /omlish/{lite/fdio → asyncs/asyncio}/__init__.py +0 -0
  201. /omlish/asyncs/{asyncio.py → asyncio/asyncio.py} +0 -0
  202. /omlish/{lite/http → asyncs/bluelet}/__init__.py +0 -0
  203. /omlish/collections/{_abc.py → abc.py} +0 -0
  204. /omlish/{fnpipes.py → funcs/pipes.py} +0 -0
  205. /omlish/io/{_abc.py → abc.py} +0 -0
  206. /omlish/sql/{_abc.py → abc.py} +0 -0
  207. {omlish-0.0.0.dev133.dist-info → omlish-0.0.0.dev177.dist-info}/LICENSE +0 -0
  208. {omlish-0.0.0.dev133.dist-info → omlish-0.0.0.dev177.dist-info}/WHEEL +0 -0
  209. {omlish-0.0.0.dev133.dist-info → omlish-0.0.0.dev177.dist-info}/entry_points.txt +0 -0
  210. {omlish-0.0.0.dev133.dist-info → omlish-0.0.0.dev177.dist-info}/top_level.txt +0 -0
@@ -1,298 +0,0 @@
1
- """
2
- TODO:
3
- - read from http
4
- - jmespath output flat, unquoted strs like jq '.[]'
5
-
6
- ==
7
-
8
- jq Command options:
9
- -n, --null-input use `null` as the single input value;
10
- -R, --raw-input read each line as string instead of JSON;
11
- -s, --slurp read all inputs into an array and use it as the single input value;
12
- -c, --compact-output compact instead of pretty-printed output;
13
- -r, --raw-output output strings without escapes and quotes;
14
- --raw-output0 implies -r and output NUL after each output;
15
- -j, --join-output implies -r and output without newline after each output;
16
- -a, --ascii-output output strings by only ASCII characters using escape sequences;
17
- -S, --sort-keys sort keys of each object on output;
18
- -C, --color-output colorize JSON output;
19
- -M, --monochrome-output disable colored output;
20
- --tab use tabs for indentation;
21
- --indent n use n spaces for indentation (max 7 spaces);
22
- --unbuffered flush output stream after each output;
23
- --stream parse the input value in streaming fashion;
24
- --stream-errors implies --stream and report parse error as an array;
25
- --seq parse input/output as application/json-seq;
26
- -f, --from-file file load filter from the file;
27
- -L directory search modules from the directory;
28
- --arg name value set $name to the string value;
29
- --argjson name value set $name to the JSON value;
30
- --slurpfile name file set $name to an array of JSON values read from the file;
31
- --rawfile name file set $name to string contents of file;
32
- --args consume remaining arguments as positional string values;
33
- --jsonargs consume remaining arguments as positional JSON values;
34
- -e, --exit-status set exit status code based on the output;
35
- -V, --version show the version;
36
- --build-configuration show jq's build configuration;
37
- -h, --help show the help;
38
- -- terminates argument processing;
39
- """
40
- import argparse
41
- import contextlib
42
- import dataclasses as dc
43
- import io
44
- import os
45
- import subprocess
46
- import sys
47
- import typing as ta
48
-
49
- from .... import check
50
- from .... import fnpipes as fp
51
- from .... import lang
52
- from .formats import FORMATS_BY_NAME
53
- from .formats import Format
54
- from .formats import Formats
55
- from .parsing import DelimitingParser
56
- from .parsing import EagerParser
57
- from .parsing import StreamBuilder
58
- from .parsing import StreamParser
59
- from .processing import ProcessingOptions
60
- from .processing import Processor
61
- from .rendering import EagerRenderer
62
- from .rendering import RenderingOptions
63
- from .rendering import StreamRenderer
64
-
65
-
66
- T = ta.TypeVar('T')
67
- U = ta.TypeVar('U')
68
-
69
-
70
- def _build_args_parser() -> argparse.ArgumentParser:
71
- parser = argparse.ArgumentParser()
72
-
73
- parser.add_argument('file', nargs='?')
74
-
75
- parser.add_argument('--stream', action='store_true')
76
- parser.add_argument('--stream-build', action='store_true')
77
-
78
- parser.add_argument('-l', '--lines', action='store_true')
79
-
80
- parser.add_argument('--read-buffer-size', type=int, default=0x4000)
81
-
82
- parser.add_argument('-f', '--format')
83
-
84
- parser.add_argument('-x', '--jmespath-expr')
85
- parser.add_argument('-F', '--flat', action='store_true')
86
-
87
- parser.add_argument('-z', '--compact', action='store_true')
88
- parser.add_argument('-p', '--pretty', action='store_true')
89
- parser.add_argument('-i', '--indent')
90
- parser.add_argument('-s', '--sort-keys', action='store_true')
91
- parser.add_argument('-R', '--raw', action='store_true')
92
- parser.add_argument('-U', '--unicode', action='store_true')
93
- parser.add_argument('-c', '--color', action='store_true')
94
-
95
- parser.add_argument('-L', '--less', action='store_true')
96
-
97
- return parser
98
-
99
-
100
- def _parse_args(args: ta.Any = None) -> ta.Any:
101
- return _build_args_parser().parse_args(args)
102
-
103
-
104
- @dc.dataclass(frozen=True, kw_only=True)
105
- class RunConfiguration:
106
- format: Format
107
- processing: ProcessingOptions
108
- rendering: RenderingOptions
109
-
110
-
111
- def _process_args(args: ta.Any) -> RunConfiguration:
112
- fmt_name = args.format
113
- if fmt_name is None:
114
- if args.file is not None:
115
- ext = args.file.rpartition('.')[2]
116
- if ext in FORMATS_BY_NAME:
117
- fmt_name = ext
118
- if fmt_name is None:
119
- fmt_name = 'json'
120
- format = FORMATS_BY_NAME[fmt_name] # noqa
121
-
122
- if args.stream:
123
- check.arg(format is Formats.JSON.value)
124
-
125
- #
126
-
127
- processing = ProcessingOptions(
128
- jmespath_expr=args.jmespath_expr,
129
- flat=args.flat,
130
- )
131
-
132
- #
133
-
134
- separators = None
135
- if args.compact:
136
- separators = (',', ':')
137
-
138
- indent = None
139
- if args.pretty:
140
- indent = 2
141
- if args.indent:
142
- try:
143
- indent = int(args.indent)
144
- except ValueError:
145
- indent = args.indent
146
-
147
- rendering = RenderingOptions(
148
- indent=indent,
149
- separators=separators,
150
- sort_keys=args.sort_keys,
151
- raw=args.raw,
152
- unicode=args.unicode,
153
- color=args.color,
154
- )
155
-
156
- #
157
-
158
- return RunConfiguration(
159
- format=format,
160
- processing=processing,
161
- rendering=rendering,
162
- )
163
-
164
-
165
- def _main() -> None:
166
- args = _parse_args()
167
-
168
- #
169
-
170
- cfg = _process_args(args)
171
-
172
- #
173
-
174
- with contextlib.ExitStack() as es:
175
- if args.file is None:
176
- in_file = sys.stdin.buffer
177
-
178
- else:
179
- in_file = es.enter_context(open(args.file, 'rb'))
180
-
181
- def yield_input() -> ta.Generator[bytes, None, None]:
182
- fd = check.isinstance(in_file.fileno(), int)
183
-
184
- while True:
185
- buf = os.read(fd, args.read_buffer_size)
186
-
187
- yield buf
188
-
189
- if not buf:
190
- break
191
-
192
- #
193
-
194
- if args.less:
195
- less = subprocess.Popen(
196
- [
197
- 'less',
198
- *(['-R'] if cfg.rendering.color else []),
199
- ],
200
- stdin=subprocess.PIPE,
201
- encoding='utf-8',
202
- )
203
- out = check.not_none(less.stdin)
204
-
205
- def close_less() -> None:
206
- out.close()
207
- less.wait()
208
-
209
- es.enter_context(lang.defer(close_less)) # noqa
210
-
211
- else:
212
- out = sys.stdout
213
-
214
- #
215
-
216
- parser: ta.Any
217
- renderer: ta.Any
218
-
219
- if args.stream:
220
- with contextlib.ExitStack() as es2:
221
- parser = es2.enter_context(StreamParser())
222
-
223
- def flush_output(
224
- fn: ta.Callable[[T], ta.Iterable[U]],
225
- i: T,
226
- ) -> ta.Generator[U, None, None]:
227
- n = 0
228
- for o in fn(i):
229
- yield o
230
- n += 1
231
- if n:
232
- out.flush()
233
-
234
- pipeline: ta.Any
235
-
236
- if args.stream_build:
237
- builder: StreamBuilder = es2.enter_context(StreamBuilder())
238
- processor = Processor(cfg.processing)
239
- renderer = EagerRenderer(cfg.rendering)
240
- trailing_newline = False
241
-
242
- def append_newlines(
243
- fn: ta.Callable[[T], ta.Iterable[str]],
244
- i: T,
245
- ) -> ta.Generator[str, None, None]:
246
- yield from fn(i)
247
- yield '\n'
248
-
249
- pipeline = lambda v: (renderer.render(v),) # Any -> [str] # noqa
250
- pipeline = fp.bind(append_newlines, pipeline) # Any -> [str]
251
- pipeline = fp.bind(lang.flatmap, pipeline) # [Any] -> [str]
252
- pipeline = fp.pipe(fp.bind(lang.flatmap, processor.process), pipeline) # [Any] -> [str]
253
- pipeline = fp.pipe(fp.bind(lang.flatmap, builder.build), pipeline) # [JsonStreamParserEvent] -> [str] # noqa
254
- pipeline = fp.pipe(parser.parse, pipeline) # bytes -> [str]
255
-
256
- else:
257
- renderer = StreamRenderer(cfg.rendering)
258
- trailing_newline = True
259
-
260
- pipeline = renderer.render # JsonStreamParserEvent -> [str]
261
- pipeline = fp.bind(lang.flatmap, pipeline) # [JsonStreamParserEvent] -> [str]
262
- pipeline = fp.pipe(parser.parse, pipeline) # bytes -> [str]
263
-
264
- pipeline = fp.bind(flush_output, pipeline) # bytes -> [str]
265
-
266
- for buf in yield_input():
267
- for s in pipeline(buf):
268
- print(s, file=out, end='')
269
-
270
- if trailing_newline:
271
- print(file=out)
272
-
273
- elif args.lines:
274
- parser = DelimitingParser(cfg.format)
275
- processor = Processor(cfg.processing)
276
- renderer = EagerRenderer(cfg.rendering)
277
-
278
- for buf in yield_input():
279
- for v in parser.parse(buf):
280
- for e in processor.process(v):
281
- s = renderer.render(e)
282
- print(s, file=out)
283
-
284
- else:
285
- parser = EagerParser(cfg.format)
286
- processor = Processor(cfg.processing)
287
- renderer = EagerRenderer(cfg.rendering)
288
-
289
- with io.TextIOWrapper(in_file) as tf:
290
- v = parser.parse(tf)
291
-
292
- for e in processor.process(v):
293
- s = renderer.render(e)
294
- print(s, file=out)
295
-
296
-
297
- if __name__ == '__main__':
298
- _main()
@@ -1,71 +0,0 @@
1
- """
2
- TODO:
3
- - options lol - csv header, newline, etc
4
- """
5
- import dataclasses as dc
6
- import enum
7
- import json
8
- import typing as ta
9
-
10
- from .... import lang
11
-
12
-
13
- if ta.TYPE_CHECKING:
14
- import ast
15
- import csv
16
- import tomllib
17
-
18
- import yaml
19
-
20
- from ... import dotenv
21
- from ... import props
22
- from ... import xml
23
-
24
- else:
25
- ast = lang.proxy_import('ast')
26
- csv = lang.proxy_import('csv')
27
- tomllib = lang.proxy_import('tomllib')
28
-
29
- yaml = lang.proxy_import('yaml')
30
-
31
- dotenv = lang.proxy_import('...dotenv', __package__)
32
- props = lang.proxy_import('...props', __package__)
33
- xml = lang.proxy_import('...xml', __package__)
34
-
35
-
36
- ##
37
-
38
-
39
- @dc.dataclass(frozen=True)
40
- class Format:
41
- names: ta.Sequence[str]
42
- load: ta.Callable[[ta.TextIO], ta.Any]
43
-
44
-
45
- class Formats(enum.Enum):
46
- JSON = Format(['json'], json.load)
47
-
48
- YAML = Format(['yaml', 'yml'], lambda f: yaml.safe_load(f))
49
-
50
- TOML = Format(['toml'], lambda f: tomllib.loads(f.read()))
51
-
52
- ENV = Format(['env', 'dotenv'], lambda f: dotenv.dotenv_values(stream=f))
53
-
54
- PROPS = Format(['properties', 'props'], lambda f: dict(props.Properties().load(f.read())))
55
-
56
- PY = Format(['py', 'python', 'repr'], lambda f: ast.literal_eval(f.read()))
57
-
58
- XML = Format(['xml'], lambda f: xml.build_simple_element(xml.parse_tree(f.read()).getroot()).as_dict())
59
-
60
- CSV = Format(['csv'], lambda f: list(csv.DictReader(f)))
61
- TSV = Format(['tsv'], lambda f: list(csv.DictReader(f, delimiter='\t')))
62
- FLAT_CSV = Format(['fcsv'], lambda f: list(csv.reader(f)))
63
- FLAT_TSV = Format(['ftsv'], lambda f: list(csv.reader(f, delimiter='\t')))
64
-
65
-
66
- FORMATS_BY_NAME: ta.Mapping[str, Format] = {
67
- n: f
68
- for e in Formats
69
- for f in [e.value]
70
- for n in f.names
71
- }
@@ -1,74 +0,0 @@
1
- # """
2
- # TODO:
3
- # - -I/-Ogz, lz4, etc
4
- # - fnpairs? or not yet just do it
5
- # """
6
- # import abc
7
- # import contextlib
8
- # import dataclasses as dc
9
- # import gzip
10
- # import os
11
- # import typing as ta
12
- #
13
- # from .... import lang
14
- #
15
- #
16
- # if ta.TYPE_CHECKING:
17
- # import bz2 as _bz2
18
- # import gzip as _gzip
19
- # import lzma as _lzma
20
- # else:
21
- # _bz2 = lang.proxy_import('bz2')
22
- # _gzip = lang.proxy_import('gzip')
23
- # _lzma = lang.proxy_import('lzma')
24
- #
25
- #
26
- # ##
27
- #
28
- #
29
- # class BaseIo(lang.Abstract):
30
- # def close(self) -> None:
31
- # raise NotImplementedError
32
- #
33
- # def fileno(self) -> int | None:
34
- # return None
35
- #
36
- #
37
- # class Input(BaseIo):
38
- # @abc.abstractmethod
39
- # def read(self, sz: int | None = None) -> bytes:
40
- # raise NotImplementedError
41
- #
42
- #
43
- # class Output(BaseIo):
44
- # @abc.abstractmethod
45
- # def write(self, data: bytes) -> int:
46
- # raise NotImplementedError
47
- #
48
- #
49
- # #
50
- #
51
- #
52
- # DEFAULT_READ_SZ = 0x4000
53
- #
54
- #
55
- # @dc.dataclass(frozen=True)
56
- # class FdIo(Input, Output):
57
- # fd: int
58
- #
59
- # default_read_sz: int = DEFAULT_READ_SZ
60
- #
61
- # def read(self, sz: int | None = None) -> bytes:
62
- # return os.read(self.fd, sz or self.default_read_sz)
63
- #
64
- # def write(self, data: bytes) -> int:
65
- # return os.write(self.fd, data)
66
- #
67
- #
68
- # ##
69
- #
70
- #
71
- # @contextlib.contextmanager
72
- # def gzip_io_codec(f: ta.IO, mode: str) -> ta.ContextManager[ta.IO]:
73
- # with gzip.open(f, mode) as o:
74
- # yield o
@@ -1,82 +0,0 @@
1
- import codecs
2
- import io
3
- import typing as ta
4
-
5
- from .... import check
6
- from .... import lang
7
- from ....lite.io import DelimitingBuffer
8
- from ..stream.build import JsonObjectBuilder
9
- from ..stream.lex import JsonStreamLexer
10
- from ..stream.parse import JsonStreamParser
11
- from ..stream.parse import JsonStreamParserEvent
12
- from .formats import Format
13
-
14
-
15
- ##
16
-
17
-
18
- class EagerParser:
19
- def __init__(self, fmt: Format) -> None:
20
- super().__init__()
21
-
22
- self._fmt = fmt
23
-
24
- def parse(self, f: ta.TextIO) -> ta.Generator[ta.Any, None, None]:
25
- return self._fmt.load(f)
26
-
27
-
28
- ##
29
-
30
-
31
- class DelimitingParser:
32
- def __init__(
33
- self,
34
- fmt: Format,
35
- *,
36
- delimiters: ta.Iterable[int] = b'\n',
37
- ) -> None:
38
- super().__init__()
39
-
40
- self._fmt = fmt
41
-
42
- self._db = DelimitingBuffer(delimiters)
43
-
44
- def parse(self, b: bytes) -> ta.Generator[ta.Any, None, None]:
45
- for chunk in self._db.feed(b):
46
- s = check.isinstance(chunk, bytes).decode('utf-8')
47
- v = self._fmt.load(io.StringIO(s))
48
- yield v
49
-
50
-
51
- ##
52
-
53
-
54
- class StreamBuilder(lang.ExitStacked):
55
- _builder: JsonObjectBuilder | None = None
56
-
57
- def __enter__(self) -> ta.Self:
58
- super().__enter__()
59
- self._builder = self._enter_context(JsonObjectBuilder())
60
- return self
61
-
62
- def build(self, e: JsonStreamParserEvent) -> ta.Generator[ta.Any, None, None]:
63
- yield from check.not_none(self._builder)(e)
64
-
65
-
66
- class StreamParser(lang.ExitStacked):
67
- _decoder: codecs.IncrementalDecoder
68
- _lex: JsonStreamLexer
69
- _parse: JsonStreamParser
70
-
71
- def __enter__(self) -> ta.Self:
72
- super().__enter__()
73
- self._decoder = codecs.getincrementaldecoder('utf-8')()
74
- self._lex = self._enter_context(JsonStreamLexer())
75
- self._parse = self._enter_context(JsonStreamParser())
76
- return self
77
-
78
- def parse(self, b: bytes) -> ta.Generator[JsonStreamParserEvent, None, None]:
79
- for s in self._decoder.decode(b, not b):
80
- for c in s:
81
- for t in self._lex(c):
82
- yield from self._parse(t)
@@ -1,48 +0,0 @@
1
- import dataclasses as dc
2
- import typing as ta
3
-
4
- from .... import lang
5
-
6
-
7
- if ta.TYPE_CHECKING:
8
- from ....specs import jmespath
9
- else:
10
- jmespath = lang.proxy_import('....specs.jmespath', __package__)
11
-
12
-
13
- ##
14
-
15
-
16
- @dc.dataclass(frozen=True, kw_only=True)
17
- class ProcessingOptions:
18
- jmespath_expr: ta.Any | None = None
19
- flat: bool = False
20
-
21
-
22
- class Processor:
23
- def __init__(self, opts: ProcessingOptions) -> None:
24
- super().__init__()
25
-
26
- self._opts = opts
27
-
28
- jmespath_expr = opts.jmespath_expr
29
- if isinstance(jmespath_expr, str):
30
- jmespath_expr = jmespath.compile(jmespath_expr)
31
- self._jmespath_expr: ta.Any | None = jmespath_expr
32
-
33
- def process(self, v: ta.Any) -> ta.Iterable[ta.Any]:
34
- if self._jmespath_expr is not None:
35
- v = self._jmespath_expr.search(v)
36
-
37
- if self._opts.flat:
38
- if (
39
- not isinstance(v, ta.Iterable) or # noqa
40
- isinstance(v, ta.Mapping) or
41
- isinstance(v, lang.BUILTIN_SCALAR_ITERABLE_TYPES)
42
- ):
43
- raise TypeError(f'Flat output must be flat collections, got {type(v)}', v)
44
-
45
- yield from v
46
-
47
- else:
48
- yield v
@@ -1,92 +0,0 @@
1
- import dataclasses as dc
2
- import json
3
- import typing as ta
4
-
5
- from .... import lang
6
- from .... import term
7
- from ..render import JsonRenderer
8
- from ..stream.parse import JsonStreamParserEvent
9
- from ..stream.render import StreamJsonRenderer
10
-
11
-
12
- ##
13
-
14
-
15
- @dc.dataclass(frozen=True, kw_only=True)
16
- class RenderingOptions:
17
- indent: int | str | None = None
18
- separators: tuple[str, str] | None = None
19
- sort_keys: bool = False
20
- raw: bool = False
21
- unicode: bool = False
22
- color: bool = False
23
-
24
-
25
- def make_render_kwargs(opts: RenderingOptions) -> ta.Mapping[str, ta.Any]:
26
- return dict(
27
- indent=opts.indent,
28
- separators=opts.separators,
29
- sort_keys=opts.sort_keys,
30
- ensure_ascii=not opts.unicode,
31
- )
32
-
33
-
34
- class Renderer(lang.Abstract):
35
- def __init__(self, opts: RenderingOptions) -> None:
36
- super().__init__()
37
- self._opts = opts
38
- self._kw = make_render_kwargs(opts)
39
-
40
-
41
- ##
42
-
43
-
44
- def term_color(o: ta.Any, state: JsonRenderer.State) -> tuple[str, str]:
45
- if state is JsonRenderer.State.KEY:
46
- return term.SGR(term.SGRs.FG.BRIGHT_BLUE), term.SGR(term.SGRs.RESET)
47
- elif isinstance(o, str):
48
- return term.SGR(term.SGRs.FG.GREEN), term.SGR(term.SGRs.RESET)
49
- else:
50
- return '', ''
51
-
52
-
53
- ##
54
-
55
-
56
- class EagerRenderer(Renderer):
57
- def render(self, v: ta.Any) -> str:
58
- if self._opts.raw:
59
- if not isinstance(v, str):
60
- raise TypeError(f'Raw output must be strings, got {type(v)}', v)
61
-
62
- return v
63
-
64
- elif self._opts.color:
65
- return JsonRenderer.render_str(
66
- v,
67
- **self._kw,
68
- style=term_color,
69
- )
70
-
71
- else:
72
- return json.dumps(
73
- v,
74
- **self._kw,
75
- )
76
-
77
-
78
- ##
79
-
80
-
81
- class StreamRenderer(Renderer):
82
- def __init__(self, opts: RenderingOptions) -> None:
83
- super().__init__(opts)
84
-
85
- self._renderer = StreamJsonRenderer(
86
- style=term_color if self._opts.color else None,
87
- delimiter='\n',
88
- **self._kw,
89
- )
90
-
91
- def render(self, e: JsonStreamParserEvent) -> ta.Generator[str, None, None]:
92
- return self._renderer.render((e,))