snowflake-cli 3.2.2__py3-none-any.whl → 3.3.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.
Files changed (55) hide show
  1. snowflake/cli/__about__.py +1 -1
  2. snowflake/cli/_app/constants.py +4 -0
  3. snowflake/cli/_app/snow_connector.py +12 -0
  4. snowflake/cli/_app/telemetry.py +10 -3
  5. snowflake/cli/_plugins/connection/util.py +12 -19
  6. snowflake/cli/_plugins/helpers/commands.py +207 -1
  7. snowflake/cli/_plugins/nativeapp/artifacts.py +10 -4
  8. snowflake/cli/_plugins/nativeapp/codegen/compiler.py +41 -17
  9. snowflake/cli/_plugins/nativeapp/codegen/setup/native_app_setup_processor.py +7 -0
  10. snowflake/cli/_plugins/nativeapp/codegen/snowpark/python_processor.py +4 -1
  11. snowflake/cli/_plugins/nativeapp/codegen/templates/templates_processor.py +42 -32
  12. snowflake/cli/_plugins/nativeapp/commands.py +92 -2
  13. snowflake/cli/_plugins/nativeapp/constants.py +5 -0
  14. snowflake/cli/_plugins/nativeapp/entities/application.py +221 -288
  15. snowflake/cli/_plugins/nativeapp/entities/application_package.py +772 -89
  16. snowflake/cli/_plugins/nativeapp/entities/application_package_child_interface.py +43 -0
  17. snowflake/cli/_plugins/nativeapp/feature_flags.py +5 -1
  18. snowflake/cli/_plugins/nativeapp/release_channel/__init__.py +13 -0
  19. snowflake/cli/_plugins/nativeapp/release_channel/commands.py +212 -0
  20. snowflake/cli/_plugins/nativeapp/release_directive/__init__.py +13 -0
  21. snowflake/cli/_plugins/nativeapp/release_directive/commands.py +165 -0
  22. snowflake/cli/_plugins/nativeapp/same_account_install_method.py +9 -17
  23. snowflake/cli/_plugins/nativeapp/sf_facade_exceptions.py +80 -0
  24. snowflake/cli/_plugins/nativeapp/sf_sql_facade.py +999 -75
  25. snowflake/cli/_plugins/nativeapp/utils.py +11 -0
  26. snowflake/cli/_plugins/nativeapp/v2_conversions/compat.py +5 -1
  27. snowflake/cli/_plugins/nativeapp/version/commands.py +31 -4
  28. snowflake/cli/_plugins/notebook/manager.py +4 -2
  29. snowflake/cli/_plugins/snowpark/snowpark_entity.py +234 -4
  30. snowflake/cli/_plugins/spcs/common.py +129 -0
  31. snowflake/cli/_plugins/spcs/services/commands.py +134 -14
  32. snowflake/cli/_plugins/spcs/services/manager.py +169 -1
  33. snowflake/cli/_plugins/stage/manager.py +12 -4
  34. snowflake/cli/_plugins/streamlit/manager.py +8 -1
  35. snowflake/cli/_plugins/streamlit/streamlit_entity.py +153 -2
  36. snowflake/cli/_plugins/workspace/commands.py +3 -2
  37. snowflake/cli/_plugins/workspace/manager.py +8 -4
  38. snowflake/cli/api/cli_global_context.py +22 -1
  39. snowflake/cli/api/config.py +6 -2
  40. snowflake/cli/api/connections.py +12 -1
  41. snowflake/cli/api/constants.py +9 -1
  42. snowflake/cli/api/entities/common.py +85 -0
  43. snowflake/cli/api/entities/utils.py +9 -8
  44. snowflake/cli/api/errno.py +60 -3
  45. snowflake/cli/api/feature_flags.py +20 -4
  46. snowflake/cli/api/metrics.py +21 -27
  47. snowflake/cli/api/project/definition_conversion.py +1 -2
  48. snowflake/cli/api/project/schemas/project_definition.py +27 -6
  49. snowflake/cli/api/project/schemas/v1/streamlit/streamlit.py +1 -1
  50. snowflake/cli/api/project/util.py +45 -0
  51. {snowflake_cli-3.2.2.dist-info → snowflake_cli-3.3.0.dist-info}/METADATA +12 -12
  52. {snowflake_cli-3.2.2.dist-info → snowflake_cli-3.3.0.dist-info}/RECORD +55 -50
  53. {snowflake_cli-3.2.2.dist-info → snowflake_cli-3.3.0.dist-info}/WHEEL +1 -1
  54. {snowflake_cli-3.2.2.dist-info → snowflake_cli-3.3.0.dist-info}/entry_points.txt +0 -0
  55. {snowflake_cli-3.2.2.dist-info → snowflake_cli-3.3.0.dist-info}/licenses/LICENSE +0 -0
