etlplus 0.8.0__py3-none-any.whl → 0.8.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.
- etlplus/cli/commands.py +645 -0
- etlplus/cli/constants.py +65 -0
- etlplus/cli/handlers.py +34 -311
- etlplus/cli/io.py +343 -0
- etlplus/cli/main.py +46 -108
- etlplus/cli/options.py +115 -0
- etlplus/cli/state.py +411 -0
- etlplus/cli/types.py +33 -0
- {etlplus-0.8.0.dist-info → etlplus-0.8.2.dist-info}/METADATA +1 -1
- {etlplus-0.8.0.dist-info → etlplus-0.8.2.dist-info}/RECORD +14 -9
- etlplus/cli/app.py +0 -1312
- {etlplus-0.8.0.dist-info → etlplus-0.8.2.dist-info}/WHEEL +0 -0
- {etlplus-0.8.0.dist-info → etlplus-0.8.2.dist-info}/entry_points.txt +0 -0
- {etlplus-0.8.0.dist-info → etlplus-0.8.2.dist-info}/licenses/LICENSE +0 -0
- {etlplus-0.8.0.dist-info → etlplus-0.8.2.dist-info}/top_level.txt +0 -0
etlplus/cli/options.py
ADDED
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
"""
|
|
2
|
+
:mod:`etlplus.cli.options` module.
|
|
3
|
+
|
|
4
|
+
Shared command-line interface (CLI) option helpers for both Typer and argparse
|
|
5
|
+
entry points.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from __future__ import annotations
|
|
9
|
+
|
|
10
|
+
import argparse
|
|
11
|
+
from collections.abc import Sequence
|
|
12
|
+
|
|
13
|
+
from .constants import DEFAULT_FILE_FORMAT
|
|
14
|
+
from .constants import FILE_FORMATS
|
|
15
|
+
from .types import DataConnectorContext
|
|
16
|
+
|
|
17
|
+
# SECTION: EXPORTS ========================================================== #
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
__all__ = [
|
|
21
|
+
# Classes
|
|
22
|
+
'FormatAction',
|
|
23
|
+
# Functions
|
|
24
|
+
'add_argparse_format_options',
|
|
25
|
+
'typer_format_option_kwargs',
|
|
26
|
+
]
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
# SECTION: CLASSES ========================================================== #
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
class FormatAction(argparse.Action):
|
|
33
|
+
"""Record when a format override flag is provided."""
|
|
34
|
+
|
|
35
|
+
def __call__(
|
|
36
|
+
self,
|
|
37
|
+
parser: argparse.ArgumentParser,
|
|
38
|
+
namespace: argparse.Namespace,
|
|
39
|
+
values: str | Sequence[object] | None,
|
|
40
|
+
option_string: str | None = None,
|
|
41
|
+
) -> None: # pragma: no cover - argparse wiring
|
|
42
|
+
setattr(namespace, self.dest, values)
|
|
43
|
+
namespace._format_explicit = True
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
# SECTION: FUNCTIONS ======================================================== #
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
def add_argparse_format_options(
|
|
50
|
+
parser: argparse.ArgumentParser,
|
|
51
|
+
*,
|
|
52
|
+
context: DataConnectorContext,
|
|
53
|
+
) -> None:
|
|
54
|
+
"""
|
|
55
|
+
Attach ``--source-format`` and ``--target-format`` arguments.
|
|
56
|
+
|
|
57
|
+
Parameters
|
|
58
|
+
----------
|
|
59
|
+
parser : argparse.ArgumentParser
|
|
60
|
+
Parser receiving the options.
|
|
61
|
+
context : DataConnectorContext
|
|
62
|
+
Either ``'source'`` or ``'target'`` to tailor help text.
|
|
63
|
+
"""
|
|
64
|
+
parser.set_defaults(_format_explicit=False)
|
|
65
|
+
parser.add_argument(
|
|
66
|
+
'--source-format',
|
|
67
|
+
choices=sorted(FILE_FORMATS),
|
|
68
|
+
default=DEFAULT_FILE_FORMAT,
|
|
69
|
+
action=FormatAction,
|
|
70
|
+
help=(
|
|
71
|
+
f'Format of the {context}. Overrides filename-based inference '
|
|
72
|
+
'when provided.'
|
|
73
|
+
),
|
|
74
|
+
)
|
|
75
|
+
parser.add_argument(
|
|
76
|
+
'--target-format',
|
|
77
|
+
choices=sorted(FILE_FORMATS),
|
|
78
|
+
default=DEFAULT_FILE_FORMAT,
|
|
79
|
+
action=FormatAction,
|
|
80
|
+
help=(
|
|
81
|
+
f'Format of the {context}. Overrides filename-based inference '
|
|
82
|
+
'when provided.'
|
|
83
|
+
),
|
|
84
|
+
)
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
def typer_format_option_kwargs(
|
|
88
|
+
*,
|
|
89
|
+
context: DataConnectorContext,
|
|
90
|
+
rich_help_panel: str = 'Format overrides',
|
|
91
|
+
) -> dict[str, object]:
|
|
92
|
+
"""
|
|
93
|
+
Return common Typer option kwargs for format overrides.
|
|
94
|
+
|
|
95
|
+
Parameters
|
|
96
|
+
----------
|
|
97
|
+
context : DataConnectorContext
|
|
98
|
+
Either ``'source'`` or ``'target'`` to tailor help text.
|
|
99
|
+
rich_help_panel : str, optional
|
|
100
|
+
The rich help panel name. Default is ``'Format overrides'``.
|
|
101
|
+
|
|
102
|
+
Returns
|
|
103
|
+
-------
|
|
104
|
+
dict[str, object]
|
|
105
|
+
The Typer option keyword arguments.
|
|
106
|
+
"""
|
|
107
|
+
return {
|
|
108
|
+
'metavar': 'FORMAT',
|
|
109
|
+
'show_default': False,
|
|
110
|
+
'rich_help_panel': rich_help_panel,
|
|
111
|
+
'help': (
|
|
112
|
+
f'Payload format when the {context} is stdin/inline or a '
|
|
113
|
+
'non-file connector. File connectors infer from extensions.'
|
|
114
|
+
),
|
|
115
|
+
}
|
etlplus/cli/state.py
ADDED
|
@@ -0,0 +1,411 @@
|
|
|
1
|
+
"""
|
|
2
|
+
:mod:`etlplus.cli.state` module.
|
|
3
|
+
|
|
4
|
+
Shared state and helper utilities for the ``etlplus`` command-line interface
|
|
5
|
+
(CLI).
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from __future__ import annotations
|
|
9
|
+
|
|
10
|
+
import argparse
|
|
11
|
+
import sys
|
|
12
|
+
from collections.abc import Collection
|
|
13
|
+
from dataclasses import dataclass
|
|
14
|
+
from pathlib import Path
|
|
15
|
+
from typing import Final
|
|
16
|
+
|
|
17
|
+
import typer
|
|
18
|
+
|
|
19
|
+
from .constants import DATA_CONNECTORS
|
|
20
|
+
|
|
21
|
+
# SECTION: EXPORTS ========================================================== #
|
|
22
|
+
|
|
23
|
+
__all__ = [
|
|
24
|
+
# Classes
|
|
25
|
+
'CliState',
|
|
26
|
+
# Functions
|
|
27
|
+
'ensure_state',
|
|
28
|
+
'format_namespace_kwargs',
|
|
29
|
+
'infer_resource_type',
|
|
30
|
+
'infer_resource_type_or_exit',
|
|
31
|
+
'infer_resource_type_soft',
|
|
32
|
+
'log_inferred_resource',
|
|
33
|
+
'ns',
|
|
34
|
+
'optional_choice',
|
|
35
|
+
'resolve_resource_type',
|
|
36
|
+
'stateful_namespace',
|
|
37
|
+
'validate_choice',
|
|
38
|
+
]
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
# SECTION: INTERNAL CONSTANTS =============================================== #
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
_DB_SCHEMES: Final[tuple[str, ...]] = (
|
|
45
|
+
'postgres://',
|
|
46
|
+
'postgresql://',
|
|
47
|
+
'mysql://',
|
|
48
|
+
)
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
# SECTION: DATA CLASSES ===================================================== #
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
@dataclass(slots=True)
|
|
55
|
+
class CliState:
|
|
56
|
+
"""
|
|
57
|
+
Mutable container for runtime CLI toggles.
|
|
58
|
+
|
|
59
|
+
Attributes
|
|
60
|
+
----------
|
|
61
|
+
pretty : bool
|
|
62
|
+
Whether to pretty-print output.
|
|
63
|
+
quiet : bool
|
|
64
|
+
Whether to suppress non-error output.
|
|
65
|
+
verbose : bool
|
|
66
|
+
Whether to enable verbose logging.
|
|
67
|
+
"""
|
|
68
|
+
|
|
69
|
+
pretty: bool = True
|
|
70
|
+
quiet: bool = False
|
|
71
|
+
verbose: bool = False
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
# SECTION: FUNCTIONS ======================================================== #
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
def ensure_state(
|
|
78
|
+
ctx: typer.Context,
|
|
79
|
+
) -> CliState:
|
|
80
|
+
"""
|
|
81
|
+
Return the :class:`CliState` stored on the :mod:`typer` context.
|
|
82
|
+
|
|
83
|
+
Initializes a new :class:`CliState` if none exists.
|
|
84
|
+
|
|
85
|
+
Parameters
|
|
86
|
+
----------
|
|
87
|
+
ctx : typer.Context
|
|
88
|
+
The Typer command context.
|
|
89
|
+
|
|
90
|
+
Returns
|
|
91
|
+
-------
|
|
92
|
+
CliState
|
|
93
|
+
The CLI state object.
|
|
94
|
+
"""
|
|
95
|
+
if not isinstance(getattr(ctx, 'obj', None), CliState):
|
|
96
|
+
ctx.obj = CliState()
|
|
97
|
+
return ctx.obj
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
def format_namespace_kwargs(
|
|
101
|
+
*,
|
|
102
|
+
format_value: str | None,
|
|
103
|
+
default: str,
|
|
104
|
+
) -> dict[str, object]:
|
|
105
|
+
"""
|
|
106
|
+
Return common namespace kwargs for format handling.
|
|
107
|
+
|
|
108
|
+
Parameters
|
|
109
|
+
----------
|
|
110
|
+
format_value : str | None
|
|
111
|
+
The explicit format value from the CLI, or ``None`` if not provided.
|
|
112
|
+
default : str
|
|
113
|
+
The default format to use if none is provided.
|
|
114
|
+
|
|
115
|
+
Returns
|
|
116
|
+
-------
|
|
117
|
+
dict[str, object]
|
|
118
|
+
The namespace keyword arguments for format handling.
|
|
119
|
+
"""
|
|
120
|
+
return {
|
|
121
|
+
'format': (format_value or default),
|
|
122
|
+
'_format_explicit': (format_value is not None),
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
|
|
126
|
+
def infer_resource_type(
|
|
127
|
+
value: str,
|
|
128
|
+
) -> str:
|
|
129
|
+
"""
|
|
130
|
+
Infer the resource type from a path, URL, or DSN string.
|
|
131
|
+
|
|
132
|
+
Parameters
|
|
133
|
+
----------
|
|
134
|
+
value : str
|
|
135
|
+
The resource identifier (path, URL, or DSN).
|
|
136
|
+
|
|
137
|
+
Returns
|
|
138
|
+
-------
|
|
139
|
+
str
|
|
140
|
+
The inferred resource type: ``file``, ``api``, or ``database``.
|
|
141
|
+
|
|
142
|
+
Raises
|
|
143
|
+
------
|
|
144
|
+
ValueError
|
|
145
|
+
If inference fails.
|
|
146
|
+
"""
|
|
147
|
+
val = (value or '').strip()
|
|
148
|
+
low = val.lower()
|
|
149
|
+
|
|
150
|
+
match (val, low):
|
|
151
|
+
case ('-', _):
|
|
152
|
+
return 'file'
|
|
153
|
+
case (_, inferred) if inferred.startswith(('http://', 'https://')):
|
|
154
|
+
return 'api'
|
|
155
|
+
case (_, inferred) if inferred.startswith(_DB_SCHEMES):
|
|
156
|
+
return 'database'
|
|
157
|
+
|
|
158
|
+
path = Path(val)
|
|
159
|
+
if path.exists() or path.suffix:
|
|
160
|
+
return 'file'
|
|
161
|
+
|
|
162
|
+
raise ValueError(
|
|
163
|
+
'Could not infer resource type. Use --from/--to to specify it.',
|
|
164
|
+
)
|
|
165
|
+
|
|
166
|
+
|
|
167
|
+
def infer_resource_type_or_exit(
|
|
168
|
+
value: str,
|
|
169
|
+
) -> str:
|
|
170
|
+
"""
|
|
171
|
+
Infer a resource type and map ``ValueError`` to ``BadParameter``.
|
|
172
|
+
|
|
173
|
+
Parameters
|
|
174
|
+
----------
|
|
175
|
+
value : str
|
|
176
|
+
The resource identifier (path, URL, or DSN).
|
|
177
|
+
|
|
178
|
+
Returns
|
|
179
|
+
-------
|
|
180
|
+
str
|
|
181
|
+
The inferred resource type: ``file``, ``api``, or ``database``.
|
|
182
|
+
|
|
183
|
+
Raises
|
|
184
|
+
------
|
|
185
|
+
typer.BadParameter
|
|
186
|
+
If inference fails.
|
|
187
|
+
"""
|
|
188
|
+
try:
|
|
189
|
+
return infer_resource_type(value)
|
|
190
|
+
except ValueError as exc: # pragma: no cover - exercised indirectly
|
|
191
|
+
raise typer.BadParameter(str(exc)) from exc
|
|
192
|
+
|
|
193
|
+
|
|
194
|
+
def infer_resource_type_soft(
|
|
195
|
+
value: str | None,
|
|
196
|
+
) -> str | None:
|
|
197
|
+
"""
|
|
198
|
+
Make a best-effort inference that tolerates inline payloads.
|
|
199
|
+
|
|
200
|
+
Parameters
|
|
201
|
+
----------
|
|
202
|
+
value : str | None
|
|
203
|
+
The resource identifier (path, URL, DSN, or inline payload).
|
|
204
|
+
|
|
205
|
+
Returns
|
|
206
|
+
-------
|
|
207
|
+
str | None
|
|
208
|
+
The inferred resource type, or ``None`` if inference failed.
|
|
209
|
+
"""
|
|
210
|
+
if value is None:
|
|
211
|
+
return None
|
|
212
|
+
try:
|
|
213
|
+
return infer_resource_type(value)
|
|
214
|
+
except ValueError:
|
|
215
|
+
return None
|
|
216
|
+
|
|
217
|
+
|
|
218
|
+
def log_inferred_resource(
|
|
219
|
+
state: CliState,
|
|
220
|
+
*,
|
|
221
|
+
role: str,
|
|
222
|
+
value: str,
|
|
223
|
+
resource_type: str | None,
|
|
224
|
+
) -> None:
|
|
225
|
+
"""
|
|
226
|
+
Emit a uniform verbose message for inferred resource types.
|
|
227
|
+
|
|
228
|
+
Parameters
|
|
229
|
+
----------
|
|
230
|
+
state : CliState
|
|
231
|
+
The current CLI state.
|
|
232
|
+
role : str
|
|
233
|
+
The resource role, e.g., ``source`` or ``target``.
|
|
234
|
+
value : str
|
|
235
|
+
The resource identifier (path, URL, or DSN).
|
|
236
|
+
resource_type : str | None
|
|
237
|
+
The inferred resource type, or ``None`` if inference failed.
|
|
238
|
+
"""
|
|
239
|
+
if not state.verbose or resource_type is None:
|
|
240
|
+
return
|
|
241
|
+
print(
|
|
242
|
+
f'Inferred {role}_type={resource_type} for {role}={value}',
|
|
243
|
+
file=sys.stderr,
|
|
244
|
+
)
|
|
245
|
+
|
|
246
|
+
|
|
247
|
+
def ns(
|
|
248
|
+
**kwargs: object,
|
|
249
|
+
) -> argparse.Namespace:
|
|
250
|
+
"""
|
|
251
|
+
Build an :class:`argparse.Namespace` for the legacy handlers.
|
|
252
|
+
|
|
253
|
+
Parameters
|
|
254
|
+
----------
|
|
255
|
+
**kwargs : object
|
|
256
|
+
Keyword arguments to include in the namespace.
|
|
257
|
+
|
|
258
|
+
Returns
|
|
259
|
+
-------
|
|
260
|
+
argparse.Namespace
|
|
261
|
+
The constructed namespace.
|
|
262
|
+
"""
|
|
263
|
+
return argparse.Namespace(**kwargs)
|
|
264
|
+
|
|
265
|
+
|
|
266
|
+
def optional_choice(
|
|
267
|
+
value: str | None,
|
|
268
|
+
choices: Collection[str],
|
|
269
|
+
*,
|
|
270
|
+
label: str,
|
|
271
|
+
) -> str | None:
|
|
272
|
+
"""
|
|
273
|
+
Validate optional CLI choice inputs while preserving ``None``.
|
|
274
|
+
|
|
275
|
+
Parameters
|
|
276
|
+
----------
|
|
277
|
+
value : str | None
|
|
278
|
+
The input value to validate, or ``None``.
|
|
279
|
+
choices : Collection[str]
|
|
280
|
+
The set of valid choices.
|
|
281
|
+
label : str
|
|
282
|
+
The label for error messages.
|
|
283
|
+
|
|
284
|
+
Returns
|
|
285
|
+
-------
|
|
286
|
+
str | None
|
|
287
|
+
The validated choice, or ``None`` if input was ``None``.
|
|
288
|
+
"""
|
|
289
|
+
if value is None:
|
|
290
|
+
return None
|
|
291
|
+
return validate_choice(value, choices, label=label)
|
|
292
|
+
|
|
293
|
+
|
|
294
|
+
def resolve_resource_type(
|
|
295
|
+
*,
|
|
296
|
+
explicit_type: str | None,
|
|
297
|
+
override_type: str | None,
|
|
298
|
+
value: str,
|
|
299
|
+
label: str,
|
|
300
|
+
conflict_error: str | None = None,
|
|
301
|
+
legacy_file_error: str | None = None,
|
|
302
|
+
) -> str:
|
|
303
|
+
"""
|
|
304
|
+
Resolve resource type preference order and validate it.
|
|
305
|
+
|
|
306
|
+
Parameters
|
|
307
|
+
----------
|
|
308
|
+
explicit_type : str | None
|
|
309
|
+
The explicit resource type from the CLI, or ``None`` if not provided.
|
|
310
|
+
override_type : str | None
|
|
311
|
+
The override resource type from the CLI, or ``None`` if not provided.
|
|
312
|
+
value : str
|
|
313
|
+
The resource identifier (path, URL, or DSN).
|
|
314
|
+
label : str
|
|
315
|
+
The label for error messages.
|
|
316
|
+
conflict_error : str | None, optional
|
|
317
|
+
The error message to raise if both explicit and override types are
|
|
318
|
+
provided, by default ``None``.
|
|
319
|
+
legacy_file_error : str | None, optional
|
|
320
|
+
The error message to raise if the explicit type is ``file``, by default
|
|
321
|
+
``None``.
|
|
322
|
+
|
|
323
|
+
Returns
|
|
324
|
+
-------
|
|
325
|
+
str
|
|
326
|
+
The resolved and validated resource type.
|
|
327
|
+
|
|
328
|
+
Raises
|
|
329
|
+
------
|
|
330
|
+
typer.BadParameter
|
|
331
|
+
If there is a conflict between explicit and override types, or if the
|
|
332
|
+
explicit type is ``file`` when disallowed.
|
|
333
|
+
"""
|
|
334
|
+
if explicit_type is not None:
|
|
335
|
+
if override_type is not None and conflict_error:
|
|
336
|
+
raise typer.BadParameter(conflict_error)
|
|
337
|
+
if legacy_file_error and explicit_type.strip().lower() == 'file':
|
|
338
|
+
raise typer.BadParameter(legacy_file_error)
|
|
339
|
+
candidate = explicit_type
|
|
340
|
+
else:
|
|
341
|
+
candidate = override_type or infer_resource_type_or_exit(value)
|
|
342
|
+
return validate_choice(candidate, DATA_CONNECTORS, label=label)
|
|
343
|
+
|
|
344
|
+
|
|
345
|
+
def stateful_namespace(
|
|
346
|
+
state: CliState,
|
|
347
|
+
*,
|
|
348
|
+
command: str,
|
|
349
|
+
**kwargs: object,
|
|
350
|
+
) -> argparse.Namespace:
|
|
351
|
+
"""
|
|
352
|
+
Attach CLI state toggles to a handler namespace.
|
|
353
|
+
|
|
354
|
+
Parameters
|
|
355
|
+
----------
|
|
356
|
+
state : CliState
|
|
357
|
+
The current CLI state.
|
|
358
|
+
command : str
|
|
359
|
+
The command name.
|
|
360
|
+
**kwargs : object
|
|
361
|
+
Additional keyword arguments for the namespace.
|
|
362
|
+
|
|
363
|
+
Returns
|
|
364
|
+
-------
|
|
365
|
+
argparse.Namespace
|
|
366
|
+
The constructed namespace with state toggles.
|
|
367
|
+
"""
|
|
368
|
+
return ns(
|
|
369
|
+
command=command,
|
|
370
|
+
pretty=state.pretty,
|
|
371
|
+
quiet=state.quiet,
|
|
372
|
+
verbose=state.verbose,
|
|
373
|
+
**kwargs,
|
|
374
|
+
)
|
|
375
|
+
|
|
376
|
+
|
|
377
|
+
def validate_choice(
|
|
378
|
+
value: str,
|
|
379
|
+
choices: Collection[str],
|
|
380
|
+
*,
|
|
381
|
+
label: str,
|
|
382
|
+
) -> str:
|
|
383
|
+
"""
|
|
384
|
+
Validate CLI input against a whitelist of choices.
|
|
385
|
+
|
|
386
|
+
Parameters
|
|
387
|
+
----------
|
|
388
|
+
value : str
|
|
389
|
+
The input value to validate.
|
|
390
|
+
choices : Collection[str]
|
|
391
|
+
The set of valid choices.
|
|
392
|
+
label : str
|
|
393
|
+
The label for error messages.
|
|
394
|
+
|
|
395
|
+
Returns
|
|
396
|
+
-------
|
|
397
|
+
str
|
|
398
|
+
The validated choice.
|
|
399
|
+
|
|
400
|
+
Raises
|
|
401
|
+
------
|
|
402
|
+
typer.BadParameter
|
|
403
|
+
If the input value is not in the set of valid choices.
|
|
404
|
+
"""
|
|
405
|
+
v = (value or '').strip()
|
|
406
|
+
if v in choices:
|
|
407
|
+
return v
|
|
408
|
+
allowed = ', '.join(sorted(choices))
|
|
409
|
+
raise typer.BadParameter(
|
|
410
|
+
f"Invalid {label} '{value}'. Choose from: {allowed}",
|
|
411
|
+
)
|
etlplus/cli/types.py
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
"""
|
|
2
|
+
:mod:`etlplus.cli.types` module.
|
|
3
|
+
|
|
4
|
+
Type aliases for :mod:`etlplus.cli` helpers.
|
|
5
|
+
|
|
6
|
+
Notes
|
|
7
|
+
-----
|
|
8
|
+
- Keeps other modules decoupled from ``typing`` details.
|
|
9
|
+
|
|
10
|
+
Examples
|
|
11
|
+
--------
|
|
12
|
+
>>> from etlplus.cli.types import DataConnectorContext
|
|
13
|
+
>>> connector: DataConnectorContext = 'source'
|
|
14
|
+
"""
|
|
15
|
+
|
|
16
|
+
from __future__ import annotations
|
|
17
|
+
|
|
18
|
+
from typing import Literal
|
|
19
|
+
|
|
20
|
+
# SECTION: EXPORTS ========================================================== #
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
__all__ = [
|
|
24
|
+
# Type Aliases
|
|
25
|
+
'DataConnectorContext',
|
|
26
|
+
]
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
# SECTION: TYPE ALIASES ===================================================== #
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
# Data connector context.
|
|
33
|
+
type DataConnectorContext = Literal['source', 'target']
|
|
@@ -31,9 +31,14 @@ etlplus/api/rate_limiting/__init__.py,sha256=ZySB1dZettEDnWvI1EHf_TZ9L08M_kKsNR-
|
|
|
31
31
|
etlplus/api/rate_limiting/config.py,sha256=2b4wIynblN-1EyMqI4aXa71SljzSjXYh5N1Nngr3jOg,9406
|
|
32
32
|
etlplus/api/rate_limiting/rate_limiter.py,sha256=Uxozqd_Ej5Lsj-M-mLT2WexChgWh7x35_YP10yqYPQA,7159
|
|
33
33
|
etlplus/cli/__init__.py,sha256=J97-Rv931IL1_b4AXnB7Fbbd7HKnHBpx18NQfC_kE6c,299
|
|
34
|
-
etlplus/cli/
|
|
35
|
-
etlplus/cli/
|
|
36
|
-
etlplus/cli/
|
|
34
|
+
etlplus/cli/commands.py,sha256=laIfpxnnJM1XZvxQxaH1IheZbIsELruC1V3BeT2l8y0,16299
|
|
35
|
+
etlplus/cli/constants.py,sha256=NJ6IvNyYEI8IdB7eMcc-vteQiiIwqid5YvmUk-5DRHY,1839
|
|
36
|
+
etlplus/cli/handlers.py,sha256=F8ZtXWdtMvhDYYDUjZ3JkGFJh2xfWsE2PKX5ZRhP0RI,11310
|
|
37
|
+
etlplus/cli/io.py,sha256=wHoKfgl-VT15cfiVeW3uPz_U7tPQ1ag7EQkRZtxPd38,7987
|
|
38
|
+
etlplus/cli/main.py,sha256=iD4zSgJwsfzhqlBCNxD7a7y5ZutqB9upxCnGtNaZ_B8,14006
|
|
39
|
+
etlplus/cli/options.py,sha256=44rgksvi0c9Evt_QzITnErVEuyGTaUulkQYZZgCke7k,3060
|
|
40
|
+
etlplus/cli/state.py,sha256=ymiGJbnEO766BOYaqm_-qZaqBwdKYnGRuttrNVhDms0,9439
|
|
41
|
+
etlplus/cli/types.py,sha256=tclhKVJXDqHzlTQBYKARfqMgDOcuBJ-Zej2pvFy96WM,652
|
|
37
42
|
etlplus/config/__init__.py,sha256=VZWzOg7d2YR9NT6UwKTv44yf2FRUMjTHynkm1Dl5Qzo,1486
|
|
38
43
|
etlplus/config/connector.py,sha256=0-TIwevHbKRHVmucvyGpPd-3tB1dKHB-dj0yJ6kq5eY,9809
|
|
39
44
|
etlplus/config/jobs.py,sha256=hmzRCqt0OvCEZZR4ONKrd3lvSv0OmayjLc4yOBk3ug8,7399
|
|
@@ -52,9 +57,9 @@ etlplus/templates/ddl.sql.j2,sha256=s8fMWvcb4eaJVXkifuib1aQPljtZ8buuyB_uA-ZdU3Q,
|
|
|
52
57
|
etlplus/templates/view.sql.j2,sha256=Iy8DHfhq5yyvrUKDxqp_aHIEXY4Tm6j4wT7YDEFWAhk,2180
|
|
53
58
|
etlplus/validation/__init__.py,sha256=Pe5Xg1_EA4uiNZGYu5WTF3j7odjmyxnAJ8rcioaplSQ,1254
|
|
54
59
|
etlplus/validation/utils.py,sha256=Mtqg449VIke0ziy_wd2r6yrwJzQkA1iulZC87FzXMjo,10201
|
|
55
|
-
etlplus-0.8.
|
|
56
|
-
etlplus-0.8.
|
|
57
|
-
etlplus-0.8.
|
|
58
|
-
etlplus-0.8.
|
|
59
|
-
etlplus-0.8.
|
|
60
|
-
etlplus-0.8.
|
|
60
|
+
etlplus-0.8.2.dist-info/licenses/LICENSE,sha256=MuNO63i6kWmgnV2pbP2SLqP54mk1BGmu7CmbtxMmT-U,1069
|
|
61
|
+
etlplus-0.8.2.dist-info/METADATA,sha256=djlodCP_KPtdG2OKttP5QcpxJHCy3-0enqnIXKIZZEY,19328
|
|
62
|
+
etlplus-0.8.2.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
63
|
+
etlplus-0.8.2.dist-info/entry_points.txt,sha256=6w-2-jzuPa55spzK34h-UKh2JTEShh38adFRONNP9QE,45
|
|
64
|
+
etlplus-0.8.2.dist-info/top_level.txt,sha256=aWWF-udn_sLGuHTM6W6MLh99ArS9ROkUWO8Mi8y1_2U,8
|
|
65
|
+
etlplus-0.8.2.dist-info/RECORD,,
|