snowflake-cli 3.13.0__py3-none-any.whl → 3.14.0__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.
@@ -16,7 +16,7 @@ from __future__ import annotations
16
16
 
17
17
  from enum import Enum, unique
18
18
 
19
- VERSION = "3.13.0"
19
+ VERSION = "3.14.0"
20
20
 
21
21
 
22
22
  @unique
@@ -382,6 +382,30 @@ class DBTManager(SqlExecutionMixin):
382
382
  self, dbt_command: str, name: FQN, run_async: bool, *dbt_cli_args
383
383
  ) -> SnowflakeCursor:
384
384
  if dbt_cli_args:
385
- dbt_command = " ".join([dbt_command, *dbt_cli_args]).strip()
386
- query = f"EXECUTE DBT PROJECT {name} args='{dbt_command}'"
385
+ processed_args = self._process_dbt_args(dbt_cli_args)
386
+ dbt_command = f"{dbt_command} {processed_args}".strip()
387
+ dbt_command_escaped = dbt_command.replace("'", "\\'")
388
+ query = f"EXECUTE DBT PROJECT {name} args='{dbt_command_escaped}'"
387
389
  return self.execute_query(query, _exec_async=run_async)
390
+
391
+ @staticmethod
392
+ def _process_dbt_args(dbt_cli_args: tuple) -> str:
393
+ """
394
+ Process dbt CLI arguments, handling special cases like --vars flag.
395
+ """
396
+ if not dbt_cli_args:
397
+ return ""
398
+
399
+ processed_args = []
400
+ i = 0
401
+ while i < len(dbt_cli_args):
402
+ arg = dbt_cli_args[i]
403
+ if arg == "--vars" and i + 1 < len(dbt_cli_args):
404
+ vars_value = dbt_cli_args[i + 1]
405
+ processed_args.append("--vars")
406
+ processed_args.append(f"'{vars_value}'")
407
+ i += 2
408
+ else:
409
+ processed_args.append(arg)
410
+ i += 1
411
+ return " ".join(processed_args)
@@ -19,6 +19,7 @@ from snowflake.cli._plugins.object.command_aliases import add_object_command_ali
19
19
  from snowflake.cli._plugins.object.commands import scope_option
20
20
  from snowflake.cli._plugins.object.manager import ObjectManager
