etlplus 0.16.0__py3-none-any.whl → 0.16.6__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 (47) hide show
  1. etlplus/README.md +22 -0
  2. etlplus/__init__.py +2 -0
  3. etlplus/api/__init__.py +14 -14
  4. etlplus/api/auth.py +9 -6
  5. etlplus/api/config.py +6 -6
  6. etlplus/api/endpoint_client.py +16 -16
  7. etlplus/api/errors.py +4 -4
  8. etlplus/api/pagination/__init__.py +6 -6
  9. etlplus/api/pagination/config.py +11 -9
  10. etlplus/api/rate_limiting/__init__.py +2 -2
  11. etlplus/api/rate_limiting/config.py +10 -10
  12. etlplus/api/rate_limiting/rate_limiter.py +2 -2
  13. etlplus/api/request_manager.py +4 -4
  14. etlplus/api/retry_manager.py +6 -6
  15. etlplus/api/transport.py +10 -10
  16. etlplus/api/types.py +47 -26
  17. etlplus/api/utils.py +49 -49
  18. etlplus/cli/commands.py +22 -22
  19. etlplus/cli/handlers.py +12 -13
  20. etlplus/{workflow/pipeline.py → config.py} +54 -91
  21. etlplus/connector/__init__.py +6 -6
  22. etlplus/connector/api.py +7 -7
  23. etlplus/connector/database.py +3 -3
  24. etlplus/connector/file.py +3 -3
  25. etlplus/connector/types.py +2 -2
  26. etlplus/enums.py +35 -167
  27. etlplus/ops/__init__.py +1 -0
  28. etlplus/ops/enums.py +173 -0
  29. etlplus/ops/extract.py +209 -22
  30. etlplus/ops/load.py +140 -34
  31. etlplus/ops/run.py +88 -103
  32. etlplus/ops/transform.py +46 -27
  33. etlplus/ops/types.py +147 -0
  34. etlplus/ops/utils.py +5 -5
  35. etlplus/ops/validate.py +13 -13
  36. etlplus/types.py +5 -102
  37. etlplus/workflow/README.md +0 -24
  38. etlplus/workflow/__init__.py +2 -4
  39. etlplus/workflow/dag.py +23 -1
  40. etlplus/workflow/jobs.py +15 -28
  41. etlplus/workflow/profile.py +4 -2
  42. {etlplus-0.16.0.dist-info → etlplus-0.16.6.dist-info}/METADATA +1 -1
  43. {etlplus-0.16.0.dist-info → etlplus-0.16.6.dist-info}/RECORD +47 -45
  44. {etlplus-0.16.0.dist-info → etlplus-0.16.6.dist-info}/WHEEL +0 -0
  45. {etlplus-0.16.0.dist-info → etlplus-0.16.6.dist-info}/entry_points.txt +0 -0
  46. {etlplus-0.16.0.dist-info → etlplus-0.16.6.dist-info}/licenses/LICENSE +0 -0
  47. {etlplus-0.16.0.dist-info → etlplus-0.16.6.dist-info}/top_level.txt +0 -0
etlplus/types.py CHANGED
@@ -12,12 +12,12 @@ Notes
12
12
  See Also
13
13
  --------
14
14
  - :mod:`etlplus.api.types` for HTTP-specific aliases and data classes
15
- - :mod:`etlplus.connector.types` for connector-specific aliases and TypedDict
16
- surfaces
15
+ - :mod:`etlplus.connector.types` for connector-specific aliases
17
16
 
18
17
  Examples
19
18
  --------
20
- >>> from etlplus.types import JSONDict, PipelineConfig
19
+ >>> from etlplus.types import JSONDict
20
+ >>> from etlplus.ops.types import PipelineConfig
21
21
  >>> payload: JSONDict = {'id': 1, 'name': 'Ada'}
22
22
  >>> isinstance(payload, dict)
23
23
  True
@@ -54,33 +54,15 @@ __all__ = [
54
54
  'JSONRecords',
55
55
  # Type Aliases (File System)
56
56
  'StrPath',
57
- # Type Aliases (Functions)
58
- 'AggregateFunc',
59
- 'OperatorFunc',
60
- # Type Aliases (Records & Fields)
61
- 'FieldName',
62
- 'Fields',
63
57
  # Type Aliases (Transform Specs)
64
58
  'StrAnyMap',
65
59
  'StrSeqMap',
66
60
  'StrStrMap',
67
- 'AggregateSpec',
68
- 'FilterSpec',
69
- 'MapSpec',
70
- 'SelectSpec',
71
- 'SortSpec',
72
- # Type Aliases (Pipelines)
73
- 'StepOrSteps',
74
- 'StepSeq',
75
- 'StepSpec',
76
- 'PipelineStepName',
77
- 'PipelineConfig',
78
- # Type Aliases (Helpers)
79
- 'StepApplier',
80
- 'SortKey',
81
61
  # Type Aliases (Networking / Runtime)
82
62
  'Sleeper',
83
63
  'Timeout',
64
+ # Type Aliases (Templates)
65
+ 'TemplateKey',
84
66
  ]
85
67
 
86
68
 
@@ -125,22 +107,6 @@ type JSONRecords = list[JSONRecord]
125
107
  # Path-like inputs accepted by file helpers.
126
108
  type StrPath = str | Path | PathLike[str]
127
109
 
128
- # -- Functions -- #
129
-
130
- # Callable reducing numeric collections into a summary value.
131
- type AggregateFunc = Callable[[list[float], int], Any]
132
-
133
- # Binary predicate consumed by filter operations.
134
- type OperatorFunc = Callable[[Any, Any], bool]
135
-
136
- # -- Records & Fields -- #
137
-
138
- # Individual field identifier referenced inside specs.
139
- type FieldName = str
140
-
141
- # Ordered list of :data:`FieldName` entries preserving projection order.
142
- type Fields = list[FieldName]
143
-
144
110
  # -- Transform Specs -- #
145
111
 
146
112
  # Kept intentionally broad for runtime-friendly validation in transform.py.
@@ -156,69 +122,6 @@ type StrStrMap = Mapping[str, str]
156
122
  # Mapping whose values are homogeneous sequences.
157
123
  type StrSeqMap = Mapping[str, Sequence[Any]]
158
124
 
159
- # Transform step specifications
160
-
161
- # Filtering spec expecting ``field``, ``op``, and ``value`` keys.
162
- type FilterSpec = StrAnyMap
163
-
164
- # Field renaming instructions mapping old keys to new ones.
165
- type MapSpec = StrStrMap
166
-
167
- # Projection spec as a field list or mapping with metadata.
168
- #
169
- # Examples
170
- # --------
171
- # >>> from etlplus.types import SelectSpec
172
- # >>> spec1: SelectSpec = ['a','b']
173
- # >>> spec2: SelectSpec = {'fields': [...]}
174
- type SelectSpec = Fields | StrSeqMap
175
-
176
- # Sort directive expressed as a field string or mapping with flags.
177
- #
178
- # Examples
179
- # --------
180
- # >>> from etlplus.types import SortSpec
181
- # >>> spec1: SortSpec = 'field'
182
- # >>> spec2: SortSpec = {'field': 'x', 'reverse': True}
183
- type SortSpec = str | StrAnyMap
184
-
185
- # Aggregate instruction covering ``field``, ``func``, and optional alias.
186
- #
187
- # Supported functions: ``avg``, ``count``, ``max``, ``min``, and ``sum``.
188
- # Examples
189
- # --------
190
- # >>> from etlplus.types import AggregateSpec
191
- # >>> spec: AggregateSpec = \
192
- # ... {'field': 'x', 'func': 'sum' | 'avg' | ..., 'alias'?: '...'}
193
- type AggregateSpec = StrAnyMap
194
-
195
- # -- Pipelines-- #
196
-
197
- # Unified pipeline step spec consumed by :mod:`etlplus.ops.transform`.
198
- type StepSpec = AggregateSpec | FilterSpec | MapSpec | SelectSpec | SortSpec
199
-
200
- # Collections of steps
201
-
202
- # Ordered collection of :data:`StepSpec` entries.
203
- type StepSeq = Sequence[StepSpec]
204
-
205
- # Accepts either a single :data:`StepSpec` or a sequence of them.
206
- type StepOrSteps = StepSpec | StepSeq
207
-
208
- # Canonical literal names for supported transform stages.
209
- type PipelineStepName = Literal['filter', 'map', 'select', 'sort', 'aggregate']
210
-
211
- # Mapping from step name to its associated specification payload.
212
- type PipelineConfig = Mapping[PipelineStepName, StepOrSteps]
213
-
214
- # -- Helpers -- #
215
-
216
- # Callable that applies step configuration to a batch of records.
217
- type StepApplier = Callable[[JSONList, Any], JSONList]
218
-
219
- # Tuple combining stable sort index and computed sort value.
220
- type SortKey = tuple[int, Any]
221
-
222
125
  # -- Networking / Runtime -- #
