sqlmesh 0.181.1.dev5__py3-none-any.whl → 0.181.2.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.181.1.dev5'
21
- __version_tuple__ = version_tuple = (0, 181, 1, 'dev5')
20
+ __version__ = version = '0.181.2.dev1'
21
+ __version_tuple__ = version_tuple = (0, 181, 2, 'dev1')
sqlmesh/cli/main.py CHANGED
@@ -546,6 +546,19 @@ def janitor(ctx: click.Context, ignore_ttl: bool, **kwargs: t.Any) -> None:
546
546
  ctx.obj.run_janitor(ignore_ttl, **kwargs)
547
547
 
548
548
 
549
+ @cli.command("destroy")
550
+ @click.pass_context
551
+ @error_handler
552
+ @cli_analytics
553
+ def destroy(ctx: click.Context, **kwargs: t.Any) -> None:
554
+ """
555
+ The destroy command removes all project resources.
556
+
557
+ This includes engine-managed objects, state tables, the SQLMesh cache and any build artifacts.
558
+ """
559
+ ctx.obj.destroy(**kwargs)
560
+
561
+
549
562
  @cli.command("dag")
550
563
  @click.argument("file", required=True)
551
564
  @click.option(
sqlmesh/core/console.py CHANGED
@@ -181,6 +181,26 @@ class JanitorConsole(abc.ABC):
181
181
  """
182
182
 
183
183
 
184
+ class DestroyConsole(abc.ABC):
185
+ """Console for describing a destroy operation"""
186
+
187
+ @abc.abstractmethod
188
+ def start_destroy(self) -> bool:
189
+ """Start a destroy operation.
190
+
191
+ Returns:
192
+ Whether or not the destroy operation should proceed
193
+ """
194
+
195
+ @abc.abstractmethod
196
+ def stop_destroy(self, success: bool = True) -> None:
197
+ """Indicates the destroy operation has ended
198
+
199
+ Args:
200
+ success: Whether or not the cleanup completed successfully
201
+ """
202
+
203
+
184
204
  class EnvironmentsConsole(abc.ABC):
185
205
  """Console for displaying environments"""
186
206
 
@@ -304,6 +324,7 @@ class Console(
304
324
  StateExporterConsole,
305
325
  StateImporterConsole,
306
326
  JanitorConsole,
327
+ DestroyConsole,
307
328
  EnvironmentsConsole,
308
329
  DifferenceConsole,
309
330
  TableDiffConsole,
@@ -744,6 +765,12 @@ class NoopConsole(Console):
744
765
  ) -> None:
745
766
  pass
746
767
 
768
+ def start_destroy(self) -> bool:
769
+ return True
770
+
771
+ def stop_destroy(self, success: bool = True) -> None:
772
+ pass
773
+
747
774
 
748
775
  def make_progress_bar(
749
776
  message: str,
@@ -1092,6 +1119,25 @@ class TerminalConsole(Console):
1092
1119
  else:
1093
1120
  self.log_error("Cleanup failed!")
1094
1121
 
1122
+ def start_destroy(self) -> bool:
1123
+ self.log_warning(
1124
+ (
1125
+ "This will permanently delete all engine-managed objects, state tables and SQLMesh cache.\n"
1126
+ "The operation is irreversible and may disrupt any currently running or scheduled plans.\n"
1127
+ "Use this command only when you intend to fully reset the project."
1128
+ )
1129
+ )
1130
+ if not self._confirm("Proceed?"):
1131
+ self.log_error("Destroy aborted!")
1132
+ return False
1133
+ return True
1134
+
1135
+ def stop_destroy(self, success: bool = False) -> None:
1136
+ if success:
1137
+ self.log_success("Destroy completed successfully.")
1138
+ else:
1139
+ self.log_error("Destroy failed!")
1140
+
1095
1141
  def start_promotion_progress(
1096
1142
  self,
1097
1143
  snapshots: t.List[SnapshotTableInfo],
@@ -3472,6 +3518,53 @@ class DebuggerTerminalConsole(TerminalConsole):
3472
3518
  ) -> None:
3473
3519
  self._write(row_diff)
3474
3520
 
3521
+ def show_table_diff(
3522
+ self,
3523
+ table_diffs: t.List[TableDiff],
3524
+ show_sample: bool = True,
3525
+ skip_grain_check: bool = False,
3526
+ temp_schema: t.Optional[str] = None,
3527
+ ) -> None:
3528
+ for table_diff in table_diffs:
3529
+ self.show_table_diff_summary(table_diff)
3530
+ self.show_schema_diff(table_diff.schema_diff())
3531
+ self.show_row_diff(
3532
+ table_diff.row_diff(temp_schema=temp_schema, skip_grain_check=skip_grain_check),
3533
+ show_sample=show_sample,
3534
+ skip_grain_check=skip_grain_check,
3535
+ )
3536
+
3537
+ def update_table_diff_progress(self, model: str) -> None:
3538
+ self._write(f"Finished table diff for: {model}")
3539
+
3540
+ def start_table_diff_progress(self, models_to_diff: int) -> None:
3541
+ self._write("Table diff started")
3542
+
3543
+ def start_table_diff_model_progress(self, model: str) -> None:
3544
+ self._write(f"Calculating differences for: {model}")
3545
+
3546
+ def stop_table_diff_progress(self, success: bool) -> None:
3547
+ self._write(f"Table diff finished with success={success}")
3548
+
3549
+ def show_table_diff_details(
3550
+ self,
3551
+ models_to_diff: t.List[str],
3552
+ ) -> None:
3553
+ if models_to_diff:
3554
+ models = "\n".join(models_to_diff)
3555
+ self._write(f"Models to compare: {models}")
3556
+
3557
+ def show_table_diff_summary(self, table_diff: TableDiff) -> None:
3558
+ if table_diff.model_name:
3559
+ self._write(f"Model: {table_diff.model_name}")
3560
+ self._write(f"Source env: {table_diff.source_alias}")
3561
+ self._write(f"Target env: {table_diff.target_alias}")
3562
+ self._write(f"Source table: {table_diff.source}")
3563
+ self._write(f"Target table: {table_diff.target}")
3564
+ _, _, key_column_names = table_diff.key_columns
3565
+ keys = ", ".join(key_column_names)
3566
+ self._write(f"Join On: {keys}")
3567
+
3475
3568
 
3476
3569
  _CONSOLE: Console = NoopConsole()
3477
3570
 
sqlmesh/core/context.py CHANGED
@@ -832,6 +832,19 @@ class GenericContext(BaseContext, t.Generic[C]):
832
832
 
833
833
  return success
834
834
 
835
+ @python_api_analytics
836
+ def destroy(self) -> bool:
837
+ success = False
838
+
839
+ if self.console.start_destroy():
840
+ try:
841
+ self._destroy()
842
+ success = True
843
+ finally:
844
+ self.console.stop_destroy(success=success)
845
+
846
+ return success
847
+
835
848
  @t.overload
836
849
  def get_model(
837
850
  self, model_or_snapshot: ModelOrSnapshot, raise_if_missing: Literal[True] = True
@@ -2537,6 +2550,22 @@ class GenericContext(BaseContext, t.Generic[C]):
2537
2550
  gateway_managed_virtual_layer=self.gateway_managed_virtual_layer,
2538
2551
  )
2539
2552
 
2553
+ def _destroy(self) -> None:
2554
+ # Invalidate all environments, including prod
2555
+ for environment in self.state_reader.get_environments():
2556
+ self.state_sync.invalidate_environment(name=environment.name, protect_prod=False)
2557
+ self.console.log_success(f"Environment '{environment.name}' invalidated.")
2558
+
2559
+ # Run janitor to clean up all objects
2560
+ self._run_janitor(ignore_ttl=True)
2561
+
2562
+ # Remove state tables, including backup tables
2563
+ self.state_sync.remove_state(including_backup=True)
2564
+ self.console.log_status_update("State tables removed.")
2565
+
2566
+ # Finally clear caches
2567
+ self.clear_caches()
2568
+
2540
2569
  def _run_janitor(self, ignore_ttl: bool = False) -> None:
2541
2570
  current_ts = now_timestamp()
2542
2571
 
@@ -347,13 +347,18 @@ class StateSync(StateReader, abc.ABC):
347
347
  """
348
348
 
349
349
  @abc.abstractmethod
350
- def invalidate_environment(self, name: str) -> None:
350
+ def invalidate_environment(self, name: str, protect_prod: bool = True) -> None:
351
351
  """Invalidates the target environment by setting its expiration timestamp to now.
352
352
 
353
353
  Args:
354
354
  name: The name of the environment to invalidate.
355
+ protect_prod: If True, prevents invalidation of the production environment.
355
356
  """
356
357
 
358
+ @abc.abstractmethod
359
+ def remove_state(self, including_backup: bool = False) -> None:
360
+ """Removes the state store objects."""
361
+
357
362
  @abc.abstractmethod
358
363
  def remove_intervals(
359
364
  self,
@@ -108,14 +108,15 @@ class EnvironmentState:
108
108
  columns_to_types=self._environment_statements_columns_to_types,
109
109
  )
110
110
 
111
- def invalidate_environment(self, name: str) -> None:
111
+ def invalidate_environment(self, name: str, protect_prod: bool = True) -> None:
112
112
  """Invalidates the environment.
113
113
 
114
114
  Args:
115
115
  name: The name of the environment
116
+ protect_prod: If True, prevents invalidation of the production environment.
116
117
  """
117
118
  name = name.lower()
118
- if name == c.PROD:
119
+ if protect_prod and name == c.PROD:
119
120
  raise SQLMeshError("Cannot invalidate the production environment.")
120
121
 
121
122
  filter_expr = exp.column("name").eq(name)
@@ -59,7 +59,7 @@ from sqlmesh.core.state_sync.db.interval import IntervalState
59
59
  from sqlmesh.core.state_sync.db.environment import EnvironmentState
60
60
  from sqlmesh.core.state_sync.db.snapshot import SnapshotState
61
61
  from sqlmesh.core.state_sync.db.version import VersionState
62
- from sqlmesh.core.state_sync.db.migrator import StateMigrator
62
+ from sqlmesh.core.state_sync.db.migrator import StateMigrator, _backup_table_name
63
63
  from sqlmesh.utils.date import TimeLike, to_timestamp, time_like_to_str, now_timestamp
64
64
  from sqlmesh.utils.errors import ConflictingPlanError, SQLMeshError
65
65
 
@@ -270,8 +270,8 @@ class EngineAdapterStateSync(StateSync):
270
270
  ) -> None:
271
271
  self.snapshot_state.unpause_snapshots(snapshots, unpaused_dt, self.interval_state)
272
272
 
273
- def invalidate_environment(self, name: str) -> None:
274
- self.environment_state.invalidate_environment(name)
273
+ def invalidate_environment(self, name: str, protect_prod: bool = True) -> None:
274
+ self.environment_state.invalidate_environment(name, protect_prod)
275
275
 
276
276
  def get_expired_snapshots(
277
277
  self, current_ts: int, ignore_ttl: bool = False
@@ -313,18 +313,26 @@ class EngineAdapterStateSync(StateSync):
313
313
  def nodes_exist(self, names: t.Iterable[str], exclude_external: bool = False) -> t.Set[str]:
314
314
  return self.snapshot_state.nodes_exist(names, exclude_external)
315
315
 
316
- def reset(self, default_catalog: t.Optional[str]) -> None:
317
- """Resets the state store to the state when it was first initialized."""
316
+ def remove_state(self, including_backup: bool = False) -> None:
317
+ """Removes the state store objects."""
318
318
  for table in (
319
319
  self.snapshot_state.snapshots_table,
320
320
  self.snapshot_state.auto_restatements_table,
321
321
  self.environment_state.environments_table,
322
+ self.environment_state.environment_statements_table,
322
323
  self.interval_state.intervals_table,
323
324
  self.plan_dags_table,
324
325
  self.version_state.versions_table,
325
326
  ):
326
327
  self.engine_adapter.drop_table(table)
328
+ if including_backup:
329
+ self.engine_adapter.drop_table(_backup_table_name(table))
330
+
327
331
  self.snapshot_state.clear_cache()
332
+
333
+ def reset(self, default_catalog: t.Optional[str]) -> None:
334
+ """Resets the state store to the state when it was first initialized."""
335
+ self.remove_state()
328
336
  self.migrate(default_catalog)
329
337
 
330
338
  @transactional()
sqlmesh/magics.py CHANGED
@@ -1111,6 +1111,13 @@ class SQLMeshMagics(Magics):
1111
1111
  args = parse_argstring(self.lint, line)
1112
1112
  context.lint_models(args.models)
1113
1113
 
1114
+ @magic_arguments()
1115
+ @line_magic
1116
+ @pass_sqlmesh_context
1117
+ def destroy(self, context: Context, line: str) -> None:
1118
+ """Removes all project resources, engine-managed objects, state tables and clears the SQLMesh cache."""
1119
+ context.destroy()
1120
+
1114
1121
 
1115
1122
  def register_magics() -> None:
1116
1123
  try:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: sqlmesh
3
- Version: 0.181.1.dev5
3
+ Version: 0.181.2.dev1
4
4
  Summary: Next-generation data transformation framework
5
5
  Author-email: "TobikoData Inc." <engineering@tobikodata.com>
6
6
  License: Apache License
@@ -1,19 +1,19 @@
1
1
  sqlmesh/__init__.py,sha256=uPXld_xTZ2NTruSfVJ_vR_w-uAxR3T-gMXAb-EphTe8,7167
2
- sqlmesh/_version.py,sha256=V8bpUP0oeVbvVW84PK7nOlJ-2zYX3cciqF_2AM_17dM,528
3
- sqlmesh/magics.py,sha256=7BU9ec9zE4tjvZ3hdEqwFX2VVV-CI0h06TGZo_Ssi8M,39070
2
+ sqlmesh/_version.py,sha256=m2QOcgt0SG7_0zqrgNZNVrrFlbqjzxcFKbczXRa2uTQ,528
3
+ sqlmesh/magics.py,sha256=P5JY9OEpIwKPZa61Nje9f2HQjsIeyVAtPxM85RGMo7s,39334
4
4
  sqlmesh/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
5
5
  sqlmesh/cicd/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
6
6
  sqlmesh/cicd/bot.py,sha256=2zlbn-DXkqQzr3lA0__IGU4XaIfXBXBKLWXNI2DRJX8,759
7
7
  sqlmesh/cicd/config.py,sha256=mpgkisSBBovlNrNZir2unT8Wes6b38RW2UsU_o4e8vY,109
8
8
  sqlmesh/cli/__init__.py,sha256=MAXAyO7isbyM-PaSdFjkJNcjn32WjOl0XzxT5gvp_vo,1690
9
9
  sqlmesh/cli/example_project.py,sha256=QAFQbw_kzqn30GLTthqsuWXbFDBpX8W6RsCgQ-jx65M,9308
10
- sqlmesh/cli/main.py,sha256=foSIAx3hyhCWLIG7XQuBE-zH7lNqSvazkgpydtJados,31564
10
+ sqlmesh/cli/main.py,sha256=Fd9nFPMJShtzLH1HXFVO1tPUATts1sziSJGYREWxmSE,31899
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=ERAYluCseNnRxWXpgtNE0MYut5CCWGoyHdPKMnYv0Fc,146135
14
+ sqlmesh/core/console.py,sha256=qPMcYwr4ktv8BJe7-2vYI3N5534mdviihK4p9YipuMQ,149415
15
15
  sqlmesh/core/constants.py,sha256=oqt6zjepUhQoWlgapKn_HpG7Pu9mrFwepdX5caNfJUI,2499
16
- sqlmesh/core/context.py,sha256=CPrmMHceymyDjjgKfkszwWxAkjTUqO90TbGfozkZJWw,113720
16
+ sqlmesh/core/context.py,sha256=kLKXwOLc_5Orv-SxvI0zbpL9ZJ0XkB9HZgd9R6uh-9Y,114691
17
17
  sqlmesh/core/context_diff.py,sha256=s9toP17d4tJfOpFH91LcjGK2CM64PVuB0MPkeFgF4hQ,20415
18
18
  sqlmesh/core/dialect.py,sha256=fPTV517IOS0nWMxYznNNQnXkQkFFrPOSKe8ghsQ0o8A,49759
19
19
  sqlmesh/core/environment.py,sha256=0TTQf4C4LXwf37fm-dfYv1qyG7vtZfQI5rizgm5g0j0,11442
@@ -102,13 +102,13 @@ sqlmesh/core/snapshot/categorizer.py,sha256=qGG5870mu1jR2whKisSBH_GFbsyh96RnzJDg
102
102
  sqlmesh/core/snapshot/definition.py,sha256=PKzBLiQ1yIycGbmslEoQyJEwtfnJHsQuY_sl1xkBcvk,84081
103
103
  sqlmesh/core/snapshot/evaluator.py,sha256=NZVgQoaSH-D7Q7PAHTRzQ5O2pdra3MUToLi9p8qAyVg,89265
104
104
  sqlmesh/core/state_sync/__init__.py,sha256=B60xj-_Xk-4jas3UphLvwkuf04G-9AyGckcblXE0aRg,869
105
- sqlmesh/core/state_sync/base.py,sha256=1gQzl8GCf0yYVfAtGYnNF86lU6rW1MAXB6Lcctd2mBs,18186
105
+ sqlmesh/core/state_sync/base.py,sha256=M3EsZ_HyV_6aCKucwdmZPWV9QFNvHm5mCCgSaQ-mE7c,18441
106
106
  sqlmesh/core/state_sync/cache.py,sha256=xKLPOrPiQeRDPMkUtSlZaMMVlUnnK2ytxGE2rilHRBY,5446
107
107
  sqlmesh/core/state_sync/common.py,sha256=THK-6AGHFBAuLXydD8QhzmzCdyl0BMrz2rB2xpmC99Y,6532
108
108
  sqlmesh/core/state_sync/export_import.py,sha256=WJ7sFX2b_RPAFE4yspJRi_4JQnaO23xpJgRxwXD0agA,8709
109
109
  sqlmesh/core/state_sync/db/__init__.py,sha256=jGCqKYB7npq4eh6H2LyfBAJWdOP-IFu0DC4CMiQgYvw,107
110
- sqlmesh/core/state_sync/db/environment.py,sha256=7HVRkRugHsGgyHZuSMil6NyTtx7B02QQN-AE18GSJWM,13382
111
- sqlmesh/core/state_sync/db/facade.py,sha256=2HcuQt8PrHXHbv3VqvzHhXHDW6_aRwTfY8oX_ntGsAs,25045
110
+ sqlmesh/core/state_sync/db/environment.py,sha256=pwc2eRxZnIiTM8ZTHSfiOslO4FqFz9ch91J3VK6U1b8,13514
111
+ sqlmesh/core/state_sync/db/facade.py,sha256=F3B6M1x3rM9XNq6L4UvpXKOf-uZUGgRPlJdIp_-mrWo,25423
112
112
  sqlmesh/core/state_sync/db/interval.py,sha256=QgdqoVyLYw15SnX8O6icHUF3ZHnI6a9rX0505-FgFNg,17964
113
113
  sqlmesh/core/state_sync/db/migrator.py,sha256=2LNUwOBNFkA1ntp-Z93S_OWxFQhOBj3ZD_ZqPCyPEAE,18139
114
114
  sqlmesh/core/state_sync/db/snapshot.py,sha256=04b2lan3KamXuX3bdnhOiaoQpXgwRFMjW08tgWIL0Qk,29596
@@ -265,7 +265,7 @@ sqlmesh/utils/pandas.py,sha256=j_tYhuPcWpzuPceZZ6IhdTVbmxYyGJW7l4FHr4bQqjM,1824
265
265
  sqlmesh/utils/pydantic.py,sha256=ioaAzYF42PutEJRyAS11-AHguiCG3yWI6VRcTVa2G-g,10470
266
266
  sqlmesh/utils/rich.py,sha256=xNZyPCqEc4TAlJlsEthg-5eYUWpaizz0QjBzO7a1Yv4,1509
267
267
  sqlmesh/utils/yaml.py,sha256=np-WVcwmwsKghCgAj1OBBMsK1SXSRn4wR-H37cGiFr8,2282
268
- sqlmesh-0.181.1.dev5.dist-info/licenses/LICENSE,sha256=OlMefUjgWJdULtf84BLW0AZZcY8DwdgQqb_1j2862j8,11346
268
+ sqlmesh-0.181.2.dev1.dist-info/licenses/LICENSE,sha256=OlMefUjgWJdULtf84BLW0AZZcY8DwdgQqb_1j2862j8,11346
269
269
  web/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
270
270
  web/client/dist/index.html,sha256=cQRIlDgkl6OgeWuHI9hM8bJhKUE9-Ji2NpQa2hlgNM8,5472
271
271
  web/client/dist/assets/Audits-4U9LnWyN.js,sha256=reXu-sKJ76kiaAZIGkCPvgO68Km9tj1PN_9mx6X6WAY,997
@@ -382,8 +382,8 @@ web/server/api/endpoints/models.py,sha256=SzS5bshzdXyM6hb948sZ_3k-xhpGCHkxkb7pHz
382
382
  web/server/api/endpoints/modules.py,sha256=8hqqgonGay_mJmpCw0IdbjsPhWlQH2VLdKAqha-myac,468
383
383
  web/server/api/endpoints/plan.py,sha256=OYuQ_4dgbhG9ibTcX1a8mvYgH3ANxw9Fhbb4wg6QWqc,9222
384
384
  web/server/api/endpoints/table_diff.py,sha256=Wd5YxeKbZB7AkrDvqFgvV9ZQlnKYOF1n5W_w2EHE_Zw,2085
385
- sqlmesh-0.181.1.dev5.dist-info/METADATA,sha256=4zzJW4BjZ10b_SHIa919RjR9Auj8Wfi-V2P402pQ-0c,25307
386
- sqlmesh-0.181.1.dev5.dist-info/WHEEL,sha256=0CuiUZ_p9E4cD6NyLD6UG80LBXYyiSYZOKDm5lp32xk,91
387
- sqlmesh-0.181.1.dev5.dist-info/entry_points.txt,sha256=pIYKtg-u-uO7BK_Y0qrdmfyj0bYrcMc3Xiqr5WE3VFk,121
388
- sqlmesh-0.181.1.dev5.dist-info/top_level.txt,sha256=bspjo5vjELQkuN0qKuTFIbsrUt3Zeo8D2mlKeHG1LdE,12
389
- sqlmesh-0.181.1.dev5.dist-info/RECORD,,
385
+ sqlmesh-0.181.2.dev1.dist-info/METADATA,sha256=Qre3CG503vJupcINvEMW5Wx5UsIBtEyX451cTlnIL4E,25307
386
+ sqlmesh-0.181.2.dev1.dist-info/WHEEL,sha256=0CuiUZ_p9E4cD6NyLD6UG80LBXYyiSYZOKDm5lp32xk,91
387
+ sqlmesh-0.181.2.dev1.dist-info/entry_points.txt,sha256=pIYKtg-u-uO7BK_Y0qrdmfyj0bYrcMc3Xiqr5WE3VFk,121
388
+ sqlmesh-0.181.2.dev1.dist-info/top_level.txt,sha256=bspjo5vjELQkuN0qKuTFIbsrUt3Zeo8D2mlKeHG1LdE,12
389
+ sqlmesh-0.181.2.dev1.dist-info/RECORD,,