etlplus 0.7.0__py3-none-any.whl → 0.8.3__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/database/orm.py CHANGED
@@ -13,9 +13,8 @@ Usage
13
13
  from __future__ import annotations
14
14
 
15
15
  import re
16
- from collections.abc import Callable
17
- from pathlib import Path
18
16
  from typing import Any
17
+ from typing import Final
19
18
 
20
19
  from sqlalchemy import Boolean
21
20
  from sqlalchemy import CheckConstraint
@@ -41,11 +40,15 @@ from sqlalchemy.orm import DeclarativeBase
41
40
  from sqlalchemy.orm import mapped_column
42
41
  from sqlalchemy.types import TypeEngine
43
42
 
43
+ from ..types import StrPath
44
44
  from .schema import ForeignKeySpec
45
45
  from .schema import TableSpec
46
46
  from .schema import load_table_specs
47
+ from .types import ModelRegistry
48
+ from .types import TypeFactory
49
+
50
+ # SECTION: EXPORTS ========================================================== #
47
51
 
48
- # SECTION: INTERNAL CONSTANTS =============================================== #
49
52
 
50
53
  __all__ = [
51
54
  # Classes
@@ -57,7 +60,9 @@ __all__ = [
57
60
  ]
58
61
 
59
62
 
60
- _TYPE_MAPPING: dict[str, Callable[[list[int]], TypeEngine]] = {
63
+ # SECTION: INTERNAL CONSTANTS =============================================== #
64
+
65
+ _TYPE_MAPPING: Final[dict[str, TypeFactory]] = {
61
66
  'int': lambda _: Integer(),
62
67
  'integer': lambda _: Integer(),
63
68
  'bigint': lambda _: Integer(),
@@ -102,6 +107,8 @@ _TYPE_MAPPING: dict[str, Callable[[list[int]], TypeEngine]] = {
102
107
  class Base(DeclarativeBase):
103
108
  """Base class for all ORM models."""
104
109
 
110
+ __abstract__ = True
111
+
105
112
 
106
113
  # SECTION: INTERNAL FUNCTIONS =============================================== #
107
114
 
@@ -191,7 +198,7 @@ def build_models(
191
198
  specs: list[TableSpec],
192
199
  *,
193
200
  base: type[DeclarativeBase] = Base,
194
- ) -> dict[str, type[DeclarativeBase]]:
201
+ ) -> ModelRegistry:
195
202
  """
196
203
  Build SQLAlchemy ORM models from table specifications.
197
204
  Parameters
@@ -202,10 +209,10 @@ def build_models(
202
209
  Base class for the ORM models (default: :class:`Base`).
203
210
  Returns
204
211
  -------
205
- dict[str, type[DeclarativeBase]]
212
+ ModelRegistry
206
213
  Registry mapping fully qualified table names to ORM model classes.
207
214
  """
208
- registry: dict[str, type[DeclarativeBase]] = {}
215
+ registry: ModelRegistry = {}
209
216
 
210
217
  for spec in specs:
211
218
  table_args: list[object] = []
@@ -302,23 +309,23 @@ def build_models(
302
309
 
303
310
 
304
311
  def load_and_build_models(
305
- path: str | Path,
312
+ path: StrPath,
306
313
  *,
307
314
  base: type[DeclarativeBase] = Base,
308
- ) -> dict[str, type[DeclarativeBase]]:
315
+ ) -> ModelRegistry:
309
316
  """
310
317
  Load table specifications from a file and build SQLAlchemy models.
311
318
 
312
319
  Parameters
313
320
  ----------
314
- path : str | Path
321
+ path : StrPath
315
322
  Path to the YAML file containing table specifications.
316
323
  base : type[DeclarativeBase], optional
317
324
  Base class for the ORM models (default: :class:`Base`).
318
325
 
319
326
  Returns
320
327
  -------
321
- dict[str, type[DeclarativeBase]]
328
+ ModelRegistry
322
329
  Registry mapping fully qualified table names to ORM model classes.
323
330
  """
324
331
  return build_models(load_table_specs(path), base=base)
@@ -16,6 +16,7 @@ from pydantic import ConfigDict
16
16
  from pydantic import Field
17
17
 
18
18
  from ..file import File
19
+ from ..types import StrPath
19
20
 
20
21
  # SECTION: EXPORTS ========================================================== #
21
22
 
@@ -244,14 +245,14 @@ class TableSpec(BaseModel):
244
245
 
245
246
 
246
247
  def load_table_specs(
247
- path: str | Path,
248
+ path: StrPath,
248
249
  ) -> list[TableSpec]:
249
250
  """
250
251
  Load table specifications from a YAML file.
251
252
 
252
253
  Parameters
253
254
  ----------
254
- path : str | Path
255
+ path : StrPath
255
256
  Path to the YAML file containing table specifications.
256
257
 
257
258
  Returns
@@ -0,0 +1,33 @@
1
+ """
2
+ :mod:`etlplus.database.types` module.
3
+
4
+ Shared type aliases leveraged across :mod:`etlplus.database` modules.
5
+ """
6
+
7
+ from __future__ import annotations
8
+
9
+ from collections.abc import Callable
10
+
11
+ from sqlalchemy.orm import DeclarativeBase
12
+ from sqlalchemy.types import TypeEngine
13
+
14
+ # SECTION: EXPORTS ========================================================== #
15
+
16
+
17
+ __all__ = [
18
+ # Type Aliases
19
+ 'ModelRegistry',
20
+ 'TypeFactory',
21
+ ]
22
+
23
+
24
+ # SECTION: TYPE ALIASES ===================================================== #
25
+
26
+
27
+ # pylint: disable=invalid-name
28
+
29
+ # Registry mapping fully qualified table names to declarative classes.
30
+ type ModelRegistry = dict[str, type[DeclarativeBase]]
31
+
32
+ # Callable producing a SQLAlchemy TypeEngine from parsed parameters.
33
+ type TypeFactory = Callable[[list[int]], TypeEngine]
etlplus/types.py CHANGED
@@ -225,3 +225,8 @@ type Sleeper = Callable[[float], None]
225
225
 
226
226
  # Numeric timeout in seconds or ``None`` for no timeout.
227
227
  type Timeout = float | None
228
+
229
+ # -- Templates -- #
230
+
231
+ # Allowed template keys for bundled DDL rendering.
232
+ type TemplateKey = Literal['ddl', 'view']
etlplus/utils.py CHANGED
@@ -6,7 +6,6 @@ Small shared helpers used across modules.
6
6
 
7
7
  from __future__ import annotations
8
8
 
9
- import argparse
10
9
  import json
11
10
  from collections.abc import Callable
12
11
  from collections.abc import Mapping
@@ -22,7 +21,6 @@ from .types import StrAnyMap
22
21
  __all__ = [
23
22
  # Data utilities
24
23
  'count_records',
25
- 'json_type',
26
24
  'print_json',
27
25
  # Mapping utilities
28
26
  'cast_str_dict',
@@ -119,35 +117,6 @@ def count_records(
119
117
  return len(data) if isinstance(data, list) else 1
120
118
 
121
119
 
122
- def json_type(
123
- option: str,
124
- ) -> Any:
125
- """
126
- Argparse ``type=`` hook that parses a JSON string.
127
-
128
- Parameters
129
- ----------
130
- option : str
131
- Raw CLI string to parse as JSON.
132
-
133
- Returns
134
- -------
135
- Any
136
- Parsed JSON value.
137
-
138
- Raises
139
- ------
140
- argparse.ArgumentTypeError
141
- If the input cannot be parsed as JSON.
142
- """
143
- try:
144
- return json.loads(option)
145
- except json.JSONDecodeError as e: # pragma: no cover - argparse path
146
- raise argparse.ArgumentTypeError(
147
- f'Invalid JSON: {e.msg} (pos {e.pos})',
148
- ) from e
149
-
150
-
151
120
  def maybe_mapping(
152
121
  value: Any,
153
122
  ) -> StrAnyMap | None:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: etlplus
3
- Version: 0.7.0
3
+ Version: 0.8.3
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
@@ -64,7 +64,7 @@ package and command-line interface for data extraction, validation, transformati
64
64
  - [Quickstart](#quickstart)
65
65
  - [Usage](#usage)
66
66
  - [Command Line Interface](#command-line-interface)
67
- - [Inspect Pipelines](#inspect-pipelines)
67
+ - [Check Pipelines](#check-pipelines)
68
68
  - [Render SQL DDL](#render-sql-ddl)
69
69
  - [Extract Data](#extract-data)
70
70
  - [Validate Data](#validate-data)
@@ -182,6 +182,9 @@ etlplus --help
182
182
  etlplus --version
183
183
  ```
184
184
 
185
+ The CLI is implemented with Typer (Click-based). There is no argparse compatibility layer, so rely
186
+ on the documented commands/flags and run `etlplus <command> --help` for current options.
187
+
185
188
  #### Check Pipelines
186
189
 
187
190
  Use `etlplus check` to explore pipeline YAML definitions without running them. The command can print
@@ -366,8 +369,6 @@ etlplus check --config examples/configs/pipeline.yml --summary
366
369
 
367
370
  # Run a job
368
371
  etlplus run --config examples/configs/pipeline.yml --job file_to_file_customers
369
-
370
- # Deprecated shim (will be removed): etlplus pipeline
371
372
  ```
372
373
 
373
374
  ### Complete ETL Pipeline Example
@@ -10,10 +10,10 @@ etlplus/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
10
10
  etlplus/run.py,sha256=X4kp5FQlIWVf1_d9oSrchKau7BFDCE1Zkscvu7WPaWw,12340
11
11
  etlplus/run_helpers.py,sha256=bj6MkaeFxjl3CeKG1HoXKx5DwAlXNERVW-GX-z1P_qQ,24373
12
12
  etlplus/transform.py,sha256=uAUVDDHYCgx7GpVez9IK3OAZM-CnCuMa9iox3vwGGJA,25296
13
- etlplus/types.py,sha256=SJiZ7wJiSnV4CEvF-9E5nSFLBo4DT9OqHQqj1GSHkv8,6042
14
- etlplus/utils.py,sha256=_fn8b-SAdxiw28VX-Ugr8sZUPZI9mEkWKAGExlgxhJA,13993
13
+ etlplus/types.py,sha256=1hsDlnF6r76zAwaUYay-i6pCM-Y0IU5nP7Crj8PLCQ4,6157
14
+ etlplus/utils.py,sha256=GrRH6N9u_U-4gs6PYpO0_Y2RwsyD3Ju9cup0b0byUbk,13367
15
15
  etlplus/validate.py,sha256=7rJoEI_SIILdPpoBqqh2UJqg9oeReDz34mYSlc3t7Qg,12989
16
- etlplus/api/README.md,sha256=UkK5PiZWXbbnMNP0MaPa56S88PjSqOwhMNCyswOhvKc,7329
16
+ etlplus/api/README.md,sha256=ZiyjxLz0LfFCzeYKXwtH8yY1OJ4hXCju7t2ICroFoU8,7215
17
17
  etlplus/api/__init__.py,sha256=P2JUYFy6Ep4t6xnsBiCBfQCkQLHYYhA-yXPXCobS8Y0,4295
18
18
  etlplus/api/auth.py,sha256=GOO5on-LoMS1GXTAhtK9rFcfpjbBcNeA6NE5UZwIq0g,12158
19
19
  etlplus/api/config.py,sha256=wRpOaZ31sPReVzEMme0jKl_37nqgraESwuYSNxP_xDo,17397
@@ -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/app.py,sha256=SYPO-NDwXgymJrACw39jZ_NJrSKAs0O8anuWR5o42WM,35893
35
- etlplus/cli/handlers.py,sha256=nFMvqHQhJ8kJZPisDCiUHeOhjlqAO6hJvRjXiJTcU74,18951
36
- etlplus/cli/main.py,sha256=ijYOy72SEsxrTEBan5yADW8CZyr0yddVF8HeMgFw6Zg,16576
34
+ etlplus/cli/commands.py,sha256=-lO8XX2IeTvdfZLeI_UpT2kH4qZuNpfujArw3IKS2vY,22585
35
+ etlplus/cli/constants.py,sha256=NJ6IvNyYEI8IdB7eMcc-vteQiiIwqid5YvmUk-5DRHY,1839
36
+ etlplus/cli/handlers.py,sha256=WBzJZz7ESU4Hljog_ON4g9PLIW6U6io_F9op7daksKY,17781
37
+ etlplus/cli/io.py,sha256=hkmbDh0HFrZhDjfZbma0Lp4tc0wrTwdD9Snqa-wNAd4,7308
38
+ etlplus/cli/main.py,sha256=_ipwLgIzkf8ks8cbu2KkVBbY3gcdaqDR98WUBdwviiw,5191
39
+ etlplus/cli/options.py,sha256=dswqAdnQ4fRJGI3xEFUyMifp0ry3rm2cCaPyEqI_99c,1199
40
+ etlplus/cli/state.py,sha256=20uKdYddYvAlR-HUQJAV-ThyXMZaPiSk9cN-tevRIpw,7991
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
@@ -41,19 +46,20 @@ etlplus/config/pipeline.py,sha256=Va4MQY6KEyKqHGMKPmh09ZcGpx95br-iNUjpkqtzVbw,95
41
46
  etlplus/config/profile.py,sha256=Ss2zedQGjkaGSpvBLTD4SZaWViMJ7TJPLB8Q2_BTpPg,1898
42
47
  etlplus/config/types.py,sha256=a0epJ3z16HQ5bY3Ctf8s_cQPa3f0HHcwdOcjCP2xoG4,4954
43
48
  etlplus/config/utils.py,sha256=4SUHMkt5bKBhMhiJm-DrnmE2Q4TfOgdNCKz8PJDS27o,3443
44
- etlplus/database/__init__.py,sha256=0gWnMlQiVHS6SVUxIT9zklQUHU36y-2RF_gN1cx7icg,1018
45
- etlplus/database/ddl.py,sha256=lIar9KIOoBRslp_P0DnpoMDXzkjt64J5-iVV7CeSV_M,7747
46
- etlplus/database/engine.py,sha256=54f-XtNKIuogJhsLV9cX_xPoBwcl_HNJTL5HqMCi8kw,3986
47
- etlplus/database/orm.py,sha256=StjeguokM70oNKq7mNXLyc4_mYUZR-EKW3oGRlsd8QE,9962
48
- etlplus/database/schema.py,sha256=BmRP2wwX2xex1phLm0tnHrP6A2AQgguA-hSLnK0xwwc,7003
49
+ etlplus/database/__init__.py,sha256=AKJsDl2RHuRGPS-eXgNJeh4aSncJP5Y0yLApBF6i7i8,1052
50
+ etlplus/database/ddl.py,sha256=z9KvHi1MPhPBLHxMDdqJgLTp3A2-lcz0gqhZ7HIE6kU,7916
51
+ etlplus/database/engine.py,sha256=7rr7YndA8LwyWJL8k1YhQbqxxmW4gWEUQjp0NwQcYtc,4061
52
+ etlplus/database/orm.py,sha256=gCSqH-CjQz6tV9133-VqgiwokK5ylun0BwXaIWfImAo,10008
53
+ etlplus/database/schema.py,sha256=HNTgglI8qvQLInr7gq--2lLmLKHzAZTL2MJUOIw9DlY,7025
54
+ etlplus/database/types.py,sha256=_pkQyC14TzAlgyeIqZG4F5LWYknZbHw3TW68Auk7Ya0,795
49
55
  etlplus/templates/__init__.py,sha256=tsniN7XJYs3NwYxJ6c2HD5upHP3CDkLx-bQCMt97UOM,106
50
56
  etlplus/templates/ddl.sql.j2,sha256=s8fMWvcb4eaJVXkifuib1aQPljtZ8buuyB_uA-ZdU3Q,4734
51
57
  etlplus/templates/view.sql.j2,sha256=Iy8DHfhq5yyvrUKDxqp_aHIEXY4Tm6j4wT7YDEFWAhk,2180
52
58
  etlplus/validation/__init__.py,sha256=Pe5Xg1_EA4uiNZGYu5WTF3j7odjmyxnAJ8rcioaplSQ,1254
53
59
  etlplus/validation/utils.py,sha256=Mtqg449VIke0ziy_wd2r6yrwJzQkA1iulZC87FzXMjo,10201
54
- etlplus-0.7.0.dist-info/licenses/LICENSE,sha256=MuNO63i6kWmgnV2pbP2SLqP54mk1BGmu7CmbtxMmT-U,1069
55
- etlplus-0.7.0.dist-info/METADATA,sha256=ulMPDyXMX6p-NcxMBSZfegGrv0LNwAu_686_TVrkJPM,19383
56
- etlplus-0.7.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
57
- etlplus-0.7.0.dist-info/entry_points.txt,sha256=6w-2-jzuPa55spzK34h-UKh2JTEShh38adFRONNP9QE,45
58
- etlplus-0.7.0.dist-info/top_level.txt,sha256=aWWF-udn_sLGuHTM6W6MLh99ArS9ROkUWO8Mi8y1_2U,8
59
- etlplus-0.7.0.dist-info/RECORD,,
60
+ etlplus-0.8.3.dist-info/licenses/LICENSE,sha256=MuNO63i6kWmgnV2pbP2SLqP54mk1BGmu7CmbtxMmT-U,1069
61
+ etlplus-0.8.3.dist-info/METADATA,sha256=fCmfB5aa9jgUEb2s_l-5j5b3vooe-l3M0pNYrrjhYAg,19513
62
+ etlplus-0.8.3.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
63
+ etlplus-0.8.3.dist-info/entry_points.txt,sha256=6w-2-jzuPa55spzK34h-UKh2JTEShh38adFRONNP9QE,45
64
+ etlplus-0.8.3.dist-info/top_level.txt,sha256=aWWF-udn_sLGuHTM6W6MLh99ArS9ROkUWO8Mi8y1_2U,8
65
+ etlplus-0.8.3.dist-info/RECORD,,