dlt-utils 0.2.0__tar.gz → 0.4.0__tar.gz
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.
- {dlt_utils-0.2.0 → dlt_utils-0.4.0}/PKG-INFO +1 -1
- {dlt_utils-0.2.0 → dlt_utils-0.4.0}/dlt_utils/__init__.py +7 -1
- dlt_utils-0.4.0/dlt_utils/args.py +373 -0
- {dlt_utils-0.2.0 → dlt_utils-0.4.0}/dlt_utils/pipeline.py +45 -0
- {dlt_utils-0.2.0 → dlt_utils-0.4.0}/dlt_utils.egg-info/PKG-INFO +1 -1
- {dlt_utils-0.2.0 → dlt_utils-0.4.0}/pyproject.toml +1 -1
- dlt_utils-0.2.0/dlt_utils/args.py +0 -154
- {dlt_utils-0.2.0 → dlt_utils-0.4.0}/README.md +0 -0
- {dlt_utils-0.2.0 → dlt_utils-0.4.0}/dlt_utils/azure_keyvault.py +0 -0
- {dlt_utils-0.2.0 → dlt_utils-0.4.0}/dlt_utils/dates.py +0 -0
- {dlt_utils-0.2.0 → dlt_utils-0.4.0}/dlt_utils/incremental.py +0 -0
- {dlt_utils-0.2.0 → dlt_utils-0.4.0}/dlt_utils/logging.py +0 -0
- {dlt_utils-0.2.0 → dlt_utils-0.4.0}/dlt_utils/schema.py +0 -0
- {dlt_utils-0.2.0 → dlt_utils-0.4.0}/dlt_utils.egg-info/SOURCES.txt +0 -0
- {dlt_utils-0.2.0 → dlt_utils-0.4.0}/dlt_utils.egg-info/dependency_links.txt +0 -0
- {dlt_utils-0.2.0 → dlt_utils-0.4.0}/dlt_utils.egg-info/requires.txt +0 -0
- {dlt_utils-0.2.0 → dlt_utils-0.4.0}/dlt_utils.egg-info/top_level.txt +0 -0
- {dlt_utils-0.2.0 → dlt_utils-0.4.0}/setup.cfg +0 -0
- {dlt_utils-0.2.0 → dlt_utils-0.4.0}/tests/test_azure_keyvault.py +0 -0
- {dlt_utils-0.2.0 → dlt_utils-0.4.0}/tests/test_dates.py +0 -0
- {dlt_utils-0.2.0 → dlt_utils-0.4.0}/tests/test_incremental.py +0 -0
|
@@ -26,10 +26,13 @@ from .args import (
|
|
|
26
26
|
add_common_args,
|
|
27
27
|
create_base_parser,
|
|
28
28
|
CommonArgs,
|
|
29
|
+
filter_by_indices,
|
|
30
|
+
resolve_start_year,
|
|
29
31
|
)
|
|
30
32
|
from .azure_keyvault import AzureKeyVault
|
|
31
33
|
from .logging import configure_logging
|
|
32
34
|
from .pipeline import (
|
|
35
|
+
cleanup_tombstones,
|
|
33
36
|
filter_resources,
|
|
34
37
|
get_resource_names,
|
|
35
38
|
mask_sensitive_value,
|
|
@@ -38,7 +41,7 @@ from .pipeline import (
|
|
|
38
41
|
)
|
|
39
42
|
|
|
40
43
|
|
|
41
|
-
__version__ = "0.
|
|
44
|
+
__version__ = "0.4.0"
|
|
42
45
|
|
|
43
46
|
__all__ = [
|
|
44
47
|
# Incremental
|
|
@@ -54,11 +57,14 @@ __all__ = [
|
|
|
54
57
|
"add_common_args",
|
|
55
58
|
"CommonArgs",
|
|
56
59
|
"create_base_parser",
|
|
60
|
+
"filter_by_indices",
|
|
61
|
+
"resolve_start_year",
|
|
57
62
|
# azure_keyvault
|
|
58
63
|
"AzureKeyVault",
|
|
59
64
|
# logging
|
|
60
65
|
"configure_logging",
|
|
61
66
|
# pipeline
|
|
67
|
+
"cleanup_tombstones",
|
|
62
68
|
"filter_resources",
|
|
63
69
|
"get_resource_names",
|
|
64
70
|
"mask_sensitive_value",
|
|
@@ -0,0 +1,373 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Common CLI arguments for dlt pipelines.
|
|
3
|
+
|
|
4
|
+
This module provides reusable argument definitions that can be added to any
|
|
5
|
+
dlt pipeline's argument parser.
|
|
6
|
+
|
|
7
|
+
Usage:
|
|
8
|
+
from dlt_utils import create_base_parser, add_common_args
|
|
9
|
+
|
|
10
|
+
# Option 1: Use pre-configured base parser
|
|
11
|
+
parser = create_base_parser(description="My pipeline")
|
|
12
|
+
parser.add_argument("--my-custom-arg", ...)
|
|
13
|
+
args = parser.parse_args()
|
|
14
|
+
|
|
15
|
+
# Option 2: Add common args to existing parser
|
|
16
|
+
parser = argparse.ArgumentParser(description="My pipeline")
|
|
17
|
+
add_common_args(parser)
|
|
18
|
+
parser.add_argument("--my-custom-arg", ...)
|
|
19
|
+
args = parser.parse_args()
|
|
20
|
+
|
|
21
|
+
# Option 3: Exclude certain args and include optional ones
|
|
22
|
+
parser = create_base_parser(
|
|
23
|
+
description="My pipeline",
|
|
24
|
+
exclude=["dev_mode", "refresh"],
|
|
25
|
+
include=["companies", "start_year"],
|
|
26
|
+
)
|
|
27
|
+
args = parser.parse_args()
|
|
28
|
+
|
|
29
|
+
# Option 4: Filter items by indices from --companies
|
|
30
|
+
all_configs = get_company_configs()
|
|
31
|
+
selected = filter_by_indices(all_configs, args.companies)
|
|
32
|
+
"""
|
|
33
|
+
import argparse
|
|
34
|
+
import logging
|
|
35
|
+
from dataclasses import dataclass
|
|
36
|
+
from datetime import datetime, timezone
|
|
37
|
+
from typing import Literal, TypeVar
|
|
38
|
+
|
|
39
|
+
logger = logging.getLogger(__name__)
|
|
40
|
+
|
|
41
|
+
T = TypeVar("T")
|
|
42
|
+
|
|
43
|
+
# All available argument names for validation
|
|
44
|
+
CORE_ARGS = {"debug", "resources", "destination", "dev_mode", "refresh", "list_resources"}
|
|
45
|
+
OPTIONAL_ARGS = {"companies", "start_year"}
|
|
46
|
+
ALL_ARGS = CORE_ARGS | OPTIONAL_ARGS
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
@dataclass
|
|
50
|
+
class CommonArgs:
|
|
51
|
+
"""
|
|
52
|
+
Dataclass representing common CLI arguments.
|
|
53
|
+
|
|
54
|
+
Attributes:
|
|
55
|
+
debug: Enable debug logging
|
|
56
|
+
destination: Target database type
|
|
57
|
+
dev_mode: Reset schema between runs
|
|
58
|
+
resources: List of resources to load (None = all)
|
|
59
|
+
refresh: Refresh mode for tables
|
|
60
|
+
list_resources: Show available resources and exit
|
|
61
|
+
companies: List of company indices to load (None = all)
|
|
62
|
+
start_year: Start year for partitioned resources (None = source default)
|
|
63
|
+
"""
|
|
64
|
+
debug: bool = False
|
|
65
|
+
destination: Literal["duckdb", "mssql"] = "mssql"
|
|
66
|
+
dev_mode: bool = False
|
|
67
|
+
resources: list[str] | None = None
|
|
68
|
+
refresh: Literal["drop_sources", "drop_resources"] | None = None
|
|
69
|
+
list_resources: bool = False
|
|
70
|
+
companies: list[int] | None = None
|
|
71
|
+
start_year: int | None = None
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
def add_common_args(
|
|
75
|
+
parser: argparse.ArgumentParser,
|
|
76
|
+
default_destination: str = "mssql",
|
|
77
|
+
destinations: list[str] | None = None,
|
|
78
|
+
exclude: list[str] | None = None,
|
|
79
|
+
include: list[str] | None = None,
|
|
80
|
+
) -> None:
|
|
81
|
+
"""
|
|
82
|
+
Add common dlt pipeline arguments to an existing parser.
|
|
83
|
+
|
|
84
|
+
Args:
|
|
85
|
+
parser: The argument parser to add arguments to.
|
|
86
|
+
default_destination: Default destination database (default: mssql).
|
|
87
|
+
destinations: List of allowed destinations (default: ["duckdb", "mssql"]).
|
|
88
|
+
exclude: List of argument names to exclude from core args.
|
|
89
|
+
Valid names: debug, resources, destination, dev_mode, refresh, list_resources
|
|
90
|
+
include: List of optional argument names to include.
|
|
91
|
+
Valid names: companies, start_year
|
|
92
|
+
|
|
93
|
+
Core arguments (added by default unless excluded):
|
|
94
|
+
--debug: Enable debug logging
|
|
95
|
+
--resources: List of resources to load
|
|
96
|
+
--destination: Target database
|
|
97
|
+
--dev-mode: Reset schema between runs
|
|
98
|
+
--refresh: Refresh mode (drop_sources or drop_resources)
|
|
99
|
+
--list-resources: Show available resources and exit
|
|
100
|
+
|
|
101
|
+
Optional arguments (only added when included):
|
|
102
|
+
--companies: List of company indices to load
|
|
103
|
+
--start-year: Start year for partitioned resources
|
|
104
|
+
|
|
105
|
+
Raises:
|
|
106
|
+
ValueError: If invalid argument names are provided in exclude or include.
|
|
107
|
+
"""
|
|
108
|
+
if destinations is None:
|
|
109
|
+
destinations = ["duckdb", "mssql"]
|
|
110
|
+
|
|
111
|
+
exclude_set = set(exclude) if exclude else set()
|
|
112
|
+
include_set = set(include) if include else set()
|
|
113
|
+
|
|
114
|
+
# Validate exclude names
|
|
115
|
+
invalid_exclude = exclude_set - CORE_ARGS
|
|
116
|
+
if invalid_exclude:
|
|
117
|
+
raise ValueError(
|
|
118
|
+
f"Invalid exclude argument(s): {invalid_exclude}. "
|
|
119
|
+
f"Valid options: {CORE_ARGS}"
|
|
120
|
+
)
|
|
121
|
+
|
|
122
|
+
# Validate include names
|
|
123
|
+
invalid_include = include_set - OPTIONAL_ARGS
|
|
124
|
+
if invalid_include:
|
|
125
|
+
raise ValueError(
|
|
126
|
+
f"Invalid include argument(s): {invalid_include}. "
|
|
127
|
+
f"Valid options: {OPTIONAL_ARGS}"
|
|
128
|
+
)
|
|
129
|
+
|
|
130
|
+
# Core arguments (added unless excluded)
|
|
131
|
+
if "debug" not in exclude_set:
|
|
132
|
+
parser.add_argument(
|
|
133
|
+
"--debug",
|
|
134
|
+
action="store_true",
|
|
135
|
+
help="Enable debug logging",
|
|
136
|
+
)
|
|
137
|
+
|
|
138
|
+
if "resources" not in exclude_set:
|
|
139
|
+
parser.add_argument(
|
|
140
|
+
"--resources",
|
|
141
|
+
nargs="*",
|
|
142
|
+
default=None,
|
|
143
|
+
help="List of resources to load (default: all)",
|
|
144
|
+
)
|
|
145
|
+
|
|
146
|
+
if "destination" not in exclude_set:
|
|
147
|
+
parser.add_argument(
|
|
148
|
+
"--destination",
|
|
149
|
+
choices=destinations,
|
|
150
|
+
default=default_destination,
|
|
151
|
+
help=f"Destination database (default: {default_destination})",
|
|
152
|
+
)
|
|
153
|
+
|
|
154
|
+
if "dev_mode" not in exclude_set:
|
|
155
|
+
parser.add_argument(
|
|
156
|
+
"--dev-mode",
|
|
157
|
+
action="store_true",
|
|
158
|
+
default=False,
|
|
159
|
+
help="Enable dev mode (resets schema between runs)",
|
|
160
|
+
)
|
|
161
|
+
|
|
162
|
+
if "refresh" not in exclude_set:
|
|
163
|
+
parser.add_argument(
|
|
164
|
+
"--refresh",
|
|
165
|
+
choices=["drop_sources", "drop_resources"],
|
|
166
|
+
default=None,
|
|
167
|
+
help=(
|
|
168
|
+
"Refresh mode: 'drop_sources' drops all tables and state for the source "
|
|
169
|
+
"(full rebuild), 'drop_resources' only drops tables and state for "
|
|
170
|
+
"selected resources"
|
|
171
|
+
),
|
|
172
|
+
)
|
|
173
|
+
|
|
174
|
+
if "list_resources" not in exclude_set:
|
|
175
|
+
parser.add_argument(
|
|
176
|
+
"--list-resources",
|
|
177
|
+
action="store_true",
|
|
178
|
+
help="List all available resources and exit",
|
|
179
|
+
)
|
|
180
|
+
|
|
181
|
+
# Optional arguments (only added when included)
|
|
182
|
+
if "companies" in include_set:
|
|
183
|
+
parser.add_argument(
|
|
184
|
+
"--companies",
|
|
185
|
+
nargs="*",
|
|
186
|
+
type=int,
|
|
187
|
+
default=None,
|
|
188
|
+
help="List of company indices to load (default: all), e.g. 1 2",
|
|
189
|
+
)
|
|
190
|
+
|
|
191
|
+
if "start_year" in include_set:
|
|
192
|
+
parser.add_argument(
|
|
193
|
+
"--start-year",
|
|
194
|
+
type=int,
|
|
195
|
+
default=None,
|
|
196
|
+
help=(
|
|
197
|
+
"Start year for partitioned resources. "
|
|
198
|
+
"Can be an absolute year (e.g., 2023) or a negative number for years back "
|
|
199
|
+
"(e.g., -0 = current year, -1 = last year, -3 = 3 years ago). "
|
|
200
|
+
"Defaults to source default if not set."
|
|
201
|
+
),
|
|
202
|
+
)
|
|
203
|
+
|
|
204
|
+
|
|
205
|
+
def create_base_parser(
|
|
206
|
+
description: str = "DLT data pipeline",
|
|
207
|
+
default_destination: str = "mssql",
|
|
208
|
+
destinations: list[str] | None = None,
|
|
209
|
+
exclude: list[str] | None = None,
|
|
210
|
+
include: list[str] | None = None,
|
|
211
|
+
) -> argparse.ArgumentParser:
|
|
212
|
+
"""
|
|
213
|
+
Create an argument parser with common dlt pipeline arguments pre-configured.
|
|
214
|
+
|
|
215
|
+
Args:
|
|
216
|
+
description: Description for the argument parser.
|
|
217
|
+
default_destination: Default destination database (default: mssql).
|
|
218
|
+
destinations: List of allowed destinations (default: ["duckdb", "mssql"]).
|
|
219
|
+
exclude: List of argument names to exclude from core args.
|
|
220
|
+
Valid names: debug, resources, destination, dev_mode, refresh, list_resources
|
|
221
|
+
include: List of optional argument names to include.
|
|
222
|
+
Valid names: companies, start_year
|
|
223
|
+
|
|
224
|
+
Returns:
|
|
225
|
+
ArgumentParser with common arguments already added.
|
|
226
|
+
|
|
227
|
+
Example:
|
|
228
|
+
# Basic usage
|
|
229
|
+
parser = create_base_parser("My Pipeline")
|
|
230
|
+
args = parser.parse_args()
|
|
231
|
+
|
|
232
|
+
# With custom args and exclusions
|
|
233
|
+
parser = create_base_parser(
|
|
234
|
+
"My Pipeline",
|
|
235
|
+
exclude=["dev_mode"],
|
|
236
|
+
include=["companies", "start_year"],
|
|
237
|
+
)
|
|
238
|
+
parser.add_argument("--my-custom-arg", type=int, default=10)
|
|
239
|
+
args = parser.parse_args()
|
|
240
|
+
"""
|
|
241
|
+
parser = argparse.ArgumentParser(description=description)
|
|
242
|
+
add_common_args(parser, default_destination, destinations, exclude, include)
|
|
243
|
+
return parser
|
|
244
|
+
|
|
245
|
+
|
|
246
|
+
def get_common_args(args: argparse.Namespace) -> CommonArgs:
|
|
247
|
+
"""
|
|
248
|
+
Extract common arguments from a parsed Namespace into a CommonArgs dataclass.
|
|
249
|
+
|
|
250
|
+
Args:
|
|
251
|
+
args: Parsed argument namespace.
|
|
252
|
+
|
|
253
|
+
Returns:
|
|
254
|
+
CommonArgs dataclass with extracted values.
|
|
255
|
+
"""
|
|
256
|
+
return CommonArgs(
|
|
257
|
+
debug=getattr(args, "debug", False),
|
|
258
|
+
destination=getattr(args, "destination", "mssql"),
|
|
259
|
+
dev_mode=getattr(args, "dev_mode", False),
|
|
260
|
+
resources=getattr(args, "resources", None),
|
|
261
|
+
refresh=getattr(args, "refresh", None),
|
|
262
|
+
list_resources=getattr(args, "list_resources", False),
|
|
263
|
+
companies=getattr(args, "companies", None),
|
|
264
|
+
start_year=getattr(args, "start_year", None),
|
|
265
|
+
)
|
|
266
|
+
|
|
267
|
+
|
|
268
|
+
def resolve_start_year(start_year: int | None) -> int | None:
|
|
269
|
+
"""
|
|
270
|
+
Resolve start_year argument to an absolute year.
|
|
271
|
+
|
|
272
|
+
Supports both absolute years (e.g., 2023) and negative offsets
|
|
273
|
+
(e.g., -0 = current year, -1 = last year, -3 = 3 years ago).
|
|
274
|
+
|
|
275
|
+
Args:
|
|
276
|
+
start_year: The start year argument from CLI. Can be:
|
|
277
|
+
- None: Returns None (let the source use its default)
|
|
278
|
+
- Positive int: Interpreted as absolute year
|
|
279
|
+
- Zero or negative int: Interpreted as years back from current year
|
|
280
|
+
(-0 = current year, -1 = last year, -2 = 2 years ago, etc.)
|
|
281
|
+
|
|
282
|
+
Returns:
|
|
283
|
+
Resolved absolute year, or None if not specified.
|
|
284
|
+
|
|
285
|
+
Example:
|
|
286
|
+
# Assuming current year is 2026
|
|
287
|
+
resolve_start_year(None) # Returns None
|
|
288
|
+
resolve_start_year(2023) # Returns 2023
|
|
289
|
+
resolve_start_year(0) # Returns 2026 (current year)
|
|
290
|
+
resolve_start_year(-1) # Returns 2025 (last year)
|
|
291
|
+
resolve_start_year(-3) # Returns 2023 (3 years ago)
|
|
292
|
+
"""
|
|
293
|
+
if start_year is None:
|
|
294
|
+
return None
|
|
295
|
+
|
|
296
|
+
current_year = datetime.now(timezone.utc).year
|
|
297
|
+
|
|
298
|
+
if start_year <= 0:
|
|
299
|
+
# Negative or zero: interpret as years back
|
|
300
|
+
# 0 = current year, -1 = last year, etc.
|
|
301
|
+
resolved = current_year + start_year # start_year is negative, so this subtracts
|
|
302
|
+
logger.debug(
|
|
303
|
+
f"Resolved start_year {start_year} to {resolved} (current year: {current_year})"
|
|
304
|
+
)
|
|
305
|
+
return resolved
|
|
306
|
+
else:
|
|
307
|
+
# Positive: interpret as absolute year
|
|
308
|
+
return start_year
|
|
309
|
+
|
|
310
|
+
|
|
311
|
+
def filter_by_indices(
|
|
312
|
+
items: list[T],
|
|
313
|
+
indices: list[int] | None,
|
|
314
|
+
item_name: str = "item",
|
|
315
|
+
) -> list[T]:
|
|
316
|
+
"""
|
|
317
|
+
Filter a list of items by 1-based indices.
|
|
318
|
+
|
|
319
|
+
If indices is None or empty, returns all items.
|
|
320
|
+
|
|
321
|
+
Args:
|
|
322
|
+
items: The list of items to filter.
|
|
323
|
+
indices: List of 1-based indices to select, or None for all items.
|
|
324
|
+
item_name: Name of the items for error messages (e.g., "company", "resource").
|
|
325
|
+
|
|
326
|
+
Returns:
|
|
327
|
+
Filtered list of items.
|
|
328
|
+
|
|
329
|
+
Raises:
|
|
330
|
+
ValueError: If no items are available or no valid indices are provided.
|
|
331
|
+
|
|
332
|
+
Example:
|
|
333
|
+
configs = [config1, config2, config3]
|
|
334
|
+
|
|
335
|
+
# Select all
|
|
336
|
+
filter_by_indices(configs, None) # Returns [config1, config2, config3]
|
|
337
|
+
|
|
338
|
+
# Select specific items
|
|
339
|
+
filter_by_indices(configs, [1, 3]) # Returns [config1, config3]
|
|
340
|
+
|
|
341
|
+
# With custom name for errors
|
|
342
|
+
filter_by_indices(configs, [5], item_name="company")
|
|
343
|
+
# Raises: ValueError: No valid companies. Available: 1-3
|
|
344
|
+
"""
|
|
345
|
+
if not items:
|
|
346
|
+
raise ValueError(f"No {item_name}s available.")
|
|
347
|
+
|
|
348
|
+
if not indices:
|
|
349
|
+
logger.info(f"Loading all {len(items)} {item_name}(s)")
|
|
350
|
+
return items
|
|
351
|
+
|
|
352
|
+
# Filter by 1-based indices
|
|
353
|
+
selected = [
|
|
354
|
+
items[i - 1]
|
|
355
|
+
for i in indices
|
|
356
|
+
if 0 < i <= len(items)
|
|
357
|
+
]
|
|
358
|
+
|
|
359
|
+
if not selected:
|
|
360
|
+
raise ValueError(
|
|
361
|
+
f"No valid {item_name}s. Available: 1-{len(items)}"
|
|
362
|
+
)
|
|
363
|
+
|
|
364
|
+
# Log any invalid indices
|
|
365
|
+
invalid = [i for i in indices if i < 1 or i > len(items)]
|
|
366
|
+
if invalid:
|
|
367
|
+
logger.warning(
|
|
368
|
+
f"Ignored invalid {item_name} indices: {invalid}. "
|
|
369
|
+
f"Valid range: 1-{len(items)}"
|
|
370
|
+
)
|
|
371
|
+
|
|
372
|
+
logger.info(f"Selected {item_name}(s): {indices}")
|
|
373
|
+
return selected
|
|
@@ -124,3 +124,48 @@ def mask_sensitive_value(value: str | None, show_chars: int = 2) -> str:
|
|
|
124
124
|
|
|
125
125
|
mid = len(value) // 2
|
|
126
126
|
return f"{value[:show_chars]}..{value[mid:mid+show_chars]}..***"
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
def cleanup_tombstones(
|
|
130
|
+
pipeline: Any,
|
|
131
|
+
resources: list[str],
|
|
132
|
+
column_name: str = "_tt_is_tombstone",
|
|
133
|
+
) -> None:
|
|
134
|
+
"""
|
|
135
|
+
Clean up tombstone records from tables after a successful pipeline run.
|
|
136
|
+
|
|
137
|
+
Tombstones are placeholder records used to ensure delete-insert semantics
|
|
138
|
+
work correctly for partitions that have no real data. After the pipeline
|
|
139
|
+
completes, these tombstone records should be removed.
|
|
140
|
+
|
|
141
|
+
Args:
|
|
142
|
+
pipeline: A dlt pipeline object with sql_client() method.
|
|
143
|
+
resources: List of resource/table names to clean tombstones from.
|
|
144
|
+
column_name: The boolean column name that marks tombstone records.
|
|
145
|
+
Defaults to "_tt_is_tombstone".
|
|
146
|
+
|
|
147
|
+
Example:
|
|
148
|
+
# Clean up tombstones from all resources except 'customer'
|
|
149
|
+
tombstone_resources = [r for r in sync_resources if r != "customer"]
|
|
150
|
+
cleanup_tombstones(pipeline, tombstone_resources)
|
|
151
|
+
|
|
152
|
+
# Clean up with a custom column name
|
|
153
|
+
cleanup_tombstones(pipeline, ["my_table"], column_name="is_tombstone")
|
|
154
|
+
"""
|
|
155
|
+
if not resources:
|
|
156
|
+
logger.debug("No resources provided for tombstone cleanup")
|
|
157
|
+
return
|
|
158
|
+
|
|
159
|
+
with pipeline.sql_client() as sql_client:
|
|
160
|
+
for resource_name in resources:
|
|
161
|
+
table_name = sql_client.make_qualified_table_name(resource_name)
|
|
162
|
+
delete_query = f"DELETE FROM {table_name} WHERE {column_name} = TRUE"
|
|
163
|
+
|
|
164
|
+
try:
|
|
165
|
+
sql_client.execute_sql(delete_query)
|
|
166
|
+
logger.info(f"Cleaned up tombstone records from {table_name}")
|
|
167
|
+
except Exception as e:
|
|
168
|
+
# Table might not exist on first run or if resource wasn't selected
|
|
169
|
+
logger.warning(
|
|
170
|
+
f"Could not clean tombstones from {table_name}: {e}"
|
|
171
|
+
)
|
|
@@ -1,154 +0,0 @@
|
|
|
1
|
-
"""
|
|
2
|
-
Common CLI arguments for dlt pipelines.
|
|
3
|
-
|
|
4
|
-
This module provides reusable argument definitions that can be added to any
|
|
5
|
-
dlt pipeline's argument parser.
|
|
6
|
-
|
|
7
|
-
Usage:
|
|
8
|
-
from dlt_utils import create_base_parser, add_common_args
|
|
9
|
-
|
|
10
|
-
# Option 1: Use pre-configured base parser
|
|
11
|
-
parser = create_base_parser(description="My pipeline")
|
|
12
|
-
parser.add_argument("--my-custom-arg", ...)
|
|
13
|
-
args = parser.parse_args()
|
|
14
|
-
|
|
15
|
-
# Option 2: Add common args to existing parser
|
|
16
|
-
parser = argparse.ArgumentParser(description="My pipeline")
|
|
17
|
-
add_common_args(parser)
|
|
18
|
-
parser.add_argument("--my-custom-arg", ...)
|
|
19
|
-
args = parser.parse_args()
|
|
20
|
-
"""
|
|
21
|
-
import argparse
|
|
22
|
-
from dataclasses import dataclass
|
|
23
|
-
from typing import Literal
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
@dataclass
|
|
27
|
-
class CommonArgs:
|
|
28
|
-
"""
|
|
29
|
-
Dataclass representing common CLI arguments.
|
|
30
|
-
|
|
31
|
-
Attributes:
|
|
32
|
-
debug: Enable debug logging
|
|
33
|
-
destination: Target database type
|
|
34
|
-
dev_mode: Reset schema between runs
|
|
35
|
-
resources: List of resources to load (None = all)
|
|
36
|
-
refresh: Refresh mode for tables
|
|
37
|
-
list_resources: Show available resources and exit
|
|
38
|
-
"""
|
|
39
|
-
debug: bool = False
|
|
40
|
-
destination: Literal["duckdb", "mssql"] = "mssql"
|
|
41
|
-
dev_mode: bool = False
|
|
42
|
-
resources: list[str] | None = None
|
|
43
|
-
refresh: Literal["drop_sources", "drop_resources"] | None = None
|
|
44
|
-
list_resources: bool = False
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
def add_common_args(
|
|
48
|
-
parser: argparse.ArgumentParser,
|
|
49
|
-
default_destination: str = "mssql",
|
|
50
|
-
destinations: list[str] | None = None,
|
|
51
|
-
) -> None:
|
|
52
|
-
"""
|
|
53
|
-
Add common dlt pipeline arguments to an existing parser.
|
|
54
|
-
|
|
55
|
-
Args:
|
|
56
|
-
parser: The argument parser to add arguments to.
|
|
57
|
-
default_destination: Default destination database (default: mssql).
|
|
58
|
-
destinations: List of allowed destinations (default: ["duckdb", "mssql"]).
|
|
59
|
-
|
|
60
|
-
Added arguments:
|
|
61
|
-
--debug: Enable debug logging
|
|
62
|
-
--resources: List of resources to load
|
|
63
|
-
--destination: Target database
|
|
64
|
-
--dev-mode: Reset schema between runs
|
|
65
|
-
--refresh: Refresh mode (drop_sources or drop_resources)
|
|
66
|
-
--list-resources: Show available resources and exit
|
|
67
|
-
"""
|
|
68
|
-
if destinations is None:
|
|
69
|
-
destinations = ["duckdb", "mssql"]
|
|
70
|
-
|
|
71
|
-
parser.add_argument(
|
|
72
|
-
"--debug",
|
|
73
|
-
action="store_true",
|
|
74
|
-
help="Enable debug logging",
|
|
75
|
-
)
|
|
76
|
-
parser.add_argument(
|
|
77
|
-
"--resources",
|
|
78
|
-
nargs="*",
|
|
79
|
-
default=None,
|
|
80
|
-
help="List of resources to load (default: all)",
|
|
81
|
-
)
|
|
82
|
-
parser.add_argument(
|
|
83
|
-
"--destination",
|
|
84
|
-
choices=destinations,
|
|
85
|
-
default=default_destination,
|
|
86
|
-
help=f"Destination database (default: {default_destination})",
|
|
87
|
-
)
|
|
88
|
-
parser.add_argument(
|
|
89
|
-
"--dev-mode",
|
|
90
|
-
action="store_true",
|
|
91
|
-
default=False,
|
|
92
|
-
help="Enable dev mode (resets schema between runs)",
|
|
93
|
-
)
|
|
94
|
-
parser.add_argument(
|
|
95
|
-
"--refresh",
|
|
96
|
-
choices=["drop_sources", "drop_resources"],
|
|
97
|
-
default=None,
|
|
98
|
-
help=(
|
|
99
|
-
"Refresh mode: 'drop_sources' drops all tables and state for the source "
|
|
100
|
-
"(full rebuild), 'drop_resources' only drops tables and state for "
|
|
101
|
-
"selected resources"
|
|
102
|
-
),
|
|
103
|
-
)
|
|
104
|
-
parser.add_argument(
|
|
105
|
-
"--list-resources",
|
|
106
|
-
action="store_true",
|
|
107
|
-
help="List all available resources and exit",
|
|
108
|
-
)
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
def create_base_parser(
|
|
112
|
-
description: str = "DLT data pipeline",
|
|
113
|
-
default_destination: str = "mssql",
|
|
114
|
-
destinations: list[str] | None = None,
|
|
115
|
-
) -> argparse.ArgumentParser:
|
|
116
|
-
"""
|
|
117
|
-
Create an argument parser with common dlt pipeline arguments pre-configured.
|
|
118
|
-
|
|
119
|
-
Args:
|
|
120
|
-
description: Description for the argument parser.
|
|
121
|
-
default_destination: Default destination database (default: mssql).
|
|
122
|
-
destinations: List of allowed destinations (default: ["duckdb", "mssql"]).
|
|
123
|
-
|
|
124
|
-
Returns:
|
|
125
|
-
ArgumentParser with common arguments already added.
|
|
126
|
-
|
|
127
|
-
Example:
|
|
128
|
-
parser = create_base_parser("My Pipeline")
|
|
129
|
-
parser.add_argument("--my-custom-arg", type=int, default=10)
|
|
130
|
-
args = parser.parse_args()
|
|
131
|
-
"""
|
|
132
|
-
parser = argparse.ArgumentParser(description=description)
|
|
133
|
-
add_common_args(parser, default_destination, destinations)
|
|
134
|
-
return parser
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
def get_common_args(args: argparse.Namespace) -> CommonArgs:
|
|
138
|
-
"""
|
|
139
|
-
Extract common arguments from a parsed Namespace into a CommonArgs dataclass.
|
|
140
|
-
|
|
141
|
-
Args:
|
|
142
|
-
args: Parsed argument namespace.
|
|
143
|
-
|
|
144
|
-
Returns:
|
|
145
|
-
CommonArgs dataclass with extracted values.
|
|
146
|
-
"""
|
|
147
|
-
return CommonArgs(
|
|
148
|
-
debug=getattr(args, "debug", False),
|
|
149
|
-
destination=getattr(args, "destination", "mssql"),
|
|
150
|
-
dev_mode=getattr(args, "dev_mode", False),
|
|
151
|
-
resources=getattr(args, "resources", None),
|
|
152
|
-
refresh=getattr(args, "refresh", None),
|
|
153
|
-
list_resources=getattr(args, "list_resources", False),
|
|
154
|
-
)
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|