etlplus 0.14.3__py3-none-any.whl → 0.15.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.
Files changed (39) hide show
  1. etlplus/README.md +4 -4
  2. etlplus/api/README.md +33 -2
  3. etlplus/api/config.py +3 -8
  4. etlplus/api/types.py +89 -0
  5. etlplus/api/utils.py +5 -1
  6. etlplus/cli/README.md +2 -2
  7. etlplus/cli/commands.py +75 -42
  8. etlplus/cli/handlers.py +32 -14
  9. etlplus/cli/main.py +1 -1
  10. etlplus/cli/state.py +4 -7
  11. etlplus/database/README.md +2 -2
  12. etlplus/database/engine.py +18 -2
  13. etlplus/database/orm.py +2 -0
  14. etlplus/file/README.md +2 -2
  15. etlplus/file/_io.py +39 -0
  16. etlplus/file/json.py +2 -14
  17. etlplus/file/yaml.py +2 -14
  18. etlplus/ops/run.py +14 -9
  19. etlplus/ops/utils.py +4 -33
  20. etlplus/ops/validate.py +3 -3
  21. etlplus/templates/README.md +2 -2
  22. etlplus/types.py +3 -2
  23. etlplus/utils.py +136 -2
  24. etlplus/{config → workflow}/README.md +6 -6
  25. etlplus/{config → workflow}/__init__.py +10 -23
  26. etlplus/{config → workflow}/connector.py +58 -44
  27. etlplus/{dag.py → workflow/dag.py} +6 -4
  28. etlplus/{config → workflow}/jobs.py +101 -38
  29. etlplus/{config → workflow}/pipeline.py +57 -49
  30. etlplus/{config → workflow}/profile.py +8 -5
  31. etlplus/workflow/types.py +115 -0
  32. {etlplus-0.14.3.dist-info → etlplus-0.15.2.dist-info}/METADATA +4 -4
  33. {etlplus-0.14.3.dist-info → etlplus-0.15.2.dist-info}/RECORD +37 -38
  34. {etlplus-0.14.3.dist-info → etlplus-0.15.2.dist-info}/WHEEL +1 -1
  35. etlplus/config/types.py +0 -204
  36. etlplus/config/utils.py +0 -120
  37. {etlplus-0.14.3.dist-info → etlplus-0.15.2.dist-info}/entry_points.txt +0 -0
  38. {etlplus-0.14.3.dist-info → etlplus-0.15.2.dist-info}/licenses/LICENSE +0 -0
  39. {etlplus-0.14.3.dist-info → etlplus-0.15.2.dist-info}/top_level.txt +0 -0
@@ -1,5 +1,5 @@
1
1
  """
2
- :mod:`etlplus.config.profile` module.
2
+ :mod:`etlplus.workflow.profile` module.
3
3
 
4
4
  Profile model for pipeline-level defaults and environment.
5
5
 
@@ -22,10 +22,13 @@ from ..utils import cast_str_dict
22
22
  # SECTION: EXPORTS ========================================================== #
23
23
 
24
24
 
25
- __all__ = ['ProfileConfig']
25
+ __all__ = [
26
+ # Data Classes
27
+ 'ProfileConfig',
28
+ ]
26
29
 
27
30
 
28
- # SECTION: CLASSES ========================================================== #
31
+ # SECTION: DATA CLASSES ===================================================== #
29
32
 
30
33
 
31
34
  @dataclass(kw_only=True, slots=True)
@@ -53,7 +56,7 @@ class ProfileConfig:
53
56
  cls,
54
57
  obj: StrAnyMap | None,
55
58
  ) -> Self:
56
- """Parse a mapping into a ``ProfileConfig`` instance.
59
+ """Parse a mapping into a :class:`ProfileConfig` instance.
57
60
 
58
61
  Parameters
59
62
  ----------
@@ -64,7 +67,7 @@ class ProfileConfig:
64
67
  -------
65
68
  Self
66
69
  Parsed profile configuration; non-mapping input yields a default
67
- instance. All ``env`` values are coerced to strings.
70
+ instance. All :attr:`env` values are coerced to strings.
68
71
  """
69
72
  if not isinstance(obj, Mapping):
70
73
  return cls()
@@ -0,0 +1,115 @@
1
+ """
2
+ :mod:`etlplus.workflow.types` module.
3
+
4
+ Type aliases and editor-only :class:`TypedDict`s for :mod:`etlplus.workflow`.
5
+
6
+ These types improve IDE autocomplete and static analysis while the runtime
7
+ parsers remain permissive.
8
+
9
+ Notes
10
+ -----
11
+ - TypedDicts in this module are intentionally ``total=False`` and are not
12
+ enforced at runtime.
13
+ - :meth:`*.from_obj` constructors accept :class:`Mapping[str, Any]` and perform
14
+ tolerant parsing and light casting. This keeps the runtime permissive while
15
+ improving autocomplete and static analysis for contributors.
16
+
17
+ Examples
18
+ --------
19
+ >>> from etlplus.workflow import Connector
20
+ >>> src: Connector = {
21
+ >>> "type": "file",
22
+ >>> "path": "/data/input.csv",
23
+ >>> }
24
+ >>> tgt: Connector = {
25
+ >>> "type": "database",
26
+ >>> "connection_string": "postgresql://user:pass@localhost/db",
27
+ >>> }
28
+ >>> from etlplus.api import RetryPolicy
29
+ >>> rp: RetryPolicy = {"max_attempts": 3, "backoff": 0.5}
30
+ """
31
+
32
+ from __future__ import annotations
33
+
34
+ from typing import Literal
35
+ from typing import TypedDict
36
+
37
+ from ..api import PaginationConfigMap
38
+ from ..api import RateLimitConfigMap
39
+ from ..types import StrAnyMap
40
+
41
+ # SECTION: EXPORTS ========================================================= #
42
+
43
+
44
+ __all__ = [
45
+ # Type Aliases
46
+ 'ConnectorType',
47
+ # Typed Dicts
48
+ 'ConnectorApiConfigMap',
49
+ 'ConnectorDbConfigMap',
50
+ 'ConnectorFileConfigMap',
51
+ ]
52
+
53
+
54
+ # SECTION: TYPE ALIASES ===================================================== #
55
+
56
+
57
+ # Literal type for supported connector kinds
58
+ type ConnectorType = Literal['api', 'database', 'file']
59
+
60
+
61
+ # SECTION: TYPED DICTS ====================================================== #
62
+
63
+
64
+ class ConnectorApiConfigMap(TypedDict, total=False):
65
+ """
66
+ Shape accepted by :meth:`ConnectorApi.from_obj` (all keys optional).
67
+
68
+ See Also
69
+ --------
70
+ - :meth:`etlplus.workflow.connector.ConnectorApi.from_obj`
71
+ """
72
+
73
+ name: str
74
+ type: ConnectorType
75
+ url: str
76
+ method: str
77
+ headers: StrAnyMap
78
+ query_params: StrAnyMap
79
+ pagination: PaginationConfigMap
80
+ rate_limit: RateLimitConfigMap
81
+ api: str
82
+ endpoint: str
83
+
84
+
85
+ class ConnectorDbConfigMap(TypedDict, total=False):
86
+ """
87
+ Shape accepted by :meth:`ConnectorDb.from_obj` (all keys optional).
88
+
89
+ See Also
90
+ --------
91
+ - :meth:`etlplus.workflow.connector.ConnectorDb.from_obj`
92
+ """
93
+
94
+ name: str
95
+ type: ConnectorType
96
+ connection_string: str
97
+ query: str
98
+ table: str
99
+ mode: str
100
+
101
+
102
+ class ConnectorFileConfigMap(TypedDict, total=False):
103
+ """
104
+ Shape accepted by :meth:`ConnectorFile.from_obj` (all keys optional).
105
+
106
+ See Also
107
+ --------
108
+ - :meth:`etlplus.workflow.connector.ConnectorFile.from_obj`
109
+ """
110
+
111
+ name: str
112
+ type: ConnectorType
113
+ format: str
114
+ path: str
115
+ options: StrAnyMap
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: etlplus
3
- Version: 0.14.3
3
+ Version: 0.15.2
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
 
@@ -1,25 +1,24 @@
1
- etlplus/README.md,sha256=HwDt6eh6p4422FOJhrpUBhfPGC82QzpsJNecs3zEtUU,1459
1
+ 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/dag.py,sha256=4EYmBsJax3y4clHv10jjdp3GrBBD_WblvtxUb_JxGCQ,2464
6
5
  etlplus/enums.py,sha256=ZxObavNilITJNT4Mf2hBy1s4kKtTFUTmrc8_whkxKNg,7541
7
6
  etlplus/mixins.py,sha256=ifGpHwWv7U00yqGf-kN93vJax2IiK4jaGtTsPsO3Oak,1350
8
7
  etlplus/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
9
- etlplus/types.py,sha256=LhyKU67CW7CcLEshE_1OIvEqWr-QVMJVYByf1221miY,6161
10
- etlplus/utils.py,sha256=BMLTWAvCJj3zLEcffBgURYnu0UGhhXsfH2WWpAt7fV8,13363
11
- etlplus/api/README.md,sha256=aGTbcL-EqaiMTS7GToibmeTIzjX-viP2OtUDfIJnZEo,7913
8
+ etlplus/types.py,sha256=-knM5bWRq49k4o-KlW-GRsENcj2P-h6oPnEmuz3EJso,6214
9
+ etlplus/utils.py,sha256=JVOBPyjIv1C9EZWZuYdqCISS-Dpa-PHrFvvruu1R0HA,17171
10
+ etlplus/api/README.md,sha256=amxS_eIcsnNuVvD0x_w8nkyfedOTYbhlY0gGhaFg0DE,8705
12
11
  etlplus/api/__init__.py,sha256=PK2lQv1FbsE7ZZS_ejevFZQSuOUHGApBc22YfHAzMqA,4615
13
12
  etlplus/api/auth.py,sha256=GOO5on-LoMS1GXTAhtK9rFcfpjbBcNeA6NE5UZwIq0g,12158
14
- etlplus/api/config.py,sha256=Xi1_FUaogQxAAx7LUTGwYr5vEB_SIFvjU_xgMGF2Fsc,17913
13
+ etlplus/api/config.py,sha256=_8_iXpaHXQN6RQ1z0e3q0LTY936IYsc1SVcE6_sPT6E,17639
15
14
  etlplus/api/endpoint_client.py,sha256=OPAvw3NkpSzeITqgRP1reyqX9Nc_XC8lAj6Yp7nV4Tw,30705
16
15
  etlplus/api/enums.py,sha256=Tvkru6V8fzQh2JM2FDLcA_yaPENOKz5JgzxLhieqEvc,1141
17
16
  etlplus/api/errors.py,sha256=XjI2xW-sypMUNUbqfc2S57-IGyWnH3oCDFhCmKYYI_Q,4648
18
17
  etlplus/api/request_manager.py,sha256=fhzPV5x7DqpKqoLvfDR8GKhBX_QBMtvZsRXxVnQQElY,18674
19
18
  etlplus/api/retry_manager.py,sha256=0GDhJVyIlb1Ww35JUWlYoa8QYUPjKLBtxQeZj3TdLbY,11306
20
19
  etlplus/api/transport.py,sha256=DVWzWFZLfQQXaTJ60w-SzdXRxiOE8llPprpUB5CtSyg,9410
21
- etlplus/api/types.py,sha256=ijHgREN5akEFF3th2yNdWbhJhXvAxh_24qQgg_sMB4w,4653
22
- etlplus/api/utils.py,sha256=I-19UPmBuOTLJs3fuCkCPbYUA4B3bXHmnRWSACP3n28,26134
20
+ etlplus/api/types.py,sha256=geuKmnf6C2P9_tpRpOF90Uu7J160OL3RQpQ_CgJsSrM,6695
21
+ etlplus/api/utils.py,sha256=U39OXcrPiLD9m0Y03pACXIIOyuuDPO6RRKuTcwEayBE,26249
23
22
  etlplus/api/pagination/__init__.py,sha256=a4UX2J0AG8RMvmHt_CCofUm5vSmFo6GAfkb8XnSXypM,1395
24
23
  etlplus/api/pagination/client.py,sha256=yMEpWqRxTCD4zRc9OYtEyUtShpGH5atiHFEAt95v2FE,5394
25
24
  etlplus/api/pagination/config.py,sha256=3dXDJ-nMbO9Zk6i344n4roBFbUlHsa294D1_plPmm6E,13579
@@ -27,35 +26,27 @@ etlplus/api/pagination/paginator.py,sha256=wtdY_er4yfjx5yTUQJ1gPq-IuWmpLAHeG5buB
27
26
  etlplus/api/rate_limiting/__init__.py,sha256=ZySB1dZettEDnWvI1EHf_TZ9L08M_kKsNR-Y_lbU6kI,1070
28
27
  etlplus/api/rate_limiting/config.py,sha256=eB-dSOG-c5awYeEpnDsQJ5pO8BJtEpGYxOunBetWiB0,9775
29
28
  etlplus/api/rate_limiting/rate_limiter.py,sha256=heAasm1KLeBFmoJKPz6W-eQbNuahMgG1E9-z8zGEUro,7035
30
- etlplus/cli/README.md,sha256=rl9VYNH5MluV0rh-eP7TbxJZ5BTMEIaksxhl_JXpYio,1233
29
+ etlplus/cli/README.md,sha256=8H_G2d3HteYIU6ReX9K9DM485QjWDT5vHMQbGD_vv20,1237
31
30
  etlplus/cli/__init__.py,sha256=J97-Rv931IL1_b4AXnB7Fbbd7HKnHBpx18NQfC_kE6c,299
32
- etlplus/cli/commands.py,sha256=g8_m3A8HEMyTRu2HctNiRoi2gtB5oSZCUEcyq-PIXos,24669
31
+ etlplus/cli/commands.py,sha256=HFlg29tO6Jwv1NXWAHmvniLCyRSlboL55Arn9B8nZAM,25028
33
32
  etlplus/cli/constants.py,sha256=E6Uy4WauLa_0zkzxqImXh-bb1gKdb9sBZQVc8QOzr2Q,1943
34
- etlplus/cli/handlers.py,sha256=gbW1jH348QmX65g4gffxrtMt2obFIw8X0dEKnwXQKPQ,18170
33
+ etlplus/cli/handlers.py,sha256=hXsgG3c6n8JDN4U3Svq6i2r21vetw5NcmXE1bGSwb9w,18560
35
34
  etlplus/cli/io.py,sha256=EFaBPYaBOyOllfMQWXgTjy-MPiGfNejicpD7ROrPyAE,7840
36
- etlplus/cli/main.py,sha256=IgeqxypixfwLHR-QcpgVMQ7vMZ865bXOh2oO9v-BWeM,5234
35
+ etlplus/cli/main.py,sha256=d5yhCS6aNo_TKMvhdTS7qeJm4yb1S58gGBrUoBV7SCs,5241
37
36
  etlplus/cli/options.py,sha256=vfXT3YLh7wG1iC-aTdSg6ItMC8l6n0Lozmy53XjqLbA,1199
38
- etlplus/cli/state.py,sha256=Pfd8ru0wYIN7eGp1_A0tioqs1LiCDZCuJ6AnjZb6yYQ,8027
37
+ etlplus/cli/state.py,sha256=3Dq5BKct0uAvRajtc2yHbsX7wqepZOwlAMKsyvQcnqk,7918
39
38
  etlplus/cli/types.py,sha256=tclhKVJXDqHzlTQBYKARfqMgDOcuBJ-Zej2pvFy96WM,652
40
- etlplus/config/README.md,sha256=ot6oFZxTz4x83mj1_FrQ13dO0z2QkRFDnkCkx7NPsSs,1636
41
- etlplus/config/__init__.py,sha256=VZWzOg7d2YR9NT6UwKTv44yf2FRUMjTHynkm1Dl5Qzo,1486
42
- etlplus/config/connector.py,sha256=0-TIwevHbKRHVmucvyGpPd-3tB1dKHB-dj0yJ6kq5eY,9809
43
- etlplus/config/jobs.py,sha256=oa2rNwacy2b_1HP_iFDLarGnn812ZVP2k5cHt4eqBIg,7843
44
- etlplus/config/pipeline.py,sha256=m4Jh0ctFcKrIx6zR7LEC0sYY5wq0o8NqOruWPlz6qmA,9494
45
- etlplus/config/profile.py,sha256=Ss2zedQGjkaGSpvBLTD4SZaWViMJ7TJPLB8Q2_BTpPg,1898
46
- etlplus/config/types.py,sha256=a0epJ3z16HQ5bY3Ctf8s_cQPa3f0HHcwdOcjCP2xoG4,4954
47
- etlplus/config/utils.py,sha256=4SUHMkt5bKBhMhiJm-DrnmE2Q4TfOgdNCKz8PJDS27o,3443
48
- etlplus/database/README.md,sha256=nUQVwLwGzmpA5_u4oYJYkPIhIuJAIdWsoeRgr4joAIE,1431
39
+ etlplus/database/README.md,sha256=3Af5BEGLkBmMoGOLtS1GQuj4wKPh_CwSp5NEPMf2uaY,1435
49
40
  etlplus/database/__init__.py,sha256=AKJsDl2RHuRGPS-eXgNJeh4aSncJP5Y0yLApBF6i7i8,1052
50
41
  etlplus/database/ddl.py,sha256=0dEM9SJMMabkhI_h-Fc0j9a1Sl5lSyZdI0bIeBVGm10,7913
51
- etlplus/database/engine.py,sha256=PUxXLvLPyc-KaxuW7fXe12wYci7EvUp-Ad1H3bGhUog,4058
52
- etlplus/database/orm.py,sha256=gCSqH-CjQz6tV9133-VqgiwokK5ylun0BwXaIWfImAo,10008
42
+ etlplus/database/engine.py,sha256=gWgTjGoo1HYHrBuYX5l2P8avAR3XithzAiqUOpLHP-8,4386
43
+ etlplus/database/orm.py,sha256=ZCHkeVEUns2eievlFzmLyVKA3YVPea1xs6vrcUBZ7Jw,10010
53
44
  etlplus/database/schema.py,sha256=813C0Dd3WE53KTYot4dgjAxctgKXLXx-8_Rk_4r2e28,7022
54
45
  etlplus/database/types.py,sha256=_pkQyC14TzAlgyeIqZG4F5LWYknZbHw3TW68Auk7Ya0,795
55
- etlplus/file/README.md,sha256=avWnyeKfs3uP3qa-DVBJ6t05jS2oFUPeQ3xf1Ph0eC0,3626
46
+ etlplus/file/README.md,sha256=ivU8svVs1fktQiW5ozvh1N-IOSLCAQ3oM9bW8DUFwIw,3630
56
47
  etlplus/file/__init__.py,sha256=X03bosSM-uSd6dh3ur0un6_ozFRw2Tm4PE6kVUjtXK8,475
57
48
  etlplus/file/_imports.py,sha256=9e8CWjyNIRcmiULEPuwtnJELUOXd4EvVv_vDnDYiB9c,3121
58
- etlplus/file/_io.py,sha256=GXTcvjfXQX4rSdyu1JNhFmqQJlirDqd8dEGCN3dHvNg,2968
49
+ etlplus/file/_io.py,sha256=2Dj7MH6r-yp_SsCe5GmuNN7Ta70qYzF_jKoMgnD3rME,3925
59
50
  etlplus/file/accdb.py,sha256=xdBLrXHDonVJ1Z6-qZRrLBXpUwqw5nZYxDuxYMJHzVs,1681
60
51
  etlplus/file/arrow.py,sha256=rYPqoCAI3cBHETYN3c0Xi7R5Nq7_prIdyESm3ll3Zos,1694
61
52
  etlplus/file/avro.py,sha256=yFQMnWPcvC0CbDCyagoB9SHRIuvl2SXIoQJTBIlw4dA,4437
@@ -77,7 +68,7 @@ etlplus/file/hdf5.py,sha256=SZ-UbXTJGOYA82hdma7AFulWo9emH5Kih_RXC7f-Bfk,1624
77
68
  etlplus/file/ini.py,sha256=HlvQyQC00oBD8KFBfznPjBx9wF1ZwXH7Yo1JaXqCq8I,1701
78
69
  etlplus/file/ion.py,sha256=9q938jROTAcuUT5sRYvS1qIeoz9p8KkVWYDDS2-2A_4,1710
79
70
  etlplus/file/jinja2.py,sha256=FFqGQjBnRgPQ-oJ3WqiKspJMj6g_J0fDKGwsoOJAEzk,1630
80
- etlplus/file/json.py,sha256=6EWsOI4RZo366FYsnPp-VkHdgAVBRVUwix-hAJZQM10,2537
71
+ etlplus/file/json.py,sha256=m4eM8cPGHYAEppwLqBdq-t9gC2GtKPLptRTBeBfRimY,2130
81
72
  etlplus/file/log.py,sha256=OmsGijXZn1VhN7BUklF8saoktxkmHh1MPLI_BbGDLyc,1681
82
73
  etlplus/file/mat.py,sha256=u3jWMK8c4k9L0uVRiQSd7JgVQF-efoJj3QiKYtt1arA,1654
83
74
  etlplus/file/mdb.py,sha256=hSCaxBbc_b9dGTBpR-Gb0UTY2r3zYUxoEiKuwpnx0kI,1657
@@ -112,24 +103,32 @@ etlplus/file/xlsm.py,sha256=6meoukAvpEIm_mvVomIo2oefPYfmHHXfE1XmFfeFpvY,1738
112
103
  etlplus/file/xlsx.py,sha256=vtiAS8Ng9FV1vCWYTd1YO2ORKIJG3HDfmqy3NkVpt0A,2182
113
104
  etlplus/file/xml.py,sha256=p5P60DiV6hyiz-t970d0d0ZXB41gVvAm3MT7dTMULa8,4360
114
105
  etlplus/file/xpt.py,sha256=JLqOkZ60awNsPXSqLKcPUwqZLPhPR05zk4EVRdEfvoU,1702
115
- etlplus/file/yaml.py,sha256=8BEqCELaTQ_nRu1iksLBHVj19P6JmcUf5__fe0yVigw,2449
106
+ etlplus/file/yaml.py,sha256=P9xzginPVVyvIPbFAp6MYWwARhK50GzgMbjZB7HwOrs,2052
116
107
  etlplus/file/zip.py,sha256=nd26V3S0edklriKnKOGDTLlO8RBXTda_zLLEQrJgKL4,4185
117
108
  etlplus/file/zsav.py,sha256=2WxjXamvzj0adDbWGMWM3-cj_LsCRjyZz4J907lNkPk,1664
118
109
  etlplus/ops/README.md,sha256=8omi7DYZhelc26JKk8Cm8QR8I3OGwziysPj1ivx41iQ,1380
119
110
  etlplus/ops/__init__.py,sha256=NIIr2f-AZj5B0piBt6gjv46Yn0SzGYxEe6BPoopRh38,1702
120
111
  etlplus/ops/extract.py,sha256=OJozX25qTjME7m9aTdVPJScT3GHHgopGM8uHo_rHm1Y,5783
121
112
  etlplus/ops/load.py,sha256=RgEKnVygRN2cPDpzihU8UsIhd4eVoj0cPe0jBuNC0u4,8328
122
- etlplus/ops/run.py,sha256=4ACM-bHoiBDbUdF9DnEJYFsIvKjZobW0nXTbVHCg4Xo,13393
113
+ etlplus/ops/run.py,sha256=JOPQxrciRUQ67FJhUcZ-pW1aiYGZUdxHLwhzWLNCaDo,13528
123
114
  etlplus/ops/transform.py,sha256=1P43WYUaw872JDU86FhbbbkP8xnBWpgEPn2Q-z4ywls,25421
