snowflake-cli-labs 3.0.0rc2__py3-none-any.whl → 3.0.0rc4__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.
Files changed (88) hide show
  1. snowflake/cli/__about__.py +1 -1
  2. snowflake/cli/_app/commands_registration/builtin_plugins.py +2 -0
  3. snowflake/cli/_app/secret.py +9 -0
  4. snowflake/cli/_app/snow_connector.py +39 -27
  5. snowflake/cli/_app/telemetry.py +28 -0
  6. snowflake/cli/_plugins/connection/commands.py +9 -4
  7. snowflake/cli/_plugins/git/manager.py +53 -7
  8. snowflake/cli/_plugins/helpers/commands.py +61 -0
  9. snowflake/cli/{api/project/schemas/snowpark/__init__.py → _plugins/helpers/plugin_spec.py} +17 -0
  10. snowflake/cli/_plugins/nativeapp/artifacts.py +10 -9
  11. snowflake/cli/_plugins/nativeapp/bundle_context.py +1 -1
  12. snowflake/cli/_plugins/nativeapp/codegen/artifact_processor.py +1 -1
  13. snowflake/cli/_plugins/nativeapp/codegen/compiler.py +6 -1
  14. snowflake/cli/_plugins/nativeapp/codegen/setup/native_app_setup_processor.py +1 -1
  15. snowflake/cli/_plugins/nativeapp/codegen/snowpark/extension_function_utils.py +1 -1
  16. snowflake/cli/_plugins/nativeapp/codegen/snowpark/models.py +1 -1
  17. snowflake/cli/_plugins/nativeapp/codegen/snowpark/python_processor.py +5 -1
  18. snowflake/cli/_plugins/nativeapp/codegen/templates/templates_processor.py +4 -1
  19. snowflake/cli/_plugins/nativeapp/commands.py +87 -96
  20. snowflake/cli/_plugins/nativeapp/entities/__init__.py +0 -0
  21. snowflake/cli/{api/entities/application_entity.py → _plugins/nativeapp/entities/application.py} +264 -83
  22. snowflake/cli/_plugins/nativeapp/entities/application_package.py +1392 -0
  23. snowflake/cli/_plugins/nativeapp/exceptions.py +0 -9
  24. snowflake/cli/_plugins/nativeapp/manager.py +69 -185
  25. snowflake/cli/_plugins/nativeapp/policy.py +3 -0
  26. snowflake/cli/_plugins/nativeapp/project_model.py +2 -2
  27. snowflake/cli/_plugins/nativeapp/run_processor.py +17 -20
  28. snowflake/cli/_plugins/nativeapp/same_account_install_method.py +0 -4
  29. snowflake/cli/_plugins/nativeapp/teardown_processor.py +4 -6
  30. snowflake/cli/_plugins/nativeapp/v2_conversions/v2_to_v1_decorator.py +122 -88
  31. snowflake/cli/_plugins/nativeapp/version/commands.py +7 -39
  32. snowflake/cli/_plugins/nativeapp/version/version_processor.py +46 -312
  33. snowflake/cli/_plugins/object/manager.py +36 -15
  34. snowflake/cli/_plugins/snowpark/commands.py +4 -4
  35. snowflake/cli/_plugins/snowpark/common.py +4 -4
  36. snowflake/cli/{api/entities → _plugins/snowpark}/snowpark_entity.py +2 -2
  37. snowflake/cli/{api/project/schemas/entities/snowpark_entity.py → _plugins/snowpark/snowpark_entity_model.py} +3 -6
  38. snowflake/cli/_plugins/snowpark/snowpark_project_paths.py +1 -1
  39. snowflake/cli/_plugins/stage/manager.py +9 -4
  40. snowflake/cli/_plugins/streamlit/commands.py +15 -3
  41. snowflake/cli/_plugins/streamlit/manager.py +12 -4
  42. snowflake/cli/{api/entities → _plugins/streamlit}/streamlit_entity.py +2 -2
  43. snowflake/cli/{api/project/schemas/entities → _plugins/streamlit}/streamlit_entity_model.py +5 -12
  44. snowflake/cli/_plugins/workspace/commands.py +116 -36
  45. snowflake/cli/_plugins/workspace/plugin_spec.py +1 -1
  46. snowflake/cli/api/cli_global_context.py +7 -0
  47. snowflake/cli/api/commands/decorators.py +14 -0
  48. snowflake/cli/api/commands/flags.py +18 -0
  49. snowflake/cli/api/commands/snow_typer.py +1 -1
  50. snowflake/cli/api/config.py +25 -6
  51. snowflake/cli/api/connections.py +3 -1
  52. snowflake/cli/api/entities/common.py +4 -0
  53. snowflake/cli/api/entities/utils.py +3 -14
  54. snowflake/cli/api/errno.py +1 -0
  55. snowflake/cli/api/identifiers.py +4 -3
  56. snowflake/cli/api/metrics.py +92 -0
  57. snowflake/cli/api/project/definition_conversion.py +61 -18
  58. snowflake/cli/api/project/schemas/entities/common.py +17 -4
  59. snowflake/cli/api/project/schemas/entities/entities.py +11 -10
  60. snowflake/cli/api/project/schemas/project_definition.py +5 -7
  61. snowflake/cli/api/project/schemas/v1/__init__.py +0 -0
  62. snowflake/cli/api/project/schemas/{identifier_model.py → v1/identifier_model.py} +0 -7
  63. snowflake/cli/api/project/schemas/v1/native_app/__init__.py +0 -0
  64. snowflake/cli/api/project/schemas/{native_app → v1/native_app}/native_app.py +4 -4
  65. snowflake/cli/api/project/schemas/v1/snowpark/__init__.py +0 -0
  66. snowflake/cli/api/project/schemas/{snowpark → v1/snowpark}/callable.py +2 -2
  67. snowflake/cli/api/project/schemas/{snowpark → v1/snowpark}/snowpark.py +2 -2
  68. snowflake/cli/api/project/schemas/v1/streamlit/__init__.py +0 -0
  69. snowflake/cli/api/project/schemas/{streamlit → v1/streamlit}/streamlit.py +2 -1
  70. snowflake/cli/api/rendering/sql_templates.py +6 -0
  71. snowflake/cli/api/rest_api.py +11 -5
  72. snowflake/cli/api/sql_execution.py +6 -15
  73. snowflake/cli/api/utils/definition_rendering.py +24 -4
  74. {snowflake_cli_labs-3.0.0rc2.dist-info → snowflake_cli_labs-3.0.0rc4.dist-info}/METADATA +9 -7
  75. {snowflake_cli_labs-3.0.0rc2.dist-info → snowflake_cli_labs-3.0.0rc4.dist-info}/RECORD +83 -79
  76. snowflake/cli/_plugins/nativeapp/init.py +0 -345
  77. snowflake/cli/api/entities/application_package_entity.py +0 -658
  78. snowflake/cli/api/project/schemas/entities/application_entity_model.py +0 -56
  79. snowflake/cli/api/project/schemas/entities/application_package_entity_model.py +0 -94
  80. snowflake/cli/api/project/schemas/streamlit/__init__.py +0 -13
  81. /snowflake/cli/{api/project/schemas/native_app → _plugins/helpers}/__init__.py +0 -0
  82. /snowflake/cli/api/project/schemas/{native_app → v1/native_app}/application.py +0 -0
  83. /snowflake/cli/api/project/schemas/{native_app → v1/native_app}/package.py +0 -0
  84. /snowflake/cli/api/project/schemas/{native_app → v1/native_app}/path_mapping.py +0 -0
  85. /snowflake/cli/api/project/schemas/{snowpark → v1/snowpark}/argument.py +0 -0
  86. {snowflake_cli_labs-3.0.0rc2.dist-info → snowflake_cli_labs-3.0.0rc4.dist-info}/WHEEL +0 -0
  87. {snowflake_cli_labs-3.0.0rc2.dist-info → snowflake_cli_labs-3.0.0rc4.dist-info}/entry_points.txt +0 -0
  88. {snowflake_cli_labs-3.0.0rc2.dist-info → snowflake_cli_labs-3.0.0rc4.dist-info}/licenses/LICENSE +0 -0
