etlplus 0.14.3__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.
- etlplus/README.md +4 -4
- etlplus/api/README.md +33 -2
- etlplus/api/auth.py +1 -1
- etlplus/api/config.py +5 -10
- etlplus/api/endpoint_client.py +4 -4
- etlplus/api/pagination/config.py +1 -1
- etlplus/api/pagination/paginator.py +6 -7
- etlplus/api/rate_limiting/config.py +4 -4
- etlplus/api/rate_limiting/rate_limiter.py +1 -1
- etlplus/api/retry_manager.py +2 -2
- etlplus/api/transport.py +1 -1
- etlplus/api/types.py +99 -0
- etlplus/api/utils.py +6 -2
- etlplus/cli/README.md +2 -2
- etlplus/cli/commands.py +75 -42
- etlplus/cli/constants.py +1 -1
- etlplus/cli/handlers.py +33 -15
- etlplus/cli/io.py +2 -2
- etlplus/cli/main.py +2 -2
- etlplus/cli/state.py +4 -7
- etlplus/connector/__init__.py +43 -0
- etlplus/connector/api.py +161 -0
- etlplus/connector/connector.py +26 -0
- etlplus/connector/core.py +132 -0
- etlplus/connector/database.py +122 -0
- etlplus/connector/enums.py +52 -0
- etlplus/connector/file.py +120 -0
- etlplus/connector/types.py +40 -0
- etlplus/connector/utils.py +122 -0
- etlplus/database/README.md +2 -2
- etlplus/database/ddl.py +2 -2
- etlplus/database/engine.py +19 -3
- etlplus/database/orm.py +2 -0
- etlplus/enums.py +1 -33
- etlplus/file/README.md +2 -2
- etlplus/file/_imports.py +1 -0
- etlplus/file/_io.py +52 -4
- etlplus/file/accdb.py +3 -2
- etlplus/file/arrow.py +3 -2
- etlplus/file/avro.py +3 -2
- etlplus/file/bson.py +3 -2
- etlplus/file/cbor.py +3 -2
- etlplus/file/cfg.py +3 -2
- etlplus/file/conf.py +3 -2
- etlplus/file/core.py +11 -8
- etlplus/file/csv.py +3 -2
- etlplus/file/dat.py +3 -2
- etlplus/file/dta.py +3 -2
- etlplus/file/duckdb.py +3 -2
- etlplus/file/enums.py +1 -1
- etlplus/file/feather.py +3 -2
- etlplus/file/fwf.py +3 -2
- etlplus/file/gz.py +3 -2
- etlplus/file/hbs.py +3 -2
- etlplus/file/hdf5.py +3 -2
- etlplus/file/ini.py +3 -2
- etlplus/file/ion.py +3 -2
- etlplus/file/jinja2.py +3 -2
- etlplus/file/json.py +5 -16
- etlplus/file/log.py +3 -2
- etlplus/file/mat.py +3 -2
- etlplus/file/mdb.py +3 -2
- etlplus/file/msgpack.py +3 -2
- etlplus/file/mustache.py +3 -2
- etlplus/file/nc.py +3 -2
- etlplus/file/ndjson.py +3 -2
- etlplus/file/numbers.py +3 -2
- etlplus/file/ods.py +3 -2
- etlplus/file/orc.py +3 -2
- etlplus/file/parquet.py +3 -2
- etlplus/file/pb.py +3 -2
- etlplus/file/pbf.py +3 -2
- etlplus/file/properties.py +3 -2
- etlplus/file/proto.py +3 -2
- etlplus/file/psv.py +3 -2
- etlplus/file/rda.py +3 -2
- etlplus/file/rds.py +3 -2
- etlplus/file/sas7bdat.py +3 -2
- etlplus/file/sav.py +3 -2
- etlplus/file/sqlite.py +3 -2
- etlplus/file/stub.py +1 -0
- etlplus/file/sylk.py +3 -2
- etlplus/file/tab.py +3 -2
- etlplus/file/toml.py +3 -2
- etlplus/file/tsv.py +3 -2
- etlplus/file/txt.py +4 -3
- etlplus/file/vm.py +3 -2
- etlplus/file/wks.py +3 -2
- etlplus/file/xls.py +3 -2
- etlplus/file/xlsm.py +3 -2
- etlplus/file/xlsx.py +3 -2
- etlplus/file/xml.py +9 -3
- etlplus/file/xpt.py +3 -2
- etlplus/file/yaml.py +5 -16
- etlplus/file/zip.py +3 -2
- etlplus/file/zsav.py +3 -2
- etlplus/ops/extract.py +13 -1
- etlplus/ops/load.py +15 -2
- etlplus/ops/run.py +18 -13
- etlplus/ops/transform.py +2 -2
- etlplus/ops/utils.py +6 -35
- etlplus/ops/validate.py +3 -3
- etlplus/templates/README.md +2 -2
- etlplus/types.py +3 -2
- etlplus/utils.py +163 -29
- etlplus/{config → workflow}/README.md +6 -6
- etlplus/workflow/__init__.py +32 -0
- etlplus/{dag.py → workflow/dag.py} +6 -4
- etlplus/{config → workflow}/jobs.py +101 -38
- etlplus/{config → workflow}/pipeline.py +59 -51
- etlplus/{config → workflow}/profile.py +8 -5
- {etlplus-0.14.3.dist-info → etlplus-0.16.0.dist-info}/METADATA +4 -4
- etlplus-0.16.0.dist-info/RECORD +141 -0
- {etlplus-0.14.3.dist-info → etlplus-0.16.0.dist-info}/WHEEL +1 -1
- etlplus/config/__init__.py +0 -56
- etlplus/config/connector.py +0 -372
- etlplus/config/types.py +0 -204
- etlplus/config/utils.py +0 -120
- etlplus-0.14.3.dist-info/RECORD +0 -135
- {etlplus-0.14.3.dist-info → etlplus-0.16.0.dist-info}/entry_points.txt +0 -0
- {etlplus-0.14.3.dist-info → etlplus-0.16.0.dist-info}/licenses/LICENSE +0 -0
- {etlplus-0.14.3.dist-info → etlplus-0.16.0.dist-info}/top_level.txt +0 -0
etlplus/config/__init__.py
DELETED
|
@@ -1,56 +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 .connector import Connector
|
|
20
|
-
from .connector import ConnectorApi
|
|
21
|
-
from .connector import ConnectorDb
|
|
22
|
-
from .connector import ConnectorFile
|
|
23
|
-
from .connector import parse_connector
|
|
24
|
-
from .jobs import ExtractRef
|
|
25
|
-
from .jobs import JobConfig
|
|
26
|
-
from .jobs import LoadRef
|
|
27
|
-
from .jobs import TransformRef
|
|
28
|
-
from .jobs import ValidationRef
|
|
29
|
-
from .pipeline import PipelineConfig
|
|
30
|
-
from .pipeline import load_pipeline_config
|
|
31
|
-
from .profile import ProfileConfig
|
|
32
|
-
from .types import ConnectorType
|
|
33
|
-
|
|
34
|
-
# SECTION: EXPORTS ========================================================== #
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
__all__ = [
|
|
38
|
-
# Connectors
|
|
39
|
-
'Connector',
|
|
40
|
-
'ConnectorType',
|
|
41
|
-
'ConnectorApi',
|
|
42
|
-
'ConnectorDb',
|
|
43
|
-
'ConnectorFile',
|
|
44
|
-
'parse_connector',
|
|
45
|
-
# Jobs / Refs
|
|
46
|
-
'ExtractRef',
|
|
47
|
-
'JobConfig',
|
|
48
|
-
'LoadRef',
|
|
49
|
-
'TransformRef',
|
|
50
|
-
'ValidationRef',
|
|
51
|
-
# Pipeline
|
|
52
|
-
'PipelineConfig',
|
|
53
|
-
'load_pipeline_config',
|
|
54
|
-
# Profile
|
|
55
|
-
'ProfileConfig',
|
|
56
|
-
]
|
etlplus/config/connector.py
DELETED
|
@@ -1,372 +0,0 @@
|
|
|
1
|
-
"""
|
|
2
|
-
:mod:`etlplus.config.connector` module.
|
|
3
|
-
|
|
4
|
-
A module defining configuration types for data source/target connectors in ETL
|
|
5
|
-
pipelines. A "connector" is any I/O endpoint:
|
|
6
|
-
|
|
7
|
-
- file (local/remote file systems)
|
|
8
|
-
- database
|
|
9
|
-
- REST API service/endpoint
|
|
10
|
-
- (future) queues, streams, etc.
|
|
11
|
-
|
|
12
|
-
Examples
|
|
13
|
-
--------
|
|
14
|
-
- Use ``ConnectorApi``/``ConnectorFile``/``ConnectorDb`` when you want the
|
|
15
|
-
concrete dataclasses.
|
|
16
|
-
- Use the ``Connector`` union for typing a value that can be any connector.
|
|
17
|
-
- Use ``parse_connector(obj)`` to construct a connector instance from a generic
|
|
18
|
-
mapping that includes a ``type`` key.
|
|
19
|
-
|
|
20
|
-
Notes
|
|
21
|
-
-----
|
|
22
|
-
- TypedDict shapes are editor hints; runtime parsing remains permissive
|
|
23
|
-
(from_obj accepts Mapping[str, Any]).
|
|
24
|
-
- TypedDicts referenced in :mod:`etlplus.config.types` remain editor hints.
|
|
25
|
-
Runtime parsing stays permissive and tolerant.
|
|
26
|
-
|
|
27
|
-
See Also
|
|
28
|
-
--------
|
|
29
|
-
- TypedDict shapes for editor hints (not enforced at runtime):
|
|
30
|
-
:mod:`etlplus.config.types.ConnectorApiConfigMap`,
|
|
31
|
-
:mod:`etlplus.config.types.ConnectorDbConfigMap`,
|
|
32
|
-
:mod:`etlplus.config.types.ConnectorFileConfigMap`.
|
|
33
|
-
"""
|
|
34
|
-
|
|
35
|
-
from __future__ import annotations
|
|
36
|
-
|
|
37
|
-
from collections.abc import Mapping
|
|
38
|
-
from dataclasses import dataclass
|
|
39
|
-
from dataclasses import field
|
|
40
|
-
from typing import TYPE_CHECKING
|
|
41
|
-
from typing import Any
|
|
42
|
-
from typing import Self
|
|
43
|
-
from typing import overload
|
|
44
|
-
|
|
45
|
-
from ..api import PaginationConfig
|
|
46
|
-
from ..api import RateLimitConfig
|
|
47
|
-
from ..types import StrAnyMap
|
|
48
|
-
from ..utils import cast_str_dict
|
|
49
|
-
from ..utils import coerce_dict
|
|
50
|
-
|
|
51
|
-
if TYPE_CHECKING: # Editor-only typing hints to avoid runtime imports
|
|
52
|
-
from .types import ConnectorApiConfigMap
|
|
53
|
-
from .types import ConnectorDbConfigMap
|
|
54
|
-
from .types import ConnectorFileConfigMap
|
|
55
|
-
from .types import ConnectorType
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
# SECTION: EXPORTS ========================================================== #
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
__all__ = [
|
|
62
|
-
# Classes
|
|
63
|
-
'ConnectorApi',
|
|
64
|
-
'ConnectorDb',
|
|
65
|
-
'ConnectorFile',
|
|
66
|
-
# Functions
|
|
67
|
-
'parse_connector',
|
|
68
|
-
# Type aliases
|
|
69
|
-
'Connector',
|
|
70
|
-
]
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
# SECTION: DATA CLASSES ===================================================== #
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
@dataclass(kw_only=True, slots=True)
|
|
77
|
-
class ConnectorApi:
|
|
78
|
-
"""
|
|
79
|
-
Configuration for an API-based data connector.
|
|
80
|
-
|
|
81
|
-
Attributes
|
|
82
|
-
----------
|
|
83
|
-
name : str
|
|
84
|
-
Unique connector name.
|
|
85
|
-
type : ConnectorType
|
|
86
|
-
Connector kind literal, always ``"api"``.
|
|
87
|
-
url : str | None
|
|
88
|
-
Direct absolute URL (when not using ``service``/``endpoint`` refs).
|
|
89
|
-
method : str | None
|
|
90
|
-
Optional HTTP method; typically omitted for sources (defaults to
|
|
91
|
-
GET) and used for targets (e.g., ``"post"``).
|
|
92
|
-
headers : dict[str, str]
|
|
93
|
-
Additional request headers.
|
|
94
|
-
query_params : dict[str, Any]
|
|
95
|
-
Default query parameters.
|
|
96
|
-
pagination : PaginationConfig | None
|
|
97
|
-
Pagination settings (optional).
|
|
98
|
-
rate_limit : RateLimitConfig | None
|
|
99
|
-
Rate limiting settings (optional).
|
|
100
|
-
api : str | None
|
|
101
|
-
Service reference into the pipeline ``apis`` block (a.k.a.
|
|
102
|
-
``service``).
|
|
103
|
-
endpoint : str | None
|
|
104
|
-
Endpoint name within the referenced service.
|
|
105
|
-
"""
|
|
106
|
-
|
|
107
|
-
# -- Attributes -- #
|
|
108
|
-
|
|
109
|
-
name: str
|
|
110
|
-
type: ConnectorType = 'api'
|
|
111
|
-
|
|
112
|
-
# Direct form
|
|
113
|
-
url: str | None = None
|
|
114
|
-
# Optional HTTP method; typically omitted for sources (defaults to GET
|
|
115
|
-
# at runtime) and used for targets (e.g., 'post', 'put').
|
|
116
|
-
method: str | None = None
|
|
117
|
-
headers: dict[str, str] = field(default_factory=dict)
|
|
118
|
-
query_params: dict[str, Any] = field(default_factory=dict)
|
|
119
|
-
pagination: PaginationConfig | None = None
|
|
120
|
-
rate_limit: RateLimitConfig | None = None
|
|
121
|
-
|
|
122
|
-
# Reference form (to top-level APIs/endpoints)
|
|
123
|
-
api: str | None = None
|
|
124
|
-
endpoint: str | None = None
|
|
125
|
-
|
|
126
|
-
# -- Class Methods -- #
|
|
127
|
-
|
|
128
|
-
@classmethod
|
|
129
|
-
@overload
|
|
130
|
-
def from_obj(cls, obj: ConnectorApiConfigMap) -> Self: ...
|
|
131
|
-
|
|
132
|
-
@classmethod
|
|
133
|
-
@overload
|
|
134
|
-
def from_obj(cls, obj: StrAnyMap) -> Self: ...
|
|
135
|
-
|
|
136
|
-
@classmethod
|
|
137
|
-
def from_obj(
|
|
138
|
-
cls,
|
|
139
|
-
obj: StrAnyMap,
|
|
140
|
-
) -> Self:
|
|
141
|
-
"""
|
|
142
|
-
Parse a mapping into a ``ConnectorApi`` instance.
|
|
143
|
-
|
|
144
|
-
Parameters
|
|
145
|
-
----------
|
|
146
|
-
obj : StrAnyMap
|
|
147
|
-
Mapping with at least ``name``.
|
|
148
|
-
|
|
149
|
-
Returns
|
|
150
|
-
-------
|
|
151
|
-
Self
|
|
152
|
-
Parsed connector instance.
|
|
153
|
-
|
|
154
|
-
Raises
|
|
155
|
-
------
|
|
156
|
-
TypeError
|
|
157
|
-
If ``name`` is missing or invalid.
|
|
158
|
-
"""
|
|
159
|
-
name = obj.get('name')
|
|
160
|
-
if not isinstance(name, str):
|
|
161
|
-
raise TypeError('ConnectorApi requires a "name" (str)')
|
|
162
|
-
headers = cast_str_dict(obj.get('headers'))
|
|
163
|
-
|
|
164
|
-
return cls(
|
|
165
|
-
name=name,
|
|
166
|
-
type='api',
|
|
167
|
-
url=obj.get('url'),
|
|
168
|
-
method=obj.get('method'),
|
|
169
|
-
headers=headers,
|
|
170
|
-
query_params=coerce_dict(obj.get('query_params')),
|
|
171
|
-
pagination=PaginationConfig.from_obj(obj.get('pagination')),
|
|
172
|
-
rate_limit=RateLimitConfig.from_obj(obj.get('rate_limit')),
|
|
173
|
-
api=obj.get('api') or obj.get('service'),
|
|
174
|
-
endpoint=obj.get('endpoint'),
|
|
175
|
-
)
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
@dataclass(kw_only=True, slots=True)
|
|
179
|
-
class ConnectorDb:
|
|
180
|
-
"""
|
|
181
|
-
Configuration for a database-based data connector.
|
|
182
|
-
|
|
183
|
-
Attributes
|
|
184
|
-
----------
|
|
185
|
-
name : str
|
|
186
|
-
Unique connector name.
|
|
187
|
-
type : ConnectorType
|
|
188
|
-
Connector kind literal, always ``"database"``.
|
|
189
|
-
connection_string : str | None
|
|
190
|
-
Connection string/DSN for the database.
|
|
191
|
-
query : str | None
|
|
192
|
-
Query to execute for extraction (optional).
|
|
193
|
-
table : str | None
|
|
194
|
-
Target/source table name (optional).
|
|
195
|
-
mode : str | None
|
|
196
|
-
Load mode hint (e.g., ``"append"``, ``"replace"``) — future use.
|
|
197
|
-
"""
|
|
198
|
-
|
|
199
|
-
# -- Attributes -- #
|
|
200
|
-
|
|
201
|
-
name: str
|
|
202
|
-
type: ConnectorType = 'database'
|
|
203
|
-
connection_string: str | None = None
|
|
204
|
-
query: str | None = None
|
|
205
|
-
table: str | None = None
|
|
206
|
-
mode: str | None = None # append|replace|upsert (future)
|
|
207
|
-
|
|
208
|
-
# -- Class Methods -- #
|
|
209
|
-
|
|
210
|
-
@classmethod
|
|
211
|
-
@overload
|
|
212
|
-
def from_obj(cls, obj: ConnectorDbConfigMap) -> Self: ...
|
|
213
|
-
|
|
214
|
-
@classmethod
|
|
215
|
-
@overload
|
|
216
|
-
def from_obj(cls, obj: StrAnyMap) -> Self: ...
|
|
217
|
-
|
|
218
|
-
@classmethod
|
|
219
|
-
def from_obj(
|
|
220
|
-
cls,
|
|
221
|
-
obj: StrAnyMap,
|
|
222
|
-
) -> Self:
|
|
223
|
-
"""
|
|
224
|
-
Parse a mapping into a ``ConnectorDb`` instance.
|
|
225
|
-
|
|
226
|
-
Parameters
|
|
227
|
-
----------
|
|
228
|
-
obj : StrAnyMap
|
|
229
|
-
Mapping with at least ``name``.
|
|
230
|
-
|
|
231
|
-
Returns
|
|
232
|
-
-------
|
|
233
|
-
Self
|
|
234
|
-
Parsed connector instance.
|
|
235
|
-
|
|
236
|
-
Raises
|
|
237
|
-
------
|
|
238
|
-
TypeError
|
|
239
|
-
If ``name`` is missing or invalid.
|
|
240
|
-
"""
|
|
241
|
-
name = obj.get('name')
|
|
242
|
-
if not isinstance(name, str):
|
|
243
|
-
raise TypeError('ConnectorDb requires a "name" (str)')
|
|
244
|
-
|
|
245
|
-
return cls(
|
|
246
|
-
name=name,
|
|
247
|
-
type='database',
|
|
248
|
-
connection_string=obj.get('connection_string'),
|
|
249
|
-
query=obj.get('query'),
|
|
250
|
-
table=obj.get('table'),
|
|
251
|
-
mode=obj.get('mode'),
|
|
252
|
-
)
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
@dataclass(kw_only=True, slots=True)
|
|
256
|
-
class ConnectorFile:
|
|
257
|
-
"""
|
|
258
|
-
Configuration for a file-based data connector.
|
|
259
|
-
|
|
260
|
-
Attributes
|
|
261
|
-
----------
|
|
262
|
-
name : str
|
|
263
|
-
Unique connector name.
|
|
264
|
-
type : ConnectorType
|
|
265
|
-
Connector kind literal, always ``"file"``.
|
|
266
|
-
format : str | None
|
|
267
|
-
File format (e.g., ``"json"``, ``"csv"``).
|
|
268
|
-
path : str | None
|
|
269
|
-
File path or URI.
|
|
270
|
-
options : dict[str, Any]
|
|
271
|
-
Reader/writer format options.
|
|
272
|
-
"""
|
|
273
|
-
|
|
274
|
-
# -- Attributes -- #
|
|
275
|
-
|
|
276
|
-
name: str
|
|
277
|
-
type: ConnectorType = 'file'
|
|
278
|
-
format: str | None = None
|
|
279
|
-
path: str | None = None
|
|
280
|
-
options: dict[str, Any] = field(default_factory=dict)
|
|
281
|
-
|
|
282
|
-
# -- Class Methods -- #
|
|
283
|
-
|
|
284
|
-
@classmethod
|
|
285
|
-
@overload
|
|
286
|
-
def from_obj(cls, obj: ConnectorFileConfigMap) -> Self: ...
|
|
287
|
-
|
|
288
|
-
@classmethod
|
|
289
|
-
@overload
|
|
290
|
-
def from_obj(cls, obj: StrAnyMap) -> Self: ...
|
|
291
|
-
|
|
292
|
-
@classmethod
|
|
293
|
-
def from_obj(
|
|
294
|
-
cls,
|
|
295
|
-
obj: StrAnyMap,
|
|
296
|
-
) -> Self:
|
|
297
|
-
"""
|
|
298
|
-
Parse a mapping into a ``ConnectorFile`` instance.
|
|
299
|
-
|
|
300
|
-
Parameters
|
|
301
|
-
----------
|
|
302
|
-
obj : StrAnyMap
|
|
303
|
-
Mapping with at least ``name``.
|
|
304
|
-
|
|
305
|
-
Returns
|
|
306
|
-
-------
|
|
307
|
-
Self
|
|
308
|
-
Parsed connector instance.
|
|
309
|
-
|
|
310
|
-
Raises
|
|
311
|
-
------
|
|
312
|
-
TypeError
|
|
313
|
-
If ``name`` is missing or invalid.
|
|
314
|
-
"""
|
|
315
|
-
name = obj.get('name')
|
|
316
|
-
if not isinstance(name, str):
|
|
317
|
-
raise TypeError('ConnectorFile requires a "name" (str)')
|
|
318
|
-
|
|
319
|
-
return cls(
|
|
320
|
-
name=name,
|
|
321
|
-
type='file',
|
|
322
|
-
format=obj.get('format'),
|
|
323
|
-
path=obj.get('path'),
|
|
324
|
-
options=coerce_dict(obj.get('options')),
|
|
325
|
-
)
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
# SECTION: FUNCTIONS ======================================================== #
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
def parse_connector(obj: Mapping[str, Any]) -> Connector:
|
|
332
|
-
"""
|
|
333
|
-
Dispatch to a concrete connector constructor based on ``type``.
|
|
334
|
-
|
|
335
|
-
Parameters
|
|
336
|
-
----------
|
|
337
|
-
obj : Mapping[str, Any]
|
|
338
|
-
Mapping with at least ``name`` and ``type``.
|
|
339
|
-
|
|
340
|
-
Returns
|
|
341
|
-
-------
|
|
342
|
-
Connector
|
|
343
|
-
Concrete connector instance.
|
|
344
|
-
|
|
345
|
-
Raises
|
|
346
|
-
------
|
|
347
|
-
TypeError
|
|
348
|
-
If ``type`` is unsupported or missing.
|
|
349
|
-
|
|
350
|
-
Notes
|
|
351
|
-
-----
|
|
352
|
-
Delegates to the tolerant ``from_obj`` constructors for each connector
|
|
353
|
-
kind.
|
|
354
|
-
"""
|
|
355
|
-
match str(obj.get('type', '')).casefold():
|
|
356
|
-
case 'file':
|
|
357
|
-
return ConnectorFile.from_obj(obj)
|
|
358
|
-
case 'database':
|
|
359
|
-
return ConnectorDb.from_obj(obj)
|
|
360
|
-
case 'api':
|
|
361
|
-
return ConnectorApi.from_obj(obj)
|
|
362
|
-
case _:
|
|
363
|
-
raise TypeError(
|
|
364
|
-
'Unsupported connector type; '
|
|
365
|
-
'expected one of {file, database, api}',
|
|
366
|
-
)
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
# SECTION: TYPED ALIASES (post-class definitions) ========================= #
|
|
370
|
-
|
|
371
|
-
# Type alias representing any supported connector
|
|
372
|
-
type Connector = ConnectorApi | ConnectorDb | ConnectorFile
|
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
|