223
126
 
224
127
  # Sleep function used by retry helpers.
@@ -12,8 +12,6 @@ Back to project overview: see the top-level [README](../../README.md).
12
12
 
13
13
  - [`etlplus.workflow` Subpackage](#etlplusworkflow-subpackage)
14
14
  - [Supported Configuration Types](#supported-configuration-types)
15
- - [Loading and Validating Configs](#loading-and-validating-configs)
16
- - [Example: Loading a Pipeline Config](#example-loading-a-pipeline-config)
17
15
  - [See Also](#see-also)
18
16
 
19
17
  ## Supported Configuration Types
@@ -23,28 +21,6 @@ Back to project overview: see the top-level [README](../../README.md).
23
21
  - **Pipeline**: End-to-end pipeline configuration
24
22
  - **Profile**: User or environment-specific settings
25
23
 
26
- ## Loading and Validating Configs
27
-
28
- Use the provided classes to load and validate configuration files:
29
-
30
- ```python
31
- from etlplus.workflow import PipelineConfig
32
-
33
- cfg = PipelineConfig.from_yaml("pipeline.yml")
34
- ```
35
-
36
- - Supports YAML and JSON formats
37
- - Validates against expected schema
38
-
39
- ## Example: Loading a Pipeline Config
40
-
41
- ```python
42
- from etlplus.workflow import PipelineConfig
43
-
44
- pipeline = PipelineConfig.from_yaml("configs/pipeline.yml")
45
- print(pipeline)
46
- ```
47
-
48
24
  ## See Also
49
25
 
50
26
  - Top-level CLI and library usage in the main [README](../../README.md)
@@ -12,8 +12,7 @@ from .jobs import JobConfig
12
12
  from .jobs import LoadRef
13
13
  from .jobs import TransformRef
14
14
  from .jobs import ValidationRef
15
- from .pipeline import PipelineConfig
16
- from .pipeline import load_pipeline_config
15
+ from .profile import ProfileConfig
17
16
 
18
17
  # SECTION: EXPORTS ========================================================== #
19
18
 
@@ -23,10 +22,9 @@ __all__ = [
23
22
  'ExtractRef',
24
23
  'JobConfig',
25
24
  'LoadRef',
26
- 'PipelineConfig',
25
+ 'ProfileConfig',
27
26
  'TransformRef',
28
27
  'ValidationRef',
29
28
  # Functions
30
- 'load_pipeline_config',
31
29
  'topological_sort_jobs',
32
30
  ]
etlplus/workflow/dag.py CHANGED
@@ -47,6 +47,28 @@ class DagError(ValueError):
47
47
  return self.message
48
48
 
49
49
 
50
+ # SECTION: INTERNAL FUNCTIONS =============================================== #
51
+
52
+
53
+ def _ready(
54
+ indegree: dict[str, int],
55
+ ) -> list[str]:
56
+ """
57
+ Return a sorted list of nodes with zero indegree.
58
+
59
+ Parameters
60
+ ----------
61
+ indegree : dict[str, int]
62
+ Mapping of node name to indegree.
63
+
64
+ Returns
65
+ -------
66
+ list[str]
67
+ Sorted list of node names ready to process.
68
+ """
69
+ return sorted(name for name, deg in indegree.items() if deg == 0)
70
+
71
+
50
72
  # SECTION: FUNCTIONS ======================================================== #
51
73
 
52
74
 
@@ -88,7 +110,7 @@ def topological_sort_jobs(
88
110
  edges[dep].add(job.name)
89
111
  indegree[job.name] += 1
90
112
 
91
- queue = deque(sorted(name for name, deg in indegree.items() if deg == 0))
113
+ queue = deque(_ready(indegree))
92
114
  ordered: list[str] = []
93
115
 
94
116
  while queue:
etlplus/workflow/jobs.py CHANGED
@@ -6,14 +6,13 @@ transform, load).
6
6
 
7
7
  Notes
8
8
  -----
9
- - Lightweight references used inside :class:`PipelineConfig` to avoid storing
10
- large nested structures.
11
9
  - All attributes are simple and optional where appropriate, keeping parsing
12
10
  tolerant.
13
11
  """
14
12
 
15
13
  from __future__ import annotations
16
14
 
15
+ from collections.abc import Sequence
17
16
  from dataclasses import dataclass
18
17
  from dataclasses import field
19
18
  from typing import Any
@@ -76,13 +75,15 @@ def _parse_depends_on(
76
75
  """
77
76
  if isinstance(value, str):
78
77
  return [value]
79
- if isinstance(value, list):
78
+ if isinstance(value, Sequence) and not isinstance(
79
+ value,
80
+ (str, bytes, bytearray),
81
+ ):
80
82
  return [entry for entry in value if isinstance(entry, str)]
81
83
  return []
82
84
 
83
85
 
84
86
  def _require_str(
85
- # data: dict[str, Any],
86
87
  data: StrAnyMap,
87
88
  key: str,
88
89
  ) -> str | None:
@@ -149,13 +150,9 @@ class ExtractRef:
149
150
  data = maybe_mapping(obj)
150
151
  if not data:
151
152
  return None
152
- source = _require_str(data, 'source')
153
- if source is None:
153
+ if (source := _require_str(data, 'source')) is None:
154
154
  return None
155
- return cls(
156
- source=source,
157
- options=coerce_dict(data.get('options')),
158
- )
155
+ return cls(source=source, options=coerce_dict(data.get('options')))
159
156
 
160
157
 
161
158
  @dataclass(kw_only=True, slots=True)
@@ -214,18 +211,13 @@ class JobConfig:
214
211
  data = maybe_mapping(obj)
215
212
  if not data:
216
213
  return None
217
- name = _require_str(data, 'name')
218
- if name is None:
214
+ if (name := _require_str(data, 'name')) is None:
219
215
  return None
220
216
 
221
- description = _coerce_optional_str(data.get('description'))
222
-
223
- depends_on = _parse_depends_on(data.get('depends_on'))
224
-
225
217
  return cls(
226
218
  name=name,
227
- description=description,
228
- depends_on=depends_on,
219
+ description=_coerce_optional_str(data.get('description')),
220
+ depends_on=_parse_depends_on(data.get('depends_on')),
229
221
  extract=ExtractRef.from_obj(data.get('extract')),
230
222
  validate=ValidationRef.from_obj(data.get('validate')),
231
223
  transform=TransformRef.from_obj(data.get('transform')),
@@ -274,8 +266,7 @@ class LoadRef:
274
266
  data = maybe_mapping(obj)
275
267
  if not data:
276
268
  return None
277
- target = _require_str(data, 'target')
278
- if target is None:
269
+ if (target := _require_str(data, 'target')) is None:
279
270
  return None
280
271
  return cls(
281
272
  target=target,
@@ -321,8 +312,7 @@ class TransformRef:
321
312
  data = maybe_mapping(obj)
322
313
  if not data:
323
314
  return None
324
- pipeline = _require_str(data, 'pipeline')
325
- if pipeline is None:
315
+ if (pipeline := _require_str(data, 'pipeline')) is None:
326
316
  return None
327
317
  return cls(pipeline=pipeline)
328
318
 
@@ -372,13 +362,10 @@ class ValidationRef:
372
362
  data = maybe_mapping(obj)
373
363
  if not data:
374
364
  return None
375
- ruleset = _require_str(data, 'ruleset')
376
- if ruleset is None:
365
+ if (ruleset := _require_str(data, 'ruleset')) is None:
377
366
  return None
378
- severity = _coerce_optional_str(data.get('severity'))
379
- phase = _coerce_optional_str(data.get('phase'))
380
367
  return cls(
381
368
  ruleset=ruleset,
382
- severity=severity,
383
- phase=phase,
369
+ severity=_coerce_optional_str(data.get('severity')),
370
+ phase=_coerce_optional_str(data.get('phase')),
384
371
  )
@@ -18,6 +18,7 @@ from typing import Self
18
18
 
19
19
  from ..types import StrAnyMap
20
20
  from ..utils import cast_str_dict
21
+ from ..utils import maybe_mapping
21
22
 
22
23
  # SECTION: EXPORTS ========================================================== #
23
24
 
@@ -56,7 +57,8 @@ class ProfileConfig:
56
57
  cls,
57
58
  obj: StrAnyMap | None,
58
59
  ) -> Self:
59
- """Parse a mapping into a :class:`ProfileConfig` instance.
60
+ """
61
+ Parse a mapping into a :class:`ProfileConfig` instance.
60
62
 
61
63
  Parameters
62
64
  ----------
@@ -73,7 +75,7 @@ class ProfileConfig:
73
75
  return cls()
74
76
 
75
77
  # Coerce all env values to strings using shared helper.
76
- env = cast_str_dict(obj.get('env'))
78
+ env = cast_str_dict(maybe_mapping(obj.get('env')))
77
79
 
78
80
  return cls(
79
81
  default_target=obj.get('default_target'),
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: etlplus
3
- Version: 0.16.0
3
+ Version: 0.16.6
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
@@ -1,49 +1,50 @@
1
- etlplus/README.md,sha256=JaMSomnMsHrTruDnonHqe83Rv4K0-e7Wy46tMeVoleU,1468
2
- etlplus/__init__.py,sha256=mgTP4PJmRmsEjTCAizzzdtzAmhuHtarmPzphzdjvLgM,277
1
+ etlplus/README.md,sha256=L3un9q7Q7Mstfh0dmSjpsZMZzsOz2tvlWw4_-Y_LZEs,1887
2
+ etlplus/__init__.py,sha256=yHZt-sjjfPjB_CrNhcT9bcMlZCfwiul39ZhQ2VfxpRs,318
3
3
  etlplus/__main__.py,sha256=btoROneNiigyfBU7BSzPKZ1R9gzBMpxcpsbPwmuHwTM,479
4
4
  etlplus/__version__.py,sha256=1E0GMK_yUWCMQFKxXjTvyMwofi0qT2k4CDNiHWiymWE,327
5
- etlplus/enums.py,sha256=8-uUOKe68cPzlmUg-e7gavkC95kbTJXRpRzvXehIsRk,6841
5
+ etlplus/config.py,sha256=6BCI9hC1yWYAy5WclIHJlg90FYeWn5vAVrT1NWUTwpE,8817
6
+ etlplus/enums.py,sha256=MfQhy3XDpN7oqLrF7_WwZojl7n8cW3RAzsZGRnAbWgc,4073
6
7
  etlplus/mixins.py,sha256=ifGpHwWv7U00yqGf-kN93vJax2IiK4jaGtTsPsO3Oak,1350
7
8
  etlplus/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
8
- etlplus/types.py,sha256=vB1Sh_5771eVv8-RClJatBQ7PcsScY6C2MvJqnI8IG8,6216
9
+ etlplus/types.py,sha256=Op2H1dcmv0Srm9prFnBZjt7f1S4Mqrus7XrdsjoZkIM,3461
9
10
  etlplus/utils.py,sha256=X-k_Y8i6oDjlE5aQu9sw3gPw7O2ikiSn4uoheVv_ERc,17091
10
11
  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
12
+ etlplus/api/__init__.py,sha256=eIHkdNBZv6ViB_5MhW3f3vWMYJLFoF4Tr3Wnb3O7B4E,4647
13
+ etlplus/api/auth.py,sha256=PZEJIBwLwnUGfF76s32a5GnLcpDvu4ghEd-wEAHx4rU,12260
14
+ etlplus/api/config.py,sha256=WmH1GOQxoBAr3vUsmYIyMbXSt7kiyNbtKjyMS1dqt-A,17653
15
+ etlplus/api/endpoint_client.py,sha256=UtvK4h_-fxINM-5QcumkcLJsL0Uw4L0L_4RMxC024Yk,30737
15
16
  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
17
+ etlplus/api/errors.py,sha256=8LuZfExUpZ67PPqPr6SdAmFA-wc0ocw4JHoBYyEcg0s,4664
18
+ etlplus/api/request_manager.py,sha256=K3tlRFflUM-_S-optnHzJx_AWcbd0ZQGVX_NytkN4zg,18690
19
+ etlplus/api/retry_manager.py,sha256=RV5xkmbExNHF_b-IN5RWx2wawiJzeklc9miGXPQb7U4,11326
20
+ etlplus/api/transport.py,sha256=f9hgtlnz5fFUsMYWdwAkSsdULJSv-276ekP8u_k3e4Y,9448
21
+ etlplus/api/types.py,sha256=gxwmgPDra7OfAPjJv2Mq45axd_s4TiGAqYtMCx167UM,8008
22
+ etlplus/api/utils.py,sha256=cxQYV0iAbhr65_yvhSii5jhfNcVQGgdwuwO86PJVD-s,26415
23
+ etlplus/api/pagination/__init__.py,sha256=K76nkMnMyM81wzbKTQynq1rRv81ndEUVEuF6cmPzvKQ,1401
23
24
  etlplus/api/pagination/client.py,sha256=yMEpWqRxTCD4zRc9OYtEyUtShpGH5atiHFEAt95v2FE,5394
24
- etlplus/api/pagination/config.py,sha256=u2hk8QmiQoIKe16sPUB6SvVqiLkuq9lUaY4Pl5-lejk,13577
25
+ etlplus/api/pagination/config.py,sha256=pt4yAGr03Esr1gEZg3Nm6kfBOM1FpWwf_t6XTpvBd4s,13596
25
26
  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
27
+ etlplus/api/rate_limiting/__init__.py,sha256=8VIjkW2wGjTFJjjAqOBSFKcKsBFuYndS4o33PLSo_q8,1072
28
+ etlplus/api/rate_limiting/config.py,sha256=U8T8BxrX87uFR-ksTG1FkmxoVr-FTaLIa0wWeXIcZss,9775
29
+ etlplus/api/rate_limiting/rate_limiter.py,sha256=qmOf15qvhFk2htMsGcHfgzATqOBd2BdrG8ShadfOIgY,7035
29
30
  etlplus/cli/README.md,sha256=8H_G2d3HteYIU6ReX9K9DM485QjWDT5vHMQbGD_vv20,1237
30
31
  etlplus/cli/__init__.py,sha256=J97-Rv931IL1_b4AXnB7Fbbd7HKnHBpx18NQfC_kE6c,299
31
- etlplus/cli/commands.py,sha256=HFlg29tO6Jwv1NXWAHmvniLCyRSlboL55Arn9B8nZAM,25028
32
+ etlplus/cli/commands.py,sha256=Mbnu_YYUrOumbDjkul9x5VjP8VXW5u08xNi4nLF9Yyo,25048
32
33
  etlplus/cli/constants.py,sha256=0F7dXIQKWUhhVu2Us527GJeknJIWpBqz7CK2e5OQgcE,1947
33
- etlplus/cli/handlers.py,sha256=uvbAyF6Ux8_5C-obCWZOrOP0QP0oiT-Km1hPhE8tDx0,18558
34
+ etlplus/cli/handlers.py,sha256=JdN7W7mqmQL9xyU7PkBtsQf7eu3j5-E2AhAQvbfy-4g,18470
34
35
  etlplus/cli/io.py,sha256=tGGNQ4ecezqj-mD285fgBVrYdphdeqApsyV9VojOj1I,7836
35
36
  etlplus/cli/main.py,sha256=68_uJwmWajhOC9o4R_ns8IQloC9BFmAKC_9GlQOxKWg,5239
36
37
  etlplus/cli/options.py,sha256=vfXT3YLh7wG1iC-aTdSg6ItMC8l6n0Lozmy53XjqLbA,1199
37
38
  etlplus/cli/state.py,sha256=3Dq5BKct0uAvRajtc2yHbsX7wqepZOwlAMKsyvQcnqk,7918
38
39
  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
40
+ etlplus/connector/__init__.py,sha256=C1nMuEvCnYS07kpoP91aWEg1utV1D4bO603OzveF7s0,1012
41
+ etlplus/connector/api.py,sha256=uXoQvOGGnZEP96H0O19nMgu7uiBfTqEFNuFl0r9oBbQ,4531
41
42
  etlplus/connector/connector.py,sha256=OQP4kK_1O6g9FnDBrE3L58LOSfImsK5EBHtKI4N71u8,574
42
43
  etlplus/connector/core.py,sha256=0GeXjlZFnyS-4j7jR_AtclQtELE6x-vodHJ4rfjFLL8,2795
43
- etlplus/connector/database.py,sha256=fK_b4r5NsFTTUv0GHoEen7sVX45wVy1JLKds0qxfVM8,3011
44
+ etlplus/connector/database.py,sha256=Y8fzcbzucIZW64g9zkqO-M_H02CiW5lB0IDk0RynWJo,3014
44
45
  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
46
+ etlplus/connector/file.py,sha256=AsEXUHOokP2s5NQoTazF3Skz7qMj-1FNdvRZj9LfdbM,2858
47
+ etlplus/connector/types.py,sha256=51UPD4edtMRiRL35ZVfbmKTodhrLUiRP5P067SZGzms,953
47
48
  etlplus/connector/utils.py,sha256=fS2hPAfuhKTg_L2xDxF5fJnsO1SuuDIiEWU7GuaJKUM,2933
48
49
  etlplus/database/README.md,sha256=3Af5BEGLkBmMoGOLtS1GQuj4wKPh_CwSp5NEPMf2uaY,1435
49
50
  etlplus/database/__init__.py,sha256=AKJsDl2RHuRGPS-eXgNJeh4aSncJP5Y0yLApBF6i7i8,1052
@@ -116,26 +117,27 @@ etlplus/file/yaml.py,sha256=b_SxDSEQPVXQv9a9Ih4wAcI940pE5Ksy5pQE6K6ckhw,2062
116
117
  etlplus/file/zip.py,sha256=8wnmnGW_pGTx65736CzAG67XIi5y98KxucRT8sNDeuQ,4195
117
118
  etlplus/file/zsav.py,sha256=5hMuBjYeHw--UL2ZCCDn6TzJkr_YNhdQhvKI6nr3WW0,1674
118
119
  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
120
+ etlplus/ops/__init__.py,sha256=r5_-pPhSLCD1nq1EbN0rQrLOGpudueeIxCH_JvT2bt0,1718
121
+ etlplus/ops/enums.py,sha256=dC_8CfaTiB2i83Az-oG-2hkjMuAfDADNbcMF2f94UeU,4014
122
+ etlplus/ops/extract.py,sha256=fPk8LLjEmCZ5U59IUm15vG5aXTmduteCqtsVIlxvvxI,11022
123
+ etlplus/ops/load.py,sha256=yicciVwomUKkdbhuRqbavKBNpT2Hg813BnQzG6IgF4o,10811
124
+ etlplus/ops/run.py,sha256=4HWelMevW0pW_76lJkoMcbzeQMiThMbxzO09wx6yoHg,11278
125
+ etlplus/ops/transform.py,sha256=-41uw_pwOGsMTUYxtXaeYOmTF_fTkN-L4Q9KT1OFe78,25671
126
+ etlplus/ops/types.py,sha256=Cvp8AJzJhJ1iYjyHd7j9ZLioxE2NdK__3g6fOI0qq6Q,4198
127
+ etlplus/ops/utils.py,sha256=9UXym1W4qCMxBkcqCPUmI1QJ27yh1kOAbVnI1KsAGwE,10855
128
+ etlplus/ops/validate.py,sha256=VtMhrH6itd_PFH4IhBOndvJpxxOPI56OAJhnrSyT_6U,13323
126
129
  etlplus/templates/README.md,sha256=IfPXlj1TGVA-uFWosHJhE2rabFW-znxOlOMazO9Z5cE,1361
127
130
  etlplus/templates/__init__.py,sha256=tsniN7XJYs3NwYxJ6c2HD5upHP3CDkLx-bQCMt97UOM,106
128
131
  etlplus/templates/ddl.sql.j2,sha256=s8fMWvcb4eaJVXkifuib1aQPljtZ8buuyB_uA-ZdU3Q,4734
129
132
  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,,
133
+ etlplus/workflow/README.md,sha256=QelyVFGX-sZM9mx3v6BXkzX36hv6MI1yK4eCPSOKNwI,1050
134
+ etlplus/workflow/__init__.py,sha256=XgCQr684om0rONrQZ61yQ0r4qqFQL0iLAAB2Mn2BRSE,594
135
+ etlplus/workflow/dag.py,sha256=-f1x8N1eb-PUuiOwEvFLmJwfR7JaMDJihlCHlhrFhgE,2937
136
+ etlplus/workflow/jobs.py,sha256=hLE9QJUzQaI0aOEon0P-xxxa6xHp997ANei4F310WRY,8711
137
+ etlplus/workflow/profile.py,sha256=FQU3bzBZ9_yjKC9kCXKN1FQDS9zjNUjtWB1r3UL95_Q,1993
138
+ etlplus-0.16.6.dist-info/licenses/LICENSE,sha256=MuNO63i6kWmgnV2pbP2SLqP54mk1BGmu7CmbtxMmT-U,1069
139
+ etlplus-0.16.6.dist-info/METADATA,sha256=_6gQGwfRwLCcr9OF_s313Nuka2e4TvxOsyHtu4M-JSE,28114
140
+ etlplus-0.16.6.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
141
+ etlplus-0.16.6.dist-info/entry_points.txt,sha256=6w-2-jzuPa55spzK34h-UKh2JTEShh38adFRONNP9QE,45
142
+ etlplus-0.16.6.dist-info/top_level.txt,sha256=aWWF-udn_sLGuHTM6W6MLh99ArS9ROkUWO8Mi8y1_2U,8
143
+ etlplus-0.16.6.dist-info/RECORD,,