snowflake-cli-labs 3.0.0rc0__py3-none-any.whl → 3.0.0rc2__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 (66) hide show
  1. snowflake/cli/__about__.py +1 -1
  2. snowflake/cli/_app/cli_app.py +10 -1
  3. snowflake/cli/_app/snow_connector.py +91 -37
  4. snowflake/cli/_app/telemetry.py +8 -4
  5. snowflake/cli/_app/version_check.py +74 -0
  6. snowflake/cli/_plugins/connection/commands.py +3 -2
  7. snowflake/cli/_plugins/git/commands.py +55 -14
  8. snowflake/cli/_plugins/git/manager.py +14 -6
  9. snowflake/cli/_plugins/nativeapp/codegen/compiler.py +18 -2
  10. snowflake/cli/_plugins/nativeapp/codegen/setup/native_app_setup_processor.py +123 -42
  11. snowflake/cli/_plugins/nativeapp/codegen/setup/setup_driver.py.source +5 -2
  12. snowflake/cli/_plugins/nativeapp/codegen/snowpark/python_processor.py +6 -11
  13. snowflake/cli/_plugins/nativeapp/codegen/templates/templates_processor.py +111 -0
  14. snowflake/cli/_plugins/nativeapp/exceptions.py +3 -3
  15. snowflake/cli/_plugins/nativeapp/manager.py +74 -144
  16. snowflake/cli/_plugins/nativeapp/project_model.py +2 -9
  17. snowflake/cli/_plugins/nativeapp/run_processor.py +56 -260
  18. snowflake/cli/_plugins/nativeapp/same_account_install_method.py +74 -0
  19. snowflake/cli/_plugins/nativeapp/teardown_processor.py +17 -246
  20. snowflake/cli/_plugins/nativeapp/v2_conversions/v2_to_v1_decorator.py +91 -17
  21. snowflake/cli/_plugins/snowpark/commands.py +5 -65
  22. snowflake/cli/_plugins/snowpark/common.py +17 -1
  23. snowflake/cli/_plugins/snowpark/models.py +2 -1
  24. snowflake/cli/_plugins/snowpark/package/anaconda_packages.py +1 -35
  25. snowflake/cli/_plugins/sql/commands.py +1 -2
  26. snowflake/cli/_plugins/stage/commands.py +2 -2
  27. snowflake/cli/_plugins/stage/manager.py +46 -15
  28. snowflake/cli/_plugins/streamlit/commands.py +4 -63
  29. snowflake/cli/_plugins/streamlit/manager.py +13 -0
  30. snowflake/cli/_plugins/workspace/action_context.py +7 -0
  31. snowflake/cli/_plugins/workspace/commands.py +145 -32
  32. snowflake/cli/_plugins/workspace/manager.py +21 -4
  33. snowflake/cli/api/cli_global_context.py +136 -313
  34. snowflake/cli/api/commands/decorators.py +1 -1
  35. snowflake/cli/api/commands/flags.py +106 -102
  36. snowflake/cli/api/commands/snow_typer.py +15 -6
  37. snowflake/cli/api/config.py +18 -5
  38. snowflake/cli/api/connections.py +214 -0
  39. snowflake/cli/api/console/abc.py +4 -2
  40. snowflake/cli/api/constants.py +11 -0
  41. snowflake/cli/api/entities/application_entity.py +687 -2
  42. snowflake/cli/api/entities/application_package_entity.py +407 -9
  43. snowflake/cli/api/entities/common.py +7 -2
  44. snowflake/cli/api/entities/utils.py +80 -20
  45. snowflake/cli/api/exceptions.py +12 -2
  46. snowflake/cli/api/feature_flags.py +0 -2
  47. snowflake/cli/api/identifiers.py +3 -0
  48. snowflake/cli/api/project/definition.py +35 -1
  49. snowflake/cli/api/project/definition_conversion.py +352 -0
  50. snowflake/cli/api/project/schemas/entities/application_package_entity_model.py +17 -0
  51. snowflake/cli/api/project/schemas/entities/common.py +0 -12
  52. snowflake/cli/api/project/schemas/identifier_model.py +2 -2
  53. snowflake/cli/api/project/schemas/project_definition.py +102 -43
  54. snowflake/cli/api/rendering/jinja.py +2 -16
  55. snowflake/cli/api/rendering/project_definition_templates.py +5 -1
  56. snowflake/cli/api/rendering/sql_templates.py +14 -4
  57. snowflake/cli/api/secure_path.py +13 -18
  58. snowflake/cli/api/secure_utils.py +90 -1
  59. snowflake/cli/api/sql_execution.py +13 -0
  60. snowflake/cli/api/utils/definition_rendering.py +7 -7
  61. {snowflake_cli_labs-3.0.0rc0.dist-info → snowflake_cli_labs-3.0.0rc2.dist-info}/METADATA +9 -9
  62. {snowflake_cli_labs-3.0.0rc0.dist-info → snowflake_cli_labs-3.0.0rc2.dist-info}/RECORD +65 -61
  63. snowflake/cli/api/commands/typer_pre_execute.py +0 -26
  64. {snowflake_cli_labs-3.0.0rc0.dist-info → snowflake_cli_labs-3.0.0rc2.dist-info}/WHEEL +0 -0
  65. {snowflake_cli_labs-3.0.0rc0.dist-info → snowflake_cli_labs-3.0.0rc2.dist-info}/entry_points.txt +0 -0
  66. {snowflake_cli_labs-3.0.0rc0.dist-info → snowflake_cli_labs-3.0.0rc2.dist-info}/licenses/LICENSE +0 -0
@@ -15,135 +15,33 @@
15
15
  from __future__ import annotations
16
16
 
17
17
  from pathlib import Path
18
- from textwrap import dedent
19
18
  from typing import Optional
20
19
 
21
20
  import typer
22
- from click import UsageError
23
21
  from snowflake.cli._plugins.nativeapp.artifacts import BundleMap
24
- from snowflake.cli._plugins.nativeapp.constants import (
25
- ALLOWED_SPECIAL_COMMENTS,
26
- COMMENT_COL,
27
- PATCH_COL,
28
- SPECIAL_COMMENT,
29
- VERSION_COL,
30
- )
31
- from snowflake.cli._plugins.nativeapp.exceptions import (
32
- ApplicationCreatedExternallyError,
33
- ApplicationPackageDoesNotExistError,
34
- )
35
22
  from snowflake.cli._plugins.nativeapp.manager import (
36
23
  NativeAppCommandProcessor,
37
24
  NativeAppManager,
38
25
  )
39
26
  from snowflake.cli._plugins.nativeapp.policy import PolicyBase
40
- from snowflake.cli._plugins.nativeapp.project_model import (
41
- NativeAppProjectModel,
27
+ from snowflake.cli._plugins.nativeapp.same_account_install_method import (
28
+ SameAccountInstallMethod,
42
29
  )
43
- from snowflake.cli._plugins.stage.manager import StageManager
44
30
  from snowflake.cli.api.console import cli_console as cc
31
+ from snowflake.cli.api.entities.application_entity import (
32
+ ApplicationEntity,
33
+ )
45
34
  from snowflake.cli.api.entities.utils import (
46
- ensure_correct_owner,
47
35
  generic_sql_error_handler,
48
36
  )
49
37
  from snowflake.cli.api.errno import (
50
38
  APPLICATION_NO_LONGER_AVAILABLE,
51
39
  APPLICATION_OWNS_EXTERNAL_OBJECTS,
52
- CANNOT_UPGRADE_FROM_LOOSE_FILES_TO_VERSION,
53
- CANNOT_UPGRADE_FROM_VERSION_TO_LOOSE_FILES,
54
- NOT_SUPPORTED_ON_DEV_MODE_APPLICATIONS,
55
- ONLY_SUPPORTED_ON_DEV_MODE_APPLICATIONS,
56
40
  )
57
41
  from snowflake.cli.api.exceptions import SnowflakeSQLExecutionError
58
42
  from snowflake.cli.api.project.schemas.native_app.native_app import NativeApp
59
- from snowflake.cli.api.project.util import (
60
- identifier_to_show_like_pattern,
61
- unquote_identifier,
62
- )
63
- from snowflake.cli.api.utils.cursor import find_all_rows
64
43
  from snowflake.connector import ProgrammingError
65
- from snowflake.connector.cursor import DictCursor, SnowflakeCursor
66
-
67
- # Reasons why an `alter application ... upgrade` might fail
68
- UPGRADE_RESTRICTION_CODES = {
69
- CANNOT_UPGRADE_FROM_LOOSE_FILES_TO_VERSION,
70
- CANNOT_UPGRADE_FROM_VERSION_TO_LOOSE_FILES,
71
- ONLY_SUPPORTED_ON_DEV_MODE_APPLICATIONS,
72
- NOT_SUPPORTED_ON_DEV_MODE_APPLICATIONS,
73
- APPLICATION_NO_LONGER_AVAILABLE,
74
- }
75
-
76
-
77
- def print_messages(create_or_upgrade_cursor: Optional[SnowflakeCursor]):
78
- """
79
- Shows messages in the console returned by the CREATE or UPGRADE
80
- APPLICATION command.
81
- """
82
- if not create_or_upgrade_cursor:
83
- return
84
-
85
- messages = [row[0] for row in create_or_upgrade_cursor.fetchall()]
86
- for message in messages:
87
- cc.warning(message)
88
- cc.message("")
89
-
90
-
91
- class SameAccountInstallMethod:
92
- _requires_created_by_cli: bool
93
- _from_release_directive: bool
94
- version: Optional[str]
95
- patch: Optional[int]
96
-
97
- def __init__(
98
- self,
99
- requires_created_by_cli: bool,
100
- version: Optional[str] = None,
101
- patch: Optional[int] = None,
102
- from_release_directive: bool = False,
103
- ):
104
- self._requires_created_by_cli = requires_created_by_cli
105
- self.version = version
106
- self.patch = patch
107
- self._from_release_directive = from_release_directive
108
-
109
- @classmethod
110
- def unversioned_dev(cls):
111
- """aka. stage dev aka loose files"""
112
- return cls(True)
113
-
114
- @classmethod
115
- def versioned_dev(cls, version: str, patch: Optional[int] = None):
116
- return cls(False, version, patch)
117
-
118
- @classmethod
119
- def release_directive(cls):
120
- return cls(False, from_release_directive=True)
121
-
122
- @property
123
- def is_dev_mode(self) -> bool:
124
- return not self._from_release_directive
125
-
126
- def using_clause(self, app: NativeAppProjectModel) -> str:
127
- if self._from_release_directive:
128
- return ""
129
-
130
- if self.version:
131
- patch_clause = f"patch {self.patch}" if self.patch else ""
132
- return f"using version {self.version} {patch_clause}"
133
-
134
- stage_name = StageManager.quote_stage_name(app.stage_fqn)
135
- return f"using {stage_name}"
136
-
137
- def ensure_app_usable(self, app: NativeAppProjectModel, show_app_row: dict):
138
- """Raise an exception if we cannot proceed with install given the pre-existing application object"""
139
-
140
- if self._requires_created_by_cli:
141
- if show_app_row[COMMENT_COL] not in ALLOWED_SPECIAL_COMMENTS:
142
- # this application object was not created by this tooling
143
- raise ApplicationCreatedExternallyError(app.app_name)
144
-
145
- # expected owner
146
- ensure_correct_owner(row=show_app_row, role=app.app_role, obj_name=app.app_name)
44
+ from snowflake.connector.cursor import SnowflakeCursor
147
45
 
148
46
 
149
47
  class NativeAppRunProcessor(NativeAppManager, NativeAppCommandProcessor):
@@ -165,35 +63,11 @@ class NativeAppRunProcessor(NativeAppManager, NativeAppCommandProcessor):
165
63
  return show_obj_cursor
166
64
 
167
65
  def get_existing_version_info(self, version: str) -> Optional[dict]:
168
- """
169
- Get the latest patch on an existing version by name in the application package.
170
- Executes 'show versions like ... in application package' query and returns
171
- the latest patch in the version as a single row, if one exists. Otherwise,
172
- returns None.
173
- """
174
- with self.use_role(self.package_role):
175
- try:
176
- query = f"show versions like {identifier_to_show_like_pattern(version)} in application package {self.package_name}"
177
- cursor = self._execute_query(query, cursor_class=DictCursor)
178
-
179
- if cursor.rowcount is None:
180
- raise SnowflakeSQLExecutionError(query)
181
-
182
- matching_rows = find_all_rows(
183
- cursor, lambda row: row[VERSION_COL] == unquote_identifier(version)
184
- )
185
-
186
- if not matching_rows:
187
- return None
188
-
189
- return max(matching_rows, key=lambda row: row[PATCH_COL])
190
-
191
- except ProgrammingError as err:
192
- if err.msg.__contains__("does not exist or not authorized"):
193
- raise ApplicationPackageDoesNotExistError(self.package_name)
194
- else:
195
- generic_sql_error_handler(err=err, role=self.package_role)
196
- return None
66
+ return ApplicationEntity.get_existing_version_info(
67
+ version=version,
68
+ package_name=self.package_name,
69
+ package_role=self.package_role,
70
+ )
197
71
 
198
72
  def drop_application_before_upgrade(
199
73
  self, policy: PolicyBase, is_interactive: bool, cascade: bool = False
@@ -249,90 +123,26 @@ class NativeAppRunProcessor(NativeAppManager, NativeAppCommandProcessor):
249
123
  install_method: SameAccountInstallMethod,
250
124
  is_interactive: bool = False,
251
125
  ):
252
- with self.use_role(self.app_role):
253
-
254
- # 1. Need to use a warehouse to create an application object
255
- with self.use_warehouse(self.application_warehouse):
256
-
257
- # 2. Check for an existing application by the same name
258
- show_app_row = self.get_existing_app_info()
259
-
260
- # 3. If existing application is found, perform a few validations and upgrade the application object.
261
- if show_app_row:
262
-
263
- install_method.ensure_app_usable(self._na_project, show_app_row)
264
-
265
- # If all the above checks are in order, proceed to upgrade
266
- try:
267
- cc.step(
268
- f"Upgrading existing application object {self.app_name}."
269
- )
270
- using_clause = install_method.using_clause(self._na_project)
271
- upgrade_cursor = self._execute_query(
272
- f"alter application {self.app_name} upgrade {using_clause}",
273
- )
274
- print_messages(upgrade_cursor)
275
-
276
- if install_method.is_dev_mode:
277
- # if debug_mode is present (controlled), ensure it is up-to-date
278
- if self.debug_mode is not None:
279
- self._execute_query(
280
- f"alter application {self.app_name} set debug_mode = {self.debug_mode}"
281
- )
282
-
283
- # hooks always executed after a create or upgrade
284
- self.execute_app_post_deploy_hooks()
285
- return
286
-
287
- except ProgrammingError as err:
288
- if err.errno not in UPGRADE_RESTRICTION_CODES:
289
- generic_sql_error_handler(err=err)
290
- else: # The existing application object was created from a different process.
291
- cc.warning(err.msg)
292
- self.drop_application_before_upgrade(policy, is_interactive)
293
-
294
- # 4. With no (more) existing application objects, create an application object using the release directives
295
- cc.step(f"Creating new application object {self.app_name} in account.")
296
-
297
- if self.app_role != self.package_role:
298
- with self.use_role(self.package_role):
299
- self._execute_query(
300
- f"grant install, develop on application package {self.package_name} to role {self.app_role}"
301
- )
302
- self._execute_query(
303
- f"grant usage on schema {self.package_name}.{self.stage_schema} to role {self.app_role}"
304
- )
305
- self._execute_query(
306
- f"grant read on stage {self.stage_fqn} to role {self.app_role}"
307
- )
308
-
309
- try:
310
- # by default, applications are created in debug mode when possible;
311
- # this can be overridden in the project definition
312
- debug_mode_clause = ""
313
- if install_method.is_dev_mode:
314
- initial_debug_mode = (
315
- self.debug_mode if self.debug_mode is not None else True
316
- )
317
- debug_mode_clause = f"debug_mode = {initial_debug_mode}"
318
-
319
- using_clause = install_method.using_clause(self._na_project)
320
- create_cursor = self._execute_query(
321
- dedent(
322
- f"""\
323
- create application {self.app_name}
324
- from application package {self.package_name} {using_clause} {debug_mode_clause}
325
- comment = {SPECIAL_COMMENT}
326
- """
327
- ),
328
- )
329
- print_messages(create_cursor)
330
-
331
- # hooks always executed after a create or upgrade
332
- self.execute_app_post_deploy_hooks()
333
-
334
- except ProgrammingError as err:
335
- generic_sql_error_handler(err)
126
+ def drop_app():
127
+ self.drop_application_before_upgrade(policy, is_interactive)
128
+
129
+ return ApplicationEntity.create_or_upgrade_app(
130
+ console=cc,
131
+ project_root=self.project_root,
132
+ package_name=self.package_name,
133
+ package_role=self.package_role,
134
+ app_name=self.app_name,
135
+ app_role=self.app_role,
136
+ app_warehouse=self.application_warehouse,
137
+ stage_schema=self.stage_schema,
138
+ stage_fqn=self.stage_fqn,
139
+ debug_mode=self.debug_mode,
140
+ policy=policy,
141
+ install_method=install_method,
142
+ is_interactive=is_interactive,
143
+ post_deploy_hooks=self.app_post_deploy_hooks,
144
+ drop_application_before_upgrade=drop_app,
145
+ )
336
146
 
337
147
  def process(
338
148
  self,
@@ -346,46 +156,32 @@ class NativeAppRunProcessor(NativeAppManager, NativeAppCommandProcessor):
346
156
  *args,
347
157
  **kwargs,
348
158
  ):
349
- """
350
- Create or upgrade the application object using the given strategy
351
- (unversioned dev, versioned dev, or same-account release directive).
352
- """
353
-
354
- # same-account release directive
355
- if from_release_directive:
356
- self.create_or_upgrade_app(
357
- policy=policy,
358
- is_interactive=is_interactive,
359
- install_method=SameAccountInstallMethod.release_directive(),
159
+ def deploy_package():
160
+ self.deploy(
161
+ bundle_map=bundle_map, prune=True, recursive=True, validate=validate
360
162
  )
361
- return
362
163
 
363
- # versioned dev
364
- if version:
365
- try:
366
- version_exists = self.get_existing_version_info(version)
367
- if not version_exists:
368
- raise UsageError(
369
- f"Application package {self.package_name} does not have any version {version} defined. Use 'snow app version create' to define a version in the application package first."
370
- )
371
- except ApplicationPackageDoesNotExistError as app_err:
372
- raise UsageError(
373
- f"Application package {self.package_name} does not exist. Use 'snow app version create' to first create an application package and then define a version in it."
374
- )
375
-
376
- self.create_or_upgrade_app(
377
- policy=policy,
378
- install_method=SameAccountInstallMethod.versioned_dev(version, patch),
379
- is_interactive=is_interactive,
380
- )
381
- return
382
-
383
- # unversioned dev
384
- self.deploy(
385
- bundle_map=bundle_map, prune=True, recursive=True, validate=validate
386
- )
387
- self.create_or_upgrade_app(
388
- policy=policy,
164
+ def drop_app():
165
+ self.drop_application_before_upgrade(policy, is_interactive)
166
+
167
+ ApplicationEntity.deploy(
168
+ console=cc,
169
+ project_root=self.project_root,
170
+ app_name=self.app_name,
171
+ app_role=self.app_role,
172
+ app_warehouse=self.application_warehouse,
173
+ package_name=self.package_name,
174
+ package_role=self.package_role,
175
+ stage_schema=self.stage_schema,
176
+ stage_fqn=self.stage_fqn,
177
+ debug_mode=self.debug_mode,
178
+ validate=validate,
179
+ from_release_directive=from_release_directive,
389
180
  is_interactive=is_interactive,
390
- install_method=SameAccountInstallMethod.unversioned_dev(),
181
+ policy=policy,
182
+ version=version,
183
+ patch=patch,
184
+ post_deploy_hooks=self.app_post_deploy_hooks,
185
+ deploy_package=deploy_package,
186
+ drop_application_before_upgrade=drop_app,
391
187
  )
@@ -0,0 +1,74 @@
1
+ from typing import Optional
2
+
3
+ from snowflake.cli._plugins.nativeapp.constants import (
4
+ ALLOWED_SPECIAL_COMMENTS,
5
+ COMMENT_COL,
6
+ )
7
+ from snowflake.cli._plugins.nativeapp.exceptions import (
8
+ ApplicationCreatedExternallyError,
9
+ )
10
+
11
+ # from snowflake.cli._plugins.nativeapp.project_model import NativeAppProjectModel
12
+ from snowflake.cli._plugins.stage.manager import StageManager
13
+ from snowflake.cli.api.entities.utils import ensure_correct_owner
14
+
15
+
16
+ class SameAccountInstallMethod:
17
+ _requires_created_by_cli: bool
18
+ _from_release_directive: bool
19
+ version: Optional[str]
20
+ patch: Optional[int]
21
+
22
+ def __init__(
23
+ self,
24
+ requires_created_by_cli: bool,
25
+ version: Optional[str] = None,
26
+ patch: Optional[int] = None,
27
+ from_release_directive: bool = False,
28
+ ):
29
+ self._requires_created_by_cli = requires_created_by_cli
30
+ self.version = version
31
+ self.patch = patch
32
+ self._from_release_directive = from_release_directive
33
+
34
+ @classmethod
35
+ def unversioned_dev(cls):
36
+ """aka. stage dev aka loose files"""
37
+ return cls(True)
38
+
39
+ @classmethod
40
+ def versioned_dev(cls, version: str, patch: Optional[int] = None):
41
+ return cls(False, version, patch)
42
+
43
+ @classmethod
44
+ def release_directive(cls):
45
+ return cls(False, from_release_directive=True)
46
+
47
+ @property
48
+ def is_dev_mode(self) -> bool:
49
+ return not self._from_release_directive
50
+
51
+ def using_clause(
52
+ self,
53
+ stage_fqn: str,
54
+ ) -> str:
55
+ if self._from_release_directive:
56
+ return ""
57
+
58
+ if self.version:
59
+ patch_clause = f"patch {self.patch}" if self.patch else ""
60
+ return f"using version {self.version} {patch_clause}"
61
+
62
+ stage_name = StageManager.quote_stage_name(stage_fqn)
63
+ return f"using {stage_name}"
64
+
65
+ def ensure_app_usable(self, app_name: str, app_role: str, show_app_row: dict):
66
+ """Raise an exception if we cannot proceed with install given the pre-existing application object"""
67
+
68
+ if self._requires_created_by_cli:
69
+ if show_app_row[COMMENT_COL] not in ALLOWED_SPECIAL_COMMENTS:
70
+ # this application object was not created by this tooling
71
+ raise ApplicationCreatedExternallyError(app_name)
72
+
73
+ # expected owner
74
+ ensure_correct_owner(row=show_app_row, role=app_role, obj_name=app_name)