etlplus 0.16.3__py3-none-any.whl → 0.16.5__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 +22 -0
  2. etlplus/__init__.py +2 -0
  3. etlplus/api/__init__.py +14 -14
  4. etlplus/api/auth.py +9 -6
  5. etlplus/api/config.py +6 -6
  6. etlplus/api/endpoint_client.py +16 -16
  7. etlplus/api/errors.py +4 -4
  8. etlplus/api/pagination/__init__.py +6 -6
  9. etlplus/api/pagination/config.py +11 -9
  10. etlplus/api/rate_limiting/__init__.py +2 -2
  11. etlplus/api/rate_limiting/config.py +10 -10
  12. etlplus/api/rate_limiting/rate_limiter.py +2 -2
  13. etlplus/api/request_manager.py +4 -4
  14. etlplus/api/retry_manager.py +6 -6
  15. etlplus/api/transport.py +10 -10
  16. etlplus/api/types.py +15 -15
  17. etlplus/api/utils.py +49 -49
  18. etlplus/cli/commands.py +22 -22
  19. etlplus/cli/handlers.py +12 -13
  20. etlplus/{workflow/pipeline.py → config.py} +17 -37
  21. etlplus/connector/__init__.py +6 -6
  22. etlplus/connector/api.py +7 -7
  23. etlplus/connector/database.py +3 -3
  24. etlplus/connector/file.py +3 -3
  25. etlplus/connector/types.py +2 -2
  26. etlplus/ops/extract.py +2 -2
  27. etlplus/ops/run.py +2 -2
  28. etlplus/ops/utils.py +5 -5
  29. etlplus/ops/validate.py +13 -13
  30. etlplus/types.py +2 -1
  31. etlplus/workflow/README.md +0 -24
  32. etlplus/workflow/__init__.py +0 -4
  33. etlplus/workflow/jobs.py +0 -2
  34. {etlplus-0.16.3.dist-info → etlplus-0.16.5.dist-info}/METADATA +1 -1
  35. {etlplus-0.16.3.dist-info → etlplus-0.16.5.dist-info}/RECORD +39 -39
  36. {etlplus-0.16.3.dist-info → etlplus-0.16.5.dist-info}/WHEEL +0 -0
  37. {etlplus-0.16.3.dist-info → etlplus-0.16.5.dist-info}/entry_points.txt +0 -0
  38. {etlplus-0.16.3.dist-info → etlplus-0.16.5.dist-info}/licenses/LICENSE +0 -0
  39. {etlplus-0.16.3.dist-info → etlplus-0.16.5.dist-info}/top_level.txt +0 -0
etlplus/api/transport.py CHANGED
@@ -41,8 +41,8 @@ from ..utils import to_positive_int
41
41
 