124
- etlplus/ops/utils.py,sha256=tbV-s3NjIGO-GfdyJFxPYIYihPibNo-4TbdRq9vWVWs,11480
125
- etlplus/ops/validate.py,sha256=gLa5zcwhxGbaIhH-OqTwDsQAgAYZSajLVGwwyeT2OZk,13257
126
- etlplus/templates/README.md,sha256=kHSZ8FWcrlrcWz0hBIbho-k1Bi-PL-DQ7g02o-g70c8,1355
115
+ etlplus/ops/utils.py,sha256=mNUcbnLl3M6rA_BPoUqG-IFPqT1zrp_EkQTs7uvzBIQ,10839
116
+ etlplus/ops/validate.py,sha256=-OLAwQNNCmmDbmj0SB7zzYXDkJfcyBP_z9nTpqImLP0,13271
117
+ etlplus/templates/README.md,sha256=IfPXlj1TGVA-uFWosHJhE2rabFW-znxOlOMazO9Z5cE,1361
127
118
  etlplus/templates/__init__.py,sha256=tsniN7XJYs3NwYxJ6c2HD5upHP3CDkLx-bQCMt97UOM,106
128
119
  etlplus/templates/ddl.sql.j2,sha256=s8fMWvcb4eaJVXkifuib1aQPljtZ8buuyB_uA-ZdU3Q,4734
129
120
  etlplus/templates/view.sql.j2,sha256=Iy8DHfhq5yyvrUKDxqp_aHIEXY4Tm6j4wT7YDEFWAhk,2180
130
- etlplus-0.14.3.dist-info/licenses/LICENSE,sha256=MuNO63i6kWmgnV2pbP2SLqP54mk1BGmu7CmbtxMmT-U,1069
131
- etlplus-0.14.3.dist-info/METADATA,sha256=0I15VHV30nTVM3CMhDZZEImeC6LV_9jtF9Fnbi3rSWg,28115
132
- etlplus-0.14.3.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
133
- etlplus-0.14.3.dist-info/entry_points.txt,sha256=6w-2-jzuPa55spzK34h-UKh2JTEShh38adFRONNP9QE,45
134
- etlplus-0.14.3.dist-info/top_level.txt,sha256=aWWF-udn_sLGuHTM6W6MLh99ArS9ROkUWO8Mi8y1_2U,8
135
- etlplus-0.14.3.dist-info/RECORD,,
121
+ etlplus/workflow/README.md,sha256=D1oloiJCOHiqpqgv3m3qpRSIUOMIQcWtIsOPv7KkNI0,1652
122
+ etlplus/workflow/__init__.py,sha256=LxI9VGlDBUc9ADoK8JNn3oVsGeaz1Uhjonn4Y5KIJdM,967
123
+ etlplus/workflow/connector.py,sha256=vnzq9-qcU4ThWeI3ZJcL8iCoaKWrSEtZ9Jixn4il2KE,9995
124
+ etlplus/workflow/dag.py,sha256=kp31dORgk0GHbct_bipU5hu_0elwBtwLsXGjMWuhFHI,2503
125
+ etlplus/workflow/jobs.py,sha256=5_jhPoT2hCGTgsbK_lIPKrB94f7tzOEUJxtU3tpvTjg,8947
126
+ etlplus/workflow/pipeline.py,sha256=eF6OYMXZ_YdDPZ5FJC6OTCAM-zsb8HxhX3IHpbb_N8w,9631
127
+ etlplus/workflow/profile.py,sha256=dZ6P50k_ZqXnrbgrbODUqgVkymbchcEqfZR-ExjTd3M,1935
128
+ etlplus/workflow/types.py,sha256=Lv1MLyM45Ob5AsMQQBqzbUaD8g7HMVxu_HoQGPeiugU,2771
129
+ etlplus-0.15.2.dist-info/licenses/LICENSE,sha256=MuNO63i6kWmgnV2pbP2SLqP54mk1BGmu7CmbtxMmT-U,1069
130
+ etlplus-0.15.2.dist-info/METADATA,sha256=Vu5cWh8OqcpKUfvMur07I7k5QlUIIFgs5tzmKv2eGG4,28114
131
+ etlplus-0.15.2.dist-info/WHEEL,sha256=qELbo2s1Yzl39ZmrAibXA2jjPLUYfnVhUNTlyF1rq0Y,92
132
+ etlplus-0.15.2.dist-info/entry_points.txt,sha256=6w-2-jzuPa55spzK34h-UKh2JTEShh38adFRONNP9QE,45
133
+ etlplus-0.15.2.dist-info/top_level.txt,sha256=aWWF-udn_sLGuHTM6W6MLh99ArS9ROkUWO8Mi8y1_2U,8
134
+ etlplus-0.15.2.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (80.9.0)
2
+ Generator: setuptools (80.10.1)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5
 
etlplus/config/types.py DELETED
@@ -1,204 +0,0 @@
1
- """
2
- :mod:`etlplus.config.types` module.
3
-
4
- Type aliases and editor-only TypedDicts for :mod:`etlplus.config`.
5
-
6
- These types improve IDE autocomplete and static analysis while the runtime
7
- parsers remain permissive.
8
-
9
- Notes
10
- -----
11
- - TypedDicts in this module are intentionally ``total=False`` and are not
12
- enforced at runtime.
13
- - ``*.from_obj`` constructors accept ``Mapping[str, Any]`` and perform
14
- tolerant parsing and light casting. This keeps the runtime permissive while
15
- improving autocomplete and static analysis for contributors.
16
-
17
- Examples
18
- --------
19
- >>> from etlplus.config import Connector
20
- >>> src: Connector = {
21
- >>> "type": "file",
22
- >>> "path": "/data/input.csv",
23
- >>> }
24
- >>> tgt: Connector = {
25
- >>> "type": "database",
26
- >>> "connection_string": "postgresql://user:pass@localhost/db",
27
- >>> }
28
- >>> from etlplus.api import RetryPolicy
29
- >>> rp: RetryPolicy = {"max_attempts": 3, "backoff": 0.5}
30
- """
31
-
32
- from __future__ import annotations
33
-
34
- from collections.abc import Mapping
35
- from typing import Any
36
- from typing import Literal
37
- from typing import TypedDict
38
-
39
- from ..api import PaginationConfigMap
40
- from ..api import RateLimitConfigMap
41
- from ..types import StrAnyMap
42
-
43
- # SECTION: EXPORTS ========================================================= #
44
-
45
-
46
- __all__ = [
47
- # Type aliases
48
- 'ConnectorType',
49
- # 'PaginationType',
50
- # TypedDicts
51
- 'ApiProfileDefaultsMap',
52
- 'ApiProfileConfigMap',
53
- 'ApiConfigMap',
54
- 'EndpointMap',
55
- 'ConnectorApiConfigMap',
56
- 'ConnectorDbConfigMap',
57
- 'ConnectorFileConfigMap',
58
- ]
59
-
60
-
61
- # SECTION: TYPE ALIASES ===================================================== #
62
-
63
-
64
- # Literal type for supported connector kinds
65
- type ConnectorType = Literal['api', 'database', 'file']
66
-
67
- # Literal type for supported pagination kinds
68
- # type PaginationType = Literal['page', 'offset', 'cursor']
69
-
70
-
71
- # SECTION: TYPED DICTS ====================================================== #
72
-
73
-
74
- class ApiConfigMap(TypedDict, total=False):
75
- """
76
- Top-level API config shape parsed by ApiConfig.from_obj.
77
-
78
- Either provide a 'base_url' with optional 'headers' and 'endpoints', or
79
- provide 'profiles' with at least one profile having a 'base_url'.
80
-
81
- See Also
82
- --------
83
- - etlplus.config.api.ApiConfig.from_obj: parses this mapping
84
- """
85
-
86
- base_url: str
87
- headers: StrAnyMap
88
- endpoints: Mapping[str, EndpointMap | str]
89
- profiles: Mapping[str, ApiProfileConfigMap]
90
-
91
-
92
- class ApiProfileConfigMap(TypedDict, total=False):
93
- """
94
- Shape accepted for a profile entry under ApiConfigMap.profiles.
95
-
96
- Notes
97
- -----
98
- `base_url` is required at runtime when profiles are provided.
99
-
100
- See Also
101
- --------
102
- - etlplus.config.api.ApiProfileConfig.from_obj: parses this mapping
103
- """
104
-
105
- base_url: str
106
- headers: StrAnyMap
107
- base_path: str
108
- auth: StrAnyMap
109
- defaults: ApiProfileDefaultsMap
110
-
111
-
112
- class ApiProfileDefaultsMap(TypedDict, total=False):
113
- """
114
- Defaults block available under a profile (all keys optional).
115
-
116
- Notes
117
- -----
118
- Runtime expects header values to be str; typing remains permissive.
119
-
120
- See Also
121
- --------
122
- - etlplus.config.api.ApiProfileConfig.from_obj: consumes this block
123
- - etlplus.config.pagination.PaginationConfig.from_obj: parses pagination
124
- - etlplus.api.rate_limiting.RateLimitConfig.from_obj: parses rate_limit
125
- """
126
-
127
- headers: StrAnyMap
128
- pagination: PaginationConfigMap | StrAnyMap
129
- rate_limit: RateLimitConfigMap | StrAnyMap
130
-
131
-
132
- class ConnectorApiConfigMap(TypedDict, total=False):
133
- """
134
- Shape accepted by ConnectorApi.from_obj (all keys optional).
135
-
136
- See Also
137
- --------
138
- - etlplus.config.connector.ConnectorApi.from_obj
139
- """
140
-
141
- name: str
142
- type: ConnectorType
143
- url: str
144
- method: str
145
- headers: StrAnyMap
146
- query_params: StrAnyMap
147
- pagination: PaginationConfigMap
148
- rate_limit: RateLimitConfigMap
149
- api: str
150
- endpoint: str
151
-
152
-
153
- class ConnectorDbConfigMap(TypedDict, total=False):
154
- """
155
- Shape accepted by ConnectorDb.from_obj (all keys optional).
156
-
157
- See Also
158
- --------
159
- - etlplus.config.connector.ConnectorDb.from_obj
160
- """
161
-
162
- name: str
163
- type: ConnectorType
164
- connection_string: str
165
- query: str
166
- table: str
167
- mode: str
168
-
169
-
170
- class ConnectorFileConfigMap(TypedDict, total=False):
171
- """
172
- Shape accepted by ConnectorFile.from_obj (all keys optional).
173
-
174
- See Also
175
- --------
176
- - etlplus.config.connector.ConnectorFile.from_obj
177
- """
178
-
179
- name: str
180
- type: ConnectorType
181
- format: str
182
- path: str
183
- options: StrAnyMap
184
-
185
-
186
- class EndpointMap(TypedDict, total=False):
187
- """
188
- Shape accepted by EndpointConfig.from_obj.
189
-
190
- One of 'path' or 'url' should be provided.
191
-
192
- See Also
193
- --------
194
- - etlplus.config.api.EndpointConfig.from_obj: parses this mapping
195
- """
196
-
197
- path: str
198
- url: str
199
- method: str
200
- path_params: StrAnyMap
201
- query_params: StrAnyMap
202
- body: Any
203
- pagination: PaginationConfigMap
204
- rate_limit: RateLimitConfigMap
etlplus/config/utils.py DELETED
@@ -1,120 +0,0 @@
1
- """
2
- :mod:`etlplus.config.utils` module.
3
-
4
- A module defining utility helpers for ETL pipeline configuration.
5
-
6
- Notes
7
- -----
8
- - Inputs to parsers favor ``Mapping[str, Any]`` to remain permissive and
9
- avoid unnecessary copies; normalization returns concrete types.
10
- - Substitution is shallow for strings and recursive for containers.
11
- - Numeric coercion helpers are intentionally forgiving: invalid values
12
- become ``None`` rather than raising.
13
- """
14
-
15
- from __future__ import annotations
16
-
17
- from collections.abc import Iterable
18
- from collections.abc import Mapping
19
- from typing import Any
20
-
21
- from ..types import StrAnyMap
22
-
23
- # SECTION: EXPORTS ========================================================== #
24
-
25
-
26
- __all__ = [
27
- # Functions
28
- 'deep_substitute',
29
- ]
30
-
31
-
32
- # SECTION: FUNCTIONS ======================================================== #
33
-
34
-
35
- def deep_substitute(
36
- value: Any,
37
- vars_map: StrAnyMap | None,
38
- env_map: Mapping[str, str] | None,
39
- ) -> Any:
40
- """
41
- Recursively substitute ``${VAR}`` tokens in nested structures.
42
-
43
- Only strings are substituted; other types are returned as-is.
44
-
45
- Parameters
46
- ----------
47
- value : Any
48
- The value to perform substitutions on.
49
- vars_map : StrAnyMap | None
50
- Mapping of variable names to replacement values (lower precedence).
51
- env_map : Mapping[str, str] | None
52
- Mapping of environment variables overriding ``vars_map`` values (higher
53
- precedence).
54
-
55
- Returns
56
- -------
57
- Any
58
- New structure with substitutions applied where tokens were found.
59
- """
60
- substitutions = _prepare_substitutions(vars_map, env_map)
61
-
62
- def _apply(node: Any) -> Any:
63
- match node:
64
- case str():
65
- return _replace_tokens(node, substitutions)
66
- case Mapping():
67
- return {k: _apply(v) for k, v in node.items()}
68
- case list() | tuple() as seq:
69
- apply = [_apply(item) for item in seq]
70
- return apply if isinstance(seq, list) else tuple(apply)
71
- case set():
72
- return {_apply(item) for item in node}
73
- case frozenset():
74
- return frozenset(_apply(item) for item in node)
75
- case _:
76
- return node
77
-
78
- return _apply(value)
79
-
80
-
81
- # SECTION: INTERNAL FUNCTIONS ============================================== #
82
-
83
-
84
- def _prepare_substitutions(
85
- vars_map: StrAnyMap | None,
86
- env_map: Mapping[str, Any] | None,
87
- ) -> tuple[tuple[str, Any], ...]:
88
- """Merge variable and environment maps into an ordered substitutions list.
89
-
90
- Parameters
91
- ----------
92
- vars_map : StrAnyMap | None
93
- Mapping of variable names to replacement values (lower precedence).
94
- env_map : Mapping[str, Any] | None
95
- Environment-backed values that override entries from ``vars_map``.
96
-
97
- Returns
98
- -------
99
- tuple[tuple[str, Any], ...]
100
- Immutable sequence of ``(name, value)`` pairs suitable for token
101
- replacement.
102
- """
103
- if not vars_map and not env_map:
104
- return ()
105
- merged: dict[str, Any] = {**(vars_map or {}), **(env_map or {})}
106
- return tuple(merged.items())
107
-
108
-
109
- def _replace_tokens(
110
- text: str,
111
- substitutions: Iterable[tuple[str, Any]],
112
- ) -> str:
113
- if not substitutions:
114
- return text
115
- out = text
116
- for name, replacement in substitutions:
117
- token = f'${{{name}}}'
118
- if token in out:
119
- out = out.replace(token, str(replacement))
120
- return out