sqlmesh 0.182.1.dev11__py3-none-any.whl → 0.183.1.dev1__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.
- sqlmesh/_version.py +2 -2
- sqlmesh/core/console.py +50 -17
- sqlmesh/core/model/definition.py +32 -23
- sqlmesh/core/plan/evaluator.py +50 -0
- sqlmesh/core/scheduler.py +243 -127
- {sqlmesh-0.182.1.dev11.dist-info → sqlmesh-0.183.1.dev1.dist-info}/METADATA +1 -1
- {sqlmesh-0.182.1.dev11.dist-info → sqlmesh-0.183.1.dev1.dist-info}/RECORD +12 -12
- {sqlmesh-0.182.1.dev11.dist-info → sqlmesh-0.183.1.dev1.dist-info}/WHEEL +1 -1
- web/server/console.py +14 -1
- {sqlmesh-0.182.1.dev11.dist-info → sqlmesh-0.183.1.dev1.dist-info}/entry_points.txt +0 -0
- {sqlmesh-0.182.1.dev11.dist-info → sqlmesh-0.183.1.dev1.dist-info}/licenses/LICENSE +0 -0
- {sqlmesh-0.182.1.dev11.dist-info → sqlmesh-0.183.1.dev1.dist-info}/top_level.txt +0 -0
sqlmesh/_version.py
CHANGED
|
@@ -17,5 +17,5 @@ __version__: str
|
|
|
17
17
|
__version_tuple__: VERSION_TUPLE
|
|
18
18
|
version_tuple: VERSION_TUPLE
|
|
19
19
|
|
|
20
|
-
__version__ = version = '0.
|
|
21
|
-
__version_tuple__ = version_tuple = (0,
|
|
20
|
+
__version__ = version = '0.183.1.dev1'
|
|
21
|
+
__version_tuple__ = version_tuple = (0, 183, 1, 'dev1')
|
sqlmesh/core/console.py
CHANGED
|
@@ -350,11 +350,14 @@ class Console(
|
|
|
350
350
|
batched_intervals: t.Dict[Snapshot, Intervals],
|
|
351
351
|
environment_naming_info: EnvironmentNamingInfo,
|
|
352
352
|
default_catalog: t.Optional[str],
|
|
353
|
+
audit_only: bool = False,
|
|
353
354
|
) -> None:
|
|
354
|
-
"""Indicates that a new snapshot evaluation progress has begun."""
|
|
355
|
+
"""Indicates that a new snapshot evaluation/auditing progress has begun."""
|
|
355
356
|
|
|
356
357
|
@abc.abstractmethod
|
|
357
|
-
def start_snapshot_evaluation_progress(
|
|
358
|
+
def start_snapshot_evaluation_progress(
|
|
359
|
+
self, snapshot: Snapshot, audit_only: bool = False
|
|
360
|
+
) -> None:
|
|
358
361
|
"""Starts the snapshot evaluation progress."""
|
|
359
362
|
|
|
360
363
|
@abc.abstractmethod
|
|
@@ -366,6 +369,7 @@ class Console(
|
|
|
366
369
|
duration_ms: t.Optional[int],
|
|
367
370
|
num_audits_passed: int,
|
|
368
371
|
num_audits_failed: int,
|
|
372
|
+
audit_only: bool = False,
|
|
369
373
|
) -> None:
|
|
370
374
|
"""Updates the snapshot evaluation progress."""
|
|
371
375
|
|
|
@@ -507,10 +511,13 @@ class NoopConsole(Console):
|
|
|
507
511
|
batched_intervals: t.Dict[Snapshot, Intervals],
|
|
508
512
|
environment_naming_info: EnvironmentNamingInfo,
|
|
509
513
|
default_catalog: t.Optional[str],
|
|
514
|
+
audit_only: bool = False,
|
|
510
515
|
) -> None:
|
|
511
516
|
pass
|
|
512
517
|
|
|
513
|
-
def start_snapshot_evaluation_progress(
|
|
518
|
+
def start_snapshot_evaluation_progress(
|
|
519
|
+
self, snapshot: Snapshot, audit_only: bool = False
|
|
520
|
+
) -> None:
|
|
514
521
|
pass
|
|
515
522
|
|
|
516
523
|
def update_snapshot_evaluation_progress(
|
|
@@ -521,6 +528,7 @@ class NoopConsole(Console):
|
|
|
521
528
|
duration_ms: t.Optional[int],
|
|
522
529
|
num_audits_passed: int,
|
|
523
530
|
num_audits_failed: int,
|
|
531
|
+
audit_only: bool = False,
|
|
524
532
|
) -> None:
|
|
525
533
|
pass
|
|
526
534
|
|
|
@@ -891,11 +899,12 @@ class TerminalConsole(Console):
|
|
|
891
899
|
batched_intervals: t.Dict[Snapshot, Intervals],
|
|
892
900
|
environment_naming_info: EnvironmentNamingInfo,
|
|
893
901
|
default_catalog: t.Optional[str],
|
|
902
|
+
audit_only: bool = False,
|
|
894
903
|
) -> None:
|
|
895
|
-
"""Indicates that a new snapshot evaluation progress has begun."""
|
|
904
|
+
"""Indicates that a new snapshot evaluation/auditing progress has begun."""
|
|
896
905
|
if not self.evaluation_progress_live:
|
|
897
906
|
self.evaluation_total_progress = make_progress_bar(
|
|
898
|
-
"Executing model batches", self.console
|
|
907
|
+
"Executing model batches" if not audit_only else "Auditing models", self.console
|
|
899
908
|
)
|
|
900
909
|
|
|
901
910
|
self.evaluation_model_progress = Progress(
|
|
@@ -916,8 +925,9 @@ class TerminalConsole(Console):
|
|
|
916
925
|
batch_sizes = {
|
|
917
926
|
snapshot: len(intervals) for snapshot, intervals in batched_intervals.items()
|
|
918
927
|
}
|
|
928
|
+
message = "Executing" if not audit_only else "Auditing"
|
|
919
929
|
self.evaluation_total_task = self.evaluation_total_progress.add_task(
|
|
920
|
-
"
|
|
930
|
+
f"{message} models...", total=sum(batch_sizes.values())
|
|
921
931
|
)
|
|
922
932
|
|
|
923
933
|
# determine column widths
|
|
@@ -943,7 +953,9 @@ class TerminalConsole(Console):
|
|
|
943
953
|
self.environment_naming_info = environment_naming_info
|
|
944
954
|
self.default_catalog = default_catalog
|
|
945
955
|
|
|
946
|
-
def start_snapshot_evaluation_progress(
|
|
956
|
+
def start_snapshot_evaluation_progress(
|
|
957
|
+
self, snapshot: Snapshot, audit_only: bool = False
|
|
958
|
+
) -> None:
|
|
947
959
|
if self.evaluation_model_progress and snapshot.name not in self.evaluation_model_tasks:
|
|
948
960
|
display_name = snapshot.display_name(
|
|
949
961
|
self.environment_naming_info,
|
|
@@ -951,7 +963,7 @@ class TerminalConsole(Console):
|
|
|
951
963
|
dialect=self.dialect,
|
|
952
964
|
)
|
|
953
965
|
self.evaluation_model_tasks[snapshot.name] = self.evaluation_model_progress.add_task(
|
|
954
|
-
f"Evaluating {display_name}...",
|
|
966
|
+
f"{'Evaluating' if not audit_only else 'Auditing'} {display_name}...",
|
|
955
967
|
view_name=display_name,
|
|
956
968
|
total=self.evaluation_model_batch_sizes[snapshot],
|
|
957
969
|
)
|
|
@@ -964,6 +976,7 @@ class TerminalConsole(Console):
|
|
|
964
976
|
duration_ms: t.Optional[int],
|
|
965
977
|
num_audits_passed: int,
|
|
966
978
|
num_audits_failed: int,
|
|
979
|
+
audit_only: bool = False,
|
|
967
980
|
) -> None:
|
|
968
981
|
"""Update the snapshot evaluation progress."""
|
|
969
982
|
if (
|
|
@@ -1003,7 +1016,7 @@ class TerminalConsole(Console):
|
|
|
1003
1016
|
self.evaluation_column_widths["duration"]
|
|
1004
1017
|
)
|
|
1005
1018
|
|
|
1006
|
-
msg = f"{batch} {display_name} {annotation} {duration}".replace(
|
|
1019
|
+
msg = f"{f'{batch} ' if not audit_only else ''}{display_name} {annotation} {duration}".replace(
|
|
1007
1020
|
self.AUDIT_PASS_MARK, self.GREEN_AUDIT_PASS_MARK
|
|
1008
1021
|
)
|
|
1009
1022
|
|
|
@@ -1015,7 +1028,10 @@ class TerminalConsole(Console):
|
|
|
1015
1028
|
|
|
1016
1029
|
model_task_id = self.evaluation_model_tasks[snapshot.name]
|
|
1017
1030
|
self.evaluation_model_progress.update(model_task_id, refresh=True, advance=1)
|
|
1018
|
-
if
|
|
1031
|
+
if (
|
|
1032
|
+
self.evaluation_model_progress._tasks[model_task_id].completed >= total_batches
|
|
1033
|
+
or audit_only
|
|
1034
|
+
):
|
|
1019
1035
|
self.evaluation_model_progress.remove_task(model_task_id)
|
|
1020
1036
|
|
|
1021
1037
|
def stop_evaluation_progress(self, success: bool = True) -> None:
|
|
@@ -3208,6 +3224,7 @@ class DatabricksMagicConsole(CaptureTerminalConsole):
|
|
|
3208
3224
|
batched_intervals: t.Dict[Snapshot, Intervals],
|
|
3209
3225
|
environment_naming_info: EnvironmentNamingInfo,
|
|
3210
3226
|
default_catalog: t.Optional[str],
|
|
3227
|
+
audit_only: bool = False,
|
|
3211
3228
|
) -> None:
|
|
3212
3229
|
self.evaluation_model_batch_sizes = {
|
|
3213
3230
|
snapshot: len(intervals) for snapshot, intervals in batched_intervals.items()
|
|
@@ -3215,7 +3232,9 @@ class DatabricksMagicConsole(CaptureTerminalConsole):
|
|
|
3215
3232
|
self.evaluation_environment_naming_info = environment_naming_info
|
|
3216
3233
|
self.default_catalog = default_catalog
|
|
3217
3234
|
|
|
3218
|
-
def start_snapshot_evaluation_progress(
|
|
3235
|
+
def start_snapshot_evaluation_progress(
|
|
3236
|
+
self, snapshot: Snapshot, audit_only: bool = False
|
|
3237
|
+
) -> None:
|
|
3219
3238
|
if not self.evaluation_batch_progress.get(snapshot.snapshot_id):
|
|
3220
3239
|
display_name = snapshot.display_name(
|
|
3221
3240
|
self.evaluation_environment_naming_info,
|
|
@@ -3235,8 +3254,14 @@ class DatabricksMagicConsole(CaptureTerminalConsole):
|
|
|
3235
3254
|
duration_ms: t.Optional[int],
|
|
3236
3255
|
num_audits_passed: int,
|
|
3237
3256
|
num_audits_failed: int,
|
|
3257
|
+
audit_only: bool = False,
|
|
3238
3258
|
) -> None:
|
|
3239
3259
|
view_name, loaded_batches = self.evaluation_batch_progress[snapshot.snapshot_id]
|
|
3260
|
+
|
|
3261
|
+
if audit_only:
|
|
3262
|
+
print(f"Completed Auditing {view_name}")
|
|
3263
|
+
return
|
|
3264
|
+
|
|
3240
3265
|
total_batches = self.evaluation_model_batch_sizes[snapshot]
|
|
3241
3266
|
|
|
3242
3267
|
loaded_batches += 1
|
|
@@ -3378,13 +3403,17 @@ class DebuggerTerminalConsole(TerminalConsole):
|
|
|
3378
3403
|
batched_intervals: t.Dict[Snapshot, Intervals],
|
|
3379
3404
|
environment_naming_info: EnvironmentNamingInfo,
|
|
3380
3405
|
default_catalog: t.Optional[str],
|
|
3406
|
+
audit_only: bool = False,
|
|
3381
3407
|
) -> None:
|
|
3408
|
+
message = "evaluation" if not audit_only else "auditing"
|
|
3382
3409
|
self._write(
|
|
3383
|
-
f"Starting
|
|
3410
|
+
f"Starting {message} for {sum(len(intervals) for intervals in batched_intervals.values())} snapshots"
|
|
3384
3411
|
)
|
|
3385
3412
|
|
|
3386
|
-
def start_snapshot_evaluation_progress(
|
|
3387
|
-
self
|
|
3413
|
+
def start_snapshot_evaluation_progress(
|
|
3414
|
+
self, snapshot: Snapshot, audit_only: bool = False
|
|
3415
|
+
) -> None:
|
|
3416
|
+
self._write(f"{'Evaluating' if not audit_only else 'Auditing'} {snapshot.name}")
|
|
3388
3417
|
|
|
3389
3418
|
def update_snapshot_evaluation_progress(
|
|
3390
3419
|
self,
|
|
@@ -3394,10 +3423,14 @@ class DebuggerTerminalConsole(TerminalConsole):
|
|
|
3394
3423
|
duration_ms: t.Optional[int],
|
|
3395
3424
|
num_audits_passed: int,
|
|
3396
3425
|
num_audits_failed: int,
|
|
3426
|
+
audit_only: bool = False,
|
|
3397
3427
|
) -> None:
|
|
3398
|
-
|
|
3399
|
-
|
|
3400
|
-
|
|
3428
|
+
message = f"Evaluating {snapshot.name} | batch={batch_idx} | duration={duration_ms}ms | num_audits_passed={num_audits_passed} | num_audits_failed={num_audits_failed}"
|
|
3429
|
+
|
|
3430
|
+
if audit_only:
|
|
3431
|
+
message = f"Auditing {snapshot.name} duration={duration_ms}ms | num_audits_passed={num_audits_passed} | num_audits_failed={num_audits_failed}"
|
|
3432
|
+
|
|
3433
|
+
self._write(message)
|
|
3401
3434
|
|
|
3402
3435
|
def stop_evaluation_progress(self, success: bool = True) -> None:
|
|
3403
3436
|
self._write(f"Stopping evaluation with success={success}")
|
sqlmesh/core/model/definition.py
CHANGED
|
@@ -1069,6 +1069,37 @@ class _Model(ModelMeta, frozen=True):
|
|
|
1069
1069
|
|
|
1070
1070
|
return data # type: ignore
|
|
1071
1071
|
|
|
1072
|
+
def _audit_metadata_hash_values(self) -> t.List[str]:
|
|
1073
|
+
from sqlmesh.core.audit.builtin import BUILT_IN_AUDITS
|
|
1074
|
+
|
|
1075
|
+
metadata = []
|
|
1076
|
+
|
|
1077
|
+
for audit_name, audit_args in sorted(self.audits, key=lambda a: a[0]):
|
|
1078
|
+
metadata.append(audit_name)
|
|
1079
|
+
if audit_name in BUILT_IN_AUDITS:
|
|
1080
|
+
for arg_name, arg_value in audit_args.items():
|
|
1081
|
+
metadata.append(arg_name)
|
|
1082
|
+
metadata.append(gen(arg_value))
|
|
1083
|
+
else:
|
|
1084
|
+
audit = self.audit_definitions[audit_name]
|
|
1085
|
+
query = (
|
|
1086
|
+
self.render_audit_query(audit, **t.cast(t.Dict[str, t.Any], audit_args))
|
|
1087
|
+
or audit.query
|
|
1088
|
+
)
|
|
1089
|
+
metadata.extend(
|
|
1090
|
+
[
|
|
1091
|
+
gen(query),
|
|
1092
|
+
audit.dialect,
|
|
1093
|
+
str(audit.skip),
|
|
1094
|
+
str(audit.blocking),
|
|
1095
|
+
]
|
|
1096
|
+
)
|
|
1097
|
+
|
|
1098
|
+
return metadata
|
|
1099
|
+
|
|
1100
|
+
def audit_metadata_hash(self) -> str:
|
|
1101
|
+
return hash_data(self._audit_metadata_hash_values())
|
|
1102
|
+
|
|
1072
1103
|
@property
|
|
1073
1104
|
def metadata_hash(self) -> str:
|
|
1074
1105
|
"""
|
|
@@ -1078,8 +1109,6 @@ class _Model(ModelMeta, frozen=True):
|
|
|
1078
1109
|
The metadata hash for the node.
|
|
1079
1110
|
"""
|
|
1080
1111
|
if self._metadata_hash is None:
|
|
1081
|
-
from sqlmesh.core.audit.builtin import BUILT_IN_AUDITS
|
|
1082
|
-
|
|
1083
1112
|
metadata = [
|
|
1084
1113
|
self.dialect,
|
|
1085
1114
|
self.owner,
|
|
@@ -1100,29 +1129,9 @@ class _Model(ModelMeta, frozen=True):
|
|
|
1100
1129
|
str(self.allow_partials),
|
|
1101
1130
|
gen(self.session_properties_) if self.session_properties_ else None,
|
|
1102
1131
|
*[gen(g) for g in self.grains],
|
|
1132
|
+
*self._audit_metadata_hash_values(),
|
|
1103
1133
|
]
|
|
1104
1134
|
|
|
1105
|
-
for audit_name, audit_args in sorted(self.audits, key=lambda a: a[0]):
|
|
1106
|
-
metadata.append(audit_name)
|
|
1107
|
-
if audit_name in BUILT_IN_AUDITS:
|
|
1108
|
-
for arg_name, arg_value in audit_args.items():
|
|
1109
|
-
metadata.append(arg_name)
|
|
1110
|
-
metadata.append(gen(arg_value))
|
|
1111
|
-
else:
|
|
1112
|
-
audit = self.audit_definitions[audit_name]
|
|
1113
|
-
query = (
|
|
1114
|
-
self.render_audit_query(audit, **t.cast(t.Dict[str, t.Any], audit_args))
|
|
1115
|
-
or audit.query
|
|
1116
|
-
)
|
|
1117
|
-
metadata.extend(
|
|
1118
|
-
[
|
|
1119
|
-
gen(query),
|
|
1120
|
-
audit.dialect,
|
|
1121
|
-
str(audit.skip),
|
|
1122
|
-
str(audit.blocking),
|
|
1123
|
-
]
|
|
1124
|
-
)
|
|
1125
|
-
|
|
1126
1135
|
for key, value in (self.virtual_properties or {}).items():
|
|
1127
1136
|
metadata.append(key)
|
|
1128
1137
|
metadata.append(gen(value))
|
sqlmesh/core/plan/evaluator.py
CHANGED
|
@@ -128,6 +128,8 @@ class BuiltInPlanEvaluator(PlanEvaluator):
|
|
|
128
128
|
execution_time=plan.execution_time,
|
|
129
129
|
)
|
|
130
130
|
|
|
131
|
+
self._run_audits_for_metadata_snapshots(plan, new_snapshots)
|
|
132
|
+
|
|
131
133
|
push_completion_status = self._push(plan, snapshots, deployability_index_for_creation)
|
|
132
134
|
if push_completion_status.is_nothing_to_do:
|
|
133
135
|
self.console.log_status_update(
|
|
@@ -545,6 +547,54 @@ class BuiltInPlanEvaluator(PlanEvaluator):
|
|
|
545
547
|
|
|
546
548
|
return set(snapshots_to_restate.values())
|
|
547
549
|
|
|
550
|
+
def _run_audits_for_metadata_snapshots(
|
|
551
|
+
self,
|
|
552
|
+
plan: EvaluatablePlan,
|
|
553
|
+
new_snapshots: t.Dict[SnapshotId, Snapshot],
|
|
554
|
+
) -> None:
|
|
555
|
+
# Filter out snapshots that are not categorized as metadata changes on models
|
|
556
|
+
metadata_snapshots = []
|
|
557
|
+
for snapshot in new_snapshots.values():
|
|
558
|
+
if not snapshot.is_metadata or not snapshot.is_model or not snapshot.evaluatable:
|
|
559
|
+
continue
|
|
560
|
+
|
|
561
|
+
metadata_snapshots.append(snapshot)
|
|
562
|
+
|
|
563
|
+
# Bulk load all the previous snapshots
|
|
564
|
+
previous_snapshots = self.state_sync.get_snapshots(
|
|
565
|
+
[
|
|
566
|
+
s.previous_version.snapshot_id(s.name)
|
|
567
|
+
for s in metadata_snapshots
|
|
568
|
+
if s.previous_version
|
|
569
|
+
]
|
|
570
|
+
).values()
|
|
571
|
+
|
|
572
|
+
# Check if any of the snapshots have modifications to the audits field by comparing the hashes
|
|
573
|
+
audit_snapshots = {}
|
|
574
|
+
for snapshot, previous_snapshot in zip(metadata_snapshots, previous_snapshots):
|
|
575
|
+
new_audits_hash = snapshot.model.audit_metadata_hash()
|
|
576
|
+
previous_audit_hash = previous_snapshot.model.audit_metadata_hash()
|
|
577
|
+
|
|
578
|
+
if snapshot.model.audits and previous_audit_hash != new_audits_hash:
|
|
579
|
+
audit_snapshots[snapshot.snapshot_id] = snapshot
|
|
580
|
+
|
|
581
|
+
if not audit_snapshots:
|
|
582
|
+
return
|
|
583
|
+
|
|
584
|
+
# If there are any snapshots to be audited, we'll reuse the scheduler's internals to audit them
|
|
585
|
+
scheduler = self.create_scheduler(audit_snapshots.values())
|
|
586
|
+
completion_status = scheduler.audit(
|
|
587
|
+
plan.environment,
|
|
588
|
+
plan.start,
|
|
589
|
+
plan.end,
|
|
590
|
+
execution_time=plan.execution_time,
|
|
591
|
+
end_bounded=plan.end_bounded,
|
|
592
|
+
interval_end_per_model=plan.interval_end_per_model,
|
|
593
|
+
)
|
|
594
|
+
|
|
595
|
+
if completion_status.is_failure:
|
|
596
|
+
raise PlanError("Plan application failed.")
|
|
597
|
+
|
|
548
598
|
|
|
549
599
|
def update_intervals_for_new_snapshots(
|
|
550
600
|
snapshots: t.Collection[Snapshot], state_sync: StateSync
|
sqlmesh/core/scheduler.py
CHANGED
|
@@ -149,8 +149,9 @@ class Scheduler:
|
|
|
149
149
|
execution_time: TimeLike,
|
|
150
150
|
deployability_index: DeployabilityIndex,
|
|
151
151
|
batch_index: int,
|
|
152
|
+
environment_naming_info: t.Optional[EnvironmentNamingInfo] = None,
|
|
152
153
|
**kwargs: t.Any,
|
|
153
|
-
) -> t.
|
|
154
|
+
) -> t.List[AuditResult]:
|
|
154
155
|
"""Evaluate a snapshot and add the processed interval to the state sync.
|
|
155
156
|
|
|
156
157
|
Args:
|
|
@@ -182,8 +183,9 @@ class Scheduler:
|
|
|
182
183
|
batch_index=batch_index,
|
|
183
184
|
**kwargs,
|
|
184
185
|
)
|
|
185
|
-
audit_results = self.
|
|
186
|
+
audit_results = self._audit_snapshot(
|
|
186
187
|
snapshot=snapshot,
|
|
188
|
+
environment_naming_info=environment_naming_info,
|
|
187
189
|
start=start,
|
|
188
190
|
end=end,
|
|
189
191
|
execution_time=execution_time,
|
|
@@ -193,32 +195,8 @@ class Scheduler:
|
|
|
193
195
|
**kwargs,
|
|
194
196
|
)
|
|
195
197
|
|
|
196
|
-
audit_errors_to_raise: t.List[AuditError] = []
|
|
197
|
-
audit_errors_to_warn: t.List[AuditError] = []
|
|
198
|
-
for audit_result in (result for result in audit_results if result.count):
|
|
199
|
-
error = AuditError(
|
|
200
|
-
audit_name=audit_result.audit.name,
|
|
201
|
-
audit_args=audit_result.audit_args,
|
|
202
|
-
model=snapshot.model_or_none,
|
|
203
|
-
count=t.cast(int, audit_result.count),
|
|
204
|
-
query=t.cast(exp.Query, audit_result.query),
|
|
205
|
-
adapter_dialect=self.snapshot_evaluator.adapter.dialect,
|
|
206
|
-
)
|
|
207
|
-
self.notification_target_manager.notify(NotificationEvent.AUDIT_FAILURE, error)
|
|
208
|
-
if is_deployable and snapshot.node.owner:
|
|
209
|
-
self.notification_target_manager.notify_user(
|
|
210
|
-
NotificationEvent.AUDIT_FAILURE, snapshot.node.owner, error
|
|
211
|
-
)
|
|
212
|
-
if audit_result.blocking:
|
|
213
|
-
audit_errors_to_raise.append(error)
|
|
214
|
-
else:
|
|
215
|
-
audit_errors_to_warn.append(error)
|
|
216
|
-
|
|
217
|
-
if audit_errors_to_raise:
|
|
218
|
-
raise NodeAuditsErrors(audit_errors_to_raise)
|
|
219
|
-
|
|
220
198
|
self.state_sync.add_interval(snapshot, start, end, is_dev=not is_deployable)
|
|
221
|
-
return audit_results
|
|
199
|
+
return audit_results
|
|
222
200
|
|
|
223
201
|
def run(
|
|
224
202
|
self,
|
|
@@ -236,101 +214,61 @@ class Scheduler:
|
|
|
236
214
|
auto_restatement_enabled: bool = False,
|
|
237
215
|
run_environment_statements: bool = False,
|
|
238
216
|
) -> CompletionStatus:
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
start: The start of the run. Defaults to the min node start date.
|
|
246
|
-
end: The end of the run. Defaults to now.
|
|
247
|
-
execution_time: The date/time time reference to use for execution time. Defaults to now.
|
|
248
|
-
restatements: A dict of snapshots to restate and their intervals.
|
|
249
|
-
interval_end_per_model: The mapping from model FQNs to target end dates.
|
|
250
|
-
ignore_cron: Whether to ignore the node's cron schedule.
|
|
251
|
-
end_bounded: If set to true, the evaluated intervals will be bounded by the target end date, disregarding lookback,
|
|
252
|
-
allow_partials, and other attributes that could cause the intervals to exceed the target end date.
|
|
253
|
-
selected_snapshots: A set of snapshot names to run. If not provided, all snapshots will be run.
|
|
254
|
-
circuit_breaker: An optional handler which checks if the run should be aborted.
|
|
255
|
-
deployability_index: Determines snapshots that are deployable in the context of this render.
|
|
256
|
-
auto_restatement_enabled: Whether to enable auto restatements.
|
|
257
|
-
|
|
258
|
-
Returns:
|
|
259
|
-
True if the execution was successful and False otherwise.
|
|
260
|
-
"""
|
|
261
|
-
restatements = restatements or {}
|
|
262
|
-
validate_date_range(start, end)
|
|
263
|
-
if isinstance(environment, str):
|
|
264
|
-
env = self.state_sync.get_environment(environment)
|
|
265
|
-
if not env:
|
|
266
|
-
raise SQLMeshError(
|
|
267
|
-
"Was not provided an environment suffix target and the environment doesn't exist."
|
|
268
|
-
"Are you running for the first time and need to run plan/apply first?"
|
|
269
|
-
)
|
|
270
|
-
environment_naming_info = env.naming_info
|
|
271
|
-
else:
|
|
272
|
-
environment_naming_info = environment
|
|
273
|
-
|
|
274
|
-
deployability_index = deployability_index or (
|
|
275
|
-
DeployabilityIndex.create(self.snapshots.values(), start=start)
|
|
276
|
-
if environment_naming_info.name != c.PROD
|
|
277
|
-
else DeployabilityIndex.all_deployable()
|
|
278
|
-
)
|
|
279
|
-
execution_time = execution_time or now_timestamp()
|
|
280
|
-
|
|
281
|
-
self.state_sync.refresh_snapshot_intervals(self.snapshots.values())
|
|
282
|
-
for s_id, interval in (restatements or {}).items():
|
|
283
|
-
self.snapshots[s_id].remove_interval(interval)
|
|
284
|
-
|
|
285
|
-
if auto_restatement_enabled:
|
|
286
|
-
auto_restated_intervals = apply_auto_restatements(self.snapshots, execution_time)
|
|
287
|
-
self.state_sync.add_snapshots_intervals(auto_restated_intervals)
|
|
288
|
-
self.state_sync.update_auto_restatements(
|
|
289
|
-
{s.name_version: s.next_auto_restatement_ts for s in self.snapshots.values()}
|
|
290
|
-
)
|
|
291
|
-
|
|
292
|
-
merged_intervals = self.merged_missing_intervals(
|
|
293
|
-
start,
|
|
294
|
-
end,
|
|
295
|
-
execution_time,
|
|
296
|
-
deployability_index=deployability_index,
|
|
297
|
-
restatements=restatements,
|
|
217
|
+
return self._run_or_audit(
|
|
218
|
+
environment=environment,
|
|
219
|
+
start=start,
|
|
220
|
+
end=end,
|
|
221
|
+
execution_time=execution_time,
|
|
222
|
+
remove_intervals=restatements,
|
|
298
223
|
interval_end_per_model=interval_end_per_model,
|
|
299
224
|
ignore_cron=ignore_cron,
|
|
300
225
|
end_bounded=end_bounded,
|
|
301
226
|
selected_snapshots=selected_snapshots,
|
|
227
|
+
circuit_breaker=circuit_breaker,
|
|
228
|
+
deployability_index=deployability_index,
|
|
229
|
+
auto_restatement_enabled=auto_restatement_enabled,
|
|
230
|
+
run_environment_statements=run_environment_statements,
|
|
302
231
|
)
|
|
303
232
|
|
|
304
|
-
|
|
305
|
-
|
|
233
|
+
def audit(
|
|
234
|
+
self,
|
|
235
|
+
environment: str | EnvironmentNamingInfo,
|
|
236
|
+
start: TimeLike,
|
|
237
|
+
end: TimeLike,
|
|
238
|
+
execution_time: t.Optional[TimeLike] = None,
|
|
239
|
+
interval_end_per_model: t.Optional[t.Dict[str, int]] = None,
|
|
240
|
+
ignore_cron: bool = False,
|
|
241
|
+
end_bounded: bool = False,
|
|
242
|
+
selected_snapshots: t.Optional[t.Set[str]] = None,
|
|
243
|
+
circuit_breaker: t.Optional[t.Callable[[], bool]] = None,
|
|
244
|
+
deployability_index: t.Optional[DeployabilityIndex] = None,
|
|
245
|
+
run_environment_statements: bool = False,
|
|
246
|
+
) -> CompletionStatus:
|
|
247
|
+
# Remove the intervals from the snapshots that will be audited so that they can be recomputed
|
|
248
|
+
# by _run_or_audit as "missing intervals" to reuse the rest of it's logic
|
|
249
|
+
remove_intervals = {}
|
|
250
|
+
for snapshot in self.snapshots.values():
|
|
251
|
+
removal_intervals = snapshot.get_removal_interval(
|
|
252
|
+
start, end, execution_time, is_preview=True
|
|
253
|
+
)
|
|
254
|
+
remove_intervals[snapshot.snapshot_id] = removal_intervals
|
|
306
255
|
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
deployability_index=deployability_index,
|
|
310
|
-
environment_naming_info=environment_naming_info,
|
|
311
|
-
execution_time=execution_time,
|
|
312
|
-
circuit_breaker=circuit_breaker,
|
|
256
|
+
return self._run_or_audit(
|
|
257
|
+
environment=environment,
|
|
313
258
|
start=start,
|
|
314
259
|
end=end,
|
|
260
|
+
execution_time=execution_time,
|
|
261
|
+
remove_intervals=remove_intervals,
|
|
262
|
+
interval_end_per_model=interval_end_per_model,
|
|
263
|
+
ignore_cron=ignore_cron,
|
|
264
|
+
end_bounded=end_bounded,
|
|
265
|
+
selected_snapshots=selected_snapshots,
|
|
266
|
+
circuit_breaker=circuit_breaker,
|
|
267
|
+
deployability_index=deployability_index,
|
|
315
268
|
run_environment_statements=run_environment_statements,
|
|
269
|
+
audit_only=True,
|
|
316
270
|
)
|
|
317
271
|
|
|
318
|
-
self.console.stop_evaluation_progress(success=not errors)
|
|
319
|
-
|
|
320
|
-
skipped_snapshots = {i[0] for i in skipped_intervals}
|
|
321
|
-
self.console.log_skipped_models(skipped_snapshots)
|
|
322
|
-
for skipped in skipped_snapshots:
|
|
323
|
-
logger.info(f"SKIPPED snapshot {skipped}\n")
|
|
324
|
-
|
|
325
|
-
for error in errors:
|
|
326
|
-
if isinstance(error.__cause__, CircuitBreakerError):
|
|
327
|
-
raise error.__cause__
|
|
328
|
-
logger.info(str(error), exc_info=error)
|
|
329
|
-
|
|
330
|
-
self.console.log_failed_models(errors)
|
|
331
|
-
|
|
332
|
-
return CompletionStatus.FAILURE if errors else CompletionStatus.SUCCESS
|
|
333
|
-
|
|
334
272
|
def batch_intervals(
|
|
335
273
|
self,
|
|
336
274
|
merged_intervals: SnapshotToIntervals,
|
|
@@ -407,6 +345,7 @@ class Scheduler:
|
|
|
407
345
|
start: t.Optional[TimeLike] = None,
|
|
408
346
|
end: t.Optional[TimeLike] = None,
|
|
409
347
|
run_environment_statements: bool = False,
|
|
348
|
+
audit_only: bool = False,
|
|
410
349
|
) -> t.Tuple[t.List[NodeExecutionFailedError[SchedulingUnit]], t.List[SchedulingUnit]]:
|
|
411
350
|
"""Runs precomputed batches of missing intervals.
|
|
412
351
|
|
|
@@ -430,6 +369,7 @@ class Scheduler:
|
|
|
430
369
|
batched_intervals,
|
|
431
370
|
environment_naming_info,
|
|
432
371
|
self.default_catalog,
|
|
372
|
+
audit_only=audit_only,
|
|
433
373
|
)
|
|
434
374
|
|
|
435
375
|
dag = self._dag(batched_intervals)
|
|
@@ -465,28 +405,29 @@ class Scheduler:
|
|
|
465
405
|
evaluation_duration_ms: t.Optional[int] = None
|
|
466
406
|
|
|
467
407
|
audit_results: t.List[AuditResult] = []
|
|
468
|
-
audit_errors_to_warn: t.List[AuditError] = []
|
|
469
408
|
try:
|
|
470
409
|
assert execution_time # mypy
|
|
471
410
|
assert deployability_index # mypy
|
|
472
|
-
audit_results, audit_errors_to_warn = self.evaluate(
|
|
473
|
-
snapshot=snapshot,
|
|
474
|
-
start=start,
|
|
475
|
-
end=end,
|
|
476
|
-
execution_time=execution_time,
|
|
477
|
-
deployability_index=deployability_index,
|
|
478
|
-
batch_index=batch_idx,
|
|
479
|
-
)
|
|
480
411
|
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
412
|
+
if audit_only:
|
|
413
|
+
audit_results = self._audit_snapshot(
|
|
414
|
+
snapshot=snapshot,
|
|
415
|
+
environment_naming_info=environment_naming_info,
|
|
416
|
+
deployability_index=deployability_index,
|
|
417
|
+
snapshots=self.snapshots_by_name,
|
|
418
|
+
start=start,
|
|
419
|
+
end=end,
|
|
420
|
+
execution_time=execution_time,
|
|
486
421
|
)
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
422
|
+
else:
|
|
423
|
+
audit_results = self.evaluate(
|
|
424
|
+
snapshot=snapshot,
|
|
425
|
+
environment_naming_info=environment_naming_info,
|
|
426
|
+
start=start,
|
|
427
|
+
end=end,
|
|
428
|
+
execution_time=execution_time,
|
|
429
|
+
deployability_index=deployability_index,
|
|
430
|
+
batch_index=batch_idx,
|
|
490
431
|
)
|
|
491
432
|
|
|
492
433
|
evaluation_duration_ms = now_timestamp() - execution_start_ts
|
|
@@ -583,6 +524,181 @@ class Scheduler:
|
|
|
583
524
|
)
|
|
584
525
|
return dag
|
|
585
526
|
|
|
527
|
+
def _run_or_audit(
|
|
528
|
+
self,
|
|
529
|
+
environment: str | EnvironmentNamingInfo,
|
|
530
|
+
start: t.Optional[TimeLike] = None,
|
|
531
|
+
end: t.Optional[TimeLike] = None,
|
|
532
|
+
execution_time: t.Optional[TimeLike] = None,
|
|
533
|
+
remove_intervals: t.Optional[t.Dict[SnapshotId, Interval]] = None,
|
|
534
|
+
interval_end_per_model: t.Optional[t.Dict[str, int]] = None,
|
|
535
|
+
ignore_cron: bool = False,
|
|
536
|
+
end_bounded: bool = False,
|
|
537
|
+
selected_snapshots: t.Optional[t.Set[str]] = None,
|
|
538
|
+
circuit_breaker: t.Optional[t.Callable[[], bool]] = None,
|
|
539
|
+
deployability_index: t.Optional[DeployabilityIndex] = None,
|
|
540
|
+
auto_restatement_enabled: bool = False,
|
|
541
|
+
run_environment_statements: bool = False,
|
|
542
|
+
audit_only: bool = False,
|
|
543
|
+
) -> CompletionStatus:
|
|
544
|
+
"""Concurrently runs or audits all snapshots in topological order.
|
|
545
|
+
|
|
546
|
+
Args:
|
|
547
|
+
environment: The environment naming info the user is targeting when applying their change.
|
|
548
|
+
Can just be the environment name if the user is targeting a remote environment and wants to get the remote
|
|
549
|
+
naming info
|
|
550
|
+
start: The start of the run. Defaults to the min node start date.
|
|
551
|
+
end: The end of the run. Defaults to now.
|
|
552
|
+
execution_time: The date/time time reference to use for execution time. Defaults to now.
|
|
553
|
+
remove_intervals: A dict of snapshots to their intervals. For evaluation, these are the intervals that will be restated. For audits,
|
|
554
|
+
these are the intervals that will be reaudited
|
|
555
|
+
interval_end_per_model: The mapping from model FQNs to target end dates.
|
|
556
|
+
ignore_cron: Whether to ignore the node's cron schedule.
|
|
557
|
+
end_bounded: If set to true, the evaluated intervals will be bounded by the target end date, disregarding lookback,
|
|
558
|
+
allow_partials, and other attributes that could cause the intervals to exceed the target end date.
|
|
559
|
+
selected_snapshots: A set of snapshot names to run. If not provided, all snapshots will be run.
|
|
560
|
+
circuit_breaker: An optional handler which checks if the run should be aborted.
|
|
561
|
+
deployability_index: Determines snapshots that are deployable in the context of this render.
|
|
562
|
+
auto_restatement_enabled: Whether to enable auto restatements.
|
|
563
|
+
|
|
564
|
+
Returns:
|
|
565
|
+
True if the execution was successful and False otherwise.
|
|
566
|
+
"""
|
|
567
|
+
validate_date_range(start, end)
|
|
568
|
+
if isinstance(environment, str):
|
|
569
|
+
env = self.state_sync.get_environment(environment)
|
|
570
|
+
if not env:
|
|
571
|
+
raise SQLMeshError(
|
|
572
|
+
"Was not provided an environment suffix target and the environment doesn't exist."
|
|
573
|
+
"Are you running for the first time and need to run plan/apply first?"
|
|
574
|
+
)
|
|
575
|
+
environment_naming_info = env.naming_info
|
|
576
|
+
else:
|
|
577
|
+
environment_naming_info = environment
|
|
578
|
+
|
|
579
|
+
deployability_index = deployability_index or (
|
|
580
|
+
DeployabilityIndex.create(self.snapshots.values(), start=start)
|
|
581
|
+
if environment_naming_info.name != c.PROD
|
|
582
|
+
else DeployabilityIndex.all_deployable()
|
|
583
|
+
)
|
|
584
|
+
execution_time = execution_time or now_timestamp()
|
|
585
|
+
|
|
586
|
+
self.state_sync.refresh_snapshot_intervals(self.snapshots.values())
|
|
587
|
+
for s_id, interval in (remove_intervals or {}).items():
|
|
588
|
+
self.snapshots[s_id].remove_interval(interval)
|
|
589
|
+
|
|
590
|
+
if auto_restatement_enabled:
|
|
591
|
+
auto_restated_intervals = apply_auto_restatements(self.snapshots, execution_time)
|
|
592
|
+
self.state_sync.add_snapshots_intervals(auto_restated_intervals)
|
|
593
|
+
self.state_sync.update_auto_restatements(
|
|
594
|
+
{s.name_version: s.next_auto_restatement_ts for s in self.snapshots.values()}
|
|
595
|
+
)
|
|
596
|
+
|
|
597
|
+
merged_intervals = self.merged_missing_intervals(
|
|
598
|
+
start,
|
|
599
|
+
end,
|
|
600
|
+
execution_time,
|
|
601
|
+
deployability_index=deployability_index,
|
|
602
|
+
restatements=remove_intervals,
|
|
603
|
+
interval_end_per_model=interval_end_per_model,
|
|
604
|
+
ignore_cron=ignore_cron,
|
|
605
|
+
end_bounded=end_bounded,
|
|
606
|
+
selected_snapshots=selected_snapshots,
|
|
607
|
+
)
|
|
608
|
+
if not merged_intervals:
|
|
609
|
+
return CompletionStatus.NOTHING_TO_DO
|
|
610
|
+
|
|
611
|
+
errors, skipped_intervals = self.run_merged_intervals(
|
|
612
|
+
merged_intervals=merged_intervals,
|
|
613
|
+
deployability_index=deployability_index,
|
|
614
|
+
environment_naming_info=environment_naming_info,
|
|
615
|
+
execution_time=execution_time,
|
|
616
|
+
circuit_breaker=circuit_breaker,
|
|
617
|
+
start=start,
|
|
618
|
+
end=end,
|
|
619
|
+
run_environment_statements=run_environment_statements,
|
|
620
|
+
audit_only=audit_only,
|
|
621
|
+
)
|
|
622
|
+
|
|
623
|
+
self.console.stop_evaluation_progress(success=not errors)
|
|
624
|
+
|
|
625
|
+
skipped_snapshots = {i[0] for i in skipped_intervals}
|
|
626
|
+
self.console.log_skipped_models(skipped_snapshots)
|
|
627
|
+
for skipped in skipped_snapshots:
|
|
628
|
+
logger.info(f"SKIPPED snapshot {skipped}\n")
|
|
629
|
+
|
|
630
|
+
for error in errors:
|
|
631
|
+
if isinstance(error.__cause__, CircuitBreakerError):
|
|
632
|
+
raise error.__cause__
|
|
633
|
+
logger.info(str(error), exc_info=error)
|
|
634
|
+
|
|
635
|
+
self.console.log_failed_models(errors)
|
|
636
|
+
|
|
637
|
+
return CompletionStatus.FAILURE if errors else CompletionStatus.SUCCESS
|
|
638
|
+
|
|
639
|
+
def _audit_snapshot(
|
|
640
|
+
self,
|
|
641
|
+
snapshot: Snapshot,
|
|
642
|
+
deployability_index: DeployabilityIndex,
|
|
643
|
+
snapshots: t.Dict[str, Snapshot],
|
|
644
|
+
start: t.Optional[TimeLike] = None,
|
|
645
|
+
end: t.Optional[TimeLike] = None,
|
|
646
|
+
execution_time: t.Optional[TimeLike] = None,
|
|
647
|
+
wap_id: t.Optional[str] = None,
|
|
648
|
+
environment_naming_info: t.Optional[EnvironmentNamingInfo] = None,
|
|
649
|
+
**kwargs: t.Any,
|
|
650
|
+
) -> t.List[AuditResult]:
|
|
651
|
+
is_deployable = deployability_index.is_deployable(snapshot)
|
|
652
|
+
|
|
653
|
+
audit_results = self.snapshot_evaluator.audit(
|
|
654
|
+
snapshot=snapshot,
|
|
655
|
+
start=start,
|
|
656
|
+
end=end,
|
|
657
|
+
execution_time=execution_time,
|
|
658
|
+
snapshots=snapshots,
|
|
659
|
+
deployability_index=deployability_index,
|
|
660
|
+
wap_id=wap_id,
|
|
661
|
+
**kwargs,
|
|
662
|
+
)
|
|
663
|
+
|
|
664
|
+
audit_errors_to_raise: t.List[AuditError] = []
|
|
665
|
+
audit_errors_to_warn: t.List[AuditError] = []
|
|
666
|
+
for audit_result in (result for result in audit_results if result.count):
|
|
667
|
+
error = AuditError(
|
|
668
|
+
audit_name=audit_result.audit.name,
|
|
669
|
+
audit_args=audit_result.audit_args,
|
|
670
|
+
model=snapshot.model_or_none,
|
|
671
|
+
count=t.cast(int, audit_result.count),
|
|
672
|
+
query=t.cast(exp.Query, audit_result.query),
|
|
673
|
+
adapter_dialect=self.snapshot_evaluator.adapter.dialect,
|
|
674
|
+
)
|
|
675
|
+
self.notification_target_manager.notify(NotificationEvent.AUDIT_FAILURE, error)
|
|
676
|
+
if is_deployable and snapshot.node.owner:
|
|
677
|
+
self.notification_target_manager.notify_user(
|
|
678
|
+
NotificationEvent.AUDIT_FAILURE, snapshot.node.owner, error
|
|
679
|
+
)
|
|
680
|
+
if audit_result.blocking:
|
|
681
|
+
audit_errors_to_raise.append(error)
|
|
682
|
+
else:
|
|
683
|
+
audit_errors_to_warn.append(error)
|
|
684
|
+
|
|
685
|
+
if audit_errors_to_raise:
|
|
686
|
+
raise NodeAuditsErrors(audit_errors_to_raise)
|
|
687
|
+
|
|
688
|
+
if environment_naming_info:
|
|
689
|
+
for audit_error in audit_errors_to_warn:
|
|
690
|
+
display_name = snapshot.display_name(
|
|
691
|
+
environment_naming_info,
|
|
692
|
+
self.default_catalog,
|
|
693
|
+
self.snapshot_evaluator.adapter.dialect,
|
|
694
|
+
)
|
|
695
|
+
self.console.log_warning(
|
|
696
|
+
f"\n{display_name}: {audit_error}.",
|
|
697
|
+
f"{audit_error}. Audit query:\n{audit_error.query.sql(audit_error.adapter_dialect)}",
|
|
698
|
+
)
|
|
699
|
+
|
|
700
|
+
return audit_results
|
|
701
|
+
|
|
586
702
|
|
|
587
703
|
def compute_interval_params(
|
|
588
704
|
snapshots: t.Collection[Snapshot],
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
sqlmesh/__init__.py,sha256=DRovDXI-9D9xeYDP7t8Fq7mI31S2btlN-LHPOK3y7PA,7240
|
|
2
|
-
sqlmesh/_version.py,sha256=
|
|
2
|
+
sqlmesh/_version.py,sha256=CdSt2H82Fsaq1-jnoVcfx_AmtltmEprat3aS3RpPnrY,528
|
|
3
3
|
sqlmesh/magics.py,sha256=9oY1Uz8uwsuTtPRg9HTYDxnGiJ7-OVRCpmCgAhbKHUU,39431
|
|
4
4
|
sqlmesh/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
5
5
|
sqlmesh/cicd/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
@@ -11,7 +11,7 @@ sqlmesh/cli/main.py,sha256=z1Af0bwqtnYHzkY0_9REpaJe-onxvXN4rLw6upyxKec,31979
|
|
|
11
11
|
sqlmesh/cli/options.py,sha256=aC_L5WnMScKzMU55BD1Y-8R-QzqCkPSYrlCI-payHRA,1333
|
|
12
12
|
sqlmesh/core/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
13
13
|
sqlmesh/core/_typing.py,sha256=e1f7xO2aZCy38M_3VoDy-XI3shyd99-IFctgIFSgXWM,497
|
|
14
|
-
sqlmesh/core/console.py,sha256
|
|
14
|
+
sqlmesh/core/console.py,sha256=o5TSVb9rN0ygerS-CeWaZTIblaa7u-OZotucwTBu4ik,150790
|
|
15
15
|
sqlmesh/core/constants.py,sha256=oqt6zjepUhQoWlgapKn_HpG7Pu9mrFwepdX5caNfJUI,2499
|
|
16
16
|
sqlmesh/core/context.py,sha256=kLKXwOLc_5Orv-SxvI0zbpL9ZJ0XkB9HZgd9R6uh-9Y,114691
|
|
17
17
|
sqlmesh/core/context_diff.py,sha256=s9toP17d4tJfOpFH91LcjGK2CM64PVuB0MPkeFgF4hQ,20415
|
|
@@ -24,7 +24,7 @@ sqlmesh/core/node.py,sha256=r4_1MRTPcU0MAlwZ5KzrykLT58B7dkKvHzPCsJmEKD8,14497
|
|
|
24
24
|
sqlmesh/core/notification_target.py,sha256=PPGoDrgbRKxr27vJEu03XqNTQLYTw0ZF_b0yAapxGeI,16158
|
|
25
25
|
sqlmesh/core/reference.py,sha256=k7OSkLqTjPR8WJjNeFj0xAJ297nZUMgb_iTVwKRRKjc,4875
|
|
26
26
|
sqlmesh/core/renderer.py,sha256=n2WEGENL-1Z53sBTI6RVH_yRVneDtNK0GxNElFaQKcE,26597
|
|
27
|
-
sqlmesh/core/scheduler.py,sha256=
|
|
27
|
+
sqlmesh/core/scheduler.py,sha256=TB03rSvPyaPMRANOJq_O_cNXvu0fc5rVaDVC9olE5kg,34196
|
|
28
28
|
sqlmesh/core/schema_diff.py,sha256=mE28W51JUQz6q8inSOw2Cds84VPIqPxI6C2ed6xLmrg,29812
|
|
29
29
|
sqlmesh/core/schema_loader.py,sha256=lvrI9k7hr1P4X4E6t3U-KrcuvdQuw0UdNlN90P2s52w,3563
|
|
30
30
|
sqlmesh/core/selector.py,sha256=9riBQ6gPySg546x0JaXXITw2eZgGe9iVKcynAUJ1mmw,12137
|
|
@@ -87,7 +87,7 @@ sqlmesh/core/model/__init__.py,sha256=C8GRZ53xuXEA9hQv3BQS9pNNyd9rZ06R_B96UYGhDu
|
|
|
87
87
|
sqlmesh/core/model/cache.py,sha256=hzpGPXxp2LFMEp6gm-8DULJKCBDGf-1kTQcfNt0xrRM,7028
|
|
88
88
|
sqlmesh/core/model/common.py,sha256=Lr2o0KCMt3HPqlc_4uiNz5BhYSUdm5bzvjCaIz58H7A,15724
|
|
89
89
|
sqlmesh/core/model/decorator.py,sha256=v_sVudNROGrtj5cZ3vgcOFnwPdzwoUGY6REAkQpIMQc,8927
|
|
90
|
-
sqlmesh/core/model/definition.py,sha256=
|
|
90
|
+
sqlmesh/core/model/definition.py,sha256=Uc0sWFosZ7V_VcFB0iVwKQotuxxrHxMqtiYJH_A2_lg,109132
|
|
91
91
|
sqlmesh/core/model/kind.py,sha256=em6wq0W4pDnxl9sBgNweosnZH1on3h349t0Pn76wwBM,35867
|
|
92
92
|
sqlmesh/core/model/meta.py,sha256=v-g1lnGPoeZ2SjV2CbVjvlec9buydiOFKkZWUm2dQPs,19071
|
|
93
93
|
sqlmesh/core/model/schema.py,sha256=QzM1cOfukuK3L-cEE9MtxKeYec3x5JvutdZAnczJSiQ,3858
|
|
@@ -95,7 +95,7 @@ sqlmesh/core/model/seed.py,sha256=ctUHH6CmeEnBVJyIAZznx0xJBm09W7VIZ-76Cfwfq28,50
|
|
|
95
95
|
sqlmesh/core/plan/__init__.py,sha256=ctpnu9mK3uTujs0It8qRMqcj9GdObXDnvSgn4rD2zqc,450
|
|
96
96
|
sqlmesh/core/plan/builder.py,sha256=ltoUlUr13uoEftYqGzjbnOa_n7-Q1CUiE9R_LgHY9Mc,38471
|
|
97
97
|
sqlmesh/core/plan/definition.py,sha256=SI3zi2poPkKJKTZogYv60Q7eIOhksaAcFUcu-J2-XqI,13218
|
|
98
|
-
sqlmesh/core/plan/evaluator.py,sha256=
|
|
98
|
+
sqlmesh/core/plan/evaluator.py,sha256=D_DegArxUsmxgVwxzQPv-RKGGcihDQeg1bdsqcpmu6s,25741
|
|
99
99
|
sqlmesh/core/snapshot/__init__.py,sha256=Z5HTetNCZGoKF1WAKXk4LWL9dc8EC8lwS2O4TtoBmt4,1317
|
|
100
100
|
sqlmesh/core/snapshot/cache.py,sha256=MRYi_koDvp2yeQ5NDGoNFzhuJTw7Vh7mI0oJyeVbqio,4022
|
|
101
101
|
sqlmesh/core/snapshot/categorizer.py,sha256=qGG5870mu1jR2whKisSBH_GFbsyh96RnzJDgkN7DV9g,2482
|
|
@@ -266,7 +266,7 @@ sqlmesh/utils/pandas.py,sha256=j_tYhuPcWpzuPceZZ6IhdTVbmxYyGJW7l4FHr4bQqjM,1824
|
|
|
266
266
|
sqlmesh/utils/pydantic.py,sha256=ioaAzYF42PutEJRyAS11-AHguiCG3yWI6VRcTVa2G-g,10470
|
|
267
267
|
sqlmesh/utils/rich.py,sha256=xNZyPCqEc4TAlJlsEthg-5eYUWpaizz0QjBzO7a1Yv4,1509
|
|
268
268
|
sqlmesh/utils/yaml.py,sha256=np-WVcwmwsKghCgAj1OBBMsK1SXSRn4wR-H37cGiFr8,2282
|
|
269
|
-
sqlmesh-0.
|
|
269
|
+
sqlmesh-0.183.1.dev1.dist-info/licenses/LICENSE,sha256=OlMefUjgWJdULtf84BLW0AZZcY8DwdgQqb_1j2862j8,11346
|
|
270
270
|
web/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
271
271
|
web/client/dist/index.html,sha256=nPqIDCJmonOaEAp4hhwrwgPdwt_F-5zzw-WW1kJqq3I,5472
|
|
272
272
|
web/client/dist/assets/Audits-DiRd7NXk.js,sha256=Q5dIFqsHps-vVYD8037NpTPW_1juQgn_Ov45smEm7Y8,1041
|
|
@@ -363,7 +363,7 @@ web/client/dist/fonts/Sohne/sohne-mono-kraftig.woff2,sha256=DGsWMljiFHztzyb0Gg_T
|
|
|
363
363
|
web/client/src/workers/sqlglot/sqlglot.py,sha256=XAMrvqcRBa7vy8bHVayYbZNyWsf1lNSjVk_odtif-YY,1566
|
|
364
364
|
web/server/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
365
365
|
web/server/app.py,sha256=b6qEJ4btjaSm2kWwQUGV--S3VE8QW0Um7f4rBdaoB_M,59
|
|
366
|
-
web/server/console.py,sha256=
|
|
366
|
+
web/server/console.py,sha256=K2fJpiZbibWaQa2OvN7YbeI9sxkXtkXwA8lJKsXfq-k,14529
|
|
367
367
|
web/server/exceptions.py,sha256=I2PPpChwhDWawQENr5kHg6DjyRGeiJ6OWZsCzEZhVzs,1533
|
|
368
368
|
web/server/main.py,sha256=9PaDa8sigo1z0AxtI3sQ3fHmDqs6uXwP-_IvoMwkznw,3199
|
|
369
369
|
web/server/models.py,sha256=SUztvOYmlHDMVOt7C36-C3tKBwm7UNRkkYeid9bc5n8,15527
|
|
@@ -384,8 +384,8 @@ web/server/api/endpoints/models.py,sha256=SzS5bshzdXyM6hb948sZ_3k-xhpGCHkxkb7pHz
|
|
|
384
384
|
web/server/api/endpoints/modules.py,sha256=8hqqgonGay_mJmpCw0IdbjsPhWlQH2VLdKAqha-myac,468
|
|
385
385
|
web/server/api/endpoints/plan.py,sha256=OYuQ_4dgbhG9ibTcX1a8mvYgH3ANxw9Fhbb4wg6QWqc,9222
|
|
386
386
|
web/server/api/endpoints/table_diff.py,sha256=Wd5YxeKbZB7AkrDvqFgvV9ZQlnKYOF1n5W_w2EHE_Zw,2085
|
|
387
|
-
sqlmesh-0.
|
|
388
|
-
sqlmesh-0.
|
|
389
|
-
sqlmesh-0.
|
|
390
|
-
sqlmesh-0.
|
|
391
|
-
sqlmesh-0.
|
|
387
|
+
sqlmesh-0.183.1.dev1.dist-info/METADATA,sha256=p0n7HFlYBHg7tUa0czVN0J2_oOKW7HL5tGZx8izIHIc,25252
|
|
388
|
+
sqlmesh-0.183.1.dev1.dist-info/WHEEL,sha256=Nw36Djuh_5VDukK0H78QzOX-_FQEo6V37m3nkm96gtU,91
|
|
389
|
+
sqlmesh-0.183.1.dev1.dist-info/entry_points.txt,sha256=pIYKtg-u-uO7BK_Y0qrdmfyj0bYrcMc3Xiqr5WE3VFk,121
|
|
390
|
+
sqlmesh-0.183.1.dev1.dist-info/top_level.txt,sha256=bspjo5vjELQkuN0qKuTFIbsrUt3Zeo8D2mlKeHG1LdE,12
|
|
391
|
+
sqlmesh-0.183.1.dev1.dist-info/RECORD,,
|
web/server/console.py
CHANGED
|
@@ -93,7 +93,11 @@ class ApiConsole(TerminalConsole):
|
|
|
93
93
|
batched_intervals: t.Dict[Snapshot, Intervals],
|
|
94
94
|
environment_naming_info: EnvironmentNamingInfo,
|
|
95
95
|
default_catalog: t.Optional[str],
|
|
96
|
+
audit_only: bool = False,
|
|
96
97
|
) -> None:
|
|
98
|
+
if audit_only:
|
|
99
|
+
return
|
|
100
|
+
|
|
97
101
|
if self.plan_apply_stage_tracker:
|
|
98
102
|
batch_sizes = {
|
|
99
103
|
snapshot: len(intervals) for snapshot, intervals in batched_intervals.items()
|
|
@@ -118,7 +122,12 @@ class ApiConsole(TerminalConsole):
|
|
|
118
122
|
|
|
119
123
|
self.log_event_plan_apply()
|
|
120
124
|
|
|
121
|
-
def start_snapshot_evaluation_progress(
|
|
125
|
+
def start_snapshot_evaluation_progress(
|
|
126
|
+
self, snapshot: Snapshot, audit_only: bool = False
|
|
127
|
+
) -> None:
|
|
128
|
+
if audit_only:
|
|
129
|
+
return
|
|
130
|
+
|
|
122
131
|
if self.plan_apply_stage_tracker and self.plan_apply_stage_tracker.backfill:
|
|
123
132
|
self.plan_apply_stage_tracker.backfill.queue.add(snapshot.name)
|
|
124
133
|
|
|
@@ -132,7 +141,11 @@ class ApiConsole(TerminalConsole):
|
|
|
132
141
|
duration_ms: t.Optional[int],
|
|
133
142
|
num_audits_passed: int,
|
|
134
143
|
num_audits_failed: int,
|
|
144
|
+
audit_only: bool = False,
|
|
135
145
|
) -> None:
|
|
146
|
+
if audit_only:
|
|
147
|
+
return
|
|
148
|
+
|
|
136
149
|
if self.plan_apply_stage_tracker and self.plan_apply_stage_tracker.backfill:
|
|
137
150
|
task = self.plan_apply_stage_tracker.backfill.tasks[snapshot.name]
|
|
138
151
|
task.completed += 1
|
|
File without changes
|
|
File without changes
|
|
File without changes
|