etlplus 0.16.0__py3-none-any.whl → 0.16.3__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/workflow/jobs.py CHANGED
@@ -14,6 +14,7 @@ Notes
14
14
 
15
15
  from __future__ import annotations
16
16
 
17
+ from collections.abc import Sequence
17
18
  from dataclasses import dataclass
18
19
  from dataclasses import field
19
20
  from typing import Any
@@ -76,13 +77,15 @@ def _parse_depends_on(
76
77
  """
77
78
  if isinstance(value, str):
78
79
  return [value]
79
- if isinstance(value, list):
80
+ if isinstance(value, Sequence) and not isinstance(
81
+ value,
82
+ (str, bytes, bytearray),
83
+ ):
80
84
  return [entry for entry in value if isinstance(entry, str)]
81
85
  return []
82
86
 
83
87
 
84
88
  def _require_str(
85
- # data: dict[str, Any],
86
89
  data: StrAnyMap,
87
90
  key: str,
88
91
  ) -> str | None:
@@ -149,13 +152,9 @@ class ExtractRef:
149
152
  data = maybe_mapping(obj)
150
153
  if not data:
151
154
  return None
152
- source = _require_str(data, 'source')
153
- if source is None:
155
+ if (source := _require_str(data, 'source')) is None:
154
156
  return None
155
- return cls(
156
- source=source,
157
- options=coerce_dict(data.get('options')),
158
- )
157
+ return cls(source=source, options=coerce_dict(data.get('options')))
159
158
 
160
159
 
161
160
  @dataclass(kw_only=True, slots=True)
@@ -214,18 +213,13 @@ class JobConfig:
214
213
  data = maybe_mapping(obj)
215
214
  if not data:
216
215
  return None
217
- name = _require_str(data, 'name')
218
- if name is None:
216
+ if (name := _require_str(data, 'name')) is None:
219
217
  return None
220
218
 
221
- description = _coerce_optional_str(data.get('description'))
222
-
223
- depends_on = _parse_depends_on(data.get('depends_on'))
224
-
225
219
  return cls(
226
220
  name=name,
227
- description=description,
228
- depends_on=depends_on,
221
+ description=_coerce_optional_str(data.get('description')),
222
+ depends_on=_parse_depends_on(data.get('depends_on')),
229
223
  extract=ExtractRef.from_obj(data.get('extract')),
230
224
  validate=ValidationRef.from_obj(data.get('validate')),
231
225
  transform=TransformRef.from_obj(data.get('transform')),
@@ -274,8 +268,7 @@ class LoadRef:
274
268
  data = maybe_mapping(obj)
275
269
  if not data:
276
270
  return None
277
- target = _require_str(data, 'target')
278
- if target is None:
271
+ if (target := _require_str(data, 'target')) is None:
279
272
  return None
280
273
  return cls(
281
274
  target=target,
@@ -321,8 +314,7 @@ class TransformRef:
321
314
  data = maybe_mapping(obj)
322
315
  if not data:
323
316
  return None
324
- pipeline = _require_str(data, 'pipeline')
325
- if pipeline is None:
317
+ if (pipeline := _require_str(data, 'pipeline')) is None:
326
318
  return None
327
319
  return cls(pipeline=pipeline)
328
320
 
@@ -372,13 +364,10 @@ class ValidationRef:
372
364
  data = maybe_mapping(obj)
373
365
  if not data:
374
366
  return None
375
- ruleset = _require_str(data, 'ruleset')
376
- if ruleset is None:
367
+ if (ruleset := _require_str(data, 'ruleset')) is None:
377
368
  return None
378
- severity = _coerce_optional_str(data.get('severity'))
379
- phase = _coerce_optional_str(data.get('phase'))
380
369
  return cls(
381
370
  ruleset=ruleset,
382
- severity=severity,
383
- phase=phase,
371
+ severity=_coerce_optional_str(data.get('severity')),
372
+ phase=_coerce_optional_str(data.get('phase')),
384
373
  )
@@ -50,20 +50,42 @@ __all__ = [
50
50
  # SECTION: INTERNAL FUNCTIONS =============================================== #
51
51
 
52
52
 
53
- def _collect_parsed[T](
53
+ def _build_connectors(
54
54
  raw: StrAnyMap,
55
+ *,
55
56
  key: str,
56
- parser: Callable[[Any], T | None],
57
- ) -> list[T]:
57
+ ) -> list[Connector]:
58
58
  """
59
- Collect parsed items from ``raw[key]`` using a tolerant parser.
59
+ Parse connector entries from a list under ``raw[key]``.
60
60
 
61
61
  Parameters
62
62
  ----------
63
63
  raw : StrAnyMap
64
64
  Raw pipeline mapping.
65
65
  key : str
66
- Key pointing to a list-like payload.
66
+ Key pointing to connector entries (e.g., ``"sources"``).
67
+
68
+ Returns
69
+ -------
70
+ list[Connector]
71
+ Parsed connector instances.
72
+ """
73
+ return list(
74
+ _collect_parsed(raw.get(key, []) or [], _parse_connector_entry),
75
+ )
76
+
77
+
78
+ def _collect_parsed[T](
79
+ items: Any,
80
+ parser: Callable[[Any], T | None],
81
+ ) -> list[T]:
82
+ """
83
+ Collect parsed items from ``raw[key]`` using a tolerant parser.
84
+
85
+ Parameters
86
+ ----------
87
+ items : Any
88
+ List-like payload to parse.
67
89
  parser : Callable[[Any], T | None]
68
90
  Parser that returns an instance or ``None`` for invalid entries.
69
91
 
@@ -72,12 +94,12 @@ def _collect_parsed[T](
72
94
  list[T]
73
95
  Parsed items, excluding invalid entries.
74
96
  """
75
- items: list[T] = []
76
- for entry in raw.get(key, []) or []:
97
+ parsed_items: list[T] = []
98
+ for entry in items or []:
77
99
  parsed = parser(entry)
78
100
  if parsed is not None:
79
- items.append(parsed)
80
- return items
101
+ parsed_items.append(parsed)
102
+ return parsed_items
81
103
 
82
104
 
83
105
  def _parse_connector_entry(
@@ -104,48 +126,6 @@ def _parse_connector_entry(
104
126
  return None
105
127
 
106
128
 
107
- def _build_sources(
108
- raw: StrAnyMap,
109
- ) -> list[Connector]:
110
- """
111
- Return a list of source connectors parsed from the mapping.
112
-
113
- Parameters
114
- ----------
115
- raw : StrAnyMap
116
- Raw pipeline mapping.
117
-
118
- Returns
119
- -------
120
- list[Connector]
121
- Parsed source connectors.
122
- """
123
- return list(
124
- _collect_parsed(raw, 'sources', _parse_connector_entry),
125
- )
126
-
127
-
128
- def _build_targets(
129
- raw: StrAnyMap,
130
- ) -> list[Connector]:
131
- """
132
- Return a list of target connectors parsed from the mapping.
133
-
134
- Parameters
135
- ----------
136
- raw : StrAnyMap
137
- Raw pipeline mapping.
138
-
139
- Returns
140
- -------
141
- list[Connector]
142
- Parsed target connectors.
143
- """
144
- return list(
145
- _collect_parsed(raw, 'targets', _parse_connector_entry),
146
- )
147
-
148
-
149
129
  # SECTION: FUNCTIONS ======================================================== #
150
130
 
151
131
 
@@ -311,17 +291,20 @@ class PipelineConfig:
311
291
  file_systems = coerce_dict(raw.get('file_systems'))
312
292
 
313
293
  # Sources
314
- sources = _build_sources(raw)
294
+ sources = _build_connectors(raw, key='sources')
315
295
 
316
296
  # Validations/Transforms
317
297
  validations = coerce_dict(raw.get('validations'))
318
298
  transforms = coerce_dict(raw.get('transforms'))
319
299
 
320
300
  # Targets
321
- targets = _build_targets(raw)
301
+ targets = _build_connectors(raw, key='targets')
322
302
 
323
303
  # Jobs
324
- jobs = _collect_parsed(raw, 'jobs', JobConfig.from_obj)
304
+ jobs: list[JobConfig] = _collect_parsed(
305
+ raw.get('jobs', []) or [],
306
+ JobConfig.from_obj,
307
+ )
325
308
 
326
309
  # Table schemas (optional, tolerant pass-through structures).
327
310
  table_schemas: list[dict[str, Any]] = []
@@ -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.3
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
@@ -2,10 +2,10 @@ etlplus/README.md,sha256=JaMSomnMsHrTruDnonHqe83Rv4K0-e7Wy46tMeVoleU,1468
2
2
  etlplus/__init__.py,sha256=mgTP4PJmRmsEjTCAizzzdtzAmhuHtarmPzphzdjvLgM,277
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/enums.py,sha256=MfQhy3XDpN7oqLrF7_WwZojl7n8cW3RAzsZGRnAbWgc,4073
6
6
  etlplus/mixins.py,sha256=ifGpHwWv7U00yqGf-kN93vJax2IiK4jaGtTsPsO3Oak,1350
7
7
  etlplus/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
8
- etlplus/types.py,sha256=vB1Sh_5771eVv8-RClJatBQ7PcsScY6C2MvJqnI8IG8,6216
8
+ etlplus/types.py,sha256=DC9424i5qNBuCVGrfNLY3Ha2sz1mU84I0btSRAH7vrc,3428
9
9
  etlplus/utils.py,sha256=X-k_Y8i6oDjlE5aQu9sw3gPw7O2ikiSn4uoheVv_ERc,17091
10
10
  etlplus/api/README.md,sha256=amxS_eIcsnNuVvD0x_w8nkyfedOTYbhlY0gGhaFg0DE,8705
11
11
  etlplus/api/__init__.py,sha256=PK2lQv1FbsE7ZZS_ejevFZQSuOUHGApBc22YfHAzMqA,4615
@@ -17,7 +17,7 @@ etlplus/api/errors.py,sha256=XjI2xW-sypMUNUbqfc2S57-IGyWnH3oCDFhCmKYYI_Q,4648
17
17
  etlplus/api/request_manager.py,sha256=fhzPV5x7DqpKqoLvfDR8GKhBX_QBMtvZsRXxVnQQElY,18674
18
18
  etlplus/api/retry_manager.py,sha256=aq9iNCxt-Puy4rAgKNtNucxw2eP1yqAKZ2lfgMkzbCk,11302
19
19
  etlplus/api/transport.py,sha256=abm-_WieBDSSbFanBwhmudBuVVm7LjYUb8vrlMXo7SA,9408
20
- etlplus/api/types.py,sha256=Ng1b83RaJSHn4jl-M1f1dsTgjXizQtrW4yOXAYjwk_4,7377
20
+ etlplus/api/types.py,sha256=UcTrB347So12l8NplY-_HDf2T5IwZL_2r8CJDUSAm5Q,7975
21
21
  etlplus/api/utils.py,sha256=lNBfJKz3fJ4RhvnnX3uxVZC__6-WKksYMSGGYi0RRqM,26247
22
22
  etlplus/api/pagination/__init__.py,sha256=a4UX2J0AG8RMvmHt_CCofUm5vSmFo6GAfkb8XnSXypM,1395
23
23
  etlplus/api/pagination/client.py,sha256=yMEpWqRxTCD4zRc9OYtEyUtShpGH5atiHFEAt95v2FE,5394
@@ -116,11 +116,13 @@ etlplus/file/yaml.py,sha256=b_SxDSEQPVXQv9a9Ih4wAcI940pE5Ksy5pQE6K6ckhw,2062
116
116
  etlplus/file/zip.py,sha256=8wnmnGW_pGTx65736CzAG67XIi5y98KxucRT8sNDeuQ,4195
117
117
  etlplus/file/zsav.py,sha256=5hMuBjYeHw--UL2ZCCDn6TzJkr_YNhdQhvKI6nr3WW0,1674
118
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
119
+ etlplus/ops/__init__.py,sha256=r5_-pPhSLCD1nq1EbN0rQrLOGpudueeIxCH_JvT2bt0,1718
120
+ etlplus/ops/enums.py,sha256=dC_8CfaTiB2i83Az-oG-2hkjMuAfDADNbcMF2f94UeU,4014
121
+ etlplus/ops/extract.py,sha256=LOYiPrALRMF7JDBabnRF24_HKnnIcfTdfXesWdS3QZM,11020
122
+ etlplus/ops/load.py,sha256=yicciVwomUKkdbhuRqbavKBNpT2Hg813BnQzG6IgF4o,10811
123
+ etlplus/ops/run.py,sha256=2Z27ahRZGVULxDelHldHzUJ_vdbBCwlkwpm5KyKFP7U,11298
124
+ etlplus/ops/transform.py,sha256=-41uw_pwOGsMTUYxtXaeYOmTF_fTkN-L4Q9KT1OFe78,25671
125
+ etlplus/ops/types.py,sha256=Cvp8AJzJhJ1iYjyHd7j9ZLioxE2NdK__3g6fOI0qq6Q,4198
124
126
  etlplus/ops/utils.py,sha256=lJmrO1KDob-xZU8Gc2SvZvMgdYLsVoaz-fTV42KkLVo,10835
125
127
  etlplus/ops/validate.py,sha256=-OLAwQNNCmmDbmj0SB7zzYXDkJfcyBP_z9nTpqImLP0,13271
126
128
  etlplus/templates/README.md,sha256=IfPXlj1TGVA-uFWosHJhE2rabFW-znxOlOMazO9Z5cE,1361
@@ -128,14 +130,14 @@ etlplus/templates/__init__.py,sha256=tsniN7XJYs3NwYxJ6c2HD5upHP3CDkLx-bQCMt97UOM
128
130
  etlplus/templates/ddl.sql.j2,sha256=s8fMWvcb4eaJVXkifuib1aQPljtZ8buuyB_uA-ZdU3Q,4734
129
131
  etlplus/templates/view.sql.j2,sha256=Iy8DHfhq5yyvrUKDxqp_aHIEXY4Tm6j4wT7YDEFWAhk,2180
130
132
  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/__init__.py,sha256=ueothwpLruyLgr3-2hW8VT1unNyFJxdmT-l_3eB2ejc,724
134
+ etlplus/workflow/dag.py,sha256=-f1x8N1eb-PUuiOwEvFLmJwfR7JaMDJihlCHlhrFhgE,2937
135
+ etlplus/workflow/jobs.py,sha256=5DmAzmEZV6XXQ-xzowkLxFzplIh8Eno3wuCmjy79xHw,8818
136
+ etlplus/workflow/pipeline.py,sha256=PA5zhcfrk--pAg3b3x4oBf29WMj5HqR8zOozz4oEmg8,9387
137
+ etlplus/workflow/profile.py,sha256=FQU3bzBZ9_yjKC9kCXKN1FQDS9zjNUjtWB1r3UL95_Q,1993
138
+ etlplus-0.16.3.dist-info/licenses/LICENSE,sha256=MuNO63i6kWmgnV2pbP2SLqP54mk1BGmu7CmbtxMmT-U,1069
139
+ etlplus-0.16.3.dist-info/METADATA,sha256=uV-JEWCscNgGsoF34kK-1TZWzWjYZKamLylPHGwhlwU,28114
140
+ etlplus-0.16.3.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
141
+ etlplus-0.16.3.dist-info/entry_points.txt,sha256=6w-2-jzuPa55spzK34h-UKh2JTEShh38adFRONNP9QE,45
142
+ etlplus-0.16.3.dist-info/top_level.txt,sha256=aWWF-udn_sLGuHTM6W6MLh99ArS9ROkUWO8Mi8y1_2U,8
143
+ etlplus-0.16.3.dist-info/RECORD,,