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 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.182.1.dev11'
21
- __version_tuple__ = version_tuple = (0, 182, 1, 'dev11')
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(self, snapshot: Snapshot) -> None:
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(self, snapshot: Snapshot) -> None:
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
- "Executing models...", total=sum(batch_sizes.values())
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(self, snapshot: Snapshot) -> None:
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 self.evaluation_model_progress._tasks[model_task_id].completed >= total_batches:
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(self, snapshot: Snapshot) -> None:
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 evaluation for {sum(len(intervals) for intervals in batched_intervals.values())} snapshots"
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(self, snapshot: Snapshot) -> None:
3387
- self._write(f"Evaluating {snapshot.name}")
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
- self._write(
3399
- f"Evaluating {snapshot.name} | batch={batch_idx} | duration={duration_ms}ms | num_audits_passed={num_audits_passed} | num_audits_failed={num_audits_failed}"
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}")
@@ -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))
@@ -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.Tuple[t.List[AuditResult], t.List[AuditError]]:
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.snapshot_evaluator.audit(
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, audit_errors_to_warn
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
- """Concurrently runs all snapshots in topological order.
240
-
241
- Args:
242
- environment: The environment naming info the user is targeting when applying their change.
243
- Can just be the environment name if the user is targeting a remote environment and wants to get the remote
244
- naming info
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
- if not merged_intervals:
305
- return CompletionStatus.NOTHING_TO_DO
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
- errors, skipped_intervals = self.run_merged_intervals(
308
- merged_intervals=merged_intervals,
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
- for audit_error in audit_errors_to_warn:
482
- display_name = snapshot.display_name(
483
- environment_naming_info,
484
- self.default_catalog,
485
- self.snapshot_evaluator.adapter.dialect,
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
- self.console.log_warning(
488
- f"\n{display_name}: {audit_error}.",
489
- f"{audit_error}. Audit query:\n{audit_error.query.sql(audit_error.adapter_dialect)}",
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,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: sqlmesh
3
- Version: 0.182.1.dev11
3
+ Version: 0.183.1.dev1
4
4
  Summary: Next-generation data transformation framework
5
5
  Author-email: "TobikoData Inc." <engineering@tobikodata.com>
6
6
  License: Apache License
@@ -1,5 +1,5 @@
1
1
  sqlmesh/__init__.py,sha256=DRovDXI-9D9xeYDP7t8Fq7mI31S2btlN-LHPOK3y7PA,7240
2
- sqlmesh/_version.py,sha256=xq4uYUyMW-tE8c0UOE-8IEknqvQyZ6agAaTeVjZRLh8,530
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=-FGOalIrfCN5ZyDIYW8Emx3GIF9qeaNfNW00lUogoFg,149608
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=r0WOHKarut-ywKLsAF5vn5WeA5Q5h7jGVk8nHR0cz_0,29414
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=qwj9smoaeVZglkTON6HTTlGzOvPwhmjgcaQ160Pjo6E,108953
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=Ocb4vxWUFRI1hD5tpkVvdJicWSa9rUfL8Qm1C3DMVts,23760
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.182.1.dev11.dist-info/licenses/LICENSE,sha256=OlMefUjgWJdULtf84BLW0AZZcY8DwdgQqb_1j2862j8,11346
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=h1NrP01ax1TtSYc-r1W3lmuaNGzC-iBH-Wc83uEi-VA,14292
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.182.1.dev11.dist-info/METADATA,sha256=h6wPxjDx8uRDrom1lsCleuWuZ2X8m-qfOz11LFYMT4o,25253
388
- sqlmesh-0.182.1.dev11.dist-info/WHEEL,sha256=QZxptf4Y1BKFRCEDxD4h2V0mBFQOVFLFEpvxHmIs52A,91
389
- sqlmesh-0.182.1.dev11.dist-info/entry_points.txt,sha256=pIYKtg-u-uO7BK_Y0qrdmfyj0bYrcMc3Xiqr5WE3VFk,121
390
- sqlmesh-0.182.1.dev11.dist-info/top_level.txt,sha256=bspjo5vjELQkuN0qKuTFIbsrUt3Zeo8D2mlKeHG1LdE,12
391
- sqlmesh-0.182.1.dev11.dist-info/RECORD,,
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,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (80.6.0)
2
+ Generator: setuptools (80.7.1)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5
 
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(self, snapshot: Snapshot) -> None:
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