etlplus 0.15.0__py3-none-any.whl → 0.16.0__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 (118) hide show
  1. etlplus/README.md +3 -3
  2. etlplus/api/README.md +31 -0
  3. etlplus/api/auth.py +1 -1
  4. etlplus/api/config.py +5 -10
  5. etlplus/api/endpoint_client.py +4 -4
  6. etlplus/api/pagination/config.py +1 -1
  7. etlplus/api/pagination/paginator.py +6 -7
  8. etlplus/api/rate_limiting/config.py +4 -4
  9. etlplus/api/rate_limiting/rate_limiter.py +1 -1
  10. etlplus/api/retry_manager.py +2 -2
  11. etlplus/api/transport.py +1 -1
  12. etlplus/api/types.py +99 -0
  13. etlplus/api/utils.py +1 -1
  14. etlplus/cli/commands.py +75 -42
  15. etlplus/cli/constants.py +1 -1
  16. etlplus/cli/handlers.py +31 -13
  17. etlplus/cli/io.py +2 -2
  18. etlplus/cli/main.py +2 -2
  19. etlplus/cli/state.py +4 -7
  20. etlplus/connector/__init__.py +43 -0
  21. etlplus/connector/api.py +161 -0
  22. etlplus/connector/connector.py +26 -0
  23. etlplus/connector/core.py +132 -0
  24. etlplus/connector/database.py +122 -0
  25. etlplus/connector/enums.py +52 -0
  26. etlplus/connector/file.py +120 -0
  27. etlplus/connector/types.py +40 -0
  28. etlplus/connector/utils.py +122 -0
  29. etlplus/database/ddl.py +2 -2
  30. etlplus/database/engine.py +19 -3
  31. etlplus/database/orm.py +2 -0
  32. etlplus/enums.py +1 -33
  33. etlplus/file/_imports.py +1 -0
  34. etlplus/file/_io.py +52 -4
  35. etlplus/file/accdb.py +3 -2
  36. etlplus/file/arrow.py +3 -2
  37. etlplus/file/avro.py +3 -2
  38. etlplus/file/bson.py +3 -2
  39. etlplus/file/cbor.py +3 -2
  40. etlplus/file/cfg.py +3 -2
  41. etlplus/file/conf.py +3 -2
  42. etlplus/file/core.py +11 -8
  43. etlplus/file/csv.py +3 -2
  44. etlplus/file/dat.py +3 -2
  45. etlplus/file/dta.py +3 -2
  46. etlplus/file/duckdb.py +3 -2
  47. etlplus/file/enums.py +1 -1
  48. etlplus/file/feather.py +3 -2
  49. etlplus/file/fwf.py +3 -2
  50. etlplus/file/gz.py +3 -2
  51. etlplus/file/hbs.py +3 -2
  52. etlplus/file/hdf5.py +3 -2
  53. etlplus/file/ini.py +3 -2
  54. etlplus/file/ion.py +3 -2
  55. etlplus/file/jinja2.py +3 -2
  56. etlplus/file/json.py +5 -16
  57. etlplus/file/log.py +3 -2
  58. etlplus/file/mat.py +3 -2
  59. etlplus/file/mdb.py +3 -2
  60. etlplus/file/msgpack.py +3 -2
  61. etlplus/file/mustache.py +3 -2
  62. etlplus/file/nc.py +3 -2
  63. etlplus/file/ndjson.py +3 -2
  64. etlplus/file/numbers.py +3 -2
  65. etlplus/file/ods.py +3 -2
  66. etlplus/file/orc.py +3 -2
  67. etlplus/file/parquet.py +3 -2
  68. etlplus/file/pb.py +3 -2
  69. etlplus/file/pbf.py +3 -2
  70. etlplus/file/properties.py +3 -2
  71. etlplus/file/proto.py +3 -2
  72. etlplus/file/psv.py +3 -2
  73. etlplus/file/rda.py +3 -2
  74. etlplus/file/rds.py +3 -2
  75. etlplus/file/sas7bdat.py +3 -2
  76. etlplus/file/sav.py +3 -2
  77. etlplus/file/sqlite.py +3 -2
  78. etlplus/file/stub.py +1 -0
  79. etlplus/file/sylk.py +3 -2
  80. etlplus/file/tab.py +3 -2
  81. etlplus/file/toml.py +3 -2
  82. etlplus/file/tsv.py +3 -2
  83. etlplus/file/txt.py +4 -3
  84. etlplus/file/vm.py +3 -2
  85. etlplus/file/wks.py +3 -2
  86. etlplus/file/xls.py +3 -2
  87. etlplus/file/xlsm.py +3 -2
  88. etlplus/file/xlsx.py +3 -2
  89. etlplus/file/xml.py +9 -3
  90. etlplus/file/xpt.py +3 -2
  91. etlplus/file/yaml.py +5 -16
  92. etlplus/file/zip.py +3 -2
  93. etlplus/file/zsav.py +3 -2
  94. etlplus/ops/extract.py +13 -1
  95. etlplus/ops/load.py +15 -2
  96. etlplus/ops/run.py +4 -4
  97. etlplus/ops/transform.py +2 -2
  98. etlplus/ops/utils.py +6 -35
  99. etlplus/ops/validate.py +3 -3
  100. etlplus/types.py +3 -2
  101. etlplus/utils.py +163 -29
  102. etlplus/workflow/__init__.py +0 -11
  103. etlplus/workflow/jobs.py +84 -27
  104. etlplus/workflow/pipeline.py +48 -48
  105. {etlplus-0.15.0.dist-info → etlplus-0.16.0.dist-info}/METADATA +4 -4
  106. etlplus-0.16.0.dist-info/RECORD +141 -0
  107. {etlplus-0.15.0.dist-info → etlplus-0.16.0.dist-info}/WHEEL +1 -1
  108. etlplus/config/README.md +0 -50
  109. etlplus/config/__init__.py +0 -33
  110. etlplus/config/types.py +0 -140
  111. etlplus/dag.py +0 -103
  112. etlplus/workflow/connector.py +0 -373
  113. etlplus/workflow/types.py +0 -115
  114. etlplus/workflow/utils.py +0 -120
  115. etlplus-0.15.0.dist-info/RECORD +0 -139
  116. {etlplus-0.15.0.dist-info → etlplus-0.16.0.dist-info}/entry_points.txt +0 -0
  117. {etlplus-0.15.0.dist-info → etlplus-0.16.0.dist-info}/licenses/LICENSE +0 -0
  118. {etlplus-0.15.0.dist-info → etlplus-0.16.0.dist-info}/top_level.txt +0 -0
