etlplus 0.14.0__py3-none-any.whl → 0.14.1__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/ops/__init__.py +8 -4
- etlplus/ops/run.py +133 -14
- {etlplus-0.14.0.dist-info → etlplus-0.14.1.dist-info}/METADATA +1 -1
- {etlplus-0.14.0.dist-info → etlplus-0.14.1.dist-info}/RECORD +8 -8
- {etlplus-0.14.0.dist-info → etlplus-0.14.1.dist-info}/WHEEL +0 -0
- {etlplus-0.14.0.dist-info → etlplus-0.14.1.dist-info}/entry_points.txt +0 -0
- {etlplus-0.14.0.dist-info → etlplus-0.14.1.dist-info}/licenses/LICENSE +0 -0
- {etlplus-0.14.0.dist-info → etlplus-0.14.1.dist-info}/top_level.txt +0 -0
etlplus/ops/__init__.py
CHANGED
|
@@ -4,10 +4,12 @@
|
|
|
4
4
|
Data operations helpers.
|
|
5
5
|
|
|
6
6
|
Importing :mod:`etlplus.ops` exposes the coarse-grained helpers most users care
|
|
7
|
-
about: ``extract``, ``transform``, ``load``, ``validate``,
|
|
8
|
-
helper delegates to the richer modules under
|
|
9
|
-
presenting a compact public API surface. Conditional
|
|
10
|
-
is available via
|
|
7
|
+
about: ``extract``, ``transform``, ``load``, ``validate``, ``run``, and
|
|
8
|
+
``run_pipeline``. Each helper delegates to the richer modules under
|
|
9
|
+
``etlplus.ops.*`` while presenting a compact public API surface. Conditional
|
|
10
|
+
validation orchestration is available via
|
|
11
|
+
:func:`etlplus.ops.utils.maybe_validate`. The legacy compatibility module
|
|
12
|
+
:mod:`etlplus.ops.__init__validation` is deprecated in favor of this package.
|
|
11
13
|
|
|
12
14
|
Examples
|
|
13
15
|
--------
|
|
@@ -42,6 +44,7 @@ See Also
|
|
|
42
44
|
from .extract import extract
|
|
43
45
|
from .load import load
|
|
44
46
|
from .run import run
|
|
47
|
+
from .run import run_pipeline
|
|
45
48
|
from .transform import transform
|
|
46
49
|
from .validate import validate
|
|
47
50
|
|
|
@@ -52,6 +55,7 @@ __all__ = [
|
|
|
52
55
|
'extract',
|
|
53
56
|
'load',
|
|
54
57
|
'run',
|
|
58
|
+
'run_pipeline',
|
|
55
59
|
'transform',
|
|
56
60
|
'validate',
|
|
57
61
|
]
|
etlplus/ops/run.py
CHANGED
|
@@ -21,7 +21,12 @@ from ..api import compose_api_target_env
|
|
|
21
21
|
from ..api import paginate_with_client
|
|
22
22
|
from ..config import load_pipeline_config
|
|
23
23
|
from ..enums import DataConnectorType
|
|
24
|
+
from ..enums import HttpMethod
|
|
25
|
+
from ..file import FileFormat
|
|
26
|
+
from ..types import JSONData
|
|
24
27
|
from ..types import JSONDict
|
|
28
|
+
from ..types import PipelineConfig
|
|
29
|
+
from ..types import StrPath
|
|
25
30
|
from ..types import Timeout
|
|
26
31
|
from ..utils import print_json
|
|
27
32
|
from .extract import extract
|
|
@@ -33,7 +38,11 @@ from .validate import validate
|
|
|
33
38
|
# SECTION: EXPORTS ========================================================== #
|
|
34
39
|
|
|
35
40
|
|
|
36
|
-
__all__ = [
|
|
41
|
+
__all__ = [
|
|
42
|
+
# Functions
|
|
43
|
+
'run',
|
|
44
|
+
'run_pipeline',
|
|
45
|
+
]
|
|
37
46
|
|
|
38
47
|
|
|
39
48
|
# SECTION: CONSTANTS ======================================================== #
|
|
@@ -42,6 +51,38 @@ __all__ = ['run']
|
|
|
42
51
|
DEFAULT_CONFIG_PATH: Final[str] = 'in/pipeline.yml'
|
|
43
52
|
|
|
44
53
|
|
|
54
|
+
# SECTION: INTERNAL FUNCTIONS =============================================== #
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
def _resolve_validation_config(
|
|
58
|
+
job_obj: Any,
|
|
59
|
+
cfg: Any,
|
|
60
|
+
) -> tuple[bool, dict[str, Any], str, str]:
|
|
61
|
+
"""
|
|
62
|
+
Resolve validation settings for a job with safe defaults.
|
|
63
|
+
|
|
64
|
+
Parameters
|
|
65
|
+
----------
|
|
66
|
+
job_obj : Any
|
|
67
|
+
Job configuration object.
|
|
68
|
+
cfg : Any
|
|
69
|
+
Pipeline configuration object with validations.
|
|
70
|
+
|
|
71
|
+
Returns
|
|
72
|
+
-------
|
|
73
|
+
tuple[bool, dict[str, Any], str, str]
|
|
74
|
+
Tuple of (enabled, rules, severity, phase).
|
|
75
|
+
"""
|
|
76
|
+
val_ref = job_obj.validate
|
|
77
|
+
if val_ref is None:
|
|
78
|
+
return False, {}, 'error', 'before_transform'
|
|
79
|
+
|
|
80
|
+
rules = cfg.validations.get(val_ref.ruleset, {})
|
|
81
|
+
severity = (val_ref.severity or 'error').lower()
|
|
82
|
+
phase = (val_ref.phase or 'before_transform').lower()
|
|
83
|
+
return True, rules, severity, phase
|
|
84
|
+
|
|
85
|
+
|
|
45
86
|
# SECTION: FUNCTIONS ======================================================== #
|
|
46
87
|
|
|
47
88
|
|
|
@@ -174,19 +215,10 @@ def run(
|
|
|
174
215
|
# keep explicit guard for defensive programming.
|
|
175
216
|
raise ValueError(f'Unsupported source type: {stype_raw}')
|
|
176
217
|
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
# Type narrowing for static checkers
|
|
182
|
-
assert val_ref is not None
|
|
183
|
-
rules = cfg.validations.get(val_ref.ruleset, {})
|
|
184
|
-
severity = (val_ref.severity or 'error').lower()
|
|
185
|
-
phase = (val_ref.phase or 'before_transform').lower()
|
|
186
|
-
else:
|
|
187
|
-
rules = {}
|
|
188
|
-
severity = 'error'
|
|
189
|
-
phase = 'before_transform'
|
|
218
|
+
enabled_validation, rules, severity, phase = _resolve_validation_config(
|
|
219
|
+
job_obj,
|
|
220
|
+
cfg,
|
|
221
|
+
)
|
|
190
222
|
|
|
191
223
|
# Pre-transform validation (if configured).
|
|
192
224
|
data = maybe_validate(
|
|
@@ -272,3 +304,90 @@ def run(
|
|
|
272
304
|
# Return the terminal load result directly; callers (e.g., CLI) can wrap
|
|
273
305
|
# it in their own envelope when needed.
|
|
274
306
|
return cast(JSONDict, result)
|
|
307
|
+
|
|
308
|
+
|
|
309
|
+
def run_pipeline(
|
|
310
|
+
*,
|
|
311
|
+
source_type: DataConnectorType | str | None = None,
|
|
312
|
+
source: StrPath | JSONData | None = None,
|
|
313
|
+
operations: PipelineConfig | None = None,
|
|
314
|
+
target_type: DataConnectorType | str | None = None,
|
|
315
|
+
target: StrPath | None = None,
|
|
316
|
+
file_format: FileFormat | str | None = None,
|
|
317
|
+
method: HttpMethod | str | None = None,
|
|
318
|
+
**kwargs: Any,
|
|
319
|
+
) -> JSONData:
|
|
320
|
+
"""
|
|
321
|
+
Run a single extract-transform-load flow without a YAML config.
|
|
322
|
+
|
|
323
|
+
Parameters
|
|
324
|
+
----------
|
|
325
|
+
source_type : DataConnectorType | str | None, optional
|
|
326
|
+
Connector type for extraction. When ``None``, ``source`` is assumed
|
|
327
|
+
to be pre-loaded data and extraction is skipped.
|
|
328
|
+
source : StrPath | JSONData | None, optional
|
|
329
|
+
Data source for extraction or the pre-loaded payload when
|
|
330
|
+
``source_type`` is ``None``.
|
|
331
|
+
operations : PipelineConfig | None, optional
|
|
332
|
+
Transform configuration passed to :func:`etlplus.ops.transform`.
|
|
333
|
+
target_type : DataConnectorType | str | None, optional
|
|
334
|
+
Connector type for loading. When ``None``, load is skipped and the
|
|
335
|
+
transformed data is returned.
|
|
336
|
+
target : StrPath | None, optional
|
|
337
|
+
Target for loading (file path, connection string, or API URL).
|
|
338
|
+
file_format : FileFormat | str | None, optional
|
|
339
|
+
File format for file sources/targets (forwarded to extract/load).
|
|
340
|
+
method : HttpMethod | str | None, optional
|
|
341
|
+
HTTP method for API loads (forwarded to :func:`etlplus.ops.load`).
|
|
342
|
+
**kwargs : Any
|
|
343
|
+
Extra keyword arguments forwarded to extract/load for API options
|
|
344
|
+
(headers, timeout, session, etc.).
|
|
345
|
+
|
|
346
|
+
Returns
|
|
347
|
+
-------
|
|
348
|
+
JSONData
|
|
349
|
+
Transformed data or the load result payload.
|
|
350
|
+
|
|
351
|
+
Raises
|
|
352
|
+
------
|
|
353
|
+
TypeError
|
|
354
|
+
Raised when extracted data is not a dict or list of dicts and no
|
|
355
|
+
target is specified.
|
|
356
|
+
ValueError
|
|
357
|
+
Raised when required source/target inputs are missing.
|
|
358
|
+
"""
|
|
359
|
+
if source_type is None:
|
|
360
|
+
if source is None:
|
|
361
|
+
raise ValueError('source or source_type is required')
|
|
362
|
+
data = source
|
|
363
|
+
else:
|
|
364
|
+
if source is None:
|
|
365
|
+
raise ValueError('source is required when source_type is set')
|
|
366
|
+
data = extract(
|
|
367
|
+
source_type,
|
|
368
|
+
cast(StrPath, source),
|
|
369
|
+
file_format=file_format,
|
|
370
|
+
**kwargs,
|
|
371
|
+
)
|
|
372
|
+
|
|
373
|
+
if operations:
|
|
374
|
+
data = transform(data, operations)
|
|
375
|
+
|
|
376
|
+
if target_type is None:
|
|
377
|
+
if not isinstance(data, (dict, list)):
|
|
378
|
+
raise TypeError(
|
|
379
|
+
f'Expected data to be dict or list of dicts, '
|
|
380
|
+
f'got {type(data).__name__}',
|
|
381
|
+
)
|
|
382
|
+
return data
|
|
383
|
+
if target is None:
|
|
384
|
+
raise ValueError('target is required when target_type is set')
|
|
385
|
+
|
|
386
|
+
return load(
|
|
387
|
+
data,
|
|
388
|
+
target_type,
|
|
389
|
+
target,
|
|
390
|
+
file_format=file_format,
|
|
391
|
+
method=method,
|
|
392
|
+
**kwargs,
|
|
393
|
+
)
|
|
@@ -115,10 +115,10 @@ etlplus/file/yaml.py,sha256=8BEqCELaTQ_nRu1iksLBHVj19P6JmcUf5__fe0yVigw,2449
|
|
|
115
115
|
etlplus/file/zip.py,sha256=nd26V3S0edklriKnKOGDTLlO8RBXTda_zLLEQrJgKL4,4185
|
|
116
116
|
etlplus/file/zsav.py,sha256=2WxjXamvzj0adDbWGMWM3-cj_LsCRjyZz4J907lNkPk,1664
|
|
117
117
|
etlplus/ops/README.md,sha256=8omi7DYZhelc26JKk8Cm8QR8I3OGwziysPj1ivx41iQ,1380
|
|
118
|
-
etlplus/ops/__init__.py,sha256=
|
|
118
|
+
etlplus/ops/__init__.py,sha256=NIIr2f-AZj5B0piBt6gjv46Yn0SzGYxEe6BPoopRh38,1702
|
|
119
119
|
etlplus/ops/extract.py,sha256=s3CaLXMY_loMoPU47rvvzyp1buk84uCzDqqaI7l3Dwg,5785
|
|
120
120
|
etlplus/ops/load.py,sha256=2jMewdjaNS1GKZ9cn94ISRSzDfqO3_s5fb_YNo_CqIc,8330
|
|
121
|
-
etlplus/ops/run.py,sha256=
|
|
121
|
+
etlplus/ops/run.py,sha256=nivgj3cY5QniNc-u4n71gr2p4wXXvt5fYQUHiOEfKUA,13395
|
|
122
122
|
etlplus/ops/transform.py,sha256=1P43WYUaw872JDU86FhbbbkP8xnBWpgEPn2Q-z4ywls,25421
|
|
123
123
|
etlplus/ops/utils.py,sha256=9cN-bmcYs87R84GllmW7fSiUEmXFqIkGbSFiPYStsbA,11198
|
|
124
124
|
etlplus/ops/validate.py,sha256=gLa5zcwhxGbaIhH-OqTwDsQAgAYZSajLVGwwyeT2OZk,13257
|
|
@@ -126,9 +126,9 @@ etlplus/templates/README.md,sha256=kHSZ8FWcrlrcWz0hBIbho-k1Bi-PL-DQ7g02o-g70c8,1
|
|
|
126
126
|
etlplus/templates/__init__.py,sha256=tsniN7XJYs3NwYxJ6c2HD5upHP3CDkLx-bQCMt97UOM,106
|
|
127
127
|
etlplus/templates/ddl.sql.j2,sha256=s8fMWvcb4eaJVXkifuib1aQPljtZ8buuyB_uA-ZdU3Q,4734
|
|
128
128
|
etlplus/templates/view.sql.j2,sha256=Iy8DHfhq5yyvrUKDxqp_aHIEXY4Tm6j4wT7YDEFWAhk,2180
|
|
129
|
-
etlplus-0.14.
|
|
130
|
-
etlplus-0.14.
|
|
131
|
-
etlplus-0.14.
|
|
132
|
-
etlplus-0.14.
|
|
133
|
-
etlplus-0.14.
|
|
134
|
-
etlplus-0.14.
|
|
129
|
+
etlplus-0.14.1.dist-info/licenses/LICENSE,sha256=MuNO63i6kWmgnV2pbP2SLqP54mk1BGmu7CmbtxMmT-U,1069
|
|
130
|
+
etlplus-0.14.1.dist-info/METADATA,sha256=hr3LS7VVswkiW_PnXQcHZFEElSZFrrgVxi5BhkKz5h8,28115
|
|
131
|
+
etlplus-0.14.1.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
132
|
+
etlplus-0.14.1.dist-info/entry_points.txt,sha256=6w-2-jzuPa55spzK34h-UKh2JTEShh38adFRONNP9QE,45
|
|
133
|
+
etlplus-0.14.1.dist-info/top_level.txt,sha256=aWWF-udn_sLGuHTM6W6MLh99ArS9ROkUWO8Mi8y1_2U,8
|
|
134
|
+
etlplus-0.14.1.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|