omlish 0.0.0.dev133__py3-none-any.whl → 0.0.0.dev177__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.
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,))