etlplus/workflow/jobs.py CHANGED
@@ -19,6 +19,7 @@ from dataclasses import field
19
19
  from typing import Any
20
20
  from typing import Self
21
21
 
22
+ from ..types import StrAnyMap
22
23
  from ..utils import coerce_dict
23
24
  from ..utils import maybe_mapping
24
25
 
@@ -35,6 +36,75 @@ __all__ = [
35
36
  ]
36
37
 
37
38
 
39
+ # SECTION: INTERNAL FUNCTIONS =============================================== #
40
+
41
+
42
+ def _coerce_optional_str(value: Any) -> str | None:
43
+ """
44
+ Normalize optional string values, coercing non-strings when needed.
45
+
46
+ Parameters
47
+ ----------
48
+ value : Any
49
+ Optional value to normalize.
50
+
51
+ Returns
52
+ -------
53
+ str | None
54
+ ``None`` when *value* is ``None``; otherwise a string value.
55
+ """
56
+ if value is None:
57
+ return None
58
+ return value if isinstance(value, str) else str(value)
59
+
60
+
61
+ def _parse_depends_on(
62
+ value: Any,
63
+ ) -> list[str]:
64
+ """
65
+ Normalize dependency declarations into a string list.
66
+
67
+ Parameters
68
+ ----------
69
+ value : Any
70
+ Input dependency specification (string or list of strings).
71
+
72
+ Returns
73
+ -------
74
+ list[str]
75
+ Normalized dependency list.
76
+ """
77
+ if isinstance(value, str):
78
+ return [value]
79
+ if isinstance(value, list):
80
+ return [entry for entry in value if isinstance(entry, str)]
81
+ return []
82
+
83
+
84
+ def _require_str(
85
+ # data: dict[str, Any],
86
+ data: StrAnyMap,
87
+ key: str,
88
+ ) -> str | None:
89
+ """
90
+ Extract a required string field from a mapping.
91
+
92
+ Parameters
93
+ ----------
94
+ data : StrAnyMap
95
+ Mapping containing the target field.
96
+ key : str
97
+ Field name to extract.
98
+
99
+ Returns
100
+ -------
101
+ str | None
102
+ The string value when present and valid; otherwise ``None``.
103
+ """
104
+ value = data.get(key)
105
+ return value if isinstance(value, str) else None
106
+
107
+
38
108
  # SECTION: DATA CLASSES ===================================================== #
39
109
 
40
110
 
@@ -79,8 +149,8 @@ class ExtractRef:
79
149
  data = maybe_mapping(obj)
80
150
  if not data:
81
151
  return None
82
- source = data.get('source')
83
- if not isinstance(source, str):
152
+ source = _require_str(data, 'source')
153
+ if source is None:
84
154
  return None