@@ -0,0 +1,43 @@
1
+ from abc import ABC, abstractmethod
2
+ from pathlib import Path
3
+ from typing import Optional
4
+
5
+
6
+ class ApplicationPackageChildInterface(ABC):
7
+ @abstractmethod
8
+ def bundle(self, bundle_root=Path, *args, **kwargs) -> None:
9
+ """
10
+ Bundles the entity artifacts into the provided root directory. Must not have any side-effects, such as deploying the artifacts into a stage, etc.
11
+ @param bundle_root: The directory where the bundle contents should be put.
12
+ """
13
+ pass
14
+
15
+ @abstractmethod
16
+ def get_deploy_sql(
17
+ self,
18
+ artifacts_dir: Path,
19
+ schema: Optional[str],
20
+ *args,
21
+ **kwargs,
22
+ ) -> str:
23
+ """
24
+ Returns the SQL that would create the entity object. Must not execute the SQL or have any other side-effects.
25
+ @param artifacts_dir: Path to the child entity artifacts directory relative to the deploy root.
26
+ @param [Optional] schema: Schema to use when creating the object.
27
+ """
28
+ pass
29
+
30
+ @abstractmethod
31
+ def get_usage_grant_sql(
32
+ self,
33
+ app_role: str,
34
+ schema: Optional[str],
35
+ *args,
36
+ **kwargs,
37
+ ) -> str:
38
+ """
39
+ Returns the SQL that would grant the required USAGE privilege to the provided application role on the entity object. Must not execute the SQL or have any other side-effects.
40
+ @param app_role: The application role to grant the privileges to.
41
+ @param [Optional] schema: The schema where the object was created.
42
+ """
43
+ pass
@@ -18,7 +18,11 @@ from snowflake.cli.api.feature_flags import BooleanFlag, FeatureFlagMixin
18
18
 
19
19
 
20
20
  @unique
21
- class FeatureFlag(FeatureFlagMixin):
21
+ class FeatureFlag(
22
+ FeatureFlagMixin
23
+ ): # TODO move this to snowflake.cli.api.feature_flags
22
24
  ENABLE_NATIVE_APP_PYTHON_SETUP = BooleanFlag(
23
25
  "ENABLE_NATIVE_APP_PYTHON_SETUP", False
24
26
  )
27
+ ENABLE_NATIVE_APP_CHILDREN = BooleanFlag("ENABLE_NATIVE_APP_CHILDREN", False)
28
+ ENABLE_RELEASE_CHANNELS = BooleanFlag("ENABLE_RELEASE_CHANNELS", None)
@@ -0,0 +1,13 @@
1
+ # Copyright (c) 2024 Snowflake Inc.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
@@ -0,0 +1,212 @@
1
+ # Copyright (c) 2024 Snowflake Inc.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ from __future__ import annotations
16
+
17
+ import logging
18
+ from typing import Optional
19
+
20
+ import typer
21
+ from snowflake.cli._plugins.nativeapp.v2_conversions.compat import (
22
+ force_project_definition_v2,
23
+ )
24
+ from snowflake.cli._plugins.workspace.manager import WorkspaceManager
25
+ from snowflake.cli.api.cli_global_context import get_cli_context
26
+ from snowflake.cli.api.commands.decorators import with_project_definition
27
+ from snowflake.cli.api.commands.snow_typer import SnowTyperFactory
28
+ from snowflake.cli.api.entities.common import EntityActions
29
+ from snowflake.cli.api.output.formats import OutputFormat
30
+ from snowflake.cli.api.output.types import (
31
+ CollectionResult,
32
+ CommandResult,
33
+ MessageResult,
34
+ )
35
+
36
+ app = SnowTyperFactory(
37
+ name="release-channel",
38
+ help="Manages release channels of an application package",
39
+ )
40
+
41
+ log = logging.getLogger(__name__)
42
+
43
+
44
+ @app.command("list", requires_connection=True)
45
+ @with_project_definition()
46
+ @force_project_definition_v2()
47
+ def release_channel_list(
48
+ channel: Optional[str] = typer.Argument(
49
+ default=None,
50
+ show_default=False,
51
+ help="The release channel to list. If not provided, all release channels are listed.",
52
+ ),
53
+ **options,
54
+ ) -> CommandResult:
55
+ """
56
+ Lists the release channels available for an application package.
57
+ """
58
+
59
+ cli_context = get_cli_context()
60
+ ws = WorkspaceManager(
61
+ project_definition=cli_context.project_definition,
62
+ project_root=cli_context.project_root,
63
+ )
64
+ package_id = options["package_entity_id"]
65
+ channels = ws.perform_action(
66
+ package_id,
67
+ EntityActions.RELEASE_CHANNEL_LIST,
68
+ release_channel=channel,
69
+ )
70
+
71
+ if cli_context.output_format == OutputFormat.JSON:
72
+ return CollectionResult(channels)
73
+
74
+
75
+ @app.command("add-accounts", requires_connection=True)
76
+ @with_project_definition()
77
+ @force_project_definition_v2()
78
+ def release_channel_add_accounts(
79
+ channel: str = typer.Argument(
80
+ show_default=False,
81
+ help="The release channel to add accounts to.",
82
+ ),
83
+ target_accounts: str = typer.Option(
84
+ show_default=False,
85
+ help="The accounts to add to the release channel. Format has to be `org1.account1,org2.account2`.",
86
+ ),
87
+ **options,
88
+ ) -> CommandResult:
89
+ """
90
+ Adds accounts to a release channel.
91
+ """
92
+
93
+ cli_context = get_cli_context()
94
+ ws = WorkspaceManager(
95
+ project_definition=cli_context.project_definition,
96
+ project_root=cli_context.project_root,
97
+ )
98
+ package_id = options["package_entity_id"]
99
+ ws.perform_action(
100
+ package_id,
101
+ EntityActions.RELEASE_CHANNEL_ADD_ACCOUNTS,
102
+ release_channel=channel,
103
+ target_accounts=target_accounts.split(","),
104
+ )
105
+
106
+ return MessageResult("Successfully added accounts to the release channel.")
107
+
108
+
109
+ @app.command("remove-accounts", requires_connection=True)
110
+ @with_project_definition()
111
+ @force_project_definition_v2()
112
+ def release_channel_remove_accounts(
113
+ channel: str = typer.Argument(
114
+ show_default=False,
115
+ help="The release channel to remove accounts from.",
116
+ ),
117
+ target_accounts: str = typer.Option(
118
+ show_default=False,
119
+ help="The accounts to remove from the release channel. Format has to be `org1.account1,org2.account2`.",
120
+ ),
121
+ **options,
122
+ ) -> CommandResult:
123
+ """
124
+ Removes accounts from a release channel.
125
+ """
126
+
127
+ cli_context = get_cli_context()
128
+ ws = WorkspaceManager(
129
+ project_definition=cli_context.project_definition,
130
+ project_root=cli_context.project_root,
131
+ )
132
+ package_id = options["package_entity_id"]
133
+ ws.perform_action(
134
+ package_id,
135
+ EntityActions.RELEASE_CHANNEL_REMOVE_ACCOUNTS,
136
+ release_channel=channel,
137
+ target_accounts=target_accounts.split(","),
138
+ )
139
+
140
+ return MessageResult("Successfully removed accounts from the release channel.")
141
+
142
+
143
+ @app.command("add-version", requires_connection=True)
144
+ @with_project_definition()
145
+ @force_project_definition_v2()
146
+ def release_channel_add_version(
147
+ channel: str = typer.Argument(
148
+ show_default=False,
149
+ help="The release channel to add a version to.",
150
+ ),
151
+ version: str = typer.Option(
152
+ show_default=False,
153
+ help="The version to add to the release channel.",
154
+ ),
155
+ **options,
156
+ ) -> CommandResult:
157
+ """
158
+ Adds a version to a release channel.
159
+ """
160
+
161
+ cli_context = get_cli_context()
162
+ ws = WorkspaceManager(
163
+ project_definition=cli_context.project_definition,
164
+ project_root=cli_context.project_root,
165
+ )
166
+ package_id = options["package_entity_id"]
167
+ ws.perform_action(
168
+ package_id,
169
+ EntityActions.RELEASE_CHANNEL_ADD_VERSION,
170
+ release_channel=channel,
171
+ version=version,
172
+ )
173
+
174
+ return MessageResult(
175
+ f"Successfully added version {version} to the release channel."
176
+ )
177
+
178
+
179
+ @app.command("remove-version", requires_connection=True)
180
+ @with_project_definition()
181
+ @force_project_definition_v2()
182
+ def release_channel_remove_version(
183
+ channel: str = typer.Argument(
184
+ show_default=False,
185
+ help="The release channel to remove a version from.",
186
+ ),
187
+ version: str = typer.Option(
188
+ show_default=False,
189
+ help="The version to remove from the release channel.",
190
+ ),
191
+ **options,
192
+ ) -> CommandResult:
193
+ """
194
+ Removes a version from a release channel.
195
+ """
196
+
197
+ cli_context = get_cli_context()
198
+ ws = WorkspaceManager(
199
+ project_definition=cli_context.project_definition,
200
+ project_root=cli_context.project_root,
201
+ )
202
+ package_id = options["package_entity_id"]
203
+ ws.perform_action(
204
+ package_id,
205
+ EntityActions.RELEASE_CHANNEL_REMOVE_VERSION,
206
+ release_channel=channel,
207
+ version=version,
208
+ )
209
+
210
+ return MessageResult(
211
+ f"Successfully removed version {version} from the release channel."
212
+ )
@@ -0,0 +1,13 @@
1
+ # Copyright (c) 2024 Snowflake Inc.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
@@ -0,0 +1,165 @@
1
+ # Copyright (c) 2024 Snowflake Inc.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ from __future__ import annotations
16
+
17
+ import logging
18
+ from typing import Optional
19
+
20
+ import typer
21
+ from snowflake.cli._plugins.nativeapp.constants import DEFAULT_CHANNEL
22
+ from snowflake.cli._plugins.nativeapp.v2_conversions.compat import (
23
+ force_project_definition_v2,
24
+ )
25
+ from snowflake.cli._plugins.workspace.manager import WorkspaceManager
26
+ from snowflake.cli.api.cli_global_context import get_cli_context
27
+ from snowflake.cli.api.commands.decorators import with_project_definition
28
+ from snowflake.cli.api.commands.flags import like_option
29
+ from snowflake.cli.api.commands.snow_typer import SnowTyperFactory
30
+ from snowflake.cli.api.entities.common import EntityActions
31
+ from snowflake.cli.api.output.types import (
32
+ CollectionResult,
33
+ CommandResult,
34
+ MessageResult,
35
+ )
36
+
37
+ app = SnowTyperFactory(
38
+ name="release-directive",
39
+ help="Manages release directives of an application package",
40
+ )
41
+
42
+ log = logging.getLogger(__name__)
43
+
44
+
45
+ @app.command("list", requires_connection=True)
46
+ @with_project_definition()
47
+ @force_project_definition_v2()
48
+ def release_directive_list(
49
+ like: str = like_option(
50
+ help_example="`snow app release-directive list --like='my%'` lists all release directives starting with 'my'",
51
+ ),
52
+ channel: Optional[str] = typer.Option(
53
+ default=None,
54
+ show_default=False,
55
+ help="The release channel to use when listing release directives. If not provided, release directives from all release channels are listed.",
56
+ ),
57
+ **options,
58
+ ) -> CommandResult:
59
+ """
60
+ Lists release directives in an application package.
61
+ If no release channel is specified, release directives for all channels are listed.
62
+ If a release channel is specified, only release directives for that channel are listed.
63
+
64
+ If `--like` is provided, only release directives matching the SQL pattern are listed.
65
+ """
66
+
67
+ cli_context = get_cli_context()
68
+ ws = WorkspaceManager(
69
+ project_definition=cli_context.project_definition,
70
+ project_root=cli_context.project_root,
71
+ )
72
+ package_id = options["package_entity_id"]
73
+ result = ws.perform_action(
74
+ package_id,
75
+ EntityActions.RELEASE_DIRECTIVE_LIST,
76
+ release_channel=channel,
77
+ like=like,
78
+ )
79
+
80
+ return CollectionResult(result)
81
+
82
+
83
+ @app.command("set", requires_connection=True)
84
+ @with_project_definition()
85
+ @force_project_definition_v2()
86
+ def release_directive_set(
87
+ directive: str = typer.Argument(
88
+ show_default=False,
89
+ help="Name of the release directive to set",
90
+ ),
91
+ channel: str = typer.Option(
92
+ DEFAULT_CHANNEL,
93
+ help="Name of the release channel to use",
94
+ ),
95
+ target_accounts: Optional[str] = typer.Option(
96
+ None,
97
+ show_default=False,
98
+ help="List of the accounts to apply the release directive to. Format has to be `org1.account1,org2.account2`",
99
+ ),
100
+ version: str = typer.Option(
101
+ show_default=False,
102
+ help="Version of the application package to use",
103
+ ),
104
+ patch: int = typer.Option(
105
+ show_default=False,
106
+ help="Patch number to use for the selected version",
107
+ ),
108
+ **options,
109
+ ) -> CommandResult:
110
+ """
111
+ Sets a release directive.
112
+
113
+ target_accounts cannot be specified for default release directives.
114
+ target_accounts field is required when creating a new non-default release directive.
115
+ """
116
+
117
+ cli_context = get_cli_context()
118
+ ws = WorkspaceManager(
119
+ project_definition=cli_context.project_definition,
120
+ project_root=cli_context.project_root,
121
+ )
122
+ package_id = options["package_entity_id"]
123
+ ws.perform_action(
124
+ package_id,
125
+ EntityActions.RELEASE_DIRECTIVE_SET,
126
+ release_directive=directive,
127
+ version=version,
128
+ patch=patch,
129
+ target_accounts=None if target_accounts is None else target_accounts.split(","),
130
+ release_channel=channel,
131
+ )
132
+ return MessageResult("Successfully set release directive.")
133
+
134
+
135
+ @app.command("unset", requires_connection=True)
136
+ @with_project_definition()
137
+ @force_project_definition_v2()
138
+ def release_directive_unset(
139
+ directive: str = typer.Argument(
140
+ show_default=False,
141
+ help="Name of the release directive",
142
+ ),
143
+ channel: str = typer.Option(
144
+ DEFAULT_CHANNEL,
145
+ help="Name of the release channel to use",
146
+ ),
147
+ **options,
148
+ ) -> CommandResult:
149
+ """
150
+ Unsets a release directive.
151
+ """
152
+
153
+ cli_context = get_cli_context()
154
+ ws = WorkspaceManager(
155
+ project_definition=cli_context.project_definition,
156
+ project_root=cli_context.project_root,
157
+ )
158
+ package_id = options["package_entity_id"]
159
+ ws.perform_action(
160
+ package_id,
161
+ EntityActions.RELEASE_DIRECTIVE_UNSET,
162
+ release_directive=directive,
163
+ release_channel=channel,
164
+ )
165
+ return MessageResult(f"Successfully unset release directive {directive}.")
@@ -1,3 +1,4 @@
1
+ from dataclasses import dataclass
1
2
  from typing import Optional
