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.
- snowflake/cli/__about__.py +1 -1
- snowflake/cli/_app/commands_registration/builtin_plugins.py +2 -0
- snowflake/cli/_app/secret.py +9 -0
- snowflake/cli/_app/snow_connector.py +39 -27
- snowflake/cli/_app/telemetry.py +28 -0
- snowflake/cli/_plugins/connection/commands.py +9 -4
- snowflake/cli/_plugins/git/manager.py +53 -7
- snowflake/cli/_plugins/helpers/commands.py +61 -0
- snowflake/cli/{api/project/schemas/snowpark/__init__.py → _plugins/helpers/plugin_spec.py} +17 -0
- snowflake/cli/_plugins/nativeapp/artifacts.py +10 -9
- snowflake/cli/_plugins/nativeapp/bundle_context.py +1 -1
- snowflake/cli/_plugins/nativeapp/codegen/artifact_processor.py +1 -1
- snowflake/cli/_plugins/nativeapp/codegen/compiler.py +6 -1
- snowflake/cli/_plugins/nativeapp/codegen/setup/native_app_setup_processor.py +1 -1
- snowflake/cli/_plugins/nativeapp/codegen/snowpark/extension_function_utils.py +1 -1
- snowflake/cli/_plugins/nativeapp/codegen/snowpark/models.py +1 -1
- snowflake/cli/_plugins/nativeapp/codegen/snowpark/python_processor.py +5 -1
- snowflake/cli/_plugins/nativeapp/codegen/templates/templates_processor.py +4 -1
- snowflake/cli/_plugins/nativeapp/commands.py +87 -96
- snowflake/cli/_plugins/nativeapp/entities/__init__.py +0 -0
- snowflake/cli/{api/entities/application_entity.py → _plugins/nativeapp/entities/application.py} +264 -83
- snowflake/cli/_plugins/nativeapp/entities/application_package.py +1392 -0
- snowflake/cli/_plugins/nativeapp/exceptions.py +0 -9
- snowflake/cli/_plugins/nativeapp/manager.py +69 -185
- snowflake/cli/_plugins/nativeapp/policy.py +3 -0
- snowflake/cli/_plugins/nativeapp/project_model.py +2 -2
- snowflake/cli/_plugins/nativeapp/run_processor.py +17 -20
- snowflake/cli/_plugins/nativeapp/same_account_install_method.py +0 -4
- snowflake/cli/_plugins/nativeapp/teardown_processor.py +4 -6
- snowflake/cli/_plugins/nativeapp/v2_conversions/v2_to_v1_decorator.py +122 -88
- snowflake/cli/_plugins/nativeapp/version/commands.py +7 -39
- snowflake/cli/_plugins/nativeapp/version/version_processor.py +46 -312
- snowflake/cli/_plugins/object/manager.py +36 -15
- snowflake/cli/_plugins/snowpark/commands.py +4 -4
- snowflake/cli/_plugins/snowpark/common.py +4 -4
- snowflake/cli/{api/entities → _plugins/snowpark}/snowpark_entity.py +2 -2
- snowflake/cli/{api/project/schemas/entities/snowpark_entity.py → _plugins/snowpark/snowpark_entity_model.py} +3 -6
- snowflake/cli/_plugins/snowpark/snowpark_project_paths.py +1 -1
- snowflake/cli/_plugins/stage/manager.py +9 -4
- snowflake/cli/_plugins/streamlit/commands.py +15 -3
- snowflake/cli/_plugins/streamlit/manager.py +12 -4
- snowflake/cli/{api/entities → _plugins/streamlit}/streamlit_entity.py +2 -2
- snowflake/cli/{api/project/schemas/entities → _plugins/streamlit}/streamlit_entity_model.py +5 -12
- snowflake/cli/_plugins/workspace/commands.py +116 -36
- snowflake/cli/_plugins/workspace/plugin_spec.py +1 -1
- snowflake/cli/api/cli_global_context.py +7 -0
- snowflake/cli/api/commands/decorators.py +14 -0
- snowflake/cli/api/commands/flags.py +18 -0
- snowflake/cli/api/commands/snow_typer.py +1 -1
- snowflake/cli/api/config.py +25 -6
- snowflake/cli/api/connections.py +3 -1
- snowflake/cli/api/entities/common.py +4 -0
- snowflake/cli/api/entities/utils.py +3 -14
- snowflake/cli/api/errno.py +1 -0
- snowflake/cli/api/identifiers.py +4 -3
- snowflake/cli/api/metrics.py +92 -0
- snowflake/cli/api/project/definition_conversion.py +61 -18
- snowflake/cli/api/project/schemas/entities/common.py +17 -4
- snowflake/cli/api/project/schemas/entities/entities.py +11 -10
- snowflake/cli/api/project/schemas/project_definition.py +5 -7
- snowflake/cli/api/project/schemas/v1/__init__.py +0 -0
- snowflake/cli/api/project/schemas/{identifier_model.py → v1/identifier_model.py} +0 -7
- snowflake/cli/api/project/schemas/v1/native_app/__init__.py +0 -0
- snowflake/cli/api/project/schemas/{native_app → v1/native_app}/native_app.py +4 -4
- snowflake/cli/api/project/schemas/v1/snowpark/__init__.py +0 -0
- snowflake/cli/api/project/schemas/{snowpark → v1/snowpark}/callable.py +2 -2
- snowflake/cli/api/project/schemas/{snowpark → v1/snowpark}/snowpark.py +2 -2
- snowflake/cli/api/project/schemas/v1/streamlit/__init__.py +0 -0
- snowflake/cli/api/project/schemas/{streamlit → v1/streamlit}/streamlit.py +2 -1
- snowflake/cli/api/rendering/sql_templates.py +6 -0
- snowflake/cli/api/rest_api.py +11 -5
- snowflake/cli/api/sql_execution.py +6 -15
- snowflake/cli/api/utils/definition_rendering.py +24 -4
- {snowflake_cli_labs-3.0.0rc2.dist-info → snowflake_cli_labs-3.0.0rc4.dist-info}/METADATA +9 -7
- {snowflake_cli_labs-3.0.0rc2.dist-info → snowflake_cli_labs-3.0.0rc4.dist-info}/RECORD +83 -79
- snowflake/cli/_plugins/nativeapp/init.py +0 -345
- snowflake/cli/api/entities/application_package_entity.py +0 -658
- snowflake/cli/api/project/schemas/entities/application_entity_model.py +0 -56
- snowflake/cli/api/project/schemas/entities/application_package_entity_model.py +0 -94
- snowflake/cli/api/project/schemas/streamlit/__init__.py +0 -13
- /snowflake/cli/{api/project/schemas/native_app → _plugins/helpers}/__init__.py +0 -0
- /snowflake/cli/api/project/schemas/{native_app → v1/native_app}/application.py +0 -0
- /snowflake/cli/api/project/schemas/{native_app → v1/native_app}/package.py +0 -0
- /snowflake/cli/api/project/schemas/{native_app → v1/native_app}/path_mapping.py +0 -0
- /snowflake/cli/api/project/schemas/{snowpark → v1/snowpark}/argument.py +0 -0
- {snowflake_cli_labs-3.0.0rc2.dist-info → snowflake_cli_labs-3.0.0rc4.dist-info}/WHEEL +0 -0
- {snowflake_cli_labs-3.0.0rc2.dist-info → snowflake_cli_labs-3.0.0rc4.dist-info}/entry_points.txt +0 -0
- {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
|
|
19
|
-
from typing import Dict, List, Optional
|
|
18
|
+
from typing import Dict, Optional
|
|
20
19
|
|
|
21
|
-
import
|
|
22
|
-
|
|
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.
|
|
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
|
-
|
|
174
|
-
|
|
175
|
-
|
|
40
|
+
force: bool,
|
|
41
|
+
interactive: bool,
|
|
42
|
+
skip_git_check: bool,
|
|
176
43
|
*args,
|
|
177
44
|
**kwargs,
|
|
178
45
|
):
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
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
|
-
|
|
288
|
-
|
|
80
|
+
force: bool,
|
|
81
|
+
interactive: bool,
|
|
289
82
|
*args,
|
|
290
83
|
**kwargs,
|
|
291
84
|
):
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
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
|
-
|
|
84
|
-
|
|
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
|
-
|
|
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
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
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.
|
|
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[
|
|
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 =
|
|
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[
|
|
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,
|