etlplus 0.7.2__py3-none-any.whl → 0.8.2__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.
- etlplus/cli/commands.py +645 -0
- etlplus/cli/constants.py +65 -0
- etlplus/cli/handlers.py +37 -358
- etlplus/cli/io.py +343 -0
- etlplus/cli/main.py +46 -131
- etlplus/cli/options.py +115 -0
- etlplus/cli/state.py +411 -0
- etlplus/cli/types.py +33 -0
- etlplus/database/ddl.py +1 -1
- etlplus/database/types.py +0 -5
- etlplus/types.py +5 -0
- {etlplus-0.7.2.dist-info → etlplus-0.8.2.dist-info}/METADATA +1 -3
- {etlplus-0.7.2.dist-info → etlplus-0.8.2.dist-info}/RECORD +17 -12
- etlplus/cli/app.py +0 -1367
- {etlplus-0.7.2.dist-info → etlplus-0.8.2.dist-info}/WHEEL +0 -0
- {etlplus-0.7.2.dist-info → etlplus-0.8.2.dist-info}/entry_points.txt +0 -0
- {etlplus-0.7.2.dist-info → etlplus-0.8.2.dist-info}/licenses/LICENSE +0 -0
- {etlplus-0.7.2.dist-info → etlplus-0.8.2.dist-info}/top_level.txt +0 -0
etlplus/cli/handlers.py
CHANGED
|
@@ -7,9 +7,6 @@ Command handler functions for the ``etlplus`` command-line interface (CLI).
|
|
|
7
7
|
from __future__ import annotations
|
|
8
8
|
|
|
9
9
|
import argparse
|
|
10
|
-
import csv
|
|
11
|
-
import io
|
|
12
|
-
import json
|
|
13
10
|
import os
|
|
14
11
|
import sys
|
|
15
12
|
from pathlib import Path
|
|
@@ -20,16 +17,14 @@ from ..config import PipelineConfig
|
|
|
20
17
|
from ..config import load_pipeline_config
|
|
21
18
|
from ..database import load_table_spec
|
|
22
19
|
from ..database import render_tables
|
|
23
|
-
from ..enums import FileFormat
|
|
24
20
|
from ..extract import extract
|
|
25
|
-
from ..file import File
|
|
26
21
|
from ..load import load
|
|
27
22
|
from ..run import run
|
|
28
23
|
from ..transform import transform
|
|
29
24
|
from ..types import JSONData
|
|
30
|
-
from ..
|
|
31
|
-
from ..utils import print_json
|
|
25
|
+
from ..types import TemplateKey
|
|
32
26
|
from ..validate import validate
|
|
27
|
+
from . import io as cli_io
|
|
33
28
|
|
|
34
29
|
# SECTION: EXPORTS ========================================================== #
|
|
35
30
|
|
|
@@ -39,7 +34,6 @@ __all__ = [
|
|
|
39
34
|
'extract_handler',
|
|
40
35
|
'check_handler',
|
|
41
36
|
'load_handler',
|
|
42
|
-
'pipeline_handler',
|
|
43
37
|
'render_handler',
|
|
44
38
|
'run_handler',
|
|
45
39
|
'transform_handler',
|
|
@@ -72,7 +66,7 @@ def _collect_table_specs(
|
|
|
72
66
|
specs: list[dict[str, Any]] = []
|
|
73
67
|
|
|
74
68
|
if spec_path:
|
|
75
|
-
specs.append(load_table_spec(Path(spec_path)))
|
|
69
|
+
specs.append(dict(load_table_spec(Path(spec_path))))
|
|
76
70
|
|
|
77
71
|
if config_path:
|
|
78
72
|
cfg = load_pipeline_config(config_path, substitute=True)
|
|
@@ -81,73 +75,6 @@ def _collect_table_specs(
|
|
|
81
75
|
return specs
|
|
82
76
|
|
|
83
77
|
|
|
84
|
-
def _emit_json(
|
|
85
|
-
data: Any,
|
|
86
|
-
*,
|
|
87
|
-
pretty: bool,
|
|
88
|
-
) -> None:
|
|
89
|
-
"""
|
|
90
|
-
Emit JSON to stdout honoring the pretty/compact preference.
|
|
91
|
-
|
|
92
|
-
Parameters
|
|
93
|
-
----------
|
|
94
|
-
data : Any
|
|
95
|
-
Arbitrary JSON-serializable payload.
|
|
96
|
-
pretty : bool
|
|
97
|
-
When ``True`` pretty-print via :func:`print_json`; otherwise emit a
|
|
98
|
-
compact JSON string.
|
|
99
|
-
"""
|
|
100
|
-
if pretty:
|
|
101
|
-
print_json(data)
|
|
102
|
-
return
|
|
103
|
-
|
|
104
|
-
dumped = json.dumps(
|
|
105
|
-
data,
|
|
106
|
-
ensure_ascii=False,
|
|
107
|
-
separators=(',', ':'),
|
|
108
|
-
)
|
|
109
|
-
print(dumped)
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
def _explicit_cli_format(
|
|
113
|
-
args: argparse.Namespace,
|
|
114
|
-
) -> str | None:
|
|
115
|
-
"""Return the explicit CLI format hint when provided."""
|
|
116
|
-
|
|
117
|
-
if not getattr(args, '_format_explicit', False):
|
|
118
|
-
return None
|
|
119
|
-
for attr in ('format', 'target_format', 'source_format'):
|
|
120
|
-
value = getattr(args, attr, None)
|
|
121
|
-
if value is None:
|
|
122
|
-
continue
|
|
123
|
-
normalized = value.strip().lower()
|
|
124
|
-
if normalized:
|
|
125
|
-
return normalized
|
|
126
|
-
return None
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
def _infer_payload_format(
|
|
130
|
-
text: str,
|
|
131
|
-
) -> str:
|
|
132
|
-
"""
|
|
133
|
-
Infer JSON vs CSV from payload text.
|
|
134
|
-
|
|
135
|
-
Parameters
|
|
136
|
-
----------
|
|
137
|
-
text : str
|
|
138
|
-
Incoming payload as plain text.
|
|
139
|
-
|
|
140
|
-
Returns
|
|
141
|
-
-------
|
|
142
|
-
str
|
|
143
|
-
``'json'`` when the text starts with ``{``/``[``, else ``'csv'``.
|
|
144
|
-
"""
|
|
145
|
-
stripped = text.lstrip()
|
|
146
|
-
if stripped.startswith('{') or stripped.startswith('['):
|
|
147
|
-
return 'json'
|
|
148
|
-
return 'csv'
|
|
149
|
-
|
|
150
|
-
|
|
151
78
|
def _check_sections(
|
|
152
79
|
cfg: PipelineConfig,
|
|
153
80
|
args: argparse.Namespace,
|
|
@@ -185,88 +112,6 @@ def _check_sections(
|
|
|
185
112
|
return sections
|
|
186
113
|
|
|
187
114
|
|
|
188
|
-
def _materialize_file_payload(
|
|
189
|
-
source: object,
|
|
190
|
-
*,
|
|
191
|
-
format_hint: str | None,
|
|
192
|
-
format_explicit: bool,
|
|
193
|
-
) -> JSONData | object:
|
|
194
|
-
"""
|
|
195
|
-
Return structured payloads when ``source`` references a file.
|
|
196
|
-
|
|
197
|
-
Parameters
|
|
198
|
-
----------
|
|
199
|
-
source : object
|
|
200
|
-
Input source of data, possibly a file path.
|
|
201
|
-
format_hint : str | None
|
|
202
|
-
Explicit format hint: 'json', 'csv', or None to infer.
|
|
203
|
-
format_explicit : bool
|
|
204
|
-
Whether an explicit format hint was provided.
|
|
205
|
-
|
|
206
|
-
Returns
|
|
207
|
-
-------
|
|
208
|
-
JSONData | object
|
|
209
|
-
Parsed JSON data when ``source`` is a file; otherwise the original
|
|
210
|
-
``source`` object.
|
|
211
|
-
"""
|
|
212
|
-
if isinstance(source, (dict, list)):
|
|
213
|
-
return cast(JSONData, source)
|
|
214
|
-
if not isinstance(source, (str, os.PathLike)):
|
|
215
|
-
return source
|
|
216
|
-
|
|
217
|
-
path = Path(source)
|
|
218
|
-
|
|
219
|
-
normalized_hint = (format_hint or '').strip().lower()
|
|
220
|
-
fmt: FileFormat | None = None
|
|
221
|
-
|
|
222
|
-
if format_explicit and normalized_hint:
|
|
223
|
-
try:
|
|
224
|
-
fmt = FileFormat(normalized_hint)
|
|
225
|
-
except ValueError:
|
|
226
|
-
fmt = None
|
|
227
|
-
elif not format_explicit:
|
|
228
|
-
suffix = path.suffix.lower().lstrip('.')
|
|
229
|
-
if suffix:
|
|
230
|
-
try:
|
|
231
|
-
fmt = FileFormat(suffix)
|
|
232
|
-
except ValueError:
|
|
233
|
-
fmt = None
|
|
234
|
-
|
|
235
|
-
if fmt is None:
|
|
236
|
-
return source
|
|
237
|
-
if fmt == FileFormat.CSV:
|
|
238
|
-
return _read_csv_rows(path)
|
|
239
|
-
return File(path, fmt).read()
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
def _parse_text_payload(
|
|
243
|
-
text: str,
|
|
244
|
-
fmt: str | None,
|
|
245
|
-
) -> JSONData | str:
|
|
246
|
-
"""
|
|
247
|
-
Parse JSON/CSV text into a Python payload.
|
|
248
|
-
|
|
249
|
-
Parameters
|
|
250
|
-
----------
|
|
251
|
-
text : str
|
|
252
|
-
The input text payload.
|
|
253
|
-
fmt : str | None
|
|
254
|
-
Explicit format hint: 'json', 'csv', or None to infer.
|
|
255
|
-
|
|
256
|
-
Returns
|
|
257
|
-
-------
|
|
258
|
-
JSONData | str
|
|
259
|
-
The parsed payload as JSON data or raw text.
|
|
260
|
-
"""
|
|
261
|
-
effective = (fmt or '').strip().lower() or _infer_payload_format(text)
|
|
262
|
-
if effective == 'json':
|
|
263
|
-
return cast(JSONData, json_type(text))
|
|
264
|
-
if effective == 'csv':
|
|
265
|
-
reader = csv.DictReader(io.StringIO(text))
|
|
266
|
-
return [dict(row) for row in reader]
|
|
267
|
-
return text
|
|
268
|
-
|
|
269
|
-
|
|
270
115
|
def _pipeline_summary(
|
|
271
116
|
cfg: PipelineConfig,
|
|
272
117
|
) -> dict[str, Any]:
|
|
@@ -295,131 +140,6 @@ def _pipeline_summary(
|
|
|
295
140
|
}
|
|
296
141
|
|
|
297
142
|
|
|
298
|
-
def _presentation_flags(
|
|
299
|
-
args: argparse.Namespace,
|
|
300
|
-
) -> tuple[bool, bool]:
|
|
301
|
-
"""
|
|
302
|
-
Return presentation toggles from the parsed namespace.
|
|
303
|
-
|
|
304
|
-
Parameters
|
|
305
|
-
----------
|
|
306
|
-
args : argparse.Namespace
|
|
307
|
-
Namespace produced by the CLI parser.
|
|
308
|
-
|
|
309
|
-
Returns
|
|
310
|
-
-------
|
|
311
|
-
tuple[bool, bool]
|
|
312
|
-
Pair of ``(pretty, quiet)`` flags with safe defaults.
|
|
313
|
-
"""
|
|
314
|
-
return getattr(args, 'pretty', True), getattr(args, 'quiet', False)
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
def _read_csv_rows(
|
|
318
|
-
path: Path,
|
|
319
|
-
) -> list[dict[str, str]]:
|
|
320
|
-
"""
|
|
321
|
-
Read CSV rows into dictionaries.
|
|
322
|
-
|
|
323
|
-
Parameters
|
|
324
|
-
----------
|
|
325
|
-
path : Path
|
|
326
|
-
Path to a CSV file.
|
|
327
|
-
|
|
328
|
-
Returns
|
|
329
|
-
-------
|
|
330
|
-
list[dict[str, str]]
|
|
331
|
-
List of dictionaries, each representing a row in the CSV file.
|
|
332
|
-
"""
|
|
333
|
-
with path.open(newline='', encoding='utf-8') as handle:
|
|
334
|
-
reader = csv.DictReader(handle)
|
|
335
|
-
return [dict(row) for row in reader]
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
def _read_stdin_text() -> str:
|
|
339
|
-
"""
|
|
340
|
-
Return every character from ``stdin`` as a single string.
|
|
341
|
-
|
|
342
|
-
Returns
|
|
343
|
-
-------
|
|
344
|
-
str
|
|
345
|
-
Entire ``stdin`` contents.
|
|
346
|
-
"""
|
|
347
|
-
return sys.stdin.read()
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
def _resolve_cli_payload(
|
|
351
|
-
source: object,
|
|
352
|
-
*,
|
|
353
|
-
format_hint: str | None,
|
|
354
|
-
format_explicit: bool,
|
|
355
|
-
hydrate_files: bool = True,
|
|
356
|
-
) -> JSONData | object:
|
|
357
|
-
"""
|
|
358
|
-
Normalize CLI-provided payloads, honoring stdin and inline data.
|
|
359
|
-
|
|
360
|
-
Parameters
|
|
361
|
-
----------
|
|
362
|
-
source : object
|
|
363
|
-
Raw CLI value (path, inline payload, or ``'-'`` for stdin).
|
|
364
|
-
format_hint : str | None
|
|
365
|
-
Explicit format hint supplied by the CLI option.
|
|
366
|
-
format_explicit : bool
|
|
367
|
-
Flag indicating whether the format hint was explicitly provided.
|
|
368
|
-
hydrate_files : bool, optional
|
|
369
|
-
When ``True`` (default) materialize file paths into structured data.
|
|
370
|
-
When ``False``, keep the original path so downstream code can stream
|
|
371
|
-
from disk directly.
|
|
372
|
-
|
|
373
|
-
Returns
|
|
374
|
-
-------
|
|
375
|
-
JSONData | object
|
|
376
|
-
Parsed payload or the original source value when hydration is
|
|
377
|
-
disabled.
|
|
378
|
-
"""
|
|
379
|
-
if isinstance(source, (os.PathLike, str)) and str(source) == '-':
|
|
380
|
-
text = _read_stdin_text()
|
|
381
|
-
return _parse_text_payload(text, format_hint)
|
|
382
|
-
|
|
383
|
-
if not hydrate_files:
|
|
384
|
-
return source
|
|
385
|
-
|
|
386
|
-
return _materialize_file_payload(
|
|
387
|
-
source,
|
|
388
|
-
format_hint=format_hint,
|
|
389
|
-
format_explicit=format_explicit,
|
|
390
|
-
)
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
def _write_json_output(
|
|
394
|
-
data: Any,
|
|
395
|
-
output_path: str | None,
|
|
396
|
-
*,
|
|
397
|
-
success_message: str,
|
|
398
|
-
) -> bool:
|
|
399
|
-
"""
|
|
400
|
-
Optionally persist JSON data to disk.
|
|
401
|
-
|
|
402
|
-
Parameters
|
|
403
|
-
----------
|
|
404
|
-
data : Any
|
|
405
|
-
Data to write.
|
|
406
|
-
output_path : str | None
|
|
407
|
-
Path to write the output to. None to print to stdout.
|
|
408
|
-
success_message : str
|
|
409
|
-
Message to print upon successful write.
|
|
410
|
-
|
|
411
|
-
Returns
|
|
412
|
-
-------
|
|
413
|
-
bool
|
|
414
|
-
True if output was written to a file, False if printed to stdout.
|
|
415
|
-
"""
|
|
416
|
-
if not output_path or output_path == '-':
|
|
417
|
-
return False
|
|
418
|
-
File(Path(output_path), FileFormat.JSON).write_json(data)
|
|
419
|
-
print(f'{success_message} {output_path}')
|
|
420
|
-
return True
|
|
421
|
-
|
|
422
|
-
|
|
423
143
|
# SECTION: FUNCTIONS ======================================================== #
|
|
424
144
|
|
|
425
145
|
|
|
@@ -441,10 +161,10 @@ def check_handler(
|
|
|
441
161
|
"""
|
|
442
162
|
cfg = load_pipeline_config(args.config, substitute=True)
|
|
443
163
|
if getattr(args, 'summary', False):
|
|
444
|
-
|
|
164
|
+
cli_io.emit_json(_pipeline_summary(cfg), pretty=True)
|
|
445
165
|
return 0
|
|
446
166
|
|
|
447
|
-
|
|
167
|
+
cli_io.emit_json(_check_sections(cfg, args), pretty=True)
|
|
448
168
|
return 0
|
|
449
169
|
|
|
450
170
|
|
|
@@ -464,13 +184,16 @@ def extract_handler(
|
|
|
464
184
|
int
|
|
465
185
|
Zero on success.
|
|
466
186
|
"""
|
|
467
|
-
pretty, _ =
|
|
468
|
-
explicit_format =
|
|
187
|
+
pretty, _ = cli_io.presentation_flags(args)
|
|
188
|
+
explicit_format = cli_io.explicit_cli_format(args)
|
|
469
189
|
|
|
470
190
|
if args.source == '-':
|
|
471
|
-
text =
|
|
472
|
-
payload =
|
|
473
|
-
|
|
191
|
+
text = cli_io.read_stdin_text()
|
|
192
|
+
payload = cli_io.parse_text_payload(
|
|
193
|
+
text,
|
|
194
|
+
getattr(args, 'format', None),
|
|
195
|
+
)
|
|
196
|
+
cli_io.emit_json(payload, pretty=pretty)
|
|
474
197
|
|
|
475
198
|
return 0
|
|
476
199
|
|
|
@@ -483,12 +206,12 @@ def extract_handler(
|
|
|
483
206
|
if output_path is None:
|
|
484
207
|
output_path = getattr(args, 'output', None)
|
|
485
208
|
|
|
486
|
-
|
|
209
|
+
cli_io.emit_or_write(
|
|
487
210
|
result,
|
|
488
211
|
output_path,
|
|
212
|
+
pretty=pretty,
|
|
489
213
|
success_message='Data extracted and saved to',
|
|
490
|
-
)
|
|
491
|
-
_emit_json(result, pretty=pretty)
|
|
214
|
+
)
|
|
492
215
|
|
|
493
216
|
return 0
|
|
494
217
|
|
|
@@ -509,14 +232,14 @@ def load_handler(
|
|
|
509
232
|
int
|
|
510
233
|
Zero on success.
|
|
511
234
|
"""
|
|
512
|
-
pretty, _ =
|
|
513
|
-
explicit_format =
|
|
235
|
+
pretty, _ = cli_io.presentation_flags(args)
|
|
236
|
+
explicit_format = cli_io.explicit_cli_format(args)
|
|
514
237
|
|
|
515
238
|
# Allow piping into load.
|
|
516
239
|
source_format = getattr(args, 'source_format', None)
|
|
517
240
|
source_value = cast(
|
|
518
241
|
str | Path | os.PathLike[str] | dict[str, Any] | list[dict[str, Any]],
|
|
519
|
-
|
|
242
|
+
cli_io.resolve_cli_payload(
|
|
520
243
|
args.source,
|
|
521
244
|
format_hint=source_format,
|
|
522
245
|
format_explicit=source_format is not None,
|
|
@@ -526,12 +249,12 @@ def load_handler(
|
|
|
526
249
|
|
|
527
250
|
# Allow piping out of load for file targets.
|
|
528
251
|
if args.target_type == 'file' and args.target == '-':
|
|
529
|
-
payload =
|
|
252
|
+
payload = cli_io.materialize_file_payload(
|
|
530
253
|
source_value,
|
|
531
254
|
format_hint=source_format,
|
|
532
255
|
format_explicit=source_format is not None,
|
|
533
256
|
)
|
|
534
|
-
|
|
257
|
+
cli_io.emit_json(payload, pretty=pretty)
|
|
535
258
|
return 0
|
|
536
259
|
|
|
537
260
|
result = load(
|
|
@@ -542,57 +265,13 @@ def load_handler(
|
|
|
542
265
|
)
|
|
543
266
|
|
|
544
267
|
output_path = getattr(args, 'output', None)
|
|
545
|
-
|
|
268
|
+
cli_io.emit_or_write(
|
|
546
269
|
result,
|
|
547
270
|
output_path,
|
|
271
|
+
pretty=pretty,
|
|
548
272
|
success_message='Load result saved to',
|
|
549
|
-
):
|
|
550
|
-
_emit_json(result, pretty=pretty)
|
|
551
|
-
|
|
552
|
-
return 0
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
def pipeline_handler(
|
|
556
|
-
args: argparse.Namespace,
|
|
557
|
-
) -> int:
|
|
558
|
-
"""
|
|
559
|
-
Inspect or run a pipeline YAML configuration.
|
|
560
|
-
|
|
561
|
-
Parameters
|
|
562
|
-
----------
|
|
563
|
-
args : argparse.Namespace
|
|
564
|
-
Parsed command-line arguments.
|
|
565
|
-
|
|
566
|
-
Returns
|
|
567
|
-
-------
|
|
568
|
-
int
|
|
569
|
-
Zero on success.
|
|
570
|
-
"""
|
|
571
|
-
print(
|
|
572
|
-
'DEPRECATED: use "etlplus check --summary|--jobs" or '
|
|
573
|
-
'"etlplus run --job/--pipeline" instead of "etlplus pipeline".',
|
|
574
|
-
file=sys.stderr,
|
|
575
273
|
)
|
|
576
274
|
|
|
577
|
-
cfg = load_pipeline_config(args.config, substitute=True)
|
|
578
|
-
|
|
579
|
-
list_flag = getattr(args, 'list', False) or getattr(args, 'jobs', False)
|
|
580
|
-
run_target = (
|
|
581
|
-
getattr(args, 'run', None)
|
|
582
|
-
or getattr(args, 'job', None)
|
|
583
|
-
or getattr(args, 'pipeline', None)
|
|
584
|
-
)
|
|
585
|
-
|
|
586
|
-
if list_flag and not run_target:
|
|
587
|
-
print_json({'jobs': _pipeline_summary(cfg)['jobs']})
|
|
588
|
-
return 0
|
|
589
|
-
|
|
590
|
-
if run_target:
|
|
591
|
-
result = run(job=run_target, config_path=args.config)
|
|
592
|
-
print_json({'status': 'ok', 'result': result})
|
|
593
|
-
return 0
|
|
594
|
-
|
|
595
|
-
print_json(_pipeline_summary(cfg))
|
|
596
275
|
return 0
|
|
597
276
|
|
|
598
277
|
|
|
@@ -600,9 +279,9 @@ def render_handler(
|
|
|
600
279
|
args: argparse.Namespace,
|
|
601
280
|
) -> int:
|
|
602
281
|
"""Render SQL DDL statements from table schema specs."""
|
|
603
|
-
_, quiet =
|
|
282
|
+
_, quiet = cli_io.presentation_flags(args)
|
|
604
283
|
|
|
605
|
-
template_value = getattr(args, 'template', 'ddl') or 'ddl'
|
|
284
|
+
template_value: TemplateKey = getattr(args, 'template', 'ddl') or 'ddl'
|
|
606
285
|
template_path = getattr(args, 'template_path', None)
|
|
607
286
|
table_filter = getattr(args, 'table', None)
|
|
608
287
|
spec_path = getattr(args, 'spec', None)
|
|
@@ -610,7 +289,7 @@ def render_handler(
|
|
|
610
289
|
|
|
611
290
|
# If the provided template points to a file, treat it as a path override.
|
|
612
291
|
file_override = template_path
|
|
613
|
-
template_key = template_value
|
|
292
|
+
template_key: TemplateKey | None = template_value
|
|
614
293
|
if template_path is None:
|
|
615
294
|
candidate_path = Path(template_value)
|
|
616
295
|
if candidate_path.exists():
|
|
@@ -677,10 +356,10 @@ def run_handler(
|
|
|
677
356
|
job_name = getattr(args, 'job', None) or getattr(args, 'pipeline', None)
|
|
678
357
|
if job_name:
|
|
679
358
|
result = run(job=job_name, config_path=args.config)
|
|
680
|
-
|
|
359
|
+
cli_io.emit_json({'status': 'ok', 'result': result}, pretty=True)
|
|
681
360
|
return 0
|
|
682
361
|
|
|
683
|
-
|
|
362
|
+
cli_io.emit_json(_pipeline_summary(cfg), pretty=True)
|
|
684
363
|
return 0
|
|
685
364
|
|
|
686
365
|
|
|
@@ -700,13 +379,13 @@ def transform_handler(
|
|
|
700
379
|
int
|
|
701
380
|
Zero on success.
|
|
702
381
|
"""
|
|
703
|
-
pretty, _ =
|
|
382
|
+
pretty, _ = cli_io.presentation_flags(args)
|
|
704
383
|
format_hint: str | None = getattr(args, 'source_format', None)
|
|
705
384
|
format_explicit: bool = format_hint is not None
|
|
706
385
|
|
|
707
386
|
payload = cast(
|
|
708
387
|
JSONData | str,
|
|
709
|
-
|
|
388
|
+
cli_io.resolve_cli_payload(
|
|
710
389
|
args.source,
|
|
711
390
|
format_hint=format_hint,
|
|
712
391
|
format_explicit=format_explicit,
|
|
@@ -715,12 +394,12 @@ def transform_handler(
|
|
|
715
394
|
|
|
716
395
|
data = transform(payload, args.operations)
|
|
717
396
|
|
|
718
|
-
|
|
397
|
+
cli_io.emit_or_write(
|
|
719
398
|
data,
|
|
720
399
|
getattr(args, 'target', None),
|
|
400
|
+
pretty=pretty,
|
|
721
401
|
success_message='Data transformed and saved to',
|
|
722
|
-
)
|
|
723
|
-
_emit_json(data, pretty=pretty)
|
|
402
|
+
)
|
|
724
403
|
|
|
725
404
|
return 0
|
|
726
405
|
|
|
@@ -741,12 +420,12 @@ def validate_handler(
|
|
|
741
420
|
int
|
|
742
421
|
Zero on success.
|
|
743
422
|
"""
|
|
744
|
-
pretty, _ =
|
|
423
|
+
pretty, _ = cli_io.presentation_flags(args)
|
|
745
424
|
format_explicit: bool = getattr(args, '_format_explicit', False)
|
|
746
425
|
format_hint: str | None = getattr(args, 'source_format', None)
|
|
747
426
|
payload = cast(
|
|
748
427
|
JSONData | str,
|
|
749
|
-
|
|
428
|
+
cli_io.resolve_cli_payload(
|
|
750
429
|
args.source,
|
|
751
430
|
format_hint=format_hint,
|
|
752
431
|
format_explicit=format_explicit,
|
|
@@ -758,7 +437,7 @@ def validate_handler(
|
|
|
758
437
|
if target_path:
|
|
759
438
|
validated_data = result.get('data')
|
|
760
439
|
if validated_data is not None:
|
|
761
|
-
|
|
440
|
+
cli_io.write_json_output(
|
|
762
441
|
validated_data,
|
|
763
442
|
target_path,
|
|
764
443
|
success_message='Validation result saved to',
|
|
@@ -769,6 +448,6 @@ def validate_handler(
|
|
|
769
448
|
file=sys.stderr,
|
|
770
449
|
)
|
|
771
450
|
else:
|
|
772
|
-
|
|
451
|
+
cli_io.emit_json(result, pretty=pretty)
|
|
773
452
|
|
|
774
453
|
return 0
|