etlplus 0.9.0__py3-none-any.whl → 0.9.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 (120) hide show
  1. etlplus/README.md +37 -0
  2. etlplus/__init__.py +1 -26
  3. etlplus/api/README.md +51 -3
  4. etlplus/api/__init__.py +10 -0
  5. etlplus/api/config.py +39 -28
  6. etlplus/api/endpoint_client.py +3 -3
  7. etlplus/api/enums.py +51 -0
  8. etlplus/api/pagination/client.py +1 -1
  9. etlplus/api/rate_limiting/config.py +13 -1
  10. etlplus/api/rate_limiting/rate_limiter.py +8 -11
  11. etlplus/api/request_manager.py +11 -6
  12. etlplus/api/transport.py +14 -2
  13. etlplus/api/types.py +96 -6
  14. etlplus/{run_helpers.py → api/utils.py} +209 -153
  15. etlplus/cli/README.md +40 -0
  16. etlplus/cli/commands.py +94 -61
  17. etlplus/cli/constants.py +1 -1
  18. etlplus/cli/handlers.py +40 -12
  19. etlplus/cli/io.py +2 -2
  20. etlplus/cli/main.py +1 -1
  21. etlplus/cli/state.py +4 -7
  22. etlplus/database/README.md +48 -0
  23. etlplus/database/ddl.py +1 -1
  24. etlplus/database/engine.py +19 -3
  25. etlplus/database/orm.py +2 -0
  26. etlplus/database/schema.py +1 -1
  27. etlplus/enums.py +1 -107
  28. etlplus/file/README.md +105 -0
  29. etlplus/file/__init__.py +25 -0
  30. etlplus/file/_imports.py +141 -0
  31. etlplus/file/_io.py +160 -0
  32. etlplus/file/accdb.py +78 -0
  33. etlplus/file/arrow.py +78 -0
  34. etlplus/file/avro.py +176 -0
  35. etlplus/file/bson.py +77 -0
  36. etlplus/file/cbor.py +78 -0
  37. etlplus/file/cfg.py +79 -0
  38. etlplus/file/conf.py +80 -0
  39. etlplus/file/core.py +322 -0
  40. etlplus/file/csv.py +79 -0
  41. etlplus/file/dat.py +78 -0
  42. etlplus/file/dta.py +77 -0
  43. etlplus/file/duckdb.py +78 -0
  44. etlplus/file/enums.py +343 -0
  45. etlplus/file/feather.py +111 -0
  46. etlplus/file/fwf.py +77 -0
  47. etlplus/file/gz.py +123 -0
  48. etlplus/file/hbs.py +78 -0
  49. etlplus/file/hdf5.py +78 -0
  50. etlplus/file/ini.py +79 -0
  51. etlplus/file/ion.py +78 -0
  52. etlplus/file/jinja2.py +78 -0
  53. etlplus/file/json.py +98 -0
  54. etlplus/file/log.py +78 -0
  55. etlplus/file/mat.py +78 -0
  56. etlplus/file/mdb.py +78 -0
  57. etlplus/file/msgpack.py +78 -0
  58. etlplus/file/mustache.py +78 -0
  59. etlplus/file/nc.py +78 -0
  60. etlplus/file/ndjson.py +108 -0
  61. etlplus/file/numbers.py +75 -0
  62. etlplus/file/ods.py +79 -0
  63. etlplus/file/orc.py +111 -0
  64. etlplus/file/parquet.py +113 -0
  65. etlplus/file/pb.py +78 -0
  66. etlplus/file/pbf.py +77 -0
  67. etlplus/file/properties.py +78 -0
  68. etlplus/file/proto.py +77 -0
  69. etlplus/file/psv.py +79 -0
  70. etlplus/file/rda.py +78 -0
  71. etlplus/file/rds.py +78 -0
  72. etlplus/file/sas7bdat.py +78 -0
  73. etlplus/file/sav.py +77 -0
  74. etlplus/file/sqlite.py +78 -0
  75. etlplus/file/stub.py +84 -0
  76. etlplus/file/sylk.py +77 -0
  77. etlplus/file/tab.py +81 -0
  78. etlplus/file/toml.py +78 -0
  79. etlplus/file/tsv.py +80 -0
  80. etlplus/file/txt.py +102 -0
  81. etlplus/file/vm.py +78 -0
  82. etlplus/file/wks.py +77 -0
  83. etlplus/file/xls.py +88 -0
  84. etlplus/file/xlsm.py +79 -0
  85. etlplus/file/xlsx.py +99 -0
  86. etlplus/file/xml.py +185 -0
  87. etlplus/file/xpt.py +78 -0
  88. etlplus/file/yaml.py +95 -0
  89. etlplus/file/zip.py +175 -0
  90. etlplus/file/zsav.py +77 -0
  91. etlplus/ops/README.md +50 -0
  92. etlplus/ops/__init__.py +61 -0
  93. etlplus/{extract.py → ops/extract.py} +81 -99
  94. etlplus/{load.py → ops/load.py} +78 -101
  95. etlplus/{run.py → ops/run.py} +159 -127
  96. etlplus/{transform.py → ops/transform.py} +75 -68
  97. etlplus/{validation → ops}/utils.py +53 -17
  98. etlplus/{validate.py → ops/validate.py} +22 -12
  99. etlplus/templates/README.md +46 -0
  100. etlplus/types.py +5 -4
  101. etlplus/utils.py +136 -2
  102. etlplus/workflow/README.md +52 -0
  103. etlplus/{config → workflow}/__init__.py +10 -23
  104. etlplus/{config → workflow}/connector.py +58 -44
  105. etlplus/workflow/dag.py +105 -0
  106. etlplus/{config → workflow}/jobs.py +105 -32
  107. etlplus/{config → workflow}/pipeline.py +59 -51
  108. etlplus/{config → workflow}/profile.py +8 -5
  109. etlplus/workflow/types.py +115 -0
  110. {etlplus-0.9.0.dist-info → etlplus-0.9.2.dist-info}/METADATA +210 -17
  111. etlplus-0.9.2.dist-info/RECORD +134 -0
  112. {etlplus-0.9.0.dist-info → etlplus-0.9.2.dist-info}/WHEEL +1 -1
  113. etlplus/config/types.py +0 -204
  114. etlplus/config/utils.py +0 -120
  115. etlplus/file.py +0 -657
  116. etlplus/validation/__init__.py +0 -44
  117. etlplus-0.9.0.dist-info/RECORD +0 -65
  118. {etlplus-0.9.0.dist-info → etlplus-0.9.2.dist-info}/entry_points.txt +0 -0
  119. {etlplus-0.9.0.dist-info → etlplus-0.9.2.dist-info}/licenses/LICENSE +0 -0
  120. {etlplus-0.9.0.dist-info → etlplus-0.9.2.dist-info}/top_level.txt +0 -0
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