2
3
 
3
4
  from snowflake.cli._plugins.nativeapp.constants import (
@@ -8,25 +9,15 @@ from snowflake.cli._plugins.nativeapp.exceptions import (
8
9
  ApplicationCreatedExternallyError,
9
10
  )
10
11
  from snowflake.cli._plugins.stage.manager import StageManager
12
+ from snowflake.cli.api.project.util import to_identifier
11
13
 
12
14
 
15
+ @dataclass
13
16
  class SameAccountInstallMethod:
14
17
  _requires_created_by_cli: bool
15
- _from_release_directive: bool
16
- version: Optional[str]
17
- patch: Optional[int]
18
-
19
- def __init__(
20
- self,
21
- requires_created_by_cli: bool,
22
- version: Optional[str] = None,
23
- patch: Optional[int] = None,
24
- from_release_directive: bool = False,
25
- ):
26
- self._requires_created_by_cli = requires_created_by_cli
27
- self.version = version
28
- self.patch = patch
29
- self._from_release_directive = from_release_directive
18
+ version: Optional[str] = None
19
+ patch: Optional[int] = None
20
+ _from_release_directive: bool = False
30
21
 
31
22
  @classmethod
32
23
  def unversioned_dev(cls):
@@ -39,7 +30,7 @@ class SameAccountInstallMethod:
39
30
 
40
31
  @classmethod
41
32
  def release_directive(cls):
42
- return cls(False, from_release_directive=True)
33
+ return cls(False, _from_release_directive=True)
43
34
 
44
35
  @property
45
36
  def is_dev_mode(self) -> bool:
@@ -53,8 +44,9 @@ class SameAccountInstallMethod:
53
44
  return ""
54
45
 
55
46
  if self.version:
47
+ version_clause = f"version {to_identifier(self.version)}"
56
48
  patch_clause = f"patch {self.patch}" if self.patch else ""
57
- return f"using version {self.version} {patch_clause}"
49
+ return f"using {version_clause} {patch_clause}"
58
50
 
59
51
  stage_name = StageManager.quote_stage_name(stage_fqn)
60
52
  return f"using {stage_name}"
@@ -11,12 +11,83 @@
11
11
  # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
12
  # See the License for the specific language governing permissions and
13
13
  # limitations under the License.
14
+ from __future__ import annotations
15
+
14
16
  from typing import NoReturn
15
17
 
16
18
  from click import ClickException
17
19
  from snowflake.cli._plugins.nativeapp.sf_facade_constants import UseObjectType
20
+ from snowflake.cli.api.errno import (
21
+ APPLICATION_FILE_NOT_FOUND_ON_STAGE,
22
+ APPLICATION_INSTANCE_EMPTY_SETUP_SCRIPT,
23
+ APPLICATION_INSTANCE_FAILED_TO_RUN_SETUP_SCRIPT,
24
+ APPLICATION_INSTANCE_NO_ACTIVE_WAREHOUSE_FOR_CREATE_OR_UPGRADE,
25
+ APPLICATION_NO_LONGER_AVAILABLE,
26
+ APPLICATION_PACKAGE_CANNOT_SET_EXTERNAL_DISTRIBUTION_WITH_SPCS,
27
+ APPLICATION_PACKAGE_MANIFEST_CONTAINER_IMAGE_URL_BAD_VALUE,
28
+ APPLICATION_PACKAGE_MANIFEST_SPECIFIED_FILE_NOT_FOUND,
29
+ APPLICATION_PACKAGE_PATCH_DOES_NOT_EXIST,
30
+ CANNOT_GRANT_NON_MANIFEST_PRIVILEGE,
31
+ CANNOT_GRANT_OBJECT_NOT_IN_APP_PACKAGE,
32
+ CANNOT_GRANT_RESTRICTED_PRIVILEGE_TO_APP_PACKAGE_SHARE,
33
+ CANNOT_UPGRADE_FROM_LOOSE_FILES_TO_VERSION,
34
+ CANNOT_UPGRADE_FROM_VERSION_TO_LOOSE_FILES,
35
+ NATIVE_APPLICATION_MANIFEST_GENERIC_JSON_ERROR,
36
+ NATIVE_APPLICATION_MANIFEST_INVALID_SYNTAX,
37
+ NATIVE_APPLICATION_MANIFEST_UNEXPECTED_VALUE_FOR_PROPERTY,
38
+ NATIVE_APPLICATION_MANIFEST_UNRECOGNIZED_FIELD,
39
+ NO_REFERENCE_SET_FOR_DEFINITION,
40
+ NO_VERSIONS_AVAILABLE_FOR_ACCOUNT,
41
+ NOT_SUPPORTED_ON_DEV_MODE_APPLICATIONS,
42
+ ONLY_SUPPORTED_ON_DEV_MODE_APPLICATIONS,
43
+ ROLE_NOT_ASSIGNED,
44
+ SNOWSERVICES_IMAGE_MANIFEST_NOT_FOUND,
45
+ SNOWSERVICES_IMAGE_REPOSITORY_FAILS_TO_RETRIEVE_IMAGE_HASH_NEW,
46
+ SNOWSERVICES_IMAGE_REPOSITORY_IMAGE_IMPORT_TO_NATIVE_APP_FAIL,
47
+ VIEW_EXPANSION_FAILED,
48
+ )
18
49
  from snowflake.connector import DatabaseError, Error, ProgrammingError
19
50
 
51
+ # Reasons why an `alter application ... upgrade` might fail
52
+ UPGRADE_RESTRICTION_CODES = {
53
+ CANNOT_UPGRADE_FROM_LOOSE_FILES_TO_VERSION,
54
+ CANNOT_UPGRADE_FROM_VERSION_TO_LOOSE_FILES,
55
+ ONLY_SUPPORTED_ON_DEV_MODE_APPLICATIONS,
56
+ NOT_SUPPORTED_ON_DEV_MODE_APPLICATIONS,
57
+ APPLICATION_NO_LONGER_AVAILABLE,
58
+ }
59
+
60
+ CREATE_OR_UPGRADE_APPLICATION_EXPECTED_USER_ERROR_CODES = {
61
+ APPLICATION_INSTANCE_FAILED_TO_RUN_SETUP_SCRIPT,
62
+ NATIVE_APPLICATION_MANIFEST_GENERIC_JSON_ERROR,
63
+ APPLICATION_INSTANCE_NO_ACTIVE_WAREHOUSE_FOR_CREATE_OR_UPGRADE,
64
+ # when setup script/manifest/readme isn't on the stage
65
+ APPLICATION_FILE_NOT_FOUND_ON_STAGE,
66
+ NATIVE_APPLICATION_MANIFEST_UNRECOGNIZED_FIELD,
67
+ SNOWSERVICES_IMAGE_MANIFEST_NOT_FOUND,
68
+ # user tried to clone tables and it failed
69
+ VIEW_EXPANSION_FAILED,
70
+ # user tried to do something with a role that wasn't assigned to them
71
+ ROLE_NOT_ASSIGNED,
72
+ APPLICATION_PACKAGE_MANIFEST_SPECIFIED_FILE_NOT_FOUND,
73
+ SNOWSERVICES_IMAGE_REPOSITORY_IMAGE_IMPORT_TO_NATIVE_APP_FAIL,
74
+ APPLICATION_PACKAGE_PATCH_DOES_NOT_EXIST,
75
+ APPLICATION_PACKAGE_MANIFEST_CONTAINER_IMAGE_URL_BAD_VALUE,
76
+ SNOWSERVICES_IMAGE_REPOSITORY_FAILS_TO_RETRIEVE_IMAGE_HASH_NEW,
77
+ NATIVE_APPLICATION_MANIFEST_UNEXPECTED_VALUE_FOR_PROPERTY,
78
+ CANNOT_GRANT_NON_MANIFEST_PRIVILEGE,
79
+ NO_REFERENCE_SET_FOR_DEFINITION,
80
+ NATIVE_APPLICATION_MANIFEST_INVALID_SYNTAX,
81
+ CANNOT_GRANT_OBJECT_NOT_IN_APP_PACKAGE,
82
+ APPLICATION_PACKAGE_MANIFEST_SPECIFIED_FILE_NOT_FOUND,
83
+ # user tried installing from release directive and there are none available
84
+ NO_VERSIONS_AVAILABLE_FOR_ACCOUNT,
85
+ APPLICATION_PACKAGE_MANIFEST_CONTAINER_IMAGE_URL_BAD_VALUE,
86
+ APPLICATION_INSTANCE_EMPTY_SETUP_SCRIPT,
87
+ APPLICATION_PACKAGE_CANNOT_SET_EXTERNAL_DISTRIBUTION_WITH_SPCS,
88
+ CANNOT_GRANT_RESTRICTED_PRIVILEGE_TO_APP_PACKAGE_SHARE,
89
+ }
90
+
20
91
 
21
92
  def handle_unclassified_error(err: Error | Exception, context: str) -> NoReturn:
22
93
  """
@@ -115,3 +186,12 @@ class InsufficientPrivilegesError(ClickException):
115
186
  if role:
116
187
  message += f" using role: {role}"
117
188
  super().__init__(message)
189
+
190
+
191
+ class UpgradeApplicationRestrictionError(UserInputError):
192
+ """
193
+ Raised when an alter application ... upgrade fails due to user error.
194
+ Must be caught and handled by the caller of an upgrade_application
195
+ """
196
+
197
+ pass