21
21
  from snowflake.cli.api.commands.flags import (
22
+ IdentifierType,
22
23
  IfExistsOption,
23
24
  IfNotExistsOption,
24
25
  OverrideableOption,
@@ -112,6 +113,12 @@ def deploy(
112
113
  variables: Optional[List[str]] = variables_flag,
113
114
  configuration: Optional[str] = configuration_flag,
114
115
  alias: Optional[str] = alias_option,
116
+ skip_plan: bool = typer.Option(
117
+ False,
118
+ "--skip-plan",
119
+ help="Skips planning step",
120
+ hidden=True,
121
+ ),
115
122
  **options,
116
123
  ):
117
124
  """
@@ -122,13 +129,15 @@ def deploy(
122
129
 
123
130
  with cli_console.spinner() as spinner:
124
131
  spinner.add_task(description=f"Deploying dcm project {identifier}", total=None)
125
- result = manager.execute(
132
+ if skip_plan:
133
+ cli_console.warning("Skipping planning step")
134
+ result = manager.deploy(
126
135
  project_identifier=identifier,
127
136
  configuration=configuration,
128
137
  from_stage=effective_stage,
129
138
  variables=variables,
130
139
  alias=alias,
131
- output_path=None,
140
+ skip_plan=skip_plan,
132
141
  )
133
142
  return QueryJsonValueResult(result)
134
143
 
@@ -152,11 +161,10 @@ def plan(
152
161
 
153
162
  with cli_console.spinner() as spinner:
154
163
  spinner.add_task(description=f"Planning dcm project {identifier}", total=None)
155
- result = manager.execute(
164
+ result = manager.plan(
156
165
  project_identifier=identifier,
157
166
  configuration=configuration,
158
167
  from_stage=effective_stage,
159
- dry_run=True,
160
168
  variables=variables,
161
169
  output_path=output_path,
162
170
  )
@@ -235,6 +243,50 @@ def drop_deployment(
235
243
  )
236
244
 
237
245
 
246
+ @app.command(requires_connection=True)
247
+ def preview(
248
+ identifier: FQN = dcm_identifier,
249
+ object_identifier: FQN = typer.Option(
250
+ ...,
251
+ "--object",
252
+ help="FQN of table/view/dynamic table to be previewed.",
253
+ show_default=False,
254
+ click_type=IdentifierType(),
255
+ ),
256
+ from_location: Optional[str] = from_option,
257
+ variables: Optional[List[str]] = variables_flag,
258
+ configuration: Optional[str] = configuration_flag,
259
+ limit: Optional[int] = typer.Option(
260
+ None,
261
+ "--limit",
262
+ help="The maximum number of rows to be returned.",
263
+ show_default=False,
264
+ ),
265
+ **options,
266
+ ):
267
+ """
268
+ Returns rows from any table, view, dynamic table.
269
+ """
270
+ manager = DCMProjectManager()
271
+ effective_stage = _get_effective_stage(identifier, from_location)
272
+
273
+ with cli_console.spinner() as spinner:
274
+ spinner.add_task(
275
+ description=f"Previewing {object_identifier}.",
276
+ total=None,
277
+ )
278
+ result = manager.preview(
279
+ project_identifier=identifier,
280
+ object_identifier=object_identifier,
281
+ configuration=configuration,
282
+ from_stage=effective_stage,
283
+ variables=variables,
284
+ limit=limit,
285
+ )
286
+
287
+ return QueryResult(result)
288
+
289
+
238
290
  def _get_effective_stage(identifier: FQN, from_location: Optional[str]):
239
291
  manager = DCMProjectManager()
240
292
  if not from_location:
@@ -62,51 +62,59 @@ class DCMProjectManager(SqlExecutionMixin):
62
62
  ObjectType.DCM_PROJECT, project_identifier, "OUTPUT_TMP_STAGE"
63
63
  )
64
64
  stage_manager.create(temp_stage_fqn, temporary=True)
65
- effective_output_path = StagePath.from_stage_str(temp_stage_fqn.identifier)
65
+ effective_output_path = StagePath.from_stage_str(
66
+ temp_stage_fqn.identifier
67
+ ).joinpath("/outputs")
66
68
  temp_stage_for_local_output = (temp_stage_fqn.identifier, Path(output_path))
67
69
  else:
68
70
  effective_output_path = StagePath.from_stage_str(output_path)
69
71
 
70
- yield effective_output_path.absolute_path()
71
-
72
- if should_download_files:
73
- assert temp_stage_for_local_output is not None
74
- stage_path, local_path = temp_stage_for_local_output
75
- stage_manager.get_recursive(stage_path=stage_path, dest_path=local_path)
76
- cli_console.step(f"Plan output saved to: {local_path.resolve()}")
77
- else:
78
- cli_console.step(f"Plan output saved to: {output_path}")
72
+ try:
73
+ yield effective_output_path.absolute_path()
74
+ finally:
75
+ if should_download_files:
76
+ assert temp_stage_for_local_output is not None
77
+ stage_path, local_path = temp_stage_for_local_output
78
+ stage_manager.get_recursive(
79
+ stage_path=effective_output_path.absolute_path(),
80
+ dest_path=local_path,
81
+ )
82
+ cli_console.step(f"Plan output saved to: {local_path.resolve()}")
83
+ else:
84
+ cli_console.step(f"Plan output saved to: {output_path}")
79
85
 
80
- def execute(
86
+ def deploy(
81
87
  self,
82
88
  project_identifier: FQN,
83
89
  from_stage: str,
84
90
  configuration: str | None = None,
85
91
  variables: List[str] | None = None,
86
- dry_run: bool = False,
87
92
  alias: str | None = None,
93
+ skip_plan: bool = False,
94
+ ):
95
+ query = f"EXECUTE DCM PROJECT {project_identifier.sql_identifier} DEPLOY"
96
+ if alias:
97
+ query += f' AS "{alias}"'
98
+ query += self._get_configuration_and_variables_query(configuration, variables)
99
+ query += self._get_from_stage_query(from_stage)
100
+ if skip_plan:
101
+ query += f" SKIP PLAN"
102
+ return self.execute_query(query=query)
103
+
104
+ def plan(
105
+ self,
106
+ project_identifier: FQN,
107
+ from_stage: str,
108
+ configuration: str | None = None,
109
+ variables: List[str] | None = None,
88
110
  output_path: str | None = None,
89
111
  ):
90
- with self._collect_output(project_identifier, output_path) if (
91
- output_path and dry_run
92
- ) else nullcontext() as output_stage:
93
- query = f"EXECUTE DCM PROJECT {project_identifier.sql_identifier}"
94
- if dry_run:
95
- query += " PLAN"
96
- else:
97
- query += " DEPLOY"
98
- if alias:
99
- query += f' AS "{alias}"'
100
- if configuration or variables:
101
- query += f" USING"
102
- if configuration:
103
- query += f" CONFIGURATION {configuration}"
104
- if variables:
105
- query += StageManager.parse_execute_variables(
106
- parse_key_value_variables(variables)
107
- ).removeprefix(" using")
108
- stage_path = StagePath.from_stage_str(from_stage)
109
- query += f" FROM {stage_path.absolute_path()}"
112
+ query = f"EXECUTE DCM PROJECT {project_identifier.sql_identifier} PLAN"
113
+ query += self._get_configuration_and_variables_query(configuration, variables)
114
+ query += self._get_from_stage_query(from_stage)
115
+ with self._collect_output(
116
+ project_identifier, output_path
117
+ ) if output_path else nullcontext() as output_stage:
110
118
  if output_stage is not None:
111
119
  query += f" OUTPUT_PATH {output_stage}"
112
120
  result = self.execute_query(query=query)
@@ -136,6 +144,42 @@ class DCMProjectManager(SqlExecutionMixin):
136
144
  query += f' "{deployment_name}"'
137
145
  return self.execute_query(query=query)
138
146
 
147
+ def preview(
148
+ self,
149
+ project_identifier: FQN,
150
+ object_identifier: FQN,
151
+ from_stage: str,
152
+ configuration: str | None = None,
153
+ variables: List[str] | None = None,
154
+ limit: int | None = None,
155
+ ):
156
+ query = f"EXECUTE DCM PROJECT {project_identifier.sql_identifier} PREVIEW {object_identifier.sql_identifier}"
157
+ query += self._get_configuration_and_variables_query(configuration, variables)
158
+ query += self._get_from_stage_query(from_stage)
159
+ if limit is not None:
160
+ query += f" LIMIT {limit}"
161
+ return self.execute_query(query=query)
162
+
163
+ @staticmethod
164
+ def _get_from_stage_query(from_stage: str) -> str:
165
+ stage_path = StagePath.from_stage_str(from_stage)
166
+ return f" FROM {stage_path.absolute_path()}"
167
+
168
+ @staticmethod
169
+ def _get_configuration_and_variables_query(
170
+ configuration: str | None, variables: List[str] | None
171
+ ) -> str:
172
+ query = ""
173
+ if configuration or variables:
174
+ query += f" USING"
175
+ if configuration:
176
+ query += f" CONFIGURATION {configuration}"
177
+ if variables:
178
+ query += StageManager.parse_execute_variables(
179
+ parse_key_value_variables(variables)
180
+ ).removeprefix(" using")
181
+ return query
182
+
139
183
  @staticmethod
140
184
  def sync_local_files(
141
185
  project_identifier: FQN, source_directory: str | None = None
@@ -166,7 +210,9 @@ class DCMProjectManager(SqlExecutionMixin):
166
210
 
167
211
  definitions = list(dcm_manifest.get("include_definitions", list()))
168
212
  if MANIFEST_FILE_NAME not in definitions:
169
- definitions.append(MANIFEST_FILE_NAME)
213
+ # append manifest file, but avoid sending it multiple times if
214
+ # there are manifests from previous runs stored in output path
215
+ definitions.append(rf"^{MANIFEST_FILE_NAME}")
170
216
 
171
217
  with cli_console.phase(f"Uploading definition files"):
172
218
  stage_fqn = FQN.from_resource(
@@ -183,7 +183,7 @@ def package_create(
183
183
  f"""
184
184
  The package {name} is successfully created, but depends on the following
185
185
  Anaconda libraries. They need to be included in project requirements,
186
- as their are not included in .zip.
186
+ as they are not included in the .zip.
187
187
  """
188
188
  )
189
189
  message += "\n".join(
@@ -127,9 +127,17 @@ def _default_file_callback(param_name: str):
127
127
  return _check_file_exists_if_not_default
128
128
 
129
129
 
130
+ LegacyOption = typer.Option(
131
+ False,
132
+ "--legacy",
133
+ help="Use legacy ROOT_LOCATION SQL syntax.",
134
+ is_flag=True,
135
+ )
136
+
137
+
130
138
  @app.command("deploy", requires_connection=True)
131
139
  @with_project_definition()
132
- @with_experimental_behaviour()
140
+ @with_experimental_behaviour() # Kept for backward compatibility
133
141
  def streamlit_deploy(
134
142
  replace: bool = ReplaceOption(
135
143
  help="Replaces the Streamlit app if it already exists. It only uploads new and overwrites existing files, "
@@ -138,16 +146,27 @@ def streamlit_deploy(
138
146
  prune: bool = PruneOption(),
139
147
  entity_id: str = entity_argument("streamlit"),
140
148
  open_: bool = OpenOption,
149
+ legacy: bool = LegacyOption,
141
150
  **options,
142
151
  ) -> CommandResult:
143
152
  """
144
153
  Deploys a Streamlit app defined in the project definition file (snowflake.yml). By default, the command uploads
145
- environment.yml and any other pages or folders, if present. If you dont specify a stage name, the `streamlit`
154
+ environment.yml and any other pages or folders, if present. If you don't specify a stage name, the `streamlit`
146
155
  stage is used. If the specified stage does not exist, the command creates it. If multiple Streamlits are defined
147
156
  in snowflake.yml and no entity_id is provided then command will raise an error.
148
157
  """
149
158
 
150
159
  cli_context = get_cli_context()
160
+ workspace_ctx = _get_current_workspace_context()
161
+
162
+ # Handle deprecated --experimental flag for backward compatibility
163
+ if options.get("experimental"):
164
+ workspace_ctx.console.warning(
165
+ "[Deprecation] The --experimental flag is deprecated. "
166
+ "Versioned deployment is now the default behavior. "
167
+ "This flag will be removed in a future version."
168
+ )
169
+
151
170
  pd = cli_context.project_definition
152
171
  if not pd.meets_version_requirement("2"):
153
172
  if not pd.streamlit:
@@ -163,7 +182,7 @@ def streamlit_deploy(
163
182
  project_definition=pd,
164
183
  entity_type=ObjectType.STREAMLIT.value.cli_name,
165
184
  ),
166
- workspace_ctx=_get_current_workspace_context(),
185
+ workspace_ctx=workspace_ctx,
167
186
  )
168
187
 
169
188
  url = streamlit.perform(
@@ -173,7 +192,7 @@ def streamlit_deploy(
173
192
  ),
174
193
  _open=open_,
175
194
  replace=replace,
176
- experimental=options.get("experimental"),
195
+ legacy=legacy,
177
196
  prune=prune,
178
197
  )
179
198
 
@@ -15,7 +15,7 @@ from snowflake.cli._plugins.workspace.context import ActionContext
15
15
  from snowflake.cli.api.artifacts.bundle_map import BundleMap
16
16
  from snowflake.cli.api.entities.common import EntityBase
17
17
  from snowflake.cli.api.entities.utils import EntityActions, sync_deploy_root_with_stage
18
- from snowflake.cli.api.feature_flags import FeatureFlag as GlobalFeatureFlag
18
+ from snowflake.cli.api.exceptions import CliError
19
19
  from snowflake.cli.api.identifiers import FQN
20
20
  from snowflake.cli.api.project.project_paths import bundle_root
21
21
  from snowflake.cli.api.project.schemas.entities.common import Identifier, PathMapping
@@ -66,12 +66,10 @@ class StreamlitEntity(EntityBase[StreamlitEntityModel]):
66
66
  self._conn, f"/#/streamlit-apps/{name.url_identifier}"
67
67
  )
68
68
 
69
- def _is_spcs_runtime_v2_mode(self, experimental: bool = False) -> bool:
69
+ def _is_spcs_runtime_v2_mode(self) -> bool:
70
70
  """Check if SPCS runtime v2 mode is enabled."""
71
71
  return (
72
- experimental
73
- and self.model.runtime_name == SPCS_RUNTIME_V2_NAME
74
- and self.model.compute_pool
72
+ self.model.runtime_name == SPCS_RUNTIME_V2_NAME and self.model.compute_pool
75
73
  )
76
74
 
77
75
  def bundle(self, output_dir: Optional[Path] = None) -> BundleMap:
@@ -93,7 +91,7 @@ class StreamlitEntity(EntityBase[StreamlitEntityModel]):
93
91
  replace: bool,
94
92
  prune: bool = False,
95
93
  bundle_map: Optional[BundleMap] = None,
96
- experimental: bool = False,
94
+ legacy: bool = False,
97
95
  *args,
98
96
  **kwargs,
99
97
  ):
@@ -104,49 +102,40 @@ class StreamlitEntity(EntityBase[StreamlitEntityModel]):
104
102
 
105
103
  console = self._workspace_ctx.console
106
104
  console.step(f"Checking if object exists")
107
- if self._object_exists() and not replace:
105
+ object_exists = self._object_exists()
106
+
107
+ if object_exists and not replace:
108
108
  raise ClickException(
109
109
  f"Streamlit {self.model.fqn.sql_identifier} already exists. Use 'replace' option to overwrite."
110
110
  )
111
111
 
112
- if (
113
- experimental
114
- or GlobalFeatureFlag.ENABLE_STREAMLIT_VERSIONED_STAGE.is_enabled()
115
- ):
116
- self._deploy_experimental(bundle_map=bundle_map, replace=replace)
117
- else:
118
- console.step(f"Uploading artifacts to stage {self.model.stage}")
119
-
120
- # We use a static method from StageManager here, but maybe this logic could be implemented elswhere, as we implement entities?
121
- name = (
122
- self.model.identifier.name
123
- if isinstance(self.model.identifier, Identifier)
124
- else self.model.identifier or self.entity_id
125
- )
126
- stage_root = StageManager.get_standard_stage_prefix(
127
- f"{FQN.from_string(self.model.stage).using_connection(self._conn)}/{name}"
112
+ if legacy and self._is_spcs_runtime_v2_mode():
113
+ raise CliError(
114
+ "runtime_name and compute_pool are not compatible with --legacy flag. "
115
+ "Please remove the --legacy flag to use versioned deployment, or remove "
116
+ "runtime_name and compute_pool from your snowflake.yml to use legacy deployment."
128
117
  )
129
- sync_deploy_root_with_stage(
130
- console=self._workspace_ctx.console,
131
- deploy_root=bundle_map.deploy_root(),
132
- bundle_map=bundle_map,
133
- prune=prune,
134
- recursive=True,
135
- stage_path_parts=StageManager().stage_path_parts_from_str(stage_root),
136
- print_diff=True,
137
- )
138
-
139
- console.step(f"Creating Streamlit object {self.model.fqn.sql_identifier}")
140
118
 
141
- self._execute_query(
142
- self.get_deploy_sql(
143
- replace=replace,
144
- from_stage_name=stage_root,
145
- experimental=False,
119
+ # Warn if replacing with a different deployment style
120
+ if object_exists and replace:
121
+ existing_is_legacy = self._is_legacy_deployment()
122
+ if existing_is_legacy and not legacy:
123
+ console.warning(
124
+ "Replacing legacy ROOT_LOCATION deployment with versioned deployment. "
125
+ "Files from the old stage location will not be automatically migrated. "
126
+ "The new deployment will use a separate versioned stage location."
127
+ )
128
+ elif not existing_is_legacy and legacy:
129
+ console.warning(
130
+ "Deployment style is changing from versioned to legacy. "
131
+ "Your existing files will remain in the versioned stage. "
132
+ "If needed, manually copy any additional files to the legacy stage after deployment."
146
133
  )
147
- )
148
134
 
149
- StreamlitManager(connection=self._conn).grant_privileges(self.model)
135
+ if legacy:
136
+ self._deploy_legacy(bundle_map=bundle_map, replace=replace, prune=prune)
137
+ else:
138
+ self._deploy_versioned(bundle_map=bundle_map, replace=replace, prune=prune)
150
139
 
151
140
  return self.perform(EntityActions.GET_URL, action_context, *args, **kwargs)
152
141
 
@@ -172,7 +161,7 @@ class StreamlitEntity(EntityBase[StreamlitEntityModel]):
172
161
  artifacts_dir: Optional[Path] = None,
173
162
  schema: Optional[str] = None,
174
163
  database: Optional[str] = None,
175
- experimental: bool = False,
164
+ legacy: bool = False,
176
165
  *args,
177
166
  **kwargs,
178
167
  ) -> str:
@@ -218,7 +207,7 @@ class StreamlitEntity(EntityBase[StreamlitEntityModel]):
218
207
 
219
208
  # SPCS runtime fields are only supported for FBE/versioned streamlits (FROM syntax)
220
209
  # Never add these fields for stage-based deployments (ROOT_LOCATION syntax)
221
- if not from_stage_name and self._is_spcs_runtime_v2_mode(experimental):
210
+ if not from_stage_name and not legacy and self._is_spcs_runtime_v2_mode():
222
211
  query += f"\nRUNTIME_NAME = '{self.model.runtime_name}'"
223
212
  query += f"\nCOMPUTE_POOL = '{self.model.compute_pool}'"
224
213
 
@@ -249,14 +238,61 @@ class StreamlitEntity(EntityBase[StreamlitEntityModel]):
249
238
  except ProgrammingError:
250
239
  return False
251
240
 
252
- def _deploy_experimental(
241
+ def _is_legacy_deployment(self) -> bool:
242
+ """Check if the existing streamlit uses legacy ROOT_LOCATION deployment."""
243
+ try:
244
+ result = self.describe().fetchone()
245
+ # Versioned deployments have live_version_location_uri, legacy ones don't
246
+ return result.get("live_version_location_uri") is None
247
+ except (ProgrammingError, AttributeError, KeyError):
248
+ # If we can't determine, assume it doesn't exist or is inaccessible
249
+ return False
250
+
251
+ def _deploy_legacy(
252
+ self, bundle_map: BundleMap, replace: bool = False, prune: bool = False
253
+ ):
254
+ console = self._workspace_ctx.console
255
+ console.step(f"Uploading artifacts to stage {self.model.stage}")
256
+
257
+ # We use a static method from StageManager here, but maybe this logic could be implemented elswhere, as we implement entities?
258
+ name = (
259
+ self.model.identifier.name
260
+ if isinstance(self.model.identifier, Identifier)
261
+ else self.model.identifier or self.entity_id
262
+ )
263
+ stage_root = StageManager.get_standard_stage_prefix(
264
+ f"{FQN.from_string(self.model.stage).using_connection(self._conn)}/{name}"
265
+ )
266
+ sync_deploy_root_with_stage(
267
+ console=self._workspace_ctx.console,
268
+ deploy_root=bundle_map.deploy_root(),
269
+ bundle_map=bundle_map,
270
+ prune=prune,
271
+ recursive=True,
272
+ stage_path_parts=StageManager().stage_path_parts_from_str(stage_root),
273
+ print_diff=True,
274
+ )
275
+
276
+ console.step(f"Creating Streamlit object {self.model.fqn.sql_identifier}")
277
+
278
+ self._execute_query(
279
+ self.get_deploy_sql(
280
+ replace=replace,
281
+ from_stage_name=stage_root,
282
+ legacy=True,
283
+ )
284
+ )
285
+
286
+ StreamlitManager(connection=self._conn).grant_privileges(self.model)
287
+
288
+ def _deploy_versioned(
253
289
  self, bundle_map: BundleMap, replace: bool = False, prune: bool = False
254
290
  ):
255
291
  self._execute_query(
256
292
  self.get_deploy_sql(
257
293
  if_not_exists=True,
258
294
  replace=replace,
259
- experimental=True,
295
+ legacy=False,
260
296
  )
261
297
  )
262
298
  try:
@@ -112,11 +112,16 @@ class CliConsole(AbstractConsole):
112
112
  result = some_operation()
113
113
  """
114
114
  with Progress(
115
- SpinnerColumn(),
115
+ SpinnerColumn(finished_text="✓"),
116
116
  TextColumn("[progress.description]{task.description}", style=SPINNER_STYLE),
117
- transient=True,
117
+ transient=False,
118
118
  ) as progress:
119
- yield progress
119
+ try:
120
+ yield progress
121
+ finally:
122
+ for task_id in progress.task_ids:
123
+ if not progress.tasks[task_id].finished:
124
+ progress.update(task_id, completed=1, total=1)
120
125
 
121
126
  def step(self, message: str):
122
127
  """Displays a message to output.
@@ -56,9 +56,6 @@ class FeatureFlagMixin(Enum):
56
56
 
57
57
  @unique
58
58
  class FeatureFlag(FeatureFlagMixin):
59
- ENABLE_STREAMLIT_VERSIONED_STAGE = BooleanFlag(
60
- "ENABLE_STREAMLIT_VERSIONED_STAGE", False
61
- )
62
59
  ENABLE_SEPARATE_AUTHENTICATION_POLICY_ID = BooleanFlag(
63
60
  "ENABLE_SEPARATE_AUTHENTICATION_POLICY_ID", False
64
61
  )
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: snowflake-cli
3
- Version: 3.13.0
3
+ Version: 3.14.0
4
4
  Summary: Snowflake CLI
5
5
  Project-URL: Source code, https://github.com/snowflakedb/snowflake-cli
6
6
  Project-URL: Bug Tracker, https://github.com/snowflakedb/snowflake-cli/issues
@@ -233,7 +233,7 @@ Requires-Dist: rich==14.0.0
233
233
  Requires-Dist: setuptools==80.8.0
234
234
  Requires-Dist: snowflake-connector-python[secure-local-storage]==3.18.0
235
235
  Requires-Dist: snowflake-core==1.7.0
236
- Requires-Dist: snowflake-snowpark-python==1.33.0; python_version < '3.12'
236
+ Requires-Dist: snowflake-snowpark-python==1.41.0
237
237
  Requires-Dist: tomlkit==0.13.3
238
238
  Requires-Dist: typer==0.17.3
239
239
  Requires-Dist: urllib3<2.6,>=1.24.3
@@ -1,4 +1,4 @@
1
- snowflake/cli/__about__.py,sha256=NP7oUH1JMseGAJuGZnoSf7lPyTihuIcAf_ouWZqpEPM,853
1
+ snowflake/cli/__about__.py,sha256=uE3v7EaCH1sCTTR9PLMUay6EVS1C0kQBKSvYzReSzlQ,853
2
2
  snowflake/cli/__init__.py,sha256=uGA_QRGW3iGwaegpFsLgOhup0zBliBSXh9ou8J439uU,578
3
3
  snowflake/cli/_app/__init__.py,sha256=CR_uTgoqHnU1XdyRhm5iQsS86yWXGVx5Ht7aGSDNFmc,765
4
4
  snowflake/cli/_app/__main__.py,sha256=ZmcFdFqAtk2mFMz-cqCFdGd0iYzc7UsLH1oT1U40S0k,858
@@ -52,11 +52,11 @@ snowflake/cli/_plugins/cortex/types.py,sha256=9KQPlQRkoR67ty8VoqsifJfaoeLJPXZzCJ
52
52
  snowflake/cli/_plugins/dbt/__init__.py,sha256=JhO1yb1LCYqYx-Ya-MlhubtiqD82CuvWF09dDMafxRM,578
53
53
  snowflake/cli/_plugins/dbt/commands.py,sha256=0CsTMMBz9cA5E9lz1CO-Vvl27liS1S7rMSGEWvZXxZc,7892
54
54
  snowflake/cli/_plugins/dbt/constants.py,sha256=KKyi4Zwe3iuygiHVq3bNk1VYqavE9UVQdRQgrGb5R2U,962
55
- snowflake/cli/_plugins/dbt/manager.py,sha256=kCybDUGTWSniyPzEhbL_M1n-fAiIoY4eddlE5qT2rDM,15141
55
+ snowflake/cli/_plugins/dbt/manager.py,sha256=i4T3yxyaaNZoyvmgJ-0EGgtUk6b8F1jvOJb1tOrLFio,15974
56
56
  snowflake/cli/_plugins/dbt/plugin_spec.py,sha256=7yEc3tLgvw3iUhALpmaVpS-iePdSMjFdFSZVybf5KTc,992
57
57
  snowflake/cli/_plugins/dcm/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
58
- snowflake/cli/_plugins/dcm/commands.py,sha256=6MMSgu54J2XwTDBCJ9b3ZbewntOasEzzCGj_IIs5JYs,7888
59
- snowflake/cli/_plugins/dcm/manager.py,sha256=Isrj2GpP3gKWR-zNB6laKBWD7ZnE3W-bsZIkkbM54uM,7329
58
+ snowflake/cli/_plugins/dcm/commands.py,sha256=r57BSxgrwrAUJS8aw9ckvN3XlOLDY83VzRLJUYPBuN8,9391
59
+ snowflake/cli/_plugins/dcm/manager.py,sha256=G2Y3ylRNuEMCpdL7yajT1cwkjgSjPXf13jVAx7IYc0Y,9048
60
60
  snowflake/cli/_plugins/dcm/plugin_spec.py,sha256=U-p1UrjS2QTkk6j5-XfMsehc6gzcFHXVDjI4qnm5aPs,992
61
61
  snowflake/cli/_plugins/git/__init__.py,sha256=uGA_QRGW3iGwaegpFsLgOhup0zBliBSXh9ou8J439uU,578
62
62
  snowflake/cli/_plugins/git/commands.py,sha256=87R8Fs_f6BUdfLv85QGlfTTH6K-Y_oDlqJyZ3jUpBVg,11320
@@ -144,7 +144,7 @@ snowflake/cli/_plugins/snowpark/snowpark_shared.py,sha256=bvKQa0FkB0UCoqIkxAJAYy
144
144
  snowflake/cli/_plugins/snowpark/zipper.py,sha256=ZKB-SGM-onVEcwkpXV2hcCuuioL8PJGHEJccPwYLILM,3585
145
145
  snowflake/cli/_plugins/snowpark/package/__init__.py,sha256=uGA_QRGW3iGwaegpFsLgOhup0zBliBSXh9ou8J439uU,578
146
146
  snowflake/cli/_plugins/snowpark/package/anaconda_packages.py,sha256=C-iiuAUc_Uouv3ABm5jKK4Ns8_pXvnBTyB10bHLRlOo,8988
147
- snowflake/cli/_plugins/snowpark/package/commands.py,sha256=USqZE-5PAVpVO5NkwCXALF5oXLadaoc9b6O4guLdjCs,6990
147
+ snowflake/cli/_plugins/snowpark/package/commands.py,sha256=vCItV2YvmAcJYWkONtYQfUSUzVSLNZ_b_OZRQBeVMQ0,6993
148
148
  snowflake/cli/_plugins/snowpark/package/manager.py,sha256=sd-SQplvq7Y4mh3AKBGRCnndKn4ZEm6VVyZJllGJ9ro,1631
149
149
  snowflake/cli/_plugins/snowpark/package/utils.py,sha256=NEvKsK_kxKt_38GVOoiq8Mq4Aq6A67rrdf1tGdP6mK8,1012
150
150
  snowflake/cli/_plugins/spcs/__init__.py,sha256=WtfeiPqu_hLaMnc7twQRTs9Uy-207T8UpHWhEoJfRLY,1292
@@ -191,10 +191,10 @@ snowflake/cli/_plugins/stage/md5.py,sha256=9B9jt3DVbSL4XyL7-4j7Tf8sI_u5CAO2LILS9
191
191
  snowflake/cli/_plugins/stage/plugin_spec.py,sha256=2APmhjF1Emtdx1Ir9vLwJ1PLgLbnu7Or8lijOi_AM2U,994
192
192
  snowflake/cli/_plugins/stage/utils.py,sha256=RiJ7bDFx92U8ffqzS0djrT_KbtWy-nk-tRbXbkaq5qI,1760
193
193
  snowflake/cli/_plugins/streamlit/__init__.py,sha256=uGA_QRGW3iGwaegpFsLgOhup0zBliBSXh9ou8J439uU,578
194
- snowflake/cli/_plugins/streamlit/commands.py,sha256=O5Og6DE86I-ZPrMXB02nBs01WAgMTmac6LeMywrvaTw,6621
194
+ snowflake/cli/_plugins/streamlit/commands.py,sha256=iWW6-8EcPTR-bH7ii9HQpr-v2Kuf7P1WtVzWwPuDsE0,7173
195
195
  snowflake/cli/_plugins/streamlit/manager.py,sha256=6Vz9WCW33_Mb8GgLGtQzgBbnLRMvllySG-3HBRIf6io,2110
196
196
  snowflake/cli/_plugins/streamlit/plugin_spec.py,sha256=swcszE2JoJWs-DzgN02CxK3myIYexsnWijkFYyYf7Ws,998
197
- snowflake/cli/_plugins/streamlit/streamlit_entity.py,sha256=lbGccFdnLBLKyk38JhluEaRDUq-mhFawjFT1Zm-oXrM,10442
197
+ snowflake/cli/_plugins/streamlit/streamlit_entity.py,sha256=guHwN8Htj2ykkruZIGIQxn7A0SanOw8PWTwNzLBPMiU,12179
198
198
  snowflake/cli/_plugins/streamlit/streamlit_entity_model.py,sha256=_PnladsEJRjICjyXZxw6HR4iC_Jl0kNym63_dQkJyS0,3049
199
199
  snowflake/cli/_plugins/streamlit/streamlit_project_paths.py,sha256=-q7EobPKqDmXk5x_gMvHsCaPT_l41vrJoxIHaGDHui4,1007
200
200
  snowflake/cli/_plugins/workspace/__init__.py,sha256=uGA_QRGW3iGwaegpFsLgOhup0zBliBSXh9ou8J439uU,578
@@ -208,7 +208,7 @@ snowflake/cli/api/connections.py,sha256=zItH6oAuLD6H2GL0I2AyGlFZkMKPmqe9RPyhlHOx
208
208
  snowflake/cli/api/constants.py,sha256=v42SRgCIpYjxm5SiEwoQefOqBVMOhw1_9f8UHrJ-v9A,4032
209
209
  snowflake/cli/api/errno.py,sha256=nVQ2kO9nPaA1uGB4yZiKTwtE2LiQmINHTutziA37c6s,3871
210
210
  snowflake/cli/api/exceptions.py,sha256=3Esa8gL0D_dsbpjWpBFWt1fQW8u4BgU59kx1B5Vgw9A,9228
211
- snowflake/cli/api/feature_flags.py,sha256=-911SN3mUBr7f3ycTXzoMS9f3mTZCwVyEjVwGoZk8i4,2533
211
+ snowflake/cli/api/feature_flags.py,sha256=OaSGFQzidBsvbNYdTulalN6Yd8s4za6LJkT4s7_UYQQ,2425
212
212
  snowflake/cli/api/identifiers.py,sha256=5h7_lTYJQvQy4_QnyPigduJyHye2_9U-1echPIgTmhk,7445
213
213
  snowflake/cli/api/metrics.py,sha256=l-khpKWvRF8OB86OhJ2H61jrcTdMDGZe_QM1_-yqWT8,10694
214
214
  snowflake/cli/api/rest_api.py,sha256=RUo4prPAGmi2iQt1o96co3pWfo2t5PLCVBB2m1jlrNA,7404
@@ -236,7 +236,7 @@ snowflake/cli/api/commands/snow_typer.py,sha256=Mgz6QbinT53vYoTO6_1LtpLY-MhnYoY5
236
236
  snowflake/cli/api/commands/utils.py,sha256=vZcVtPZsuH312FPf9yw-JooNWE7Tli-zVWh4u-gQk7c,1605
237
237
  snowflake/cli/api/console/__init__.py,sha256=jKSsXJDqyQZwJ--5eRzUqb2nNvq-lo_NC1pbqK5xROI,665
238
238
  snowflake/cli/api/console/abc.py,sha256=GzoaGSfVT-Usws06DznwQJLMSidUMePgVEmAY6Izv6Y,3583
239
- snowflake/cli/api/console/console.py,sha256=Q6_R0dRAQF0NpCbx7QpD2HjlqdbRvDMH6pzJDcD3kY4,5204
239
+ snowflake/cli/api/console/console.py,sha256=RwEDrZ0vOigZldtju-wSJYxW2IOWhXnMnr57wROaPRE,5448
240
240
  snowflake/cli/api/console/enum.py,sha256=0dhepH8DEmxLjij9XxFX3kEZ_WE267zsffzecEwA2fU,675
241
241
  snowflake/cli/api/entities/common.py,sha256=_IaDpqneQdE6MRZ6B7-dLXP2XiFBvoaNjjki59GP-_c,6071
242
242
  snowflake/cli/api/entities/resolver.py,sha256=yD1m71X7-JPQ6dy5mKyzVR_9d3Eji4z-nRfKd_lqXFo,5922
@@ -293,8 +293,8 @@ snowflake/cli/api/utils/path_utils.py,sha256=OgR7cwbHXqP875RgPJGrAvDC1RRTU-2-Yss
293
293
  snowflake/cli/api/utils/python_api_utils.py,sha256=wTNxXrma78wPvBz-Jo-ixNtP8ZjDCDh4TvciEnhYIAM,300
294
294
  snowflake/cli/api/utils/templating_functions.py,sha256=zu2oK1BEC9yyWtDx17Hr-VAYHvCtagaOdxIrm70JQys,4955
295
295
  snowflake/cli/api/utils/types.py,sha256=fVKuls8axKSsBzPqWwrkwkwoXXmedqxNJKqfXrrGyBM,1190
296
- snowflake_cli-3.13.0.dist-info/METADATA,sha256=FqUdQPcReUFqjjbgI0yfZKlGJH73bsfmDj-ZevDaAys,18501
297
- snowflake_cli-3.13.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
298
- snowflake_cli-3.13.0.dist-info/entry_points.txt,sha256=6QmSI0wUX6p7f-dGvrPdswlQyVAVGi1AtOUbE8X6bho,58
299
- snowflake_cli-3.13.0.dist-info/licenses/LICENSE,sha256=mJMA3Uz2AbjU_kVggo1CAx01XhBsI7BSi2H7ggUg_-c,11344
300
- snowflake_cli-3.13.0.dist-info/RECORD,,
296
+ snowflake_cli-3.14.0.dist-info/METADATA,sha256=_MqI77CTPtDBrt8VHfoNfQB8SgPY1__k1J8CPjR6lq0,18476
297
+ snowflake_cli-3.14.0.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
298
+ snowflake_cli-3.14.0.dist-info/entry_points.txt,sha256=6QmSI0wUX6p7f-dGvrPdswlQyVAVGi1AtOUbE8X6bho,58
299
+ snowflake_cli-3.14.0.dist-info/licenses/LICENSE,sha256=mJMA3Uz2AbjU_kVggo1CAx01XhBsI7BSi2H7ggUg_-c,11344
300
+ snowflake_cli-3.14.0.dist-info/RECORD,,
@@ -1,4 +1,4 @@
1
1
  Wheel-Version: 1.0
2
- Generator: hatchling 1.27.0
2
+ Generator: hatchling 1.28.0
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any