@@ -15,266 +15,59 @@
15
15
  from __future__ import annotations
16
16
 
17
17
  from pathlib import Path
18
- from textwrap import dedent
19
- from typing import Dict, List, Optional
18
+ from typing import Dict, Optional
20
19
 
21
- import typer
22
- from click import BadOptionUsage, ClickException
23
- from snowflake.cli._plugins.nativeapp.artifacts import (
24
- BundleMap,
25
- find_version_info_in_manifest_file,
26
- )
27
- from snowflake.cli._plugins.nativeapp.constants import VERSION_COL
28
- from snowflake.cli._plugins.nativeapp.exceptions import (
29
- ApplicationPackageAlreadyExistsError,
30
- ApplicationPackageDoesNotExistError,
20
+ from snowflake.cli._plugins.nativeapp.entities.application_package import (
21
+ ApplicationPackageEntity,
31
22
  )
32
23
  from snowflake.cli._plugins.nativeapp.manager import (
33
24
  NativeAppCommandProcessor,
34
25
  NativeAppManager,
35
26
  )
36
- from snowflake.cli._plugins.nativeapp.policy import PolicyBase
37
27
  from snowflake.cli._plugins.nativeapp.run_processor import NativeAppRunProcessor
38
28
  from snowflake.cli.api.console import cli_console as cc
39
- from snowflake.cli.api.entities.utils import ensure_correct_owner
40
- from snowflake.cli.api.exceptions import SnowflakeSQLExecutionError
41
- from snowflake.cli.api.project.schemas.native_app.native_app import NativeApp
42
- from snowflake.cli.api.project.util import to_identifier, unquote_identifier
43
- from snowflake.cli.api.utils.cursor import (
44
- find_all_rows,
45
- )
46
- from snowflake.connector import ProgrammingError
47
- from snowflake.connector.cursor import DictCursor
48
-
49
-
50
- def check_index_changes_in_git_repo(
51
- project_root: Path, policy: PolicyBase, is_interactive: bool
52
- ) -> None:
53
- """
54
- Checks if the project root, i.e. the native apps project is a git repository. If it is a git repository,
55
- it also checks if there any local changes to the directory that may not be on the application package stage.
56
- """
57
- from git import Repo
58
- from git.exc import InvalidGitRepositoryError
59
-
60
- try:
61
- repo = Repo(project_root, search_parent_directories=True)
62
- assert repo.git_dir is not None
63
-
64
- # Check if the repo has any changes, including untracked files
65
- if repo.is_dirty(untracked_files=True):
66
- cc.warning(
67
- "Changes detected in the git repository. "
68
- "(Rerun your command with --skip-git-check flag to ignore this check)"
69
- )
70
- repo.git.execute(["git", "status"])
71
-
72
- user_prompt = (
73
- "You have local changes in this repository that are not part of a previous commit. "
74
- "Do you still want to continue?"
75
- )
76
- if not policy.should_proceed(user_prompt):
77
- if is_interactive:
78
- cc.message("Not creating a new version.")
79
- raise typer.Exit(0)
80
- else:
81
- cc.message(
82
- "Cannot create a new version non-interactively without --force."
83
- )
84
- raise typer.Exit(1)
85
-
86
- except InvalidGitRepositoryError:
87
- pass # not a git repository, which is acceptable
29
+ from snowflake.cli.api.project.schemas.v1.native_app.native_app import NativeApp
88
30
 
89
31
 
90
32
  class NativeAppVersionCreateProcessor(NativeAppRunProcessor):
91
33
  def __init__(self, project_definition: Dict, project_root: Path):
92
34
  super().__init__(project_definition, project_root)
93
35
 
94
- def get_existing_release_directive_info_for_version(
95
- self, version: str
96
- ) -> List[dict]:
97
- """
98
- Get all existing release directives, if present, set on the version defined in an application package.
99
- It executes a 'show release directives in application package' query and returns the filtered results, if they exist.
100
- """
101
- with self.use_role(self.package_role):
102
- show_obj_query = (
103
- f"show release directives in application package {self.package_name}"
104
- )
105
- show_obj_cursor = self._execute_query(
106
- show_obj_query, cursor_class=DictCursor
107
- )
108
-
109
- if show_obj_cursor.rowcount is None:
110
- raise SnowflakeSQLExecutionError(show_obj_query)
111
-
112
- show_obj_rows = find_all_rows(
113
- show_obj_cursor,
114
- lambda row: row[VERSION_COL] == unquote_identifier(version),
115
- )
116
-
117
- return show_obj_rows
118
-
119
- def add_new_version(self, version: str) -> None:
120
- """
121
- Defines a new version in an existing application package.
122
- """
123
- # Make the version a valid identifier, adding quotes if necessary
124
- version = to_identifier(version)
125
- with self.use_role(self.package_role):
126
- cc.step(
127
- f"Defining a new version {version} in application package {self.package_name}"
128
- )
129
- add_version_query = dedent(
130
- f"""\
131
- alter application package {self.package_name}
132
- add version {version}
133
- using @{self.stage_fqn}
134
- """
135
- )
136
- self._execute_query(add_version_query, cursor_class=DictCursor)
137
- cc.message(
138
- f"Version {version} created for application package {self.package_name}."
139
- )
140
-
141
- def add_new_patch_to_version(self, version: str, patch: Optional[int] = None):
142
- """
143
- Add a new patch, optionally a custom one, to an existing version in an application package.
144
- """
145
- # Make the version a valid identifier, adding quotes if necessary
146
- version = to_identifier(version)
147
- with self.use_role(self.package_role):
148
- cc.step(
149
- f"Adding new patch to version {version} defined in application package {self.package_name}"
150
- )
151
- add_version_query = dedent(
152
- f"""\
153
- alter application package {self.package_name}
154
- add patch {patch if patch else ""} for version {version}
155
- using @{self.stage_fqn}
156
- """
157
- )
158
- result_cursor = self._execute_query(
159
- add_version_query, cursor_class=DictCursor
160
- )
161
-
162
- show_row = result_cursor.fetchall()[0]
163
- new_patch = show_row["patch"]
164
- cc.message(
165
- f"Patch {new_patch} created for version {version} defined in application package {self.package_name}."
166
- )
167
-
168
36
  def process(
169
37
  self,
170
- bundle_map: BundleMap,
171
38
  version: Optional[str],
172
39
  patch: Optional[int],
173
- policy: PolicyBase,
174
- git_policy: PolicyBase,
175
- is_interactive: bool,
40
+ force: bool,
41
+ interactive: bool,
42
+ skip_git_check: bool,
176
43
  *args,
177
44
  **kwargs,
178
45
  ):
179
- """
180
- Perform bundle, application package creation, stage upload, version and/or patch to an application package.
181
- """
182
-
183
- # Make sure version is not None before proceeding any further.
184
- # This will raise an exception if version information is not found. Patch can be None.
185
- if not version:
186
- cc.message(
187
- "Version was not provided through the Snowflake CLI. Checking version in the manifest.yml instead."
188
- )
189
-
190
- version, patch = find_version_info_in_manifest_file(self.deploy_root)
191
- if not version:
192
- raise ClickException(
193
- "Manifest.yml file does not contain a value for the version field."
194
- )
195
-
196
- # Check if --patch needs to throw a bad option error, either if application package does not exist or if version does not exist
197
- if patch:
198
- try:
199
- if not self.get_existing_version_info(version):
200
- raise BadOptionUsage(
201
- option_name="patch",
202
- message=f"Cannot create a custom patch when version {version} is not defined in the application package {self.package_name}. Try again without using --patch.",
203
- )
204
- except ApplicationPackageDoesNotExistError as app_err:
205
- raise BadOptionUsage(
206
- option_name="patch",
207
- message=f"Cannot create a custom patch when application package {self.package_name} does not exist. Try again without using --patch.",
208
- )
209
-
210
- if git_policy.should_proceed():
211
- check_index_changes_in_git_repo(
212
- project_root=self.project_root,
213
- policy=policy,
214
- is_interactive=is_interactive,
215
- )
216
-
217
- # TODO: consider using self.deploy() instead
218
-
219
- try:
220
- self.create_app_package()
221
- except ApplicationPackageAlreadyExistsError as e:
222
- cc.warning(e.message)
223
- if not policy.should_proceed("Proceed with using this package?"):
224
- raise typer.Abort() from e
225
-
226
- with self.use_role(self.package_role):
227
- # Now that the application package exists, create shared data
228
- self._apply_package_scripts()
229
-
230
- # Upload files from deploy root local folder to the above stage
231
- self.sync_deploy_root_with_stage(
232
- bundle_map=bundle_map,
233
- role=self.package_role,
234
- prune=True,
235
- recursive=True,
236
- stage_fqn=self.stage_fqn,
237
- )
238
- with self.use_package_warehouse():
239
- self.execute_package_post_deploy_hooks()
240
-
241
- # Warn if the version exists in a release directive(s)
242
- existing_release_directives = (
243
- self.get_existing_release_directive_info_for_version(version)
46
+ return ApplicationPackageEntity.version_create(
47
+ console=cc,
48
+ project_root=self.project_root,
49
+ deploy_root=self.deploy_root,
50
+ bundle_root=self.bundle_root,
51
+ generated_root=self.generated_root,
52
+ artifacts=self.artifacts,
53
+ package_name=self.package_name,
54
+ package_role=self.package_role,
55
+ package_distribution=self.package_distribution,
56
+ prune=True,
57
+ recursive=True,
58
+ paths=None,
59
+ print_diff=True,
60
+ validate=True,
61
+ stage_fqn=self.stage_fqn,
62
+ package_warehouse=self.package_warehouse,
63
+ post_deploy_hooks=self.package_post_deploy_hooks,
64
+ package_scripts=self.package_scripts,
65
+ version=version,
66
+ patch=patch,
67
+ force=force,
68
+ interactive=interactive,
69
+ skip_git_check=skip_git_check,
244
70
  )
245
- if existing_release_directives:
246
- release_directive_names = ", ".join(
247
- row["name"] for row in existing_release_directives
248
- )
249
- cc.warning(
250
- dedent(
251
- f"""\
252
- Version {version} already defined in application package {self.package_name} and in release directive(s): {release_directive_names}.
253
- """
254
- )
255
- )
256
-
257
- user_prompt = (
258
- f"Are you sure you want to create a new patch for version {version} in application "
259
- f"package {self.package_name}? Once added, this operation cannot be undone."
260
- )
261
- if not policy.should_proceed(user_prompt):
262
- if is_interactive:
263
- cc.message("Not creating a new patch.")
264
- raise typer.Exit(0)
265
- else:
266
- cc.message(
267
- "Cannot create a new patch non-interactively without --force."
268
- )
269
- raise typer.Exit(1)
270
-
271
- # Define a new version in the application package
272
- if not self.get_existing_version_info(version):
273
- self.add_new_version(version=version)
274
- return # A new version created automatically has patch 0, we do not need to further increment the patch.
275
-
276
- # Add a new patch to an existing (old) version
277
- self.add_new_patch_to_version(version=version, patch=patch)
278
71
 
279
72
 
280
73
  class NativeAppVersionDropProcessor(NativeAppManager, NativeAppCommandProcessor):
@@ -284,81 +77,22 @@ class NativeAppVersionDropProcessor(NativeAppManager, NativeAppCommandProcessor)
284
77
  def process(
285
78
  self,
286
79
  version: Optional[str],
287
- policy: PolicyBase,
288
- is_interactive: bool,
80
+ force: bool,
81
+ interactive: bool,
289
82
  *args,
290
83
  **kwargs,
291
84
  ):
292
- """
293
- Drops a version defined in an application package. If --force is provided, then no user prompts will be executed.
294
- """
295
-
296
- # 1. Check for existing an existing application package
297
- show_obj_row = self.get_existing_app_pkg_info()
298
- if show_obj_row:
299
- # Check for the right owner role
300
- ensure_correct_owner(
301
- row=show_obj_row, role=self.package_role, obj_name=self.package_name
302
- )
303
- else:
304
- raise ApplicationPackageDoesNotExistError(self.package_name)
305
-
306
- # 2. Check distribution of the existing application package
307
- actual_distribution = self.get_app_pkg_distribution_in_snowflake
308
- if not self.verify_project_distribution(actual_distribution):
309
- cc.warning(
310
- f"Continuing to execute `snow app version drop` on application package {self.package_name} with distribution '{actual_distribution}'."
311
- )
312
-
313
- # 3. If the user did not pass in a version string, determine from manifest.yml
314
- if not version:
315
- cc.message(
316
- dedent(
317
- f"""\
318
- Version was not provided through the Snowflake CLI. Checking version in the manifest.yml instead.
319
- This step will bundle your app artifacts to determine the location of the manifest.yml file.
320
- """
321
- )
322
- )
323
- self.build_bundle()
324
- version, _ = find_version_info_in_manifest_file(self.deploy_root)
325
- if not version:
326
- raise ClickException(
327
- "Manifest.yml file does not contain a value for the version field."
328
- )
329
-
330
- # Make the version a valid identifier, adding quotes if necessary
331
- version = to_identifier(version)
332
-
333
- cc.step(
334
- dedent(
335
- f"""\
336
- About to drop version {version} in application package {self.package_name}.
337
- """
338
- )
339
- )
340
-
341
- # If user did not provide --force, ask for confirmation
342
- user_prompt = (
343
- f"Are you sure you want to drop version {version} in application package {self.package_name}? Once dropped, this operation cannot be undone.",
344
- )
345
- if not policy.should_proceed(user_prompt):
346
- if is_interactive:
347
- cc.message("Not dropping version.")
348
- raise typer.Exit(0)
349
- else:
350
- cc.message("Cannot drop version non-interactively without --force.")
351
- raise typer.Exit(1)
352
-
353
- # Drop the version
354
- with self.use_role(self.package_role):
355
- try:
356
- self._execute_query(
357
- f"alter application package {self.package_name} drop version {version}"
358
- )
359
- except ProgrammingError as err:
360
- raise err # e.g. version is referenced in a release directive(s)
361
-
362
- cc.message(
363
- f"Version {version} in application package {self.package_name} dropped successfully."
85
+ return ApplicationPackageEntity.version_drop(
86
+ console=cc,
87
+ project_root=self.project_root,
88
+ deploy_root=self.deploy_root,
89
+ bundle_root=self.bundle_root,
90
+ generated_root=self.generated_root,
91
+ artifacts=self.artifacts,
92
+ package_name=self.package_name,
93
+ package_role=self.package_role,
94
+ package_distribution=self.package_distribution,
95
+ version=version,
96
+ force=force,
97
+ interactive=interactive,
364
98
  )
@@ -14,7 +14,6 @@
14
14
 
15
15
  from __future__ import annotations
16
16
 
17
- from textwrap import dedent
18
17
  from typing import Any, Dict, Optional, Tuple, Union
19
18
 
20
19
  from click import ClickException
@@ -28,6 +27,7 @@ from snowflake.cli.api.sql_execution import SqlExecutionMixin
28
27
  from snowflake.connector import ProgrammingError
29
28
  from snowflake.connector.cursor import SnowflakeCursor
30
29
  from snowflake.connector.errors import BadRequest
30
+ from snowflake.connector.vendored.requests.exceptions import HTTPError
31
31
 
32
32
 
33
33
  def _get_object_names(object_type: str) -> ObjectNames:
@@ -77,21 +77,42 @@ class ObjectManager(SqlExecutionMixin):
77
77
  def create(self, object_type: str, object_data: Dict[str, Any]) -> str:
78
78
  rest = RestApi(self._conn)
79
79
  url = rest.determine_url_for_create_query(object_type=object_type)
80
-
81
80
  try:
82
81
  response = rest.send_rest_request(url=url, method="post", data=object_data)
83
- # workaround as SnowflakeRestful class ignores some errors, dropping their info and returns {} instead.
84
- if not response:
82
+ except Exception as err:
83
+ _handle_create_error_codes(err)
84
+ return response["status"]
85
+
86
+
87
+ def _handle_create_error_codes(err: Exception) -> None:
88
+ # according to https://docs.snowflake.com/developer-guide/snowflake-rest-api/reference/
89
+ if isinstance(err, BadRequest):
90
+ raise ClickException(
91
+ "400 bad request: Incorrect object definition (arguments misspelled or malformatted)."
92
+ )
93
+ if isinstance(err, HTTPError):
94
+ match err_code := err.response.status_code:
95
+ case 401:
85
96
  raise ClickException(
86
- dedent(
87
- """ An unexpected error occurred while creating the object. Try again with --debug for more info.
88
- Most probable reasons:
89
- * object you are trying to create already exists
90
- * role you are using do not have permissions to create this object"""
91
- )
97
+ "401 unauthorized: role you are using does not have permissions to create this object."
92
98
  )
93
- return response["status"]
94
- except BadRequest:
95
- raise ClickException(
96
- "Incorrect object definition (arguments misspelled or malformatted)."
97
- )
99
+ # error 403 should be handled by connector
100
+ # error 404 is handled by determine-url logic
101
+ # error 405 should not happen under assumption that "all listable objects can be created"
102
+ case 408:
103
+ raise ClickException(
104
+ "408 timeout: the request timed out and was not completed by the server."
105
+ )
106
+ case 409:
107
+ raise ClickException(
108
+ "409 conflict: object you're trying to create already exists."
109
+ )
110
+ # error 410 is a network maintenance debugging - should not happen to the user
111
+ case 429:
112
+ raise ClickException(
113
+ "429 too many requests. The number of requests hit the rate limit."
114
+ )
115
+ case 500 | 503 | 504:
116
+ raise ClickException(f"{err_code} internal server error.")
117
+ case _:
118
+ raise err
@@ -46,6 +46,10 @@ from snowflake.cli._plugins.snowpark.package.anaconda_packages import (
46
46
  AnacondaPackagesManager,
47
47
  )
48
48
  from snowflake.cli._plugins.snowpark.package.commands import app as package_app
49
+ from snowflake.cli._plugins.snowpark.snowpark_entity_model import (
50
+ FunctionEntityModel,
51
+ ProcedureEntityModel,
52
+ )
49
53
  from snowflake.cli._plugins.snowpark.snowpark_project_paths import (
50
54
  SnowparkProjectPaths,
51
55
  )
@@ -87,10 +91,6 @@ from snowflake.cli.api.output.types import (
87
91
  from snowflake.cli.api.project.definition_conversion import (
88
92
  convert_project_definition_to_v2,
89
93
  )
90
- from snowflake.cli.api.project.schemas.entities.snowpark_entity import (
91
- FunctionEntityModel,
92
- ProcedureEntityModel,
93
- )
94
94
  from snowflake.cli.api.project.schemas.project_definition import (
95
95
  ProjectDefinition,
96
96
  ProjectDefinitionV2,
@@ -21,6 +21,10 @@ from typing import Dict, List, Set
21
21
 
22
22
  from click import UsageError
23
23
  from snowflake.cli._plugins.snowpark.models import Requirement
24
+ from snowflake.cli._plugins.snowpark.snowpark_entity_model import (
25
+ ProcedureEntityModel,
26
+ SnowparkEntityModel,
27
+ )
24
28
  from snowflake.cli._plugins.snowpark.snowpark_project_paths import Artefact
25
29
  from snowflake.cli.api.console import cli_console
26
30
  from snowflake.cli.api.constants import (
@@ -30,10 +34,6 @@ from snowflake.cli.api.constants import (
30
34
  PROJECT_TEMPLATE_VARIABLE_OPENING,
31
35
  ObjectType,
32
36
  )
33
- from snowflake.cli.api.project.schemas.entities.snowpark_entity import (
34
- ProcedureEntityModel,
35
- SnowparkEntityModel,
36
- )
37
37
  from snowflake.cli.api.sql_execution import SqlExecutionMixin
38
38
  from snowflake.connector.cursor import SnowflakeCursor
39
39
 
@@ -1,10 +1,10 @@
1
1
  from typing import Generic, TypeVar
2
2
 
3
- from snowflake.cli.api.entities.common import EntityBase
4
- from snowflake.cli.api.project.schemas.entities.snowpark_entity import (
3
+ from snowflake.cli._plugins.snowpark.snowpark_entity_model import (
5
4
  FunctionEntityModel,
6
5
  ProcedureEntityModel,
7
6
  )
7
+ from snowflake.cli.api.entities.common import EntityBase
8
8
 
9
9
  T = TypeVar("T")
10
10
 
@@ -22,12 +22,13 @@ from snowflake.cli.api.identifiers import FQN
22
22
  from snowflake.cli.api.project.schemas.entities.common import (
23
23
  EntityModelBase,
24
24
  ExternalAccessBaseModel,
25
+ ImportsBaseModel,
25
26
  )
26
- from snowflake.cli.api.project.schemas.snowpark.argument import Argument
27
27
  from snowflake.cli.api.project.schemas.updatable_model import (
28
28
  DiscriminatorField,
29
29
  UpdatableModel,
30
30
  )
31
+ from snowflake.cli.api.project.schemas.v1.snowpark.argument import Argument
31
32
 
32
33
 
33
34
  class PathMapping(UpdatableModel):
@@ -43,7 +44,7 @@ class PathMapping(UpdatableModel):
43
44
  )
44
45
 
45
46
 
46
- class SnowparkEntityModel(EntityModelBase, ExternalAccessBaseModel):
47
+ class SnowparkEntityModel(EntityModelBase, ExternalAccessBaseModel, ImportsBaseModel):
47
48
  handler: str = Field(
48
49
  title="Function’s or procedure’s implementation of the object inside source module",
49
50
  examples=["functions.hello_function"],
@@ -57,10 +58,6 @@ class SnowparkEntityModel(EntityModelBase, ExternalAccessBaseModel):
57
58
  runtime: Optional[Union[str, float]] = Field(
58
59
  title="Python version to use when executing ", default=None
59
60
  )
60
- imports: Optional[List[str]] = Field(
61
- title="Stage and path to previously uploaded files you want to import",
62
- default=[],
63
- )
64
61
  stage: str = Field(title="Stage in which artifacts will be stored")
65
62
  artifacts: List[Union[PathMapping, str]] = Field(title="List of required sources")
66
63
 
@@ -16,11 +16,11 @@ from __future__ import annotations
16
16
  from dataclasses import dataclass
17
17
  from pathlib import Path, PurePosixPath
18
18
 
19
+ from snowflake.cli._plugins.snowpark.snowpark_entity_model import PathMapping
19
20
  from snowflake.cli._plugins.snowpark.zipper import zip_dir
20
21
  from snowflake.cli.api.console import cli_console
21
22
  from snowflake.cli.api.constants import DEPLOYMENT_STAGE
22
23
  from snowflake.cli.api.identifiers import FQN
23
- from snowflake.cli.api.project.schemas.entities.snowpark_entity import PathMapping
24
24
  from snowflake.cli.api.secure_path import SecurePath
25
25
 
26
26
 
@@ -57,6 +57,9 @@ EXECUTE_SUPPORTED_FILES_FORMATS = (
57
57
  ".py",
58
58
  ) # tuple to preserve order but it's a set
59
59
 
60
+ # Replace magic numbers with constants
61
+ OMIT_FIRST = slice(1, None)
62
+
60
63
 
61
64
  @dataclass
62
65
  class StagePathParts:
@@ -67,7 +70,7 @@ class StagePathParts:
67
70
 
68
71
  @classmethod
69
72
  def get_directory(cls, stage_path: str) -> str:
70
- return "/".join(Path(stage_path).parts[1:])
73
+ return "/".join(Path(stage_path).parts[OMIT_FIRST])
71
74
 
72
75
  @property
73
76
  def path(self) -> str:
@@ -119,7 +122,9 @@ class DefaultStagePathParts(StagePathParts):
119
122
  self.directory = self.get_directory(stage_path)
120
123
  self.stage = StageManager.get_stage_from_path(stage_path)
121
124
  stage_name = self.stage.split(".")[-1]
122
- stage_name = stage_name[1:] if stage_name.startswith("@") else stage_name
125
+ stage_name = (
126
+ stage_name[OMIT_FIRST] if stage_name.startswith("@") else stage_name
127
+ )
123
128
  self.stage_name = stage_name
124
129
  self.is_directory = True if stage_path.endswith("/") else False
125
130
 
@@ -133,7 +138,7 @@ class DefaultStagePathParts(StagePathParts):
133
138
 
134
139
  def replace_stage_prefix(self, file_path: str) -> str:
135
140
  stage = Path(self.stage).parts[0]
136
- file_path_without_prefix = Path(file_path).parts[1:]
141
+ file_path_without_prefix = Path(file_path).parts[OMIT_FIRST]
137
142
  return f"{stage}/{'/'.join(file_path_without_prefix)}"
138
143
 
139
144
  def add_stage_prefix(self, file_path: str) -> str:
@@ -461,7 +466,7 @@ class StageManager(SqlExecutionMixin):
461
466
  on_error: OnErrorType,
462
467
  ) -> Dict:
463
468
  try:
464
- query = f"execute immediate from {file_stage_path}"
469
+ query = f"execute immediate from {self.quote_stage_name(file_stage_path)}"
465
470
  if variables:
466
471
  query += variables
467
472
  self._execute_query(query)
@@ -26,6 +26,9 @@ from snowflake.cli._plugins.object.command_aliases import (
26
26
  scope_option,
27
27
  )
28
28
  from snowflake.cli._plugins.streamlit.manager import StreamlitManager
29
+ from snowflake.cli._plugins.streamlit.streamlit_entity_model import (
30
+ StreamlitEntityModel,
31
+ )
29
32
  from snowflake.cli.api.cli_global_context import get_cli_context
30
33
  from snowflake.cli.api.commands.decorators import (
31
34
  with_experimental_behaviour,
@@ -49,9 +52,6 @@ from snowflake.cli.api.output.types import (
49
52
  from snowflake.cli.api.project.definition_conversion import (
50
53
  convert_project_definition_to_v2,
51
54
  )
52
- from snowflake.cli.api.project.schemas.entities.streamlit_entity_model import (
53
- StreamlitEntityModel,
54
- )
55
55
 
56
56
  app = SnowTyperFactory(
57
57
  name="streamlit",
@@ -81,6 +81,18 @@ add_object_command_aliases(
81
81
  )
82
82
 
83
83
 
84
+ @app.command(requires_connection=True)
85
+ def execute(
86
+ name: FQN = StreamlitNameArgument,
87
+ **options,
88
+ ):
89
+ """
90
+ Executes a streamlit in a headless mode.
91
+ """
92
+ _ = StreamlitManager().execute(app_name=name)
93
+ return MessageResult(f"Streamlit {name} executed.")
94
+
95
+
84
96
  @app.command("share", requires_connection=True)
85
97
  def streamlit_share(
86
98
  name: FQN = StreamlitNameArgument,