85
155
  return cls(
86
156
  source=source,
@@ -144,22 +214,13 @@ class JobConfig:
144
214
  data = maybe_mapping(obj)
145
215
  if not data:
146
216
  return None
147
- name = data.get('name')
148
- if not isinstance(name, str):
217
+ name = _require_str(data, 'name')
218
+ if name is None:
149
219
  return None
150
220
 
151
- description = data.get('description')
152
- if description is not None and not isinstance(description, str):
153
- description = str(description)
221
+ description = _coerce_optional_str(data.get('description'))
154
222
 
155
- depends_raw = data.get('depends_on')
156
- depends_on: list[str] = []
157
- if isinstance(depends_raw, str):
158
- depends_on = [depends_raw]
159
- elif isinstance(depends_raw, list):
160
- for entry in depends_raw:
161
- if isinstance(entry, str):
162
- depends_on.append(entry)
223
+ depends_on = _parse_depends_on(data.get('depends_on'))
163
224
 
164
225
  return cls(
165
226
  name=name,
@@ -213,8 +274,8 @@ class LoadRef:
213
274
  data = maybe_mapping(obj)
214
275
  if not data:
215
276
  return None
216
- target = data.get('target')
217
- if not isinstance(target, str):
277
+ target = _require_str(data, 'target')
278
+ if target is None:
218
279
  return None
219
280
  return cls(
220
281
  target=target,
@@ -260,8 +321,8 @@ class TransformRef:
260
321
  data = maybe_mapping(obj)
261
322
  if not data:
262
323
  return None
263
- pipeline = data.get('pipeline')
264
- if not isinstance(pipeline, str):
324
+ pipeline = _require_str(data, 'pipeline')
325
+ if pipeline is None:
265
326
  return None
266
327
  return cls(pipeline=pipeline)
267
328
 
@@ -311,15 +372,11 @@ class ValidationRef:
311
372
  data = maybe_mapping(obj)
312
373
  if not data:
313
374
  return None
314
- ruleset = data.get('ruleset')
315
- if not isinstance(ruleset, str):
375
+ ruleset = _require_str(data, 'ruleset')
376
+ if ruleset is None:
316
377
  return None
317
- severity = data.get('severity')
318
- if severity is not None and not isinstance(severity, str):
319
- severity = str(severity)
320
- phase = data.get('phase')
321
- if phase is not None and not isinstance(phase, str):
322
- phase = str(phase)
378
+ severity = _coerce_optional_str(data.get('severity'))
379
+ phase = _coerce_optional_str(data.get('phase'))
323
380
  return cls(
324
381
  ruleset=ruleset,
325
382
  severity=severity,
@@ -16,6 +16,7 @@ Notes
16
16
  from __future__ import annotations
17
17
 
18
18
  import os
19
+ from collections.abc import Callable
19
20
  from collections.abc import Mapping
20
21
  from dataclasses import dataclass
21
22
  from dataclasses import field
@@ -24,16 +25,16 @@ from typing import Any
24
25
  from typing import Self
25
26
 
26
27
  from ..api import ApiConfig
28
+ from ..connector import Connector
29
+ from ..connector import parse_connector
27
30
  from ..file import File
28
31
  from ..file import FileFormat
29
32
  from ..types import StrAnyMap
30
33
  from ..utils import coerce_dict
34
+ from ..utils import deep_substitute
31
35
  from ..utils import maybe_mapping
32
- from .connector import Connector
33
- from .connector import parse_connector
34
36
  from .jobs import JobConfig
35
37
  from .profile import ProfileConfig
36
- from .utils import deep_substitute
37
38
 
38
39
  # SECTION: EXPORTS ========================================================== #
39
40
 
@@ -49,55 +50,65 @@ __all__ = [
49
50
  # SECTION: INTERNAL FUNCTIONS =============================================== #
50
51
 
51
52
 
52
- def _build_jobs(
53
+ def _collect_parsed[T](
53
54
  raw: StrAnyMap,
54
- ) -> list[JobConfig]:
55
+ key: str,
56
+ parser: Callable[[Any], T | None],
57
+ ) -> list[T]:
55
58
  """
56
- Return a list of ``JobConfig`` objects parsed from the mapping.
59
+ Collect parsed items from ``raw[key]`` using a tolerant parser.
57
60
 
58
61
  Parameters
59
62
  ----------
60
63
  raw : StrAnyMap
61
64
  Raw pipeline mapping.
65
+ key : str
66
+ Key pointing to a list-like payload.
67
+ parser : Callable[[Any], T | None]
68
+ Parser that returns an instance or ``None`` for invalid entries.
62
69
 
63
70
  Returns
64
71
  -------
65
- list[JobConfig]
66
- Parsed job configurations.
72
+ list[T]
73
+ Parsed items, excluding invalid entries.
67
74
  """
68
- jobs: list[JobConfig] = []
69
- for job_raw in raw.get('jobs', []) or []:
70
- job_cfg = JobConfig.from_obj(job_raw)
71
- if job_cfg is not None:
72
- jobs.append(job_cfg)
73
-
74
- return jobs
75
+ items: list[T] = []
76
+ for entry in raw.get(key, []) or []:
77
+ parsed = parser(entry)
78
+ if parsed is not None:
79
+ items.append(parsed)
80
+ return items
75
81
 
76
82
 
77
- def _build_sources(
78
- raw: StrAnyMap,
79
- ) -> list[Connector]:
83
+ def _parse_connector_entry(
84
+ obj: Any,
85
+ ) -> Connector | None:
80
86
  """
81
- Return a list of source connectors parsed from the mapping.
87
+ Parse a connector mapping into a concrete connector instance.
82
88
 
83
89
  Parameters
84
90
  ----------
85
- raw : StrAnyMap
86
- Raw pipeline mapping.
91
+ obj : Any
92
+ Candidate connector mapping.
87
93
 
88
94
  Returns
89
95
  -------
90
- list[Connector]
91
- Parsed source connectors.
96
+ Connector | None
97
+ Parsed connector instance or ``None`` when invalid.
92
98
  """
93
- return _build_connectors(raw, 'sources')
99
+ if not (entry := maybe_mapping(obj)):
100
+ return None
101
+ try:
102
+ return parse_connector(entry)
103
+ except TypeError:
104
+ return None
94
105
 
95
106
 
96
- def _build_targets(
107
+ def _build_sources(
97
108
  raw: StrAnyMap,
98
109
  ) -> list[Connector]:
99
110
  """
100
- Return a list of target connectors parsed from the mapping.
111
+ Return a list of source connectors parsed from the mapping.
101
112
 
102
113
  Parameters
103
114
  ----------
@@ -107,43 +118,32 @@ def _build_targets(
107
118
  Returns
108
119
  -------
109
120
  list[Connector]
110
- Parsed target connectors.
121
+ Parsed source connectors.
111
122
  """
112
- return _build_connectors(raw, 'targets')
123
+ return list(
124
+ _collect_parsed(raw, 'sources', _parse_connector_entry),
125
+ )
113
126
 
114
127
 
115
- def _build_connectors(
128
+ def _build_targets(
116
129
  raw: StrAnyMap,
117
- key: str,
118
130
  ) -> list[Connector]:
119
131
  """
120
- Return parsed connectors from ``raw[key]`` using tolerant parsing.
121
-
122
- Unknown or malformed entries are skipped to preserve permissiveness.
132
+ Return a list of target connectors parsed from the mapping.
123
133
 
124
134
  Parameters
125
135
  ----------
126
136
  raw : StrAnyMap
127
137
  Raw pipeline mapping.
128
- key : str
129
- List-containing top-level key ("sources" or "targets").
130
138
 
131
139
  Returns
132
140
  -------
133
141
  list[Connector]
134
- Constructed connector instances (malformed entries skipped).
142
+ Parsed target connectors.
135
143
  """
136
- items: list[Connector] = []
137
- for obj in raw.get(key, []) or []:
138
- if not (entry := maybe_mapping(obj)):
139
- continue
140
- try:
141
- items.append(parse_connector(entry))
142
- except TypeError:
143
- # Skip unsupported types or malformed entries
144
- continue
145
-
146
- return items
144
+ return list(
145
+ _collect_parsed(raw, 'targets', _parse_connector_entry),
146
+ )
147
147
 
148
148
 
149
149
  # SECTION: FUNCTIONS ======================================================== #
@@ -321,7 +321,7 @@ class PipelineConfig:
321
321
  targets = _build_targets(raw)
322
322
 
323
323
  # Jobs
324
- jobs = _build_jobs(raw)
324
+ jobs = _collect_parsed(raw, 'jobs', JobConfig.from_obj)
325
325
 
326
326
  # Table schemas (optional, tolerant pass-through structures).
327
327
  table_schemas: list[dict[str, Any]] = []
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: etlplus
3
- Version: 0.15.0
3
+ Version: 0.16.0
4
4
  Summary: A Swiss Army knife for simple ETL operations
5
5
  Home-page: https://github.com/Dagitali/ETLPlus
6
6
  Author: ETLPlus Team
@@ -805,12 +805,12 @@ Navigate to detailed documentation for each subpackage:
805
805
 
806
806
  - [etlplus.api](etlplus/api/README.md): Lightweight HTTP client and paginated REST helpers
807
807
  - [etlplus.file](etlplus/file/README.md): Unified file format support and helpers
808
- - [etlplus.config](etlplus/config/README.md): Configuration helpers for connectors, pipelines, jobs,
809
- and profiles
810
- - [etlplus.cli](etlplus/cli/README.md): Command-line interface for ETLPlus workflows
808
+ - [etlplus.cli](etlplus/cli/README.md): Command-line interface definitions for `etlplus`
811
809
  - [etlplus.database](etlplus/database/README.md): Database engine, schema, and ORM helpers
812
810
  - [etlplus.templates](etlplus/templates/README.md): SQL and DDL template helpers
813
811
  - [etlplus.validation](etlplus/validation/README.md): Data validation utilities and helpers
812
+ - [etlplus.workflow](etlplus/workflow/README.md): Helpers for data connectors, pipelines, jobs, and
813
+ profiles
814
814
 
815
815
  ### Community Health
816
816
 
@@ -0,0 +1,141 @@
1
+ etlplus/README.md,sha256=JaMSomnMsHrTruDnonHqe83Rv4K0-e7Wy46tMeVoleU,1468
2
+ etlplus/__init__.py,sha256=mgTP4PJmRmsEjTCAizzzdtzAmhuHtarmPzphzdjvLgM,277
3
+ etlplus/__main__.py,sha256=btoROneNiigyfBU7BSzPKZ1R9gzBMpxcpsbPwmuHwTM,479
4
+ etlplus/__version__.py,sha256=1E0GMK_yUWCMQFKxXjTvyMwofi0qT2k4CDNiHWiymWE,327
5
+ etlplus/enums.py,sha256=8-uUOKe68cPzlmUg-e7gavkC95kbTJXRpRzvXehIsRk,6841
6
+ etlplus/mixins.py,sha256=ifGpHwWv7U00yqGf-kN93vJax2IiK4jaGtTsPsO3Oak,1350
7
+ etlplus/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
8
+ etlplus/types.py,sha256=vB1Sh_5771eVv8-RClJatBQ7PcsScY6C2MvJqnI8IG8,6216
9
+ etlplus/utils.py,sha256=X-k_Y8i6oDjlE5aQu9sw3gPw7O2ikiSn4uoheVv_ERc,17091
10
+ etlplus/api/README.md,sha256=amxS_eIcsnNuVvD0x_w8nkyfedOTYbhlY0gGhaFg0DE,8705
11
+ etlplus/api/__init__.py,sha256=PK2lQv1FbsE7ZZS_ejevFZQSuOUHGApBc22YfHAzMqA,4615
12
+ etlplus/api/auth.py,sha256=wgNC9WDrb-5QjI81q5jl7pQHwNNHq7lVUF7uWw2jRP0,12154
13
+ etlplus/api/config.py,sha256=0Exfn208ijFep3gdww2KdqPxO4NKA4FG_rcn5x5dHM4,17635
14
+ etlplus/api/endpoint_client.py,sha256=Nekx-8mpU41EtbOyOcW4mjmch1jyPqtHu60_rfxF0Pw,30697
15
+ etlplus/api/enums.py,sha256=Tvkru6V8fzQh2JM2FDLcA_yaPENOKz5JgzxLhieqEvc,1141
16
+ etlplus/api/errors.py,sha256=XjI2xW-sypMUNUbqfc2S57-IGyWnH3oCDFhCmKYYI_Q,4648
17
+ etlplus/api/request_manager.py,sha256=fhzPV5x7DqpKqoLvfDR8GKhBX_QBMtvZsRXxVnQQElY,18674
18
+ etlplus/api/retry_manager.py,sha256=aq9iNCxt-Puy4rAgKNtNucxw2eP1yqAKZ2lfgMkzbCk,11302
19
+ etlplus/api/transport.py,sha256=abm-_WieBDSSbFanBwhmudBuVVm7LjYUb8vrlMXo7SA,9408
20
+ etlplus/api/types.py,sha256=Ng1b83RaJSHn4jl-M1f1dsTgjXizQtrW4yOXAYjwk_4,7377
21
+ etlplus/api/utils.py,sha256=lNBfJKz3fJ4RhvnnX3uxVZC__6-WKksYMSGGYi0RRqM,26247
22
+ etlplus/api/pagination/__init__.py,sha256=a4UX2J0AG8RMvmHt_CCofUm5vSmFo6GAfkb8XnSXypM,1395
23
+ etlplus/api/pagination/client.py,sha256=yMEpWqRxTCD4zRc9OYtEyUtShpGH5atiHFEAt95v2FE,5394
24
+ etlplus/api/pagination/config.py,sha256=u2hk8QmiQoIKe16sPUB6SvVqiLkuq9lUaY4Pl5-lejk,13577
25
+ etlplus/api/pagination/paginator.py,sha256=B0OK_0FVmUz3-lCDeKgDOqYJOoEQtjO6I5eSmK58tbY,24433
26
+ etlplus/api/rate_limiting/__init__.py,sha256=ZySB1dZettEDnWvI1EHf_TZ9L08M_kKsNR-Y_lbU6kI,1070
27
+ etlplus/api/rate_limiting/config.py,sha256=Byc_kmnwFmjjfDEFIdc_sHc7Wnjde1NGgsjPHgE9_xo,9765
28
+ etlplus/api/rate_limiting/rate_limiter.py,sha256=uYxn-l2qwLUKVclDQ3vJIIP3fozJx2JlHhz7_zyXVbA,7033
29
+ etlplus/cli/README.md,sha256=8H_G2d3HteYIU6ReX9K9DM485QjWDT5vHMQbGD_vv20,1237
30
+ etlplus/cli/__init__.py,sha256=J97-Rv931IL1_b4AXnB7Fbbd7HKnHBpx18NQfC_kE6c,299
31
+ etlplus/cli/commands.py,sha256=HFlg29tO6Jwv1NXWAHmvniLCyRSlboL55Arn9B8nZAM,25028
32
+ etlplus/cli/constants.py,sha256=0F7dXIQKWUhhVu2Us527GJeknJIWpBqz7CK2e5OQgcE,1947
33
+ etlplus/cli/handlers.py,sha256=uvbAyF6Ux8_5C-obCWZOrOP0QP0oiT-Km1hPhE8tDx0,18558
34
+ etlplus/cli/io.py,sha256=tGGNQ4ecezqj-mD285fgBVrYdphdeqApsyV9VojOj1I,7836
35
+ etlplus/cli/main.py,sha256=68_uJwmWajhOC9o4R_ns8IQloC9BFmAKC_9GlQOxKWg,5239
36
+ etlplus/cli/options.py,sha256=vfXT3YLh7wG1iC-aTdSg6ItMC8l6n0Lozmy53XjqLbA,1199
37
+ etlplus/cli/state.py,sha256=3Dq5BKct0uAvRajtc2yHbsX7wqepZOwlAMKsyvQcnqk,7918
38
+ etlplus/cli/types.py,sha256=tclhKVJXDqHzlTQBYKARfqMgDOcuBJ-Zej2pvFy96WM,652
39
+ etlplus/connector/__init__.py,sha256=KMBUPBFU1xA4aVkA2RxrdZ3IR6yWHr-F86GYK05wyKg,1006
40
+ etlplus/connector/api.py,sha256=vkeoqR94cVtEW4uKeVzuXKji08ojzd0fyqhtLSQ0V1k,4524
41
+ etlplus/connector/connector.py,sha256=OQP4kK_1O6g9FnDBrE3L58LOSfImsK5EBHtKI4N71u8,574
42
+ etlplus/connector/core.py,sha256=0GeXjlZFnyS-4j7jR_AtclQtELE6x-vodHJ4rfjFLL8,2795
43
+ etlplus/connector/database.py,sha256=fK_b4r5NsFTTUv0GHoEen7sVX45wVy1JLKds0qxfVM8,3011
44
+ etlplus/connector/enums.py,sha256=43NziUOpol4YvBtM13WJJzY1EAQOjaWESxLl7J2ZT8U,1069
45
+ etlplus/connector/file.py,sha256=c8zBKRYnrXXqLZRpB_FRBMFlel5BU6GFEDFdfX6uk9c,2855
46
+ etlplus/connector/types.py,sha256=j8eet-a701VC6VQa1pIYLt4HdDcQp8druXtOCb7UMLw,945
47
+ etlplus/connector/utils.py,sha256=fS2hPAfuhKTg_L2xDxF5fJnsO1SuuDIiEWU7GuaJKUM,2933
48
+ etlplus/database/README.md,sha256=3Af5BEGLkBmMoGOLtS1GQuj4wKPh_CwSp5NEPMf2uaY,1435
49
+ etlplus/database/__init__.py,sha256=AKJsDl2RHuRGPS-eXgNJeh4aSncJP5Y0yLApBF6i7i8,1052
50
+ etlplus/database/ddl.py,sha256=-7EAbyLkU8m3eYlHSNLFOQr1I4fPEbF0hTyByzjyvsU,7909
51
+ etlplus/database/engine.py,sha256=eDFnp4vzhoKuyLJSeHYpndHLUr27neS7CgdvMw8mNok,4384
52
+ etlplus/database/orm.py,sha256=ZCHkeVEUns2eievlFzmLyVKA3YVPea1xs6vrcUBZ7Jw,10010
53
+ etlplus/database/schema.py,sha256=813C0Dd3WE53KTYot4dgjAxctgKXLXx-8_Rk_4r2e28,7022
54
+ etlplus/database/types.py,sha256=_pkQyC14TzAlgyeIqZG4F5LWYknZbHw3TW68Auk7Ya0,795
55
+ etlplus/file/README.md,sha256=ivU8svVs1fktQiW5ozvh1N-IOSLCAQ3oM9bW8DUFwIw,3630
56
+ etlplus/file/__init__.py,sha256=X03bosSM-uSd6dh3ur0un6_ozFRw2Tm4PE6kVUjtXK8,475
57
+ etlplus/file/_imports.py,sha256=Cozv7d5G2P9PNgy2M4vrz0Wzo7hx9FTC0WcGcuVqga0,3193
58
+ etlplus/file/_io.py,sha256=Z3aTujy0rpbMKJHvO2UZ6bA1ohO-6ZiemyxF4GsayRc,3951
59
+ etlplus/file/accdb.py,sha256=mMwnNXd3rB0Z_1uN6wpiF0jL4flUmZbMBoiIS3Fq5mg,1691
60
+ etlplus/file/arrow.py,sha256=nkSXiDCFOSbEJX387h-c91WeYPFZehj2r3_iznVy5HE,1704
61
+ etlplus/file/avro.py,sha256=GR9GbDNcQ7TpaPKhcC6JL79XicSmNDIhH3cP0QDmLJg,4447
62
+ etlplus/file/bson.py,sha256=CYpA1PSPzyM9Dtv5ik3RG0GUwLjucJGbrhyo7THcVa0,1623
63
+ etlplus/file/cbor.py,sha256=NNQkCRenh9YOYdeR-w-AbUfK9sjGkwoA0Idtr-dclm4,1677
64
+ etlplus/file/cfg.py,sha256=HuGuxNIKPWyg14mIBlVB5Ch_npf9zObRt2mgoymzB_A,1720
65
+ etlplus/file/conf.py,sha256=x6OH9in-VKkTIPtlwbYEsYDJ703oFJjUFHVCoFULhvk,1778
66
+ etlplus/file/core.py,sha256=IzcG4pQLq3QCQhswbgdWKxHSvmzvWzYweBrz7t6HDDo,8888
67
+ etlplus/file/csv.py,sha256=FTdxlVs3vsaj_t7vGY-unNiCpJI2TWuiaf2_8dJan6M,1754
68
+ etlplus/file/dat.py,sha256=o4FN-6_HCVXuD-If3aYfIqU4QTZMvECNZ5Yx4wr15ew,1652
69
+ etlplus/file/dta.py,sha256=7DuvvKSgbpBoKZHm7CWJ7NKstRasp0fUEj1XF02YgsE,1626
70
+ etlplus/file/duckdb.py,sha256=kCFxNUEI9gEeeMWJuCHyfKVsqvhij4Q7LJVpZ3AMDYw,1641
71
+ etlplus/file/enums.py,sha256=5cwIfcoYGEjaX0AzaJzY0PjztKykzFTQ1HBnb2NTEXs,11065
72
+ etlplus/file/feather.py,sha256=joOdQf_oIu__i8hwy5X4eK6MSqh6O0kKnub2VWD_Clg,2679
73
+ etlplus/file/fwf.py,sha256=ktXIKatOPUs6YeB30K7BNvfwwB4BkXoYEomsvCjk_ss,1599
74
+ etlplus/file/gz.py,sha256=NfiXiE37rS2YC7dk1YC1ELbbEpzJdypIy-no9cVoaco,2641
75
+ etlplus/file/hbs.py,sha256=jxAPY10R_2vhP-1QWGBmANCI1dJ9vetaLo5Mp8kMa3Y,1624
76
+ etlplus/file/hdf5.py,sha256=hjpBUue5ss6R8ljZ-gYxDxpOLGBKgNvmAvn97uNmYAw,1634
77
+ etlplus/file/ini.py,sha256=ZL_0Wq5-yNcveyKF-minH2AFh-RmspM06myHquAobao,1711
78
+ etlplus/file/ion.py,sha256=ZK0g-47GQi9fCDT4EeXCgiVbWmmj7SU1WHwt-CrLwCU,1720
79
+ etlplus/file/jinja2.py,sha256=TV-ZIzsJIg4hJyvWI7TWaMRjqL2s18Dg3ig3Hs50_pE,1640
80
+ etlplus/file/json.py,sha256=vY3UYjzQzmJUAY0avR2cm70hTTED4xEF38WEEj0DhDQ,2140
81
+ etlplus/file/log.py,sha256=6Te617oy8RWrzCa6hC0O65ygPIpfzkLBcP-x9glwM9g,1691
82
+ etlplus/file/mat.py,sha256=JbZ7SziCqYZR8LljyLoSn05_-bPSzNH16KNB-wvzdpM,1664
83
+ etlplus/file/mdb.py,sha256=Xlxx9RZlnErOrzYRFnzzOZltc99FalhoUY-oAiiQpPg,1667
84
+ etlplus/file/msgpack.py,sha256=GOYfgxyK2N8Opy8kLsz4uDhVrT1vyOcVQ4eJvdhrNdA,1668
85
+ etlplus/file/mustache.py,sha256=qOddtbtZwDyoXzHzqxpnUoO_lWKf3NPyfp-V21o0cRw,1657
86
+ etlplus/file/nc.py,sha256=a1_er7Fco0FVw3GtDrd_OzZAI7U_sP9x-wi9qRgebaw,1680
87
+ etlplus/file/ndjson.py,sha256=jpZgLZL-Vy4a6tsm5cxy0G9kW-x-X5kFSbnUn-XjIJw,2442
88
+ etlplus/file/numbers.py,sha256=HkG3ISk35FZnorwECuciIiI4HZWFp9E-mRhOfhYclx8,1620
89
+ etlplus/file/ods.py,sha256=MVEM1E2uLFmnTyCnyhljsrgdBC8psUGSVUGLmiuZTLM,1810
90
+ etlplus/file/orc.py,sha256=RdK4IERoLWnGSgpBclfDmwMmtac8VYyet3Z9AFCyj2E,2612
91
+ etlplus/file/parquet.py,sha256=6klk-GgNnFBbsRU0J8LiGm5c67A6FcX1AEZNf-cNSPM,2768
92
+ etlplus/file/pb.py,sha256=0OOSmuFUfmB-DZILSA9FO2JgXfJmt9TnigH3E2gW4AI,1625
93
+ etlplus/file/pbf.py,sha256=89fF58WkXmOBJh8Jh2zcA0cKBkB5neXMWyz95toPnXo,1630
94
+ etlplus/file/properties.py,sha256=4KSRGWo_-fthVdOnJKXqUvHA2I6igcGWW9fnWJK7oLA,1728
95
+ etlplus/file/proto.py,sha256=LjHFWVYEIyADwpd9Lzzd1FAcM8pFXN1pwoptxEDOvfQ,1678
96
+ etlplus/file/psv.py,sha256=J-fPTMgTZFHZWJL6kLKaFgLXhtEtK66hJW59YLaWe9E,1736
97
+ etlplus/file/rda.py,sha256=dSrHwLl_qu8bhnltWIuYqxpguP3JLH39JLOVxHsHLhE,1678
98
+ etlplus/file/rds.py,sha256=o1IKY6CmLXSp-Iv7kBDFkT8X5QVTy5uVAZMm-7sUo4Y,1635
99
+ etlplus/file/sas7bdat.py,sha256=yyX7YrnmZ91EY9WeTB_eZAqjCSEgD_9WTLGpD4Sv5AY,1716
100
+ etlplus/file/sav.py,sha256=ij02gnYOevRV9e8dbDwi3plulkw-qEQoxccvydHXZK4,1607
101
+ etlplus/file/sqlite.py,sha256=NRb93RuIDlu1eRMZnYDjDBhFO88gkDT7tvpmfgA4hQE,1662
102
+ etlplus/file/stub.py,sha256=4vlqjIo_bBy69dIU2y2iy5fqnezt_bOuS218zyijQfs,1749
103
+ etlplus/file/sylk.py,sha256=QwciGJVWxEKz3TH4s7hshHHLAfKiCqBxyV4umg9EVQI,1667
104
+ etlplus/file/tab.py,sha256=Y9u5J-efoKIMIYnARhrPXA2KEF0pJ7deZF4zkz7ZID0,1994
105
+ etlplus/file/toml.py,sha256=0kGJEF2353kNQWFbYd8G4XWjuPHvdl7vPILCWglsyk0,1636
106
+ etlplus/file/tsv.py,sha256=SUe-UeL3zExX2idvpHiMWuRm5VQ8AyqqlNJckc9CDCU,1776
107
+ etlplus/file/txt.py,sha256=Ys7MmKBOiHQnRK0Bb3VuIIny2_1Ejr-V_YdPlUfOEjc,2321
108
+ etlplus/file/vm.py,sha256=K3EE-4TpXECcHxS1EEVmLOidkqj-MJeeztTRTRUaQ1o,1599
109
+ etlplus/file/wks.py,sha256=dZtf_6ObJVUj_m7XIUAzuTDQkmYk0mhA9LF3rVltatI,1665
110
+ etlplus/file/xls.py,sha256=dNfhaDSbSy-xQrE3qriCrmfXRQY7HqAtog91b-7RmpA,1782
111
+ etlplus/file/xlsm.py,sha256=pZHybknmipUHEwjQBHWiU4HfVMLkGG7Zxe3rxBrxPT0,1748
112
+ etlplus/file/xlsx.py,sha256=UOwz-IIeRU2GyAI8Upx2hn7v3KPZalpIaGO9hXuaOGo,2192
113
+ etlplus/file/xml.py,sha256=lor8KsclDSy1tdOExL1GmYpaQVcZGRNEwOd2liiPPbk,4389
114
+ etlplus/file/xpt.py,sha256=L70o8cIGWPeBdbfVJk-b9I9PE2MICtLkwhJjzqIeBgU,1712
115
+ etlplus/file/yaml.py,sha256=b_SxDSEQPVXQv9a9Ih4wAcI940pE5Ksy5pQE6K6ckhw,2062
116
+ etlplus/file/zip.py,sha256=8wnmnGW_pGTx65736CzAG67XIi5y98KxucRT8sNDeuQ,4195
117
+ etlplus/file/zsav.py,sha256=5hMuBjYeHw--UL2ZCCDn6TzJkr_YNhdQhvKI6nr3WW0,1674
118
+ etlplus/ops/README.md,sha256=8omi7DYZhelc26JKk8Cm8QR8I3OGwziysPj1ivx41iQ,1380
119
+ etlplus/ops/__init__.py,sha256=NIIr2f-AZj5B0piBt6gjv46Yn0SzGYxEe6BPoopRh38,1702
120
+ etlplus/ops/extract.py,sha256=xNHcKdx8LrnvIMWUFG-SmszpAlclz2jhvKFfX-sFGLI,5994
121
+ etlplus/ops/load.py,sha256=sxADrZ0CE4NfJ7T4Chwa6ckTkK3gSjYRdJW4qL-B61k,8536
122
+ etlplus/ops/run.py,sha256=x7bYrokpBE4XRfl6Rq7xeD3s-5A9P4HUVlufj_PxoTw,13526
123
+ etlplus/ops/transform.py,sha256=H9DxAA-c9kwklAnmiZK21w7FMJnHfu0bLcguXfIGE-k,25417
124
+ etlplus/ops/utils.py,sha256=lJmrO1KDob-xZU8Gc2SvZvMgdYLsVoaz-fTV42KkLVo,10835
125
+ etlplus/ops/validate.py,sha256=-OLAwQNNCmmDbmj0SB7zzYXDkJfcyBP_z9nTpqImLP0,13271
126
+ etlplus/templates/README.md,sha256=IfPXlj1TGVA-uFWosHJhE2rabFW-znxOlOMazO9Z5cE,1361
127
+ etlplus/templates/__init__.py,sha256=tsniN7XJYs3NwYxJ6c2HD5upHP3CDkLx-bQCMt97UOM,106
128
+ etlplus/templates/ddl.sql.j2,sha256=s8fMWvcb4eaJVXkifuib1aQPljtZ8buuyB_uA-ZdU3Q,4734
129
+ etlplus/templates/view.sql.j2,sha256=Iy8DHfhq5yyvrUKDxqp_aHIEXY4Tm6j4wT7YDEFWAhk,2180
130
+ etlplus/workflow/README.md,sha256=D1oloiJCOHiqpqgv3m3qpRSIUOMIQcWtIsOPv7KkNI0,1652
131
+ etlplus/workflow/__init__.py,sha256=PWWAv4Bb94hls8YDZXU5DY5aXMbtSYOLYHqGRThxoA4,668
132
+ etlplus/workflow/dag.py,sha256=kp31dORgk0GHbct_bipU5hu_0elwBtwLsXGjMWuhFHI,2503
133
+ etlplus/workflow/jobs.py,sha256=onvzsZpTpZUWIivIGR4SjbUPSZ1X0nXpxAW0O0VumhQ,8945
134
+ etlplus/workflow/pipeline.py,sha256=7bGvMywBu_H6XLsYjeNBS_NmVH7Bo7BmuzkWm-BAXMI,9633
135
+ etlplus/workflow/profile.py,sha256=dZ6P50k_ZqXnrbgrbODUqgVkymbchcEqfZR-ExjTd3M,1935
136
+ etlplus-0.16.0.dist-info/licenses/LICENSE,sha256=MuNO63i6kWmgnV2pbP2SLqP54mk1BGmu7CmbtxMmT-U,1069
137
+ etlplus-0.16.0.dist-info/METADATA,sha256=soyAK0MDUoH-U0-WQt40XS6zH8L8Q5dywyHtEO3cUGo,28114
138
+ etlplus-0.16.0.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
139
+ etlplus-0.16.0.dist-info/entry_points.txt,sha256=6w-2-jzuPa55spzK34h-UKh2JTEShh38adFRONNP9QE,45
140
+ etlplus-0.16.0.dist-info/top_level.txt,sha256=aWWF-udn_sLGuHTM6W6MLh99ArS9ROkUWO8Mi8y1_2U,8
141
+ etlplus-0.16.0.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (80.10.1)
2
+ Generator: setuptools (80.10.2)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5
 
etlplus/config/README.md DELETED
@@ -1,50 +0,0 @@
1
- # `etlplus.config` Subpackage
2
-
3
- Documentation for the `etlplus.config` subpackage: type definitions and config shape helpers for
4
- ETLPlus.
5
-
6
- - Exposes TypedDict-based config schemas for API profiles and endpoints
7
- - Provides exported type aliases for API configuration maps
8
- - Designed for Python 3.13 typing and editor assistance (runtime parsing lives elsewhere)
9
-
10
- Back to project overview: see the top-level [README](../../README.md).
11
-
12
- - [`etlplus.config` Subpackage](#etlplusconfig-subpackage)
13
- - [Modules](#modules)
14
- - [Exported Types](#exported-types)
15
- - [Example: Typing an API Config](#example-typing-an-api-config)
16
- - [See Also](#see-also)
17
-
18
- ## Modules
19
-
20
- - `etlplus.config.__init__`: package exports and high-level package notes
21
- - `etlplus.config.types`: TypedDict-based config schemas
22
-
23
- ## Exported Types
24
-
25
- - `ApiConfigMap`: top-level API config shape
26
- - `ApiProfileConfigMap`: per-profile API config shape
27
- - `ApiProfileDefaultsMap`: defaults block within a profile
28
- - `EndpointMap`: endpoint config shape
29
-
30
- ## Example: Typing an API Config
31
-
32
- ```python
33
- from etlplus.config import ApiConfigMap
34
-
35
- api_cfg: ApiConfigMap = {
36
- "base_url": "https://example.test",
37
- "headers": {"Authorization": "Bearer token"},
38
- "endpoints": {
39
- "users": {
40
- "path": "/users",
41
- "method": "GET",
42
- },
43
- },
44
- }
45
- ```
46
-
47
- ## See Also
48
-
49
- - Top-level CLI and library usage in the main [README](../../README.md)
50
- - Config type definitions in [types.py](types.py)
@@ -1,33 +0,0 @@
1
- """
2
- :mod:`etlplus.config` package.
3
-
4
- Configuration models and helpers for ETLPlus.
5
-
6
- This package defines models for data sources/targets ("connectors"), APIs,
7
- pagination/rate limits, pipeline orchestration, and related utilities. The
8
- parsers are permissive (accepting ``Mapping[str, Any]``) and normalize to
9
- concrete types without raising on unknown/optional fields.
10
-
11
- Notes
12
- -----
13
- - The models use ``@dataclass(slots=True)`` and avoid mutating inputs.
14
- - TypedDicts are editor/type-checking hints and are not enforced at runtime.
15
- """
16
-
17
- from __future__ import annotations
18
-
19
- from .types import ApiConfigMap
20
- from .types import ApiProfileConfigMap
21
- from .types import ApiProfileDefaultsMap
22
- from .types import EndpointMap
23
-
24
- # SECTION: EXPORTS ========================================================== #
25
-
26
-
27
- __all__ = [
28
- # Typed Dicts
29
- 'ApiConfigMap',
30
- 'ApiProfileConfigMap',
31
- 'ApiProfileDefaultsMap',
32
- 'EndpointMap',
33
- ]