42
42
  __all__ = [
43
43
  # Classes
44
- 'HTTPAdapterMountConfig',
45
- 'HTTPAdapterRetryConfig',
44
+ 'HTTPAdapterMountConfigDict',
45
+ 'HTTPAdapterRetryConfigDict',
46
46
  # Functions
47
47
  'build_http_adapter',
48
48
  'build_session_with_adapters',
@@ -52,7 +52,7 @@ __all__ = [
52
52
  # SECTION: TYPED DICTS ====================================================== #
53
53
 
54
54
 
55
- class HTTPAdapterRetryConfig(TypedDict, total=False):
55
+ class HTTPAdapterRetryConfigDict(TypedDict, total=False):
56
56
  """
57
57
  Retry configuration for urllib3 ``Retry``.
58
58
 
@@ -89,7 +89,7 @@ class HTTPAdapterRetryConfig(TypedDict, total=False):
89
89
 
90
90
  Examples
91
91
  --------
92
- >>> retry_cfg: HTTPAdapterRetryConfig = {
92
+ >>> retry_cfg: HTTPAdapterRetryConfigDict = {
93
93
  ... 'total': 5,
94
94
  ... 'backoff_factor': 0.5,
95
95
  ... 'status_forcelist': [429, 503],
@@ -111,7 +111,7 @@ class HTTPAdapterRetryConfig(TypedDict, total=False):
111
111
  respect_retry_after_header: bool
112
112
 
113
113
 
114
- class HTTPAdapterMountConfig(TypedDict, total=False):
114
+ class HTTPAdapterMountConfigDict(TypedDict, total=False):
115
115
  """
116
116
  Configuration mapping for mounting an ``HTTPAdapter`` on a ``Session``.
117
117
 
@@ -132,13 +132,13 @@ class HTTPAdapterMountConfig(TypedDict, total=False):
132
132
  pool_block : bool
133
133
  Whether the pool should block for connections instead of creating new
134
134
  ones.
135
- max_retries : int | HTTPAdapterRetryConfig
135
+ max_retries : int | HTTPAdapterRetryConfigDict
136
136
  Retry configuration passed to ``HTTPAdapter`` (int) or converted to
137
137
  ``Retry``.
138
138
 
139
139
  Examples
140
140
  --------
141
- >>> adapter_cfg: HTTPAdapterMountConfig = {
141
+ >>> adapter_cfg: HTTPAdapterMountConfigDict = {
142
142
  ... 'prefix': 'https://',
143
143
  ... 'pool_connections': 10,
144
144
  ... 'pool_maxsize': 10,
@@ -156,7 +156,7 @@ class HTTPAdapterMountConfig(TypedDict, total=False):
156
156
  pool_connections: int
157
157
  pool_maxsize: int
158
158
  pool_block: bool
159
- max_retries: int | HTTPAdapterRetryConfig
159
+ max_retries: int | HTTPAdapterRetryConfigDict
160
160
 
161
161
 
162
162
  # SECTION: INTERNAL FUNCTIONS ============================================== #
@@ -306,7 +306,7 @@ def build_http_adapter(
306
306
 
307
307
 
308
308
  def build_session_with_adapters(
309
- adapters_cfg: Sequence[HTTPAdapterMountConfig],
309
+ adapters_cfg: Sequence[HTTPAdapterMountConfigDict],
310
310
  ) -> requests.Session:
311
311
  """
312
312
  Mount adapters described by *adapters_cfg* onto a new session.
@@ -316,7 +316,7 @@ def build_session_with_adapters(
316
316
 
317
317
  Parameters
318
318
  ----------
319
- adapters_cfg : Sequence[HTTPAdapterMountConfig]
319
+ adapters_cfg : Sequence[HTTPAdapterMountConfigDict]
320
320
  Configuration mappings describing the adapter prefix, pooling
321
321
  values, and retry policy for each mounted adapter.
322
322
 
etlplus/api/types.py CHANGED
@@ -43,10 +43,10 @@ __all__ = [
43
43
  'Params',
44
44
  'Url',
45
45
  # Typed Dicts
46
- 'ApiConfigMap',
47
- 'ApiProfileConfigMap',
48
- 'ApiProfileDefaultsMap',
49
- 'EndpointMap',
46
+ 'ApiConfigDict',
47
+ 'ApiProfileConfigDict',
48
+ 'ApiProfileDefaultsDict',
49
+ 'EndpointConfigDict',
50
50
  ]
51
51
 
52
52
 
@@ -83,7 +83,7 @@ def _to_dict(
83
83
  # SECTION: TYPED DICTS ====================================================== #
84
84
 
85
85
 
86
- class ApiConfigMap(TypedDict, total=False):
86
+ class ApiConfigDict(TypedDict, total=False):
87
87
  """
88
88
  Top-level API config shape parsed by
89
89
  :meth:`etlplus.api.config.ApiConfig.from_obj`.
@@ -99,11 +99,11 @@ class ApiConfigMap(TypedDict, total=False):
99
99
 
100
100
  base_url: str
101
101
  headers: StrAnyMap
102
- endpoints: Mapping[str, EndpointMap | str]
103
- profiles: Mapping[str, ApiProfileConfigMap]
102
+ endpoints: Mapping[str, EndpointConfigDict | str]
103
+ profiles: Mapping[str, ApiProfileConfigDict]
104
104
 
105
105
 
106
- class ApiProfileConfigMap(TypedDict, total=False):
106
+ class ApiProfileConfigDict(TypedDict, total=False):
107
107
  """
108
108
  Shape accepted for a profile entry under
109
109
  :meth:`etlplus.api.config.ApiConfig.from_obj`.
@@ -123,10 +123,10 @@ class ApiProfileConfigMap(TypedDict, total=False):
123
123
  headers: StrAnyMap
124
124
  base_path: str
125
125
  auth: StrAnyMap
126
- defaults: ApiProfileDefaultsMap
126
+ defaults: ApiProfileDefaultsDict
127
127
 
128
128
 
129
- class ApiProfileDefaultsMap(TypedDict, total=False):
129
+ class ApiProfileDefaultsDict(TypedDict, total=False):
130
130
  """
131
131
  Defaults block available under a profile (all keys optional).
132
132
 
@@ -147,11 +147,11 @@ class ApiProfileDefaultsMap(TypedDict, total=False):
147
147
  """
148
148
 
149
149
  headers: StrAnyMap
150
- pagination: StrAnyMap # PaginationConfigMap | StrAnyMap
151
- rate_limit: StrAnyMap # RateLimitConfigMap | StrAnyMap
150
+ pagination: StrAnyMap # PaginationConfigDict | StrAnyMap
151
+ rate_limit: StrAnyMap # RateLimitConfigDict | StrAnyMap
152
152
 
153
153
 
154
- class EndpointMap(TypedDict, total=False):
154
+ class EndpointConfigDict(TypedDict, total=False):
155
155
  """
156
156
  Shape accepted by :meth:`etlplus.api.config.EndpointConfig.from_obj`.
157
157
 
@@ -168,8 +168,8 @@ class EndpointMap(TypedDict, total=False):
168
168
  path_params: StrAnyMap
169
169
  query_params: StrAnyMap
170
170
  body: Any
171
- pagination: StrAnyMap # PaginationConfigMap | StrAnyMap
172
- rate_limit: StrAnyMap # RateLimitConfigMap | StrAnyMap
171
+ pagination: StrAnyMap # PaginationConfigDict | StrAnyMap
172
+ rate_limit: StrAnyMap # RateLimitConfigDict | StrAnyMap
173
173
 
174
174
 
175
175
  # SECTION: DATA CLASSES ===================================================== #
etlplus/api/utils.py CHANGED
@@ -22,11 +22,11 @@ from .config import EndpointConfig
22
22
  from .endpoint_client import EndpointClient
23
23
  from .enums import HttpMethod
24
24
  from .pagination import PaginationConfig
25
- from .pagination import PaginationConfigMap
25
+ from .pagination import PaginationConfigDict
26
26
  from .rate_limiting import RateLimitConfig
27
- from .rate_limiting import RateLimitConfigMap
27
+ from .rate_limiting import RateLimitConfigDict
28
28
  from .rate_limiting import RateLimiter
29
- from .retry_manager import RetryPolicy
29
+ from .retry_manager import RetryPolicyDict
30
30
  from .types import Headers
31
31
  from .types import Params
32
32
  from .types import Url
@@ -53,16 +53,16 @@ __all__ = [
53
53
  'paginate_with_client',
54
54
  'resolve_request',
55
55
  # Typed Dicts
56
- 'ApiRequestEnv',
57
- 'ApiTargetEnv',
58
- 'SessionConfig',
56
+ 'ApiRequestEnvDict',
57
+ 'ApiTargetEnvDict',
58
+ 'SessionConfigDict',
59
59
  ]
60
60
 
61
61
 
62
62
  # SECTION: TYPED DICTS ====================================================== #
63
63
 
64
64
 
65
- class BaseApiHttpEnv(TypedDict, total=False):
65
+ class BaseApiHttpEnvDict(TypedDict, total=False):
66
66
  """
67
67
  Common HTTP request environment for API interactions.
68
68
 
@@ -78,7 +78,7 @@ class BaseApiHttpEnv(TypedDict, total=False):
78
78
  session: requests.Session | None
79
79
 
80
80
 
81
- class ApiRequestEnv(BaseApiHttpEnv, total=False):
81
+ class ApiRequestEnvDict(BaseApiHttpEnvDict, total=False):
82
82
  """
83
83
  Composed HTTP request environment configuration for REST API sources.
84
84
 
@@ -96,15 +96,15 @@ class ApiRequestEnv(BaseApiHttpEnv, total=False):
96
96
 
97
97
  # Request
98
98
  params: dict[str, Any]
99
- pagination: PaginationConfigMap | None
99
+ pagination: PaginationConfigDict | None
100
100
  sleep_seconds: float
101
101
 
102
102
  # Reliability
103
- retry: RetryPolicy | None
103
+ retry: RetryPolicyDict | None
104
104
  retry_network_errors: bool
105
105
 
106
106
 
107
- class ApiTargetEnv(BaseApiHttpEnv, total=False):
107
+ class ApiTargetEnvDict(BaseApiHttpEnvDict, total=False):
108
108
  """
109
109
  Composed HTTP request environment configuration for REST API targets.
110
110
 
@@ -126,7 +126,7 @@ class ApiTargetEnv(BaseApiHttpEnv, total=False):
126
126
  method: str | None
127
127
 
128
128
 
129
- class SessionConfig(TypedDict, total=False):
129
+ class SessionConfigDict(TypedDict, total=False):
130
130
  """
131
131
  Minimal session configuration schema accepted by the
132
132
  :class:`requests.Session` runner.
@@ -148,14 +148,14 @@ class SessionConfig(TypedDict, total=False):
148
148
 
149
149
 
150
150
  def _build_session_optional(
151
- cfg: SessionConfig | None,
151
+ cfg: SessionConfigDict | None,
152
152
  ) -> requests.Session | None:
153
153
  """
154
154
  Return a configured session when *cfg* is a mapping.
155
155
 
156
156
  Parameters
157
157
  ----------
158
- cfg : SessionConfig | None
158
+ cfg : SessionConfigDict | None
159
159
  Session configuration mapping.
160
160
 
161
161
  Returns
@@ -164,7 +164,7 @@ def _build_session_optional(
164
164
  Configured session or ``None``.
165
165
  """
166
166
  if isinstance(cfg, Mapping):
167
- return build_session(cast(SessionConfig, cfg))
167
+ return build_session(cast(SessionConfigDict, cfg))
168
168
  return None
169
169
 
170
170
 
@@ -233,9 +233,9 @@ def _inherit_http_from_api_endpoint(
233
233
  ep: EndpointConfig,
234
234
  url: Url | None,
235
235
  headers: dict[str, str],
236
- session_cfg: SessionConfig | None,
236
+ session_cfg: SessionConfigDict | None,
237
237
  force_url: bool = False,
238
- ) -> tuple[Url | None, dict[str, str], SessionConfig | None]:
238
+ ) -> tuple[Url | None, dict[str, str], SessionConfigDict | None]:
239
239
  """
240
240
  Return HTTP settings inherited from API + endpoint definitions.
241
241
 
@@ -249,14 +249,14 @@ def _inherit_http_from_api_endpoint(
249
249
  Existing URL to use when not forcing endpoint URL.
250
250
  headers : dict[str, str]
251
251
  Existing headers to augment.
252
- session_cfg : SessionConfig | None
252
+ session_cfg : SessionConfigDict | None
253
253
  Existing session configuration to augment.
254
254
  force_url : bool, optional
255
255
  Whether to always use the endpoint URL.
256
256
 
257
257
  Returns
258
258
  -------
259
- tuple[Url | None, dict[str, str], SessionConfig | None]
259
+ tuple[Url | None, dict[str, str], SessionConfigDict | None]
260
260
  Resolved URL, headers, and session configuration.
261
261
  """
262
262
  if force_url or not url:
@@ -269,8 +269,8 @@ def _inherit_http_from_api_endpoint(
269
269
  def _merge_session_cfg_three(
270
270
  api_cfg: ApiConfig,
271
271
  ep: EndpointConfig,
272
- source_session_cfg: SessionConfig | None,
273
- ) -> SessionConfig | None:
272
+ source_session_cfg: SessionConfigDict | None,
273
+ ) -> SessionConfigDict | None:
274
274
  """
275
275
  Merge session configurations from API, endpoint, and source.
276
276
 
@@ -280,12 +280,12 @@ def _merge_session_cfg_three(
280
280
  API configuration.
281
281
  ep : EndpointConfig
282
282
  Endpoint configuration.
283
- source_session_cfg : SessionConfig | None
283
+ source_session_cfg : SessionConfigDict | None
284
284
  Source session configuration.
285
285
 
286
286
  Returns
287
287
  -------
288
- SessionConfig | None
288
+ SessionConfigDict | None
289
289
  Merged session configuration.
290
290
  """
291
291
  api_sess = getattr(api_cfg, 'session', None)
@@ -297,7 +297,7 @@ def _merge_session_cfg_three(
297
297
  merged.update(ep_sess)
298
298
  if isinstance(source_session_cfg, Mapping):
299
299
  merged.update(source_session_cfg)
300
- return cast(SessionConfig | None, (merged or None))
300
+ return cast(SessionConfigDict | None, (merged or None))
301
301
 
302
302
 
303
303
  def _update_mapping(
@@ -361,7 +361,7 @@ def compose_api_request_env(
361
361
  cfg: Any,
362
362
  source_obj: Any,
363
363
  ex_opts: Mapping[str, Any] | None,
364
- ) -> ApiRequestEnv:
364
+ ) -> ApiRequestEnvDict:
365
365
  """
366
366
  Compose the API request environment.
367
367
 
@@ -376,7 +376,7 @@ def compose_api_request_env(
376
376
 
377
377
  Returns
378
378
  -------
379
- ApiRequestEnv
379
+ ApiRequestEnvDict
380
380
  The composed API request environment.
381
381
  """
382
382
  ex_opts = ex_opts or {}
@@ -393,13 +393,13 @@ def compose_api_request_env(
393
393
  headers: dict[str, str] = cast(dict[str, str], coerce_dict(source_headers))
394
394
  pagination = getattr(source_obj, 'pagination', None)
395
395
  rate_limit = getattr(source_obj, 'rate_limit', None)
396
- retry: RetryPolicy | None = cast(
397
- RetryPolicy | None,
396
+ retry: RetryPolicyDict | None = cast(
397
+ RetryPolicyDict | None,
398
398
  getattr(source_obj, 'retry', None),
399
399
  )
400
400
  retry_network_errors = getattr(source_obj, 'retry_network_errors', None)
401
401
  session_cfg = cast(
402
- SessionConfig | None,
402
+ SessionConfigDict | None,
403
403
  getattr(source_obj, 'session', None),
404
404
  )
405
405
  api_name = getattr(source_obj, 'api', None)
@@ -435,7 +435,7 @@ def compose_api_request_env(
435
435
  api_cfg.effective_rate_limit_defaults(),
436
436
  )
437
437
  retry = cast(
438
- RetryPolicy | None,
438
+ RetryPolicyDict | None,
439
439
  _coalesce(
440
440
  retry,
441
441
  getattr(ep, 'retry', None),
@@ -465,8 +465,8 @@ def compose_api_request_env(
465
465
  timeout: Timeout = ex_opts.get('timeout')
466
466
  pag_ov = ex_opts.get('pagination', {})
467
467
  rl_ov = ex_opts.get('rate_limit', {})
468
- rty_ov: RetryPolicy | None = cast(
469
- RetryPolicy | None,
468
+ rty_ov: RetryPolicyDict | None = cast(
469
+ RetryPolicyDict | None,
470
470
  (ex_opts.get('retry') if 'retry' in ex_opts else None),
471
471
  )
472
472
  rne_ov = (
@@ -474,7 +474,7 @@ def compose_api_request_env(
474
474
  if 'retry_network_errors' in ex_opts
475
475
  else None
476
476
  )
477
- sess_ov = cast(SessionConfig | None, ex_opts.get('session'))
477
+ sess_ov = cast(SessionConfigDict | None, ex_opts.get('session'))
478
478
  sleep_s = compute_rl_sleep_seconds(rate_limit, rl_ov) or 0.0
479
479
  if rty_ov is not None:
480
480
  retry = rty_ov
@@ -485,8 +485,8 @@ def compose_api_request_env(
485
485
  cast(Mapping[str, Any], session_cfg or {}),
486
486
  )
487
487
  base_cfg.update(sess_ov)
488
- session_cfg = cast(SessionConfig, base_cfg)
489
- pag_cfg: PaginationConfigMap | None = build_pagination_cfg(
488
+ session_cfg = cast(SessionConfigDict, base_cfg)
489
+ pag_cfg: PaginationConfigDict | None = build_pagination_cfg(
490
490
  pagination,
491
491
  pag_ov,
492
492
  )
@@ -513,7 +513,7 @@ def compose_api_target_env(
513
513
  cfg: Any,
514
514
  target_obj: Any,
515
515
  overrides: Mapping[str, Any] | None,
516
- ) -> ApiTargetEnv:
516
+ ) -> ApiTargetEnvDict:
517
517
  """
518
518
  Compose the API target environment.
519
519
 
@@ -528,7 +528,7 @@ def compose_api_target_env(
528
528
 
529
529
  Returns
530
530
  -------
531
- ApiTargetEnv
531
+ ApiTargetEnvDict
532
532
  Composed API target environment.
533
533
  """
534
534
  ov = overrides or {}
@@ -553,8 +553,8 @@ def compose_api_target_env(
553
553
  timeout: Timeout = (
554
554
  cast(Timeout, ov.get('timeout')) if 'timeout' in ov else None
555
555
  )
556
- sess_cfg: SessionConfig | None = cast(
557
- SessionConfig | None,
556
+ sess_cfg: SessionConfigDict | None = cast(
557
+ SessionConfigDict | None,
558
558
  ov.get('session'),
559
559
  )
560
560
  api_name = getattr(target_obj, 'api', None)
@@ -583,7 +583,7 @@ def compose_api_target_env(
583
583
  def build_pagination_cfg(
584
584
  pagination: PaginationConfig | None,
585
585
  overrides: Mapping[str, Any] | None,
586
- ) -> PaginationConfigMap | None:
586
+ ) -> PaginationConfigDict | None:
587
587
  """
588
588
  Build pagination configuration.
589
589
 
@@ -596,7 +596,7 @@ def build_pagination_cfg(
596
596
 
597
597
  Returns
598
598
  -------
599
- PaginationConfigMap | None
599
+ PaginationConfigDict | None
600
600
  Pagination configuration.
601
601
  """
602
602
  ptype: str | None = None
@@ -683,7 +683,7 @@ def build_pagination_cfg(
683
683
  case _:
684
684
  pass
685
685
 
686
- return cast(PaginationConfigMap, cfg)
686
+ return cast(PaginationConfigDict, cfg)
687
687
 
688
688
 
689
689
  def paginate_with_client(
@@ -692,7 +692,7 @@ def paginate_with_client(
692
692
  params: Params | None,
693
693
  headers: Headers | None,
694
694
  timeout: Timeout,
695
- pagination: PaginationConfigMap | None,
695
+ pagination: PaginationConfigDict | None,
696
696
  sleep_seconds: float | None,
697
697
  ) -> Any:
698
698
  """
@@ -710,7 +710,7 @@ def paginate_with_client(
710
710
  Headers to include in the API request.
711
711
  timeout : Timeout
712
712
  Timeout configuration for the API request.
713
- pagination : PaginationConfigMap | None
713
+ pagination : PaginationConfigDict | None
714
714
  Pagination configuration for the API request.
715
715
  sleep_seconds : float | None
716
716
  Sleep duration between API requests.
@@ -771,9 +771,9 @@ def compute_rl_sleep_seconds(
771
771
  else:
772
772
  rl_map = cast(Mapping[str, Any] | None, rate_limit)
773
773
 
774
- rl_mapping = cast(RateLimitConfigMap | None, rl_map)
774
+ rl_mapping = cast(RateLimitConfigDict | None, rl_map)
775
775
 
776
- typed_override: RateLimitConfigMap | None = None
776
+ typed_override: RateLimitConfigDict | None = None
777
777
  if overrides:
778
778
  filtered: dict[str, float | None] = {}
779
779
  if 'sleep_seconds' in overrides:
@@ -787,7 +787,7 @@ def compute_rl_sleep_seconds(
787
787
  overrides.get('max_per_sec'),
788
788
  )
789
789
  if filtered:
790
- typed_override = cast(RateLimitConfigMap, filtered)
790
+ typed_override = cast(RateLimitConfigDict, filtered)
791
791
 
792
792
  return RateLimiter.resolve_sleep_seconds(
793
793
  rate_limit=rl_mapping,
@@ -796,14 +796,14 @@ def compute_rl_sleep_seconds(
796
796
 
797
797
 
798
798
  def build_session(
799
- cfg: SessionConfig | None,
799
+ cfg: SessionConfigDict | None,
800
800
  ) -> requests.Session:
801
801
  """
802
802
  Build a requests.Session object with the given configuration.
803
803
 
804
804
  Parameters
805
805
  ----------
806
- cfg : SessionConfig | None
806
+ cfg : SessionConfigDict | None
807
807
  Session configuration.
808
808
 
809
809
  Returns
etlplus/cli/commands.py CHANGED
@@ -62,6 +62,16 @@ __all__ = ['app']
62
62
  # SECTION: TYPE ALIASES ==================================================== #
63
63
 
64
64
 
65
+ ConfigOption = Annotated[
66
+ str,
67
+ typer.Option(
68
+ ...,
69
+ '--config',
70
+ metavar='PATH',
71
+ help='Path to YAML-formatted configuration file.',
72
+ ),
73
+ ]
74
+
65
75
  JobOption = Annotated[
66
76
  str | None,
67
77
  typer.Option(
@@ -97,16 +107,6 @@ OutputOption = Annotated[
97
107
  ),
98
108
  ]
99
109
 
100
- PipelineConfigOption = Annotated[
101
- str,
102
- typer.Option(
103
- ...,
104
- '--config',
105
- metavar='PATH',
106
- help='Path to pipeline YAML configuration file.',
107
- ),
108
- ]
109
-
110
110
  PipelineOption = Annotated[
111
111
  str | None,
112
112
  typer.Option(
@@ -407,7 +407,7 @@ def _root(
407
407
  @app.command('check')
408
408
  def check_cmd(
409
409
  ctx: typer.Context,
410
- config: PipelineConfigOption,
410
+ config: ConfigOption,
411
411
  jobs: JobsOption = False,
412
412
  pipelines: PipelinesOption = False,
413
413
  sources: SourcesOption = False,
@@ -422,20 +422,20 @@ def check_cmd(
422
422
  ----------
423
423
  ctx : typer.Context
424
424
  The Typer context.
425
- config : PipelineConfigOption
425
+ config : ConfigOption
426
426
  Path to pipeline YAML configuration file.
427
- jobs : bool, optional
427
+ jobs : JobsOption, optional
428
428
  List available job names and exit. Default is ``False``.
429
- pipelines : bool, optional
429
+ pipelines : PipelinesOption, optional
430
430
  List ETL pipelines. Default is ``False``.
431
- sources : bool, optional
431
+ sources : SourcesOption, optional
432
432
  List data sources. Default is ``False``.
433
- summary : bool, optional
433
+ summary : SummaryOption, optional
434
434
  Show pipeline summary (name, version, sources, targets, jobs). Default
435
435
  is ``False``.
436
- targets : bool, optional
436
+ targets : TargetsOption, optional
437
437
  List data targets. Default is ``False``.
438
- transforms : bool, optional
438
+ transforms : TransformsOption, optional
439
439
  List data transforms. Default is ``False``.
440
440
 
441
441
  Returns
@@ -725,7 +725,7 @@ def render_cmd(
725
725
  @app.command('run')
726
726
  def run_cmd(
727
727
  ctx: typer.Context,
728
- config: PipelineConfigOption,
728
+ config: ConfigOption,
729
729
  job: JobOption = None,
730
730
  pipeline: PipelineOption = None,
731
731
  ) -> int:
@@ -736,11 +736,11 @@ def run_cmd(
736
736
  ----------
737
737
  ctx : typer.Context
738
738
  The Typer context.
739
- config : PipelineConfigOption
739
+ config : ConfigOption
740
740
  Path to pipeline YAML configuration file.
741
- job : str | None, optional
741
+ job : JobOption, optional
742
742
  Name of the job to run. Default is ``None``.
743
- pipeline : str | None, optional
743
+ pipeline : PipelineOption, optional
744
744
  Name of the pipeline to run. Default is ``None``.
745
745
 
746
746
  Returns
etlplus/cli/handlers.py CHANGED
@@ -14,6 +14,7 @@ from typing import Any
14
14
  from typing import Literal
15
15
  from typing import cast
16
16
 
17
+ from .. import Config
17
18
  from ..database import load_table_spec
18
19
  from ..database import render_tables
19
20
  from ..file import File
@@ -23,11 +24,9 @@ from ..ops import load
23
24
  from ..ops import run
24
25
  from ..ops import transform
25
26
  from ..ops import validate
26
- from ..ops.validate import FieldRules
27
+ from ..ops.validate import FieldRulesDict
27
28
  from ..types import JSONData
28
29
  from ..types import TemplateKey
29
- from ..workflow import PipelineConfig
30
- from ..workflow import load_pipeline_config
31
30
  from . import io as cli_io
32
31
 
33
32
  # SECTION: EXPORTS ========================================================== #
@@ -73,14 +72,14 @@ def _collect_table_specs(
73
72
  specs.append(dict(load_table_spec(Path(spec_path))))
74
73
 
75
74
  if config_path:
76
- cfg = load_pipeline_config(config_path, substitute=True)
75
+ cfg = Config.from_yaml(config_path, substitute=True)
77
76
  specs.extend(getattr(cfg, 'table_schemas', []))
78
77
 
79
78
  return specs
80
79
 
81
80
 
82
81
  def _check_sections(
83
- cfg: PipelineConfig,
82
+ cfg: Config,
84
83
  *,
85
84
  jobs: bool,
86
85
  pipelines: bool,
@@ -93,7 +92,7 @@ def _check_sections(
93
92
 
94
93
  Parameters
95
94
  ----------
96
- cfg : PipelineConfig
95
+ cfg : Config
97
96
  The loaded pipeline configuration.
98
97
  jobs : bool
99
98
  Whether to include job metadata.
@@ -133,14 +132,14 @@ def _check_sections(
133
132
 
134
133
 
135
134
  def _pipeline_summary(
136
- cfg: PipelineConfig,
135
+ cfg: Config,
137
136
  ) -> dict[str, Any]:
138
137
  """
139
138
  Return a human-friendly snapshot of a pipeline config.
140
139
 
141
140
  Parameters
142
141
  ----------
143
- cfg : PipelineConfig
142
+ cfg : Config
144
143
  The loaded pipeline configuration.
145
144
 
146
145
  Returns
@@ -229,7 +228,7 @@ def check_handler(
229
228
  Zero on success.
230
229
 
231
230
  """
232
- cfg = load_pipeline_config(config, substitute=substitute)
231
+ cfg = Config.from_yaml(config, substitute=substitute)
233
232
  if summary:
234
233
  cli_io.emit_json(_pipeline_summary(cfg), pretty=True)
235
234
  return 0
@@ -514,7 +513,7 @@ def run_handler(
514
513
  int
515
514
  Zero on success.
516
515
  """
517
- cfg = load_pipeline_config(config, substitute=True)
516
+ cfg = Config.from_yaml(config, substitute=True)
518
517
 
519
518
  job_name = job or pipeline
520
519
  if job_name:
@@ -662,7 +661,7 @@ def validate_handler(
662
661
  if not isinstance(rules_payload, dict):
663
662
  raise ValueError('rules must resolve to a mapping of field rules')
664
663
 
665
- field_rules = cast(Mapping[str, FieldRules], rules_payload)
664
+ field_rules = cast(Mapping[str, FieldRulesDict], rules_payload)
666
665
  result = validate(payload, field_rules)
667
666
 
668
667
  if target and target != '-':
@@ -671,11 +670,11 @@ def validate_handler(
671
670
  cli_io.write_json_output(
672
671
  validated_data,
673
672
  target,
674
- success_message='Validation result saved to',
673
+ success_message='ValidationDict result saved to',
675
674
  )
676
675
  else:
677
676
  print(
678
- f'Validation failed, no data to save for {target}',
677
+ f'ValidationDict failed, no data to save for {target}',
679
678
  file=sys.stderr,
680
679
  )
